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>