Module Name:    src
Committed By:   kardel
Date:           Thu Mar 28 10:44:29 UTC 2019

Modified Files:
        src/sys/dev/scsipi: scsi_spc.h scsiconf.c scsipi_base.c scsipiconf.c
            scsipiconf.h
        src/sys/dev/usb: umass_scsipi.c

Log Message:
Add reading of supported opcodes and their timeouts
at attachment time. Though this information is optional,
it allows to override our fixed timeouts with device
provided timeouts. These timeouts will override the
hardcoded values if the device provided timeouts
exceed the hardcoded values and are less than a day.

Using the device provided timeouts avoids premature
device resets and unreliable operation due to
inadequate timeouts.

Due to the limited implementations of USB
umass devices this feature is disabled for all
umass attached devices.


To generate a diff of this commit:
cvs rdiff -u -r1.5 -r1.6 src/sys/dev/scsipi/scsi_spc.h
cvs rdiff -u -r1.283 -r1.284 src/sys/dev/scsipi/scsiconf.c
cvs rdiff -u -r1.181 -r1.182 src/sys/dev/scsipi/scsipi_base.c
cvs rdiff -u -r1.44 -r1.45 src/sys/dev/scsipi/scsipiconf.c
cvs rdiff -u -r1.129 -r1.130 src/sys/dev/scsipi/scsipiconf.h
cvs rdiff -u -r1.60 -r1.61 src/sys/dev/usb/umass_scsipi.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/scsipi/scsi_spc.h
diff -u src/sys/dev/scsipi/scsi_spc.h:1.5 src/sys/dev/scsipi/scsi_spc.h:1.6
--- src/sys/dev/scsipi/scsi_spc.h:1.5	Sat Feb  6 23:13:59 2010
+++ src/sys/dev/scsipi/scsi_spc.h	Thu Mar 28 10:44:29 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: scsi_spc.h,v 1.5 2010/02/06 23:13:59 cegger Exp $	*/
+/*	$NetBSD: scsi_spc.h,v 1.6 2019/03/28 10:44:29 kardel Exp $	*/
 
 /*-
  * Copyright (c) 2005 The NetBSD Foundation, Inc.
@@ -406,6 +406,70 @@ struct scsi_reserve_release_10_idparam {
  */
 
 /*
+ * MAINTENANCE_IN[REPORT SUPPORTED OPERATION CODES]
+ */
+#define SCSI_MAINTENANCE_IN		0xA3
+
+struct scsi_repsuppopcode {
+	u_int8_t opcode;
+	u_int8_t svcaction;
+#define RSOC_REPORT_SUPPORTED_OPCODES	0x0C
+
+	u_int8_t repoption;
+#define RSOC_ALL           0x00 /* report all */
+#define RSOC_ONE           0x01 /* report one */
+#define RSOC_ONESACD       0x02 /* report one or CHECK CONDITION */
+#define RSOC_ONESA         0x03 /* report one mark presense in data */
+#define RSOC_RCTD          0x80 /* report timeouts */
+
+	u_int8_t reqopcode;
+	u_int8_t reqsvcaction[2];
+	u_int8_t alloclen[4];
+	u_int8_t _res0;
+	u_int8_t control;
+};
+
+struct scsi_repsupopcode_all_commands_descriptor {
+        u_int8_t opcode;
+        u_int8_t _res0;
+        u_int8_t serviceaction[2];
+        u_int8_t _res1;
+        u_int8_t flags;
+#define RSOC_ACD_CTDP         0x02    /* timeouts present */
+#define RSOC_ACD_SERVACTV     0x01    /* service action valid */
+        u_int8_t cdblen[2];
+};
+
+struct scsi_repsupopcode_one_command_descriptor {
+        u_int8_t _res0;
+        u_int8_t support;
+#define RSOC_OCD_CTDP              0x80 /* timeouts present */
+#define RSOC_OCD_SUP_NOT_AVAIL     0x00 /* not available */
+#define RSOC_OCD_SUP_NOT_SUPP      0x01 /* not supported */
+#define RSOC_OCD_SUP_SUPP_STD      0x03 /* supported - standard */
+#define RSOC_OCD_SUP_SUPP_VENDOR   0x05 /* supported - vendor */
+#define RSOC_OCD_SUP               0x07 /* mask for support field */
+
+        u_int8_t cdblen[2];
+        /*
+	 * u_int8_t usage[0...]- cdblen bytes
+	 * usage data
+	 */
+	/*
+	 * scsi_repsupopcode_timeouts_descriptor
+	 * if  RSOC_OCD_CTDP is set
+	 */
+};
+
+struct scsi_repsupopcode_timeouts_descriptor {
+        u_int8_t descriptor_length[2];
+        u_int8_t _res0;
+        u_int8_t cmd_specific;
+        u_int8_t nom_process_timeout[4];
+        u_int8_t cmd_process_timeout[4];
+};
+
+/*
  * REQUEST SENSE
  */
 

Index: src/sys/dev/scsipi/scsiconf.c
diff -u src/sys/dev/scsipi/scsiconf.c:1.283 src/sys/dev/scsipi/scsiconf.c:1.284
--- src/sys/dev/scsipi/scsiconf.c:1.283	Sat Jan 12 13:59:53 2019
+++ src/sys/dev/scsipi/scsiconf.c	Thu Mar 28 10:44:29 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: scsiconf.c,v 1.283 2019/01/12 13:59:53 tsutsui Exp $	*/
+/*	$NetBSD: scsiconf.c,v 1.284 2019/03/28 10:44:29 kardel Exp $	*/
 
 /*-
  * Copyright (c) 1998, 1999, 2004 The NetBSD Foundation, Inc.
@@ -48,7 +48,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: scsiconf.c,v 1.283 2019/01/12 13:59:53 tsutsui Exp $");
+__KERNEL_RCSID(0, "$NetBSD: scsiconf.c,v 1.284 2019/03/28 10:44:29 kardel Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -500,9 +500,11 @@ scsibusprint(void *aux, const char *pnp)
 	strnvisx(revision, sizeof(revision), inqbuf->revision, 4,
 	    VIS_TRIM|VIS_SAFE|VIS_OCTAL);
 
-	aprint_normal(" target %d lun %d: <%s, %s, %s> %s %s",
-	    target, lun, vendor, product, revision, dtype,
-	    inqbuf->removable ? "removable" : "fixed");
+	aprint_normal(" target %d lun %d: <%s, %s, %s> %s %s%s",
+		      target, lun, vendor, product, revision, dtype,
+		      inqbuf->removable ? "removable" : "fixed",
+		      (sa->sa_periph->periph_opcs != NULL)
+		        ? " timeout-info" : "");
 
 	return (UNCONF);
 }
@@ -1018,6 +1020,13 @@ scsi_probe_device(struct scsibus_softc *
 	if ((cf = config_search_loc(config_stdsubmatch, sc->sc_dev,
 	     "scsibus", locs, &sa)) != NULL) {
 		scsipi_insert_periph(chan, periph);
+
+		/*
+		 * determine supported opcodes and
+		 * timeouts if available
+		 */
+		scsipi_get_opcodeinfo(periph);
+
 		/*
 		 * XXX Can't assign periph_dev here, because we'll
 		 * XXX need it before config_attach() returns.  Must

Index: src/sys/dev/scsipi/scsipi_base.c
diff -u src/sys/dev/scsipi/scsipi_base.c:1.181 src/sys/dev/scsipi/scsipi_base.c:1.182
--- src/sys/dev/scsipi/scsipi_base.c:1.181	Tue Feb  5 11:11:32 2019
+++ src/sys/dev/scsipi/scsipi_base.c	Thu Mar 28 10:44:29 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: scsipi_base.c,v 1.181 2019/02/05 11:11:32 mrg Exp $	*/
+/*	$NetBSD: scsipi_base.c,v 1.182 2019/03/28 10:44:29 kardel Exp $	*/
 
 /*-
  * Copyright (c) 1998, 1999, 2000, 2002, 2003, 2004 The NetBSD Foundation, Inc.
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: scsipi_base.c,v 1.181 2019/02/05 11:11:32 mrg Exp $");
+__KERNEL_RCSID(0, "$NetBSD: scsipi_base.c,v 1.182 2019/03/28 10:44:29 kardel Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_scsi.h"
@@ -84,6 +84,8 @@ static void	scsipi_channel_freeze_locked
 static void	scsipi_adapter_lock(struct scsipi_adapter *adapt);
 static void	scsipi_adapter_unlock(struct scsipi_adapter *adapt);
 
+static void	scsipi_update_timeouts(struct scsipi_xfer *xs);
+
 static struct pool scsipi_xfer_pool;
 
 int scsipi_xs_count = 0;
@@ -860,7 +862,7 @@ scsipi_interpret_sense(struct scsipi_xfe
 	sense = &xs->sense.scsi_sense;
 #ifdef SCSIPI_DEBUG
 	if (periph->periph_flags & SCSIPI_DB1) {
-		int count;
+	        int count, len;
 		scsipi_printaddr(periph);
 		printf(" sense debug information:\n");
 		printf("\tcode 0x%x valid %d\n",
@@ -879,8 +881,9 @@ scsipi_interpret_sense(struct scsipi_xfe
 			sense->info[2],
 			sense->info[3],
 			sense->extra_len);
-		printf("\textra: ");
-		for (count = 0; count < SSD_ADD_BYTES_LIM(sense); count++)
+		len = SSD_ADD_BYTES_LIM(sense);
+		printf("\textra (up to %d bytes): ", len);
+		for (count = 0; count < len; count++)
 			printf("0x%x ", sense->csi[count]);
 		printf("\n");
 	}
@@ -1354,6 +1357,197 @@ scsipi_mode_select_big(struct scsipi_per
 }
 
 /*
+ * scsipi_get_opcodeinfo:
+ *
+ * query the device for supported commends and their timeout
+ * building a timeout lookup table if timeout information is available.
+ */
+void
+scsipi_get_opcodeinfo(struct scsipi_periph *periph)
+{
+	u_int8_t *data;
+	int len = 16*1024;
+	int rc;
+	struct scsi_repsuppopcode cmd;
+	
+	/* refrain from asking for supported opcodes */
+	if (periph->periph_quirks & PQUIRK_NOREPSUPPOPC ||
+	    periph->periph_type == T_PROCESSOR || /* spec. */
+	    periph->periph_type == T_CDROM) /* spec. */
+		return;
+
+	scsipi_free_opcodeinfo(periph);
+
+	/*
+	 * query REPORT SUPPORTED OPERATION CODES
+	 * if OK
+	 *   enumerate all codes
+	 *     if timeout exists insert maximum into opcode table
+	 */
+
+	data = malloc(len, M_DEVBUF, M_NOWAIT|M_ZERO);
+	if (data == NULL) {
+		SC_DEBUG(periph, SCSIPI_DB3,
+			 ("unable to allocate data buffer "
+			  "for REPORT SUPPORTED OPERATION CODES\n"));
+		return;
+	}
+
+	memset(&cmd, 0, sizeof(cmd));
+	
+	cmd.opcode = SCSI_MAINTENANCE_IN;
+	cmd.svcaction = RSOC_REPORT_SUPPORTED_OPCODES;
+	cmd.repoption = RSOC_RCTD|RSOC_ALL;
+	_lto4b(len, cmd.alloclen);
+	
+	rc = scsipi_command(periph, (void *)&cmd, sizeof(cmd),
+			    (void *)data, len, 0, 1000, NULL,
+			    XS_CTL_DATA_IN|XS_CTL_SILENT);
+
+	if (rc == 0) {
+		int count;
+                int dlen = _4btol(data);
+                u_int8_t *c = data + 4;
+		
+		SC_DEBUG(periph, SCSIPI_DB3,
+			 ("supported opcode timeout-values loaded\n"));
+		SC_DEBUG(periph, SCSIPI_DB3,
+			 ("CMD  LEN  SA    spec  nom. time  cmd timeout\n"));
+
+		struct scsipi_opcodes *tot =
+		  (struct scsipi_opcodes *)malloc(sizeof(struct scsipi_opcodes),
+						  M_DEVBUF, M_NOWAIT|M_ZERO);
+
+		count = 0;
+                while (tot != NULL &&
+		       dlen >= (int)sizeof(struct scsi_repsupopcode_all_commands_descriptor)) {
+                        struct scsi_repsupopcode_all_commands_descriptor *acd
+				= (struct scsi_repsupopcode_all_commands_descriptor *)c;
+#ifdef SCSIPI_DEBUG
+                        int cdblen = _2btol((const u_int8_t *)&acd->cdblen);
+#endif
+                        dlen -= sizeof(struct scsi_repsupopcode_all_commands_descriptor);
+                        c += sizeof(struct scsi_repsupopcode_all_commands_descriptor);
+                        SC_DEBUG(periph, SCSIPI_DB3,
+				 ("0x%02x(%2d) ", acd->opcode, cdblen));
+			
+			tot->opcode_info[acd->opcode].ti_flags = SCSIPI_TI_VALID;
+			
+                        if (acd->flags & RSOC_ACD_SERVACTV) {
+                                SC_DEBUGN(periph, SCSIPI_DB3,
+					 ("0x%02x%02x ",
+					  acd->serviceaction[0],
+					  acd->serviceaction[1]));
+                        } else {
+				SC_DEBUGN(periph, SCSIPI_DB3, ("       "));
+                        }
+			
+                        if (acd->flags & RSOC_ACD_CTDP
+			    && dlen >= (int)sizeof(struct scsi_repsupopcode_timeouts_descriptor)) {
+                                struct scsi_repsupopcode_timeouts_descriptor *td
+					= (struct scsi_repsupopcode_timeouts_descriptor *)c;
+                                long nomto = _4btol(td->nom_process_timeout);
+                                long cmdto = _4btol(td->cmd_process_timeout);
+				long t = (cmdto > nomto) ? cmdto : nomto;
+
+                                dlen -= sizeof(struct scsi_repsupopcode_timeouts_descriptor);
+                                c += sizeof(struct scsi_repsupopcode_timeouts_descriptor);
+
+                                SC_DEBUGN(periph, SCSIPI_DB3,
+					  ("0x%02x %10ld %10ld",
+					   td->cmd_specific,
+					   nomto, cmdto));
+
+				if (t > tot->opcode_info[acd->opcode].ti_timeout) {
+					tot->opcode_info[acd->opcode].ti_timeout = t;
+					++count;
+				}
+                        }
+                        SC_DEBUGN(periph, SCSIPI_DB3,("\n"));
+                }
+
+		if (count > 0) {
+			periph->periph_opcs = tot;
+		} else {
+			free(tot, M_DEVBUF);
+			SC_DEBUG(periph, SCSIPI_DB3,
+			 	("no usable timeout values available\n"));
+		}
+	} else {
+		SC_DEBUG(periph, SCSIPI_DB3,
+			 ("SCSI_MAINTENANCE_IN"
+			  "[RSOC_REPORT_SUPPORTED_OPCODES] failed error=%d"
+			  " - no device provided timeout "
+			  "values available\n", rc));
+	}
+
+	free(data, M_DEVBUF);
+}
+
+/*
+ * scsipi_update_timeouts:
+ * 	Overide timeout value if device/config provided
+ *      timeouts are available.
+ */
+static void
+scsipi_update_timeouts(struct scsipi_xfer *xs)
+{
+	struct scsipi_opcodes *opcs;
+	u_int8_t cmd;
+	int timeout;
+	struct scsipi_opinfo *oi;
+	
+	if (xs->timeout <= 0) {
+		return;	
+	}
+	
+	opcs = xs->xs_periph->periph_opcs;
+	
+	if (opcs == NULL) {
+		return;
+	}
+	
+	cmd = xs->cmd->opcode;
+	oi = &opcs->opcode_info[cmd];
+	
+	timeout = 1000 * (int)oi->ti_timeout;
+
+
+	if (timeout > xs->timeout && timeout < 86400000) {
+		/*
+		 * pick up device configured timeouts if they
+		 * are longer than the requested ones but less
+		 * than a day
+		 */
+#ifdef SCSIPI_DEBUG
+		if ((oi->ti_flags & SCSIPI_TI_LOGGED) == 0) {
+			SC_DEBUG(xs->xs_periph, SCSIPI_DB3,
+				 ("Overriding command 0x%02x "
+				  "timeout of %d with %d ms\n",
+				  cmd, xs->timeout, timeout));
+			oi->ti_flags |= SCSIPI_TI_LOGGED;
+		}
+#endif
+		xs->timeout = timeout;
+	}
+}
+
+/*
+ * scsipi_free_opcodeinfo:
+ *
+ * free the opcode information table
+ */
+void
+scsipi_free_opcodeinfo(struct scsipi_periph *periph)
+{
+	if (periph->periph_opcs != NULL) {
+		free(periph->periph_opcs, M_DEVBUF);
+	}
+
+	periph->periph_opcs = NULL;
+}
+
+/*
  * scsipi_done:
  *
  *	This routine is called by an adapter's interrupt handler when
@@ -1970,6 +2164,8 @@ scsipi_execute_xs(struct scsipi_xfer *xs
 
 	KASSERT(!cold);
 
+	scsipi_update_timeouts(xs);
+	
 	(chan->chan_bustype->bustype_cmd)(xs);
 
 	xs->xs_status &= ~XS_STS_DONE;

Index: src/sys/dev/scsipi/scsipiconf.c
diff -u src/sys/dev/scsipi/scsipiconf.c:1.44 src/sys/dev/scsipi/scsipiconf.c:1.45
--- src/sys/dev/scsipi/scsipiconf.c:1.44	Tue Apr 11 14:32:43 2017
+++ src/sys/dev/scsipi/scsipiconf.c	Thu Mar 28 10:44:29 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: scsipiconf.c,v 1.44 2017/04/11 14:32:43 christos Exp $	*/
+/*	$NetBSD: scsipiconf.c,v 1.45 2019/03/28 10:44:29 kardel Exp $	*/
 
 /*-
  * Copyright (c) 1998, 1999, 2004 The NetBSD Foundation, Inc.
@@ -48,7 +48,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: scsipiconf.c,v 1.44 2017/04/11 14:32:43 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: scsipiconf.c,v 1.45 2019/03/28 10:44:29 kardel Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -134,6 +134,7 @@ scsipi_alloc_periph(int malloc_flag)
 		return NULL;
 
 	periph->periph_dev = NULL;
+	periph->periph_opcs = NULL;
 
 	/*
 	 * Start with one command opening.  The periph driver
@@ -158,6 +159,7 @@ scsipi_alloc_periph(int malloc_flag)
 void
 scsipi_free_periph(struct scsipi_periph *periph)
 {
+	scsipi_free_opcodeinfo(periph);
 	cv_destroy(&periph->periph_cv);
 	free(periph, M_DEVBUF);
 }

Index: src/sys/dev/scsipi/scsipiconf.h
diff -u src/sys/dev/scsipi/scsipiconf.h:1.129 src/sys/dev/scsipi/scsipiconf.h:1.130
--- src/sys/dev/scsipi/scsipiconf.h:1.129	Sun Oct  7 18:14:32 2018
+++ src/sys/dev/scsipi/scsipiconf.h	Thu Mar 28 10:44:29 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: scsipiconf.h,v 1.129 2018/10/07 18:14:32 christos Exp $	*/
+/*	$NetBSD: scsipiconf.h,v 1.130 2019/03/28 10:44:29 kardel Exp $	*/
 
 /*-
  * Copyright (c) 1998, 1999, 2000, 2004 The NetBSD Foundation, Inc.
@@ -352,9 +352,28 @@ struct scsipi_channel {
  */
 #define	PERIPH_NTAGWORDS	((256 / 8) / sizeof(u_int32_t))
 
-
 #ifdef _KERNEL
 /*
+ * scsipi_opcodes:
+ *      This optionally allocated structure documents
+ *      valid opcodes and timeout values for the respective
+ *      opcodes overriding the requested timeouts.
+ *      It is created when SCSI_MAINTENANCE_IN/
+ *      RSOC_REPORT_SUPPORTED_OPCODES can provide information
+ *      at attach time.
+ */
+struct scsipi_opcodes 
+{
+	struct scsipi_opinfo
+	{
+		long          ti_timeout;	/* timeout in seconds (> 0 => VALID) */
+		unsigned long ti_flags;
+#define SCSIPI_TI_VALID  0x0001	        /* valid op code */
+#define SCSIPI_TI_LOGGED 0x8000	        /* override logged during debug */
+	} opcode_info[0x100];
+};
+
+/*
  * scsipi_periph:
  *
  *	This structure describes the path between a peripheral device
@@ -401,6 +420,9 @@ struct scsipi_periph {
 
 	int	periph_qfreeze;		/* queue freeze count */
 
+	/* available opcodes and timeout information */
+	struct scsipi_opcodes *periph_opcs;
+	
 	/* Bitmap of free command tags. */
 	u_int32_t periph_freetags[PERIPH_NTAGWORDS];
 
@@ -479,8 +501,9 @@ struct scsipi_periph {
 #define PQUIRK_CAP_NODT		0x00200000	/* signals DT, but can't. */
 #define PQUIRK_START		0x00400000	/* needs start before tur */
 #define	PQUIRK_NOFUA		0x00800000	/* does not grok FUA */
-
-
+#define PQUIRK_NOREPSUPPOPC     0x01000000      /* does not grok
+						   REPORT SUPPORTED OPCODES
+						   to fetch device timeouts */
 /*
  * Error values an adapter driver may return
  */
@@ -681,6 +704,8 @@ void	scsipi_user_done(struct scsipi_xfer
 int	scsipi_interpret_sense(struct scsipi_xfer *);
 void	scsipi_wait_drain(struct scsipi_periph *);
 void	scsipi_kill_pending(struct scsipi_periph *);
+void    scsipi_get_opcodeinfo(struct scsipi_periph *periph);
+void    scsipi_free_opcodeinfo(struct scsipi_periph *periph);
 struct scsipi_periph *scsipi_alloc_periph(int);
 void	scsipi_free_periph(struct scsipi_periph *);
 

Index: src/sys/dev/usb/umass_scsipi.c
diff -u src/sys/dev/usb/umass_scsipi.c:1.60 src/sys/dev/usb/umass_scsipi.c:1.61
--- src/sys/dev/usb/umass_scsipi.c:1.60	Sun Feb 10 19:23:55 2019
+++ src/sys/dev/usb/umass_scsipi.c	Thu Mar 28 10:44:29 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: umass_scsipi.c,v 1.60 2019/02/10 19:23:55 jdolecek Exp $	*/
+/*	$NetBSD: umass_scsipi.c,v 1.61 2019/03/28 10:44:29 kardel Exp $	*/
 
 /*
  * Copyright (c) 2001, 2003, 2012 The NetBSD Foundation, Inc.
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: umass_scsipi.c,v 1.60 2019/02/10 19:23:55 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: umass_scsipi.c,v 1.61 2019/03/28 10:44:29 kardel Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_usb.h"
@@ -212,7 +212,8 @@ umass_scsipi_setup(struct umass_softc *s
 	sc->bus = &scbus->base;
 
 	/* Only use big commands for USB SCSI devices. */
-	sc->sc_busquirks |= PQUIRK_ONLYBIG;
+	/* Do not ask for timeouts.  */
+	sc->sc_busquirks |= PQUIRK_ONLYBIG|PQUIRK_NOREPSUPPOPC;
 
 	/* Fill in the adapter. */
 	memset(&scbus->sc_adapter, 0, sizeof(scbus->sc_adapter));

Reply via email to