Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 16 Nov 1995 15:21:50 +0100 (MET)
From:      J Wunsch <j@ida.interface-business.de>
To:        freebsd-scsi@freebsd.org
Subject:   SCSI reprobe
Message-ID:  <199511161421.PAA00329@ida.interface-business.de>

next in thread | raw e-mail | index | archive | help
Hi all,

i've noticed that the SCSI reprobe always hung my ahc controller
(scsi -f /dev/... -r).

After some more investigation, it's quite clear that it's caused by a
bunch of assumptions that all the probe and initialize functions of
the various devices are only being called at system init time, and
therefore could not use interrupts.  I'm wondering why everything used
to work with an aha controller...  For ahc, it always ended up in the
controller code hanging inside an ahc_poll() which should not have
been called in the first place once the kernel has been initialized.

I've made the following changes in order to pass the SCSI_NOSLEEP |
SCSI_NOMASK flags down from higher-level functions, depending on
whether the bus/device probe functions are being called by the ioctl,
or by the adapter initialization code (comments continued below):

--- scsiconf.c.orig	Mon Oct  9 11:08:52 1995
+++ scsiconf.c	Thu Nov 16 15:09:17 1995
@@ -647,7 +647,8 @@
 #define SCSI_DELAY 2
 #endif	/* SCSI_DELAY */
 	DELAY(1000000 * SCSI_DELAY);
-	scsi_probe_bus(scsibus,-1,-1);
+	/* use poll mode at init time */
+	scsi_probe_bus(scsibus, -1, -1, SCSI_NOSLEEP | SCSI_NOMASK);
 }
 
 /*
@@ -660,11 +661,11 @@
 {
 	if (bus == -1) {
 		for(bus = 0; bus < scbusses->nelem; bus++) {
-			scsi_probe_bus(bus, targ, lun);
+			scsi_probe_bus(bus, targ, lun, 0);
 		}
 		return 0;
 	} else {
-		return scsi_probe_bus(bus, targ, lun);
+		return scsi_probe_bus(bus, targ, lun, 0);
 	}
 }
 
@@ -845,7 +846,7 @@
  * targ and lun optionally narrow the search if not -1
  */
 errval
-scsi_probe_bus(int bus, int targ, int lun)
+scsi_probe_bus(int bus, int targ, int lun, int flags)
 {
 	struct scsibus_data *scsibus_data ;
 	int	maxtarg,mintarg,maxlun,minlun;
@@ -906,7 +907,8 @@
 			sc_link->target = targ;
 			sc_link->lun = lun;
 			sc_link->quirks = 0;
-			bestmatch = scsi_probedev(sc_link, &maybe_more, &type);
+			bestmatch = scsi_probedev(sc_link, &maybe_more, &type,
+						  flags);
 #ifdef NEW_SCSICONF
 			if (bestmatch) {
 			    sc_link->quirks = bestmatch->quirks;
@@ -987,10 +989,11 @@
  * entry.
  */
 struct scsidevs *
-scsi_probedev(sc_link, maybe_more, type_p)
+scsi_probedev(sc_link, maybe_more, type_p, flags)
 	boolean *maybe_more;
 	struct scsi_link *sc_link;
 	int *type_p;
+	int flags;
 {
 	u_int8  target = sc_link->target;
 	u_int8  lu = sc_link->lun;
@@ -1018,9 +1021,9 @@
 		sc_link->flags &= ~(SDEV_DB1 | SDEV_DB2 | SDEV_DB3 | SDEV_DB4);
 #endif	/* SCSIDEBUG */
 	/* catch unit attn */
-	scsi_test_unit_ready(sc_link, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT);
+	scsi_test_unit_ready(sc_link, flags | SCSI_SILENT);
 #ifdef	DOUBTFULL
-	switch (scsi_test_unit_ready(sc_link, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT)) {
+	switch (scsi_test_unit_ready(sc_link, flags | SCSI_SILENT)) {
 	case 0:		/* said it WAS ready */
 	case EBUSY:		/* replied 'NOT READY' but WAS present, continue */
 	case ENXIO:
@@ -1035,11 +1038,11 @@
 #ifdef	SCSI_2_DEF
 	/* some devices need to be told to go to SCSI2 */
 	/* However some just explode if you tell them this.. leave it out */
-	scsi_change_def(sc_link, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT);
+	scsi_change_def(sc_link, flags | SCSI_SILENT);
 #endif /*SCSI_2_DEF */
 
 	/* Now go ask the device all about itself */
-	if (scsi_inquire(sc_link, inqbuf, SCSI_NOSLEEP | SCSI_NOMASK) != 0) {
+	if (scsi_inquire(sc_link, inqbuf, flags) != 0) {
 		return (struct scsidevs *) 0;
 	}
 
--- scsiconf.h.orig	Tue May 30 10:13:47 1995
+++ scsiconf.h	Thu Nov 16 13:35:13 1995
@@ -420,8 +420,8 @@
 errval scsi_inquire( struct scsi_link *sc_link,
 			struct scsi_inquiry_data *inqbuf, u_int32 flags);
 errval scsi_prevent( struct scsi_link *sc_link, u_int32 type,u_int32 flags);
-errval scsi_probe_bus __P((int, int, int));
-errval scsi_probe_busses __P(( int, int, int));
+errval scsi_probe_bus __P((int bus, int targ, int lun, int flags));
+errval scsi_probe_busses __P(( int bus, int targ, int lun));
 errval scsi_start_unit( struct scsi_link *sc_link, u_int32 flags);
 errval scsi_stop_unit(struct scsi_link *sc_link, u_int32 eject, u_int32 flags);
 void scsi_done(struct scsi_xfer *xs);
--- su.c.orig	Wed May  3 20:09:20 1995
+++ su.c	Thu Nov 16 13:38:43 1995
@@ -186,7 +186,7 @@
 		 */
 		int bus = SCSI_BUS(dev), lun = SCSI_LUN(dev), id =  SCSI_ID(dev);
 
-		if (scsi_probe_bus(bus, id, lun) || getsws(dev, type, &bdev, &cdev,
+		if (scsi_probe_bus(bus, id, lun, 0) || getsws(dev, type, &bdev, &cdev,
 		&base))
 			return ENXIO;
 	}


This basically fixes the problem, but opens up another can of worms
whenever the reprobe actually finds a new device, and wants to wire
this one into the system.  In my case, the reprobe found a new tape
drive, and these lines in st.c:

errval
stattach(struct scsi_link *sc_link)
{
...
	if (st_mode_sense(unit, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT,
	                        ^^^^^^^^^^^^^^^^^^^^^^^^^^
		NULL, 0, 0)) {
		printf("drive offline");
	} else {
		printf("density code 0x%lx, ", st->media_density);
		if (!scsi_test_unit_ready(sc_link, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT)) {
		                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^


...caused it to hang again.  I assume this is a basic problem also
inside the other device-specific driver, and gave up by now.  Perhaps
there's a better solution to base the decision of polled
vs. intterupt-controlled mode on?

(The above diff's are made on a 2.0.5 system, but the problem persists
on -current, and it seems to be adapter-independent in its nature.)

-- 
J"org Wunsch					       Unix support engineer
joerg_wunsch@interface-business.de
					[private: http://www.sax.de/~joerg/]



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199511161421.PAA00329>