Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev Add reading of supported opcodes and their timeouts



details:   https://anonhg.NetBSD.org/src/rev/5332fd86b0be
branches:  trunk
changeset: 449902:5332fd86b0be
user:      kardel <kardel%NetBSD.org@localhost>
date:      Thu Mar 28 10:44:29 2019 +0000

description:
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.

diffstat:

 sys/dev/scsipi/scsi_spc.h    |   66 +++++++++++++-
 sys/dev/scsipi/scsiconf.c    |   19 ++-
 sys/dev/scsipi/scsipi_base.c |  206 +++++++++++++++++++++++++++++++++++++++++-
 sys/dev/scsipi/scsipiconf.c  |    6 +-
 sys/dev/scsipi/scsipiconf.h  |   33 ++++++-
 sys/dev/usb/umass_scsipi.c   |    7 +-
 6 files changed, 317 insertions(+), 20 deletions(-)

diffs (truncated from 513 to 300 lines):

diff -r d8ef641a63cf -r 5332fd86b0be sys/dev/scsipi/scsi_spc.h
--- a/sys/dev/scsipi/scsi_spc.h Thu Mar 28 08:56:55 2019 +0000
+++ b/sys/dev/scsipi/scsi_spc.h Thu Mar 28 10:44:29 2019 +0000
@@ -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 @@
  */
 
 /*
+ * 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
  */
 
diff -r d8ef641a63cf -r 5332fd86b0be sys/dev/scsipi/scsiconf.c
--- a/sys/dev/scsipi/scsiconf.c Thu Mar 28 08:56:55 2019 +0000
+++ b/sys/dev/scsipi/scsiconf.c Thu Mar 28 10:44:29 2019 +0000
@@ -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 @@
        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 @@
        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
diff -r d8ef641a63cf -r 5332fd86b0be sys/dev/scsipi/scsipi_base.c
--- a/sys/dev/scsipi/scsipi_base.c      Thu Mar 28 08:56:55 2019 +0000
+++ b/sys/dev/scsipi/scsipi_base.c      Thu Mar 28 10:44:29 2019 +0000
@@ -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_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 @@
        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 @@
                        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_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 "



Home | Main Index | Thread Index | Old Index