Subject: kern/6090: need user requestd SCSI bus resets and beefier midlayer for that
To: None <gnats-bugs@gnats.netbsd.org>
From: Matthew Jacob <mjacob@nas.nasa.gov>
List: netbsd-bugs
Date: 09/02/1998 19:37:29
>Number:         6090
>Category:       kern
>Synopsis:       need user requestd SCSI bus resets and beefier midlayer for that
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    kern-bug-people (Kernel Bug People)
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Wed Sep  2 19:50:01 1998
>Last-Modified:
>Originator:     
>Organization:
	NASA Ames
>Release:        090298
>Environment:
	
System: NetBSD mathom.nas.nasa.gov 1.3H NetBSD 1.3H (ALPHA) #11: Wed Sep 2 10:47:26 PDT 1998 mjacob@mathom.nas.nasa.gov:/space/NetBSD-current/src/sys/arch/alpha/compile/ALPHA alpha


>Description:

A number of SCSI bus hang situations can only be solved by a SCSI bus
reset being issued. It would be desirable to have this not be the case,
and handle all via timeouts and BDRs, but it still is necessary.

On top of that the midlayer needs to somehow handle retries for a
command destroyed by a SCSI bus reset differently than just a plain EIO.
Alternatively, having the done function for target drivers be expanded,
or have the interpret_sense function be expanded to give the target
driver more explicit control wouldn't be a bad thing either.

The current SCSI_RESET flag is supposed to reset a device (and is currently
misinterpreted by the ncr driver as a SCSI bus reset). It still is
desirable to reset a device as opposed to a bus, and this method
probably doesn't need to change.


>How-To-Repeat:
	
>Fix:

A couple of observations and a suggested fix with diffs against 1.3
(but could really apply in -current):

1) If a device has set up retries, it's making a statement that the
command being issued can be rerun up to that number of retries.
This could be used to decide whether that command, if destroyed
by a SCSI bus reset, could be rerun by the middle layer. This
really also predicates a new adapter return code (XS_RESET).

2) open_target_lu/close_target_lu routines in the scsipi_adapter
structure are completely unused in this BSD port. I suggest
replacing them with an adapter_ioctl entry point (and a 'notused')
entry point. One adapter_ioctl command could be to reset a BUS.

Index: dev/scsipi/scsiconf.h
===================================================================
RCS file: /cvs-src/NetBSD-mss3/src/sys/dev/scsipi/scsiconf.h,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 scsiconf.h
--- scsiconf.h  1997/11/14 00:00:14     1.1.1.1
+++ scsiconf.h  1998/08/26 00:36:46
@@ -85,6 +85,7 @@
 void   scsi_print_sense __P((struct scsipi_xfer *, int));
 #endif
 int    scsi_probe_busses __P((int, int, int));
+int    scsi_reset_bus __P((int));
 int    scsi_scsipi_cmd __P((struct scsipi_link *, struct scsipi_generic *,
            int cmdlen, u_char *data_addr, int datalen, int retries,
            int timeout, struct buf *bp, int flags));
Index: dev/scsipi/scsipi_base.c
===================================================================
RCS file: /cvs-src/NetBSD-mss3/src/sys/dev/scsipi/scsipi_base.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 scsipi_base.c
--- scsipi_base.c       1997/11/14 00:00:14     1.1.1.1
+++ scsipi_base.c       1998/09/03 00:15:43
@@ -469,10 +469,30 @@
                break;
  
        case XS_SELTIMEOUT:
-               /* XXX Disable device? */
-               error = EIO;
+               if ((xs->flags & SCSI_AUTOCONF) == 0) {
+                       /*
+                        * Not right. We should probably just plain
+                        * retry, but we'll let the busy count predominate.
+                        */
+                       goto retry;
+               } 
+               error = ENODEV;
                break;
 
+       case XS_RESET:
+               /*
+                * If a command had retries, then it can be restarted
+                * with impunity.
+                */ 
+               if (xs->retries) {      
+                       SC_DEBUG(xs->sc_link, SDEV_DB3,
+                           ("restarting command destroyed by reset\n"));
+                       xs->error = XS_NOERROR;
+                       xs->flags &= ~ITSDONE;    
+                       return (ERESTART);
+               } 
+               error = EIO;
+               break;
        default:  
                (*xs->sc_link->sc_print_addr)(xs->sc_link);
                printf("unknown error category from scsipi driver\n");
Index: dev/scsipi/scsipi_ioctl.c      
===================================================================
RCS file: /cvs-src/NetBSD-mss3/src/sys/dev/scsipi/scsipi_ioctl.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 scsipi_ioctl.c
--- scsipi_ioctl.c      1997/11/14 00:00:14     1.1.1.1
+++ scsipi_ioctl.c      1998/09/02 01:41:12
@@ -364,6 +364,12 @@
                return (0); 
        }
 #if NSCSIBUS > 0
+       case SCIOBRESET:
+               if (sc_link->type != BUS_SCSI) {
+                       return (EINVAL);
+               } else {
+                       return (scsi_reset_bus(sc_link->scsipi_scsi.scsibus));
+               }
        case SCIOCREPROBE: { 
                struct scsi_addr *sca = (struct scsi_addr *)addr;
                if (sca->type != TYPE_SCSI)
@@ -416,6 +422,7 @@
                return (ENODEV);
        }   
 #endif
+       
        default: 
                return (ENOTTY);
        }  


Index: dev/scsipi/scsipiconf.h
===================================================================
RCS file: /cvs-src/NetBSD-mss3/src/sys/dev/scsipi/scsipiconf.h,v
retrieving revision 1.2
diff -u -r1.2 scsipiconf.h
--- scsipiconf.h        1998/07/16 01:10:19     1.2  
+++ scsipiconf.h        1998/09/03 00:13:26
@@ -86,6 +86,7 @@

 struct buf;
 struct scsipi_xfer;
+struct scsipi_link; 

 struct scsipi_generic {
        u_int8_t opcode;
@@ -137,11 +138,16 @@
 struct scsipi_adapter {
        int     (*scsipi_cmd) __P((struct scsipi_xfer *));
        void    (*scsipi_minphys) __P((struct buf *));
-       int     (*open_target_lu) __P((void)); 
-       int     (*close_target_lu) __P((void));
+       int     (*adapter_ioctl) __P((int, struct scsipi_link *));
+       int     (*notused) __P((void));
 };
 
 /*
+ * Adapter Commands
+ */
+#define        ADPCMD_BRESET   0
+
+/*
  * This structure describes the connection between an adapter driver and
  * a device driver, and is used by each to call services provided by
  * the other, and to allow generic scsipi glue code to call these services
@@ -283,6 +295,7 @@
 #define XS_SELTIMEOUT  3       /* The device timed out.. turned off?     */
 #define XS_TIMEOUT     4       /* The Timeout reported was caught by SW  */
 #define XS_BUSY                5       /* The device busy, try again later?
  */
+#define        XS_RESET        6       /* SCSI Bus reset */

 /*
  * This describes matching information for scsipi_inqmatch().  The more things
Index: sys/scsiio.h
===================================================================
RCS file: /cvs-src/NetBSD-mss3/src/sys/sys/scsiio.h,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 scsiio.h
--- scsiio.h    1997/11/14 00:00:58     1.1.1.1 
+++ scsiio.h    1998/09/02 01:38:26
@@ -74,6 +74,6 @@
 #define SCIOCDECONFIG  _IO('Q', 5)     /* please dissappear */
 #define SCIOCRECONFIG  _IO('Q', 6)     /* please check again */
 #define SCIOCRESET     _IO('Q', 7)     /* reset the device */
-
+#define        SCIOBRESET      _IO('Q', 8)     /* reset bus the device is on */
 
 #endif /* _SYS_SCSIIO_H_ */
Index: dev/scsipi/scsiconf.c
===================================================================
RCS file: /cvs-src/NetBSD-mss3/src/sys/dev/scsipi/scsiconf.c,v
retrieving revision 1.2
diff -u -r1.2 scsiconf.c
--- scsiconf.c  1998/03/11 19:48:32     1.2
+++ scsiconf.c  1998/09/02 21:52:51
@@ -260,6 +260,30 @@  
 }      
                
 /*
+ * Reset the identified scsi bus. It must be already set up,
+ * and this will only work if the adapter has a adapter ioctl
+ * entry point.
+ */
+int                     
+scsi_reset_bus(bus)
+       int bus;
+{
+       struct scsipi_link *sc_link; 
+       struct scsibus_softc *scsi;
+
+       if (bus < 0 || bus >= scsibus_cd.cd_ndevs ||
+           scsibus_cd.cd_devs[bus] == NULL) { 
+               return (ENXIO);
+       }       
+       scsi = scsibus_cd.cd_devs[bus];
+       sc_link = scsi->adapter_link;
+       if (sc_link->adapter->adapter_ioctl == NULL) {
+               return (ENODEV);
+       } 
+       return ((sc_link->adapter->adapter_ioctl)(ADPCMD_BRESET, sc_link));
+}
+
+/*
  * Probe the requested scsi bus. It must be already set up.
  * target and lun optionally narrow the search if not -1
  */    

>Audit-Trail:
>Unformatted: