Print this page
    
NEX-17999 SCSI enclosure services (ses) non-response causes device tree operation deadlock
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/lib/fm/libdiskstatus/common/ds_scsi_uscsi.c
          +++ new/usr/src/lib/fm/libdiskstatus/common/ds_scsi_uscsi.c
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  11   11   * and limitations under the License.
  12   12   *
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  
  22   22  /*
  23   23   * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  24   24   * Use is subject to license terms.
  25   25   */
  26   26  
  27   27  #pragma ident   "%Z%%M% %I%     %E% SMI"
  28   28  
  29   29  /*
  30   30   * This file contains routines for sending and receiving SCSI commands.  The
  31   31   * higher level logic is contained in ds_scsi.c.
  32   32   */
  33   33  
  34   34  #include <assert.h>
  35   35  #include <sys/types.h>
  36   36  #include <sys/param.h>
  37   37  #include <inttypes.h>
  38   38  #include <stdio.h>
  39   39  #include <stdlib.h>
  40   40  #include <string.h>
  41   41  #include <errno.h>
  42   42  #include <stdarg.h>
  43   43  #include <limits.h>
  44   44  #include <utility.h>
  45   45  #include <unistd.h>
  46   46  #include <stropts.h>
  47   47  #include <alloca.h>
  48   48  
  49   49  #include "ds_scsi.h"
  50   50  #include "ds_scsi_uscsi.h"
  51   51  
  52   52  #define MSGBUFLEN 64
  53   53  #define USCSI_DEFAULT_TIMEOUT   45
  54   54  #define USCSI_TIMEOUT_MAX       INT_MAX
  55   55  
  56   56  static diskaddr_t scsi_extract_sense_info_descr(
  57   57      struct scsi_descr_sense_hdr *sdsp, int rqlen);
  58   58  static void scsi_print_extended_sense(struct scsi_extended_sense *rq,
  59   59      int rqlen);
  60   60  static void scsi_print_descr_sense(struct scsi_descr_sense_hdr *rq, int rqlen);
  61   61  
  62   62  typedef struct slist {
  63   63          char    *str;
  64   64          int     value;
  65   65  } slist_t;
  66   66  
  67   67  static char *
  68   68  find_string(slist_t *slist, int match_value)
  69   69  {
  70   70          for (; slist->str != NULL; slist++) {
  71   71                  if (slist->value == match_value) {
  72   72                          return (slist->str);
  73   73                  }
  74   74          }
  75   75  
  76   76          return ((char *)NULL);
  77   77  }
  78   78  
  79   79  /*
  80   80   * Strings for printing mode sense page control values
  81   81   */
  82   82  static slist_t page_control_strings[] = {
  83   83          { "current",    PC_CURRENT },
  84   84          { "changeable", PC_CHANGEABLE },
  85   85          { "default",    PC_DEFAULT },
  86   86          { "saved",      PC_SAVED },
  87   87          { NULL,         0 }
  88   88  };
  89   89  
  90   90  /*
  91   91   * Strings for printing the mode select options
  92   92   */
  93   93  static slist_t mode_select_strings[] = {
  94   94          { "",           0 },
  95   95          { "(pf)",       MODE_SELECT_PF },
  96   96          { "(sp)",       MODE_SELECT_SP },
  97   97          { "(pf,sp)",    MODE_SELECT_PF|MODE_SELECT_SP },
  98   98          { NULL,         0 }
  99   99  };
 100  100  
 101  101  static slist_t sensekey_strings[] = {
 102  102          { "No sense error",     KEY_NO_SENSE            },
 103  103          { "Recoverable error",  KEY_RECOVERABLE_ERROR   },
 104  104          { "Not ready error",    KEY_NOT_READY           },
 105  105          { "Medium error",       KEY_MEDIUM_ERROR        },
 106  106          { "Hardware error",     KEY_HARDWARE_ERROR      },
 107  107          { "Illegal request",    KEY_ILLEGAL_REQUEST     },
 108  108          { "Unit attention error", KEY_UNIT_ATTENTION    },
 109  109          { "Write protect error", KEY_WRITE_PROTECT      },
 110  110          { "Blank check error",  KEY_BLANK_CHECK         },
 111  111          { "Vendor unique error", KEY_VENDOR_UNIQUE      },
 112  112          { "Copy aborted error", KEY_COPY_ABORTED        },
 113  113          { "Aborted command",    KEY_ABORTED_COMMAND     },
 114  114          { "Equal error",        KEY_EQUAL               },
 115  115          { "Volume overflow",    KEY_VOLUME_OVERFLOW     },
 116  116          { "Miscompare error",   KEY_MISCOMPARE          },
 117  117          { "Reserved error",     KEY_RESERVED            },
 118  118          { NULL,                 0                       }
 119  119  };
 120  120  
 121  121  static slist_t scsi_cmdname_strings[] = {
 122  122          { "mode select",        SCMD_MODE_SELECT        },
 123  123          { "mode sense",         SCMD_MODE_SENSE         },
 124  124          { "mode select(10)",    SCMD_MODE_SELECT_G1     },
 125  125          { "mode sense(10)",     SCMD_MODE_SENSE_G1      },
 126  126          { "log sense",          SCMD_LOG_SENSE_G1       },
 127  127          { "request sense",      SCMD_REQUEST_SENSE      },
 128  128          { NULL,                 0                       }
 129  129  };
 130  130  
 131  131  static struct _scsi_asq_key_strings {
 132  132          uint_t asc;
 133  133          uint_t ascq;
 134  134          const char *message;
 135  135  } extended_sense_list[] = {
 136  136          { 0x00, 0x00, "no additional sense info" },
 137  137          { 0x00, 0x01, "filemark detected" },
 138  138          { 0x00, 0x02, "end of partition/medium detected" },
 139  139          { 0x00, 0x03, "setmark detected" },
 140  140          { 0x00, 0x04, "begining of partition/medium detected" },
 141  141          { 0x00, 0x05, "end of data detected" },
 142  142          { 0x00, 0x06, "i/o process terminated" },
 143  143          { 0x00, 0x11, "audio play operation in progress" },
 144  144          { 0x00, 0x12, "audio play operation paused" },
 145  145          { 0x00, 0x13, "audio play operation successfully completed" },
 146  146          { 0x00, 0x14, "audio play operation stopped due to error" },
 147  147          { 0x00, 0x15, "no current audio status to return" },
 148  148          { 0x00, 0x16, "operation in progress" },
 149  149          { 0x00, 0x17, "cleaning requested" },
 150  150          { 0x00, 0x18, "erase operation in progress" },
 151  151          { 0x00, 0x19, "locate operation in progress" },
 152  152          { 0x00, 0x1A, "rewind operation in progress" },
 153  153          { 0x00, 0x1B, "set capacity operation in progress" },
 154  154          { 0x00, 0x1C, "verify operation in progress" },
 155  155          { 0x01, 0x00, "no index/sector signal" },
 156  156          { 0x02, 0x00, "no seek complete" },
 157  157          { 0x03, 0x00, "peripheral device write fault" },
 158  158          { 0x03, 0x01, "no write current" },
 159  159          { 0x03, 0x02, "excessive write errors" },
 160  160          { 0x04, 0x00, "LUN not ready" },
 161  161          { 0x04, 0x01, "LUN is becoming ready" },
 162  162          { 0x04, 0x02, "LUN initializing command required" },
 163  163          { 0x04, 0x03, "LUN not ready intervention required" },
 164  164          { 0x04, 0x04, "LUN not ready format in progress" },
 165  165          { 0x04, 0x05, "LUN not ready, rebuild in progress" },
 166  166          { 0x04, 0x06, "LUN not ready, recalculation in progress" },
 167  167          { 0x04, 0x07, "LUN not ready, operation in progress" },
 168  168          { 0x04, 0x08, "LUN not ready, long write in progress" },
 169  169          { 0x04, 0x09, "LUN not ready, self-test in progress" },
 170  170          { 0x04, 0x0A, "LUN not accessible, asymmetric access state "
 171  171                  "transition" },
 172  172          { 0x04, 0x0B, "LUN not accessible, target port in standby state" },
 173  173          { 0x04, 0x0C, "LUN not accessible, target port in unavailable state" },
 174  174          { 0x04, 0x10, "LUN not ready, auxiliary memory not accessible" },
 175  175          { 0x05, 0x00, "LUN does not respond to selection" },
 176  176          { 0x06, 0x00, "reference position found" },
 177  177          { 0x07, 0x00, "multiple peripheral devices selected" },
 178  178          { 0x08, 0x00, "LUN communication failure" },
 179  179          { 0x08, 0x01, "LUN communication time-out" },
 180  180          { 0x08, 0x02, "LUN communication parity error" },
 181  181          { 0x08, 0x03, "LUN communication crc error (ultra-DMA/32)" },
 182  182          { 0x08, 0x04, "unreachable copy target" },
 183  183          { 0x09, 0x00, "track following error" },
 184  184          { 0x09, 0x01, "tracking servo failure" },
 185  185          { 0x09, 0x02, "focus servo failure" },
 186  186          { 0x09, 0x03, "spindle servo failure" },
 187  187          { 0x09, 0x04, "head select fault" },
 188  188          { 0x0a, 0x00, "error log overflow" },
 189  189          { 0x0b, 0x00, "warning" },
 190  190          { 0x0b, 0x01, "warning - specified temperature exceeded" },
 191  191          { 0x0b, 0x02, "warning - enclosure degraded" },
 192  192          { 0x0c, 0x00, "write error" },
 193  193          { 0x0c, 0x01, "write error - recovered with auto reallocation" },
 194  194          { 0x0c, 0x02, "write error - auto reallocation failed" },
 195  195          { 0x0c, 0x03, "write error - recommend reassignment" },
 196  196          { 0x0c, 0x04, "compression check miscompare error" },
 197  197          { 0x0c, 0x05, "data expansion occurred during compression" },
 198  198          { 0x0c, 0x06, "block not compressible" },
 199  199          { 0x0c, 0x07, "write error - recovery needed" },
 200  200          { 0x0c, 0x08, "write error - recovery failed" },
 201  201          { 0x0c, 0x09, "write error - loss of streaming" },
 202  202          { 0x0c, 0x0a, "write error - padding blocks added" },
 203  203          { 0x0c, 0x0b, "auxiliary memory write error" },
 204  204          { 0x0c, 0x0c, "write error - unexpected unsolicited data" },
 205  205          { 0x0c, 0x0d, "write error - not enough unsolicited data" },
 206  206          { 0x0d, 0x00, "error detected by third party temporary initiator" },
 207  207          { 0x0d, 0x01, "third party device failure" },
 208  208          { 0x0d, 0x02, "copy target device not reachable" },
 209  209          { 0x0d, 0x03, "incorrect copy target device type" },
 210  210          { 0x0d, 0x04, "copy target device data underrun" },
 211  211          { 0x0d, 0x05, "copy target device data overrun" },
 212  212          { 0x0e, 0x00, "invalid information unit" },
 213  213          { 0x0e, 0x01, "information unit too short" },
 214  214          { 0x0e, 0x02, "information unit too long" },
 215  215          { 0x10, 0x00, "ID CRC or ECC error" },
 216  216          { 0x11, 0x00, "unrecovered read error" },
 217  217          { 0x11, 0x01, "read retries exhausted" },
 218  218          { 0x11, 0x02, "error too long to correct" },
 219  219          { 0x11, 0x03, "multiple read errors" },
 220  220          { 0x11, 0x04, "unrecovered read error - auto reallocate failed" },
 221  221          { 0x11, 0x05, "L-EC uncorrectable error" },
 222  222          { 0x11, 0x06, "CIRC unrecovered error" },
 223  223          { 0x11, 0x07, "data re-synchronization error" },
 224  224          { 0x11, 0x08, "incomplete block read" },
 225  225          { 0x11, 0x09, "no gap found" },
 226  226          { 0x11, 0x0a, "miscorrected error" },
 227  227          { 0x11, 0x0b, "unrecovered read error - recommend reassignment" },
 228  228          { 0x11, 0x0c, "unrecovered read error - recommend rewrite the data" },
 229  229          { 0x11, 0x0d, "de-compression crc error" },
 230  230          { 0x11, 0x0e, "cannot decompress using declared algorithm" },
 231  231          { 0x11, 0x0f, "error reading UPC/EAN number" },
 232  232          { 0x11, 0x10, "error reading ISRC number" },
 233  233          { 0x11, 0x11, "read error - loss of streaming" },
 234  234          { 0x11, 0x12, "auxiliary memory read error" },
 235  235          { 0x11, 0x13, "read error - failed retransmission request" },
 236  236          { 0x12, 0x00, "address mark not found for ID field" },
 237  237          { 0x13, 0x00, "address mark not found for data field" },
 238  238          { 0x14, 0x00, "recorded entity not found" },
 239  239          { 0x14, 0x01, "record not found" },
 240  240          { 0x14, 0x02, "filemark or setmark not found" },
 241  241          { 0x14, 0x03, "end-of-data not found" },
 242  242          { 0x14, 0x04, "block sequence error" },
 243  243          { 0x14, 0x05, "record not found - recommend reassignment" },
 244  244          { 0x14, 0x06, "record not found - data auto-reallocated" },
 245  245          { 0x14, 0x07, "locate operation failure" },
 246  246          { 0x15, 0x00, "random positioning error" },
 247  247          { 0x15, 0x01, "mechanical positioning error" },
 248  248          { 0x15, 0x02, "positioning error detected by read of medium" },
 249  249          { 0x16, 0x00, "data sync mark error" },
 250  250          { 0x16, 0x01, "data sync error - data rewritten" },
 251  251          { 0x16, 0x02, "data sync error - recommend rewrite" },
 252  252          { 0x16, 0x03, "data sync error - data auto-reallocated" },
 253  253          { 0x16, 0x04, "data sync error - recommend reassignment" },
 254  254          { 0x17, 0x00, "recovered data with no error correction" },
 255  255          { 0x17, 0x01, "recovered data with retries" },
 256  256          { 0x17, 0x02, "recovered data with positive head offset" },
 257  257          { 0x17, 0x03, "recovered data with negative head offset" },
 258  258          { 0x17, 0x04, "recovered data with retries and/or CIRC applied" },
 259  259          { 0x17, 0x05, "recovered data using previous sector id" },
 260  260          { 0x17, 0x06, "recovered data without ECC - data auto-reallocated" },
 261  261          { 0x17, 0x07, "recovered data without ECC - recommend reassignment" },
 262  262          { 0x17, 0x08, "recovered data without ECC - recommend rewrite" },
 263  263          { 0x17, 0x09, "recovered data without ECC - data rewritten" },
 264  264          { 0x18, 0x00, "recovered data with error correction" },
 265  265          { 0x18, 0x01, "recovered data with error corr. & retries applied" },
 266  266          { 0x18, 0x02, "recovered data - data auto-reallocated" },
 267  267          { 0x18, 0x03, "recovered data with CIRC" },
 268  268          { 0x18, 0x04, "recovered data with L-EC" },
 269  269          { 0x18, 0x05, "recovered data - recommend reassignment" },
 270  270          { 0x18, 0x06, "recovered data - recommend rewrite" },
 271  271          { 0x18, 0x07, "recovered data with ECC - data rewritten" },
 272  272          { 0x18, 0x08, "recovered data with linking" },
 273  273          { 0x19, 0x00, "defect list error" },
 274  274          { 0x1a, 0x00, "parameter list length error" },
 275  275          { 0x1b, 0x00, "synchronous data xfer error" },
 276  276          { 0x1c, 0x00, "defect list not found" },
 277  277          { 0x1c, 0x01, "primary defect list not found" },
 278  278          { 0x1c, 0x02, "grown defect list not found" },
 279  279          { 0x1d, 0x00, "miscompare during verify" },
 280  280          { 0x1e, 0x00, "recovered ID with ECC" },
 281  281          { 0x1f, 0x00, "partial defect list transfer" },
 282  282          { 0x20, 0x00, "invalid command operation code" },
 283  283          { 0x20, 0x01, "access denied - initiator pending-enrolled" },
 284  284          { 0x20, 0x02, "access denied - no access rights" },
 285  285          { 0x20, 0x03, "access denied - invalid mgmt id key" },
 286  286          { 0x20, 0x04, "illegal command while in write capable state" },
 287  287          { 0x20, 0x06, "illegal command while in explicit address mode" },
 288  288          { 0x20, 0x07, "illegal command while in implicit address mode" },
 289  289          { 0x20, 0x08, "access denied - enrollment conflict" },
 290  290          { 0x20, 0x09, "access denied - invalid lu identifier" },
 291  291          { 0x20, 0x0a, "access denied - invalid proxy token" },
 292  292          { 0x20, 0x0b, "access denied - ACL LUN conflict" },
 293  293          { 0x21, 0x00, "logical block address out of range" },
 294  294          { 0x21, 0x01, "invalid element address" },
 295  295          { 0x21, 0x02, "invalid address for write" },
 296  296          { 0x22, 0x00, "illegal function" },
 297  297          { 0x24, 0x00, "invalid field in cdb" },
 298  298          { 0x24, 0x01, "cdb decryption error" },
 299  299          { 0x25, 0x00, "LUN not supported" },
 300  300          { 0x26, 0x00, "invalid field in param list" },
 301  301          { 0x26, 0x01, "parameter not supported" },
 302  302          { 0x26, 0x02, "parameter value invalid" },
 303  303          { 0x26, 0x03, "threshold parameters not supported" },
 304  304          { 0x26, 0x04, "invalid release of persistent reservation" },
 305  305          { 0x26, 0x05, "data decryption error" },
 306  306          { 0x26, 0x06, "too many target descriptors" },
 307  307          { 0x26, 0x07, "unsupported target descriptor type code" },
 308  308          { 0x26, 0x08, "too many segment descriptors" },
 309  309          { 0x26, 0x09, "unsupported segment descriptor type code" },
 310  310          { 0x26, 0x0a, "unexpected inexact segment" },
 311  311          { 0x26, 0x0b, "inline data length exceeded" },
 312  312          { 0x26, 0x0c, "invalid operation for copy source or destination" },
 313  313          { 0x26, 0x0d, "copy segment granularity violation" },
 314  314          { 0x27, 0x00, "write protected" },
 315  315          { 0x27, 0x01, "hardware write protected" },
 316  316          { 0x27, 0x02, "LUN software write protected" },
 317  317          { 0x27, 0x03, "associated write protect" },
 318  318          { 0x27, 0x04, "persistent write protect" },
 319  319          { 0x27, 0x05, "permanent write protect" },
 320  320          { 0x27, 0x06, "conditional write protect" },
 321  321          { 0x28, 0x00, "medium may have changed" },
 322  322          { 0x28, 0x01, "import or export element accessed" },
 323  323          { 0x29, 0x00, "power on, reset, or bus reset occurred" },
 324  324          { 0x29, 0x01, "power on occurred" },
 325  325          { 0x29, 0x02, "scsi bus reset occurred" },
 326  326          { 0x29, 0x03, "bus device reset message occurred" },
 327  327          { 0x29, 0x04, "device internal reset" },
 328  328          { 0x29, 0x05, "transceiver mode changed to single-ended" },
 329  329          { 0x29, 0x06, "transceiver mode changed to LVD" },
 330  330          { 0x29, 0x07, "i_t nexus loss occurred" },
 331  331          { 0x2a, 0x00, "parameters changed" },
 332  332          { 0x2a, 0x01, "mode parameters changed" },
 333  333          { 0x2a, 0x02, "log parameters changed" },
 334  334          { 0x2a, 0x03, "reservations preempted" },
 335  335          { 0x2a, 0x04, "reservations released" },
 336  336          { 0x2a, 0x05, "registrations preempted" },
 337  337          { 0x2a, 0x06, "asymmetric access state changed" },
 338  338          { 0x2a, 0x07, "implicit asymmetric access state transition failed" },
 339  339          { 0x2b, 0x00, "copy cannot execute since host cannot disconnect" },
 340  340          { 0x2c, 0x00, "command sequence error" },
 341  341          { 0x2c, 0x03, "current program area is not empty" },
 342  342          { 0x2c, 0x04, "current program area is empty" },
 343  343          { 0x2c, 0x06, "persistent prevent conflict" },
 344  344          { 0x2c, 0x07, "previous busy status" },
 345  345          { 0x2c, 0x08, "previous task set full status" },
 346  346          { 0x2c, 0x09, "previous reservation conflict status" },
 347  347          { 0x2d, 0x00, "overwrite error on update in place" },
 348  348          { 0x2e, 0x00, "insufficient time for operation" },
 349  349          { 0x2f, 0x00, "commands cleared by another initiator" },
 350  350          { 0x30, 0x00, "incompatible medium installed" },
 351  351          { 0x30, 0x01, "cannot read medium - unknown format" },
 352  352          { 0x30, 0x02, "cannot read medium - incompatible format" },
 353  353          { 0x30, 0x03, "cleaning cartridge installed" },
 354  354          { 0x30, 0x04, "cannot write medium - unknown format" },
 355  355          { 0x30, 0x05, "cannot write medium - incompatible format" },
 356  356          { 0x30, 0x06, "cannot format medium - incompatible medium" },
 357  357          { 0x30, 0x07, "cleaning failure" },
 358  358          { 0x30, 0x08, "cannot write - application code mismatch" },
 359  359          { 0x30, 0x09, "current session not fixated for append" },
 360  360          { 0x30, 0x10, "medium not formatted" },
 361  361          { 0x31, 0x00, "medium format corrupted" },
 362  362          { 0x31, 0x01, "format command failed" },
 363  363          { 0x31, 0x02, "zoned formatting failed due to spare linking" },
 364  364          { 0x32, 0x00, "no defect spare location available" },
 365  365          { 0x32, 0x01, "defect list update failure" },
 366  366          { 0x33, 0x00, "tape length error" },
 367  367          { 0x34, 0x00, "enclosure failure" },
 368  368          { 0x35, 0x00, "enclosure services failure" },
 369  369          { 0x35, 0x01, "unsupported enclosure function" },
 370  370          { 0x35, 0x02, "enclosure services unavailable" },
 371  371          { 0x35, 0x03, "enclosure services transfer failure" },
 372  372          { 0x35, 0x04, "enclosure services transfer refused" },
 373  373          { 0x36, 0x00, "ribbon, ink, or toner failure" },
 374  374          { 0x37, 0x00, "rounded parameter" },
 375  375          { 0x39, 0x00, "saving parameters not supported" },
 376  376          { 0x3a, 0x00, "medium not present" },
 377  377          { 0x3a, 0x01, "medium not present - tray closed" },
 378  378          { 0x3a, 0x02, "medium not present - tray open" },
 379  379          { 0x3a, 0x03, "medium not present - loadable" },
 380  380          { 0x3a, 0x04, "medium not present - medium auxiliary memory "
 381  381                  "accessible" },
 382  382          { 0x3b, 0x00, "sequential positioning error" },
 383  383          { 0x3b, 0x01, "tape position error at beginning-of-medium" },
 384  384          { 0x3b, 0x02, "tape position error at end-of-medium" },
 385  385          { 0x3b, 0x08, "reposition error" },
 386  386          { 0x3b, 0x0c, "position past beginning of medium" },
 387  387          { 0x3b, 0x0d, "medium destination element full" },
 388  388          { 0x3b, 0x0e, "medium source element empty" },
 389  389          { 0x3b, 0x0f, "end of medium reached" },
 390  390          { 0x3b, 0x11, "medium magazine not accessible" },
 391  391          { 0x3b, 0x12, "medium magazine removed" },
 392  392          { 0x3b, 0x13, "medium magazine inserted" },
 393  393          { 0x3b, 0x14, "medium magazine locked" },
 394  394          { 0x3b, 0x15, "medium magazine unlocked" },
 395  395          { 0x3b, 0x16, "mechanical positioning or changer error" },
 396  396          { 0x3d, 0x00, "invalid bits in indentify message" },
 397  397          { 0x3e, 0x00, "LUN has not self-configured yet" },
 398  398          { 0x3e, 0x01, "LUN failure" },
 399  399          { 0x3e, 0x02, "timeout on LUN" },
 400  400          { 0x3e, 0x03, "LUN failed self-test" },
 401  401          { 0x3e, 0x04, "LUN unable to update self-test log" },
 402  402          { 0x3f, 0x00, "target operating conditions have changed" },
 403  403          { 0x3f, 0x01, "microcode has been changed" },
 404  404          { 0x3f, 0x02, "changed operating definition" },
 405  405          { 0x3f, 0x03, "inquiry data has changed" },
 406  406          { 0x3f, 0x04, "component device attached" },
 407  407          { 0x3f, 0x05, "device identifier changed" },
 408  408          { 0x3f, 0x06, "redundancy group created or modified" },
 409  409          { 0x3f, 0x07, "redundancy group deleted" },
 410  410          { 0x3f, 0x08, "spare created or modified" },
 411  411          { 0x3f, 0x09, "spare deleted" },
 412  412          { 0x3f, 0x0a, "volume set created or modified" },
 413  413          { 0x3f, 0x0b, "volume set deleted" },
 414  414          { 0x3f, 0x0c, "volume set deassigned" },
 415  415          { 0x3f, 0x0d, "volume set reassigned" },
 416  416          { 0x3f, 0x0e, "reported LUNs data has changed" },
 417  417          { 0x3f, 0x0f, "echo buffer overwritten" },
 418  418          { 0x3f, 0x10, "medium loadable" },
 419  419          { 0x3f, 0x11, "medium auxiliary memory accessible" },
 420  420          { 0x40, 0x00, "ram failure" },
 421  421          { 0x41, 0x00, "data path failure" },
 422  422          { 0x42, 0x00, "power-on or self-test failure" },
 423  423          { 0x43, 0x00, "message error" },
 424  424          { 0x44, 0x00, "internal target failure" },
 425  425          { 0x45, 0x00, "select or reselect failure" },
 426  426          { 0x46, 0x00, "unsuccessful soft reset" },
 427  427          { 0x47, 0x00, "scsi parity error" },
 428  428          { 0x47, 0x01, "data phase crc error detected" },
 429  429          { 0x47, 0x02, "scsi parity error detected during st data phase" },
 430  430          { 0x47, 0x03, "information unit iucrc error detected" },
 431  431          { 0x47, 0x04, "asynchronous information protection error detected" },
 432  432          { 0x47, 0x05, "protocol service crc error" },
 433  433          { 0x47, 0x7f, "some commands cleared by iscsi protocol event" },
 434  434          { 0x48, 0x00, "initiator detected error message received" },
 435  435          { 0x49, 0x00, "invalid message error" },
 436  436          { 0x4a, 0x00, "command phase error" },
 437  437          { 0x4b, 0x00, "data phase error" },
 438  438          { 0x4b, 0x01, "invalid target port transfer tag received" },
 439  439          { 0x4b, 0x02, "too much write data" },
 440  440          { 0x4b, 0x03, "ack/nak timeout" },
 441  441          { 0x4b, 0x04, "nak received" },
 442  442          { 0x4b, 0x05, "data offset error" },
 443  443          { 0x4c, 0x00, "logical unit failed self-configuration" },
 444  444          { 0x4d, 0x00, "tagged overlapped commands (ASCQ = queue tag)" },
 445  445          { 0x4e, 0x00, "overlapped commands attempted" },
 446  446          { 0x50, 0x00, "write append error" },
 447  447          { 0x51, 0x00, "erase failure" },
 448  448          { 0x52, 0x00, "cartridge fault" },
 449  449          { 0x53, 0x00, "media load or eject failed" },
 450  450          { 0x53, 0x01, "unload tape failure" },
 451  451          { 0x53, 0x02, "medium removal prevented" },
 452  452          { 0x54, 0x00, "scsi to host system interface failure" },
 453  453          { 0x55, 0x00, "system resource failure" },
 454  454          { 0x55, 0x01, "system buffer full" },
 455  455          { 0x55, 0x02, "insufficient reservation resources" },
 456  456          { 0x55, 0x03, "insufficient resources" },
 457  457          { 0x55, 0x04, "insufficient registration resources" },
 458  458          { 0x55, 0x05, "insufficient access control resources" },
 459  459          { 0x55, 0x06, "auxiliary memory out of space" },
 460  460          { 0x57, 0x00, "unable to recover TOC" },
 461  461          { 0x58, 0x00, "generation does not exist" },
 462  462          { 0x59, 0x00, "updated block read" },
 463  463          { 0x5a, 0x00, "operator request or state change input" },
 464  464          { 0x5a, 0x01, "operator medium removal request" },
 465  465          { 0x5a, 0x02, "operator selected write protect" },
 466  466          { 0x5a, 0x03, "operator selected write permit" },
 467  467          { 0x5b, 0x00, "log exception" },
 468  468          { 0x5b, 0x01, "threshold condition met" },
 469  469          { 0x5b, 0x02, "log counter at maximum" },
 470  470          { 0x5b, 0x03, "log list codes exhausted" },
 471  471          { 0x5c, 0x00, "RPL status change" },
 472  472          { 0x5c, 0x01, "spindles synchronized" },
 473  473          { 0x5c, 0x02, "spindles not synchronized" },
 474  474          { 0x5d, 0x00, "drive operation marginal, service immediately"
 475  475                      " (failure prediction threshold exceeded)" },
 476  476          { 0x5d, 0x01, "media failure prediction threshold exceeded" },
 477  477          { 0x5d, 0x02, "LUN failure prediction threshold exceeded" },
 478  478          { 0x5d, 0x03, "spare area exhaustion prediction threshold exceeded" },
 479  479          { 0x5d, 0x10, "hardware impending failure general hard drive failure" },
 480  480          { 0x5d, 0x11, "hardware impending failure drive error rate too high" },
 481  481          { 0x5d, 0x12, "hardware impending failure data error rate too high" },
 482  482          { 0x5d, 0x13, "hardware impending failure seek error rate too high" },
 483  483          { 0x5d, 0x14, "hardware impending failure too many block reassigns" },
 484  484          { 0x5d, 0x15, "hardware impending failure access times too high" },
 485  485          { 0x5d, 0x16, "hardware impending failure start unit times too high" },
 486  486          { 0x5d, 0x17, "hardware impending failure channel parametrics" },
 487  487          { 0x5d, 0x18, "hardware impending failure controller detected" },
 488  488          { 0x5d, 0x19, "hardware impending failure throughput performance" },
 489  489          { 0x5d, 0x1a, "hardware impending failure seek time performance" },
 490  490          { 0x5d, 0x1b, "hardware impending failure spin-up retry count" },
 491  491          { 0x5d, 0x1c, "hardware impending failure drive calibration retry "
 492  492                  "count" },
 493  493          { 0x5d, 0x20, "controller impending failure general hard drive "
 494  494                  "failure" },
 495  495          { 0x5d, 0x21, "controller impending failure drive error rate too "
 496  496                  "high" },
 497  497          { 0x5d, 0x22, "controller impending failure data error rate too high" },
 498  498          { 0x5d, 0x23, "controller impending failure seek error rate too high" },
 499  499          { 0x5d, 0x24, "controller impending failure too many block reassigns" },
 500  500          { 0x5d, 0x25, "controller impending failure access times too high" },
 501  501          { 0x5d, 0x26, "controller impending failure start unit times too "
 502  502                  "high" },
 503  503          { 0x5d, 0x27, "controller impending failure channel parametrics" },
 504  504          { 0x5d, 0x28, "controller impending failure controller detected" },
 505  505          { 0x5d, 0x29, "controller impending failure throughput performance" },
 506  506          { 0x5d, 0x2a, "controller impending failure seek time performance" },
 507  507          { 0x5d, 0x2b, "controller impending failure spin-up retry count" },
 508  508          { 0x5d, 0x2c, "controller impending failure drive calibration retry "
 509  509                  "cnt" },
 510  510          { 0x5d, 0x30, "data channel impending failure general hard drive "
 511  511                  "failure" },
 512  512          { 0x5d, 0x31, "data channel impending failure drive error rate too "
 513  513                  "high" },
 514  514          { 0x5d, 0x32, "data channel impending failure data error rate too "
 515  515                  "high" },
 516  516          { 0x5d, 0x33, "data channel impending failure seek error rate too "
 517  517                  "high" },
 518  518          { 0x5d, 0x34, "data channel impending failure too many block "
 519  519                  "reassigns" },
 520  520          { 0x5d, 0x35, "data channel impending failure access times too high" },
 521  521          { 0x5d, 0x36, "data channel impending failure start unit times too "
 522  522                  "high" },
 523  523          { 0x5d, 0x37, "data channel impending failure channel parametrics" },
 524  524          { 0x5d, 0x38, "data channel impending failure controller detected" },
 525  525          { 0x5d, 0x39, "data channel impending failure throughput performance" },
 526  526          { 0x5d, 0x3a, "data channel impending failure seek time performance" },
 527  527          { 0x5d, 0x3b, "data channel impending failure spin-up retry count" },
 528  528          { 0x5d, 0x3c, "data channel impending failure drive calibrate retry "
 529  529                  "cnt" },
 530  530          { 0x5d, 0x40, "servo impending failure general hard drive failure" },
 531  531          { 0x5d, 0x41, "servo impending failure drive error rate too high" },
 532  532          { 0x5d, 0x42, "servo impending failure data error rate too high" },
 533  533          { 0x5d, 0x43, "servo impending failure seek error rate too high" },
 534  534          { 0x5d, 0x44, "servo impending failure too many block reassigns" },
 535  535          { 0x5d, 0x45, "servo impending failure access times too high" },
 536  536          { 0x5d, 0x46, "servo impending failure start unit times too high" },
 537  537          { 0x5d, 0x47, "servo impending failure channel parametrics" },
 538  538          { 0x5d, 0x48, "servo impending failure controller detected" },
 539  539          { 0x5d, 0x49, "servo impending failure throughput performance" },
 540  540          { 0x5d, 0x4a, "servo impending failure seek time performance" },
 541  541          { 0x5d, 0x4b, "servo impending failure spin-up retry count" },
 542  542          { 0x5d, 0x4c, "servo impending failure drive calibration retry count" },
 543  543          { 0x5d, 0x50, "spindle impending failure general hard drive failure" },
 544  544          { 0x5d, 0x51, "spindle impending failure drive error rate too high" },
 545  545          { 0x5d, 0x52, "spindle impending failure data error rate too high" },
 546  546          { 0x5d, 0x53, "spindle impending failure seek error rate too high" },
 547  547          { 0x5d, 0x54, "spindle impending failure too many block reassigns" },
 548  548          { 0x5d, 0x55, "spindle impending failure access times too high" },
 549  549          { 0x5d, 0x56, "spindle impending failure start unit times too high" },
 550  550          { 0x5d, 0x57, "spindle impending failure channel parametrics" },
 551  551          { 0x5d, 0x58, "spindle impending failure controller detected" },
 552  552          { 0x5d, 0x59, "spindle impending failure throughput performance" },
 553  553          { 0x5d, 0x5a, "spindle impending failure seek time performance" },
 554  554          { 0x5d, 0x5b, "spindle impending failure spin-up retry count" },
 555  555          { 0x5d, 0x5c, "spindle impending failure drive calibration retry "
 556  556                  "count" },
 557  557          { 0x5d, 0x60, "firmware impending failure general hard drive failure" },
 558  558          { 0x5d, 0x61, "firmware impending failure drive error rate too high" },
 559  559          { 0x5d, 0x62, "firmware impending failure data error rate too high" },
 560  560          { 0x5d, 0x63, "firmware impending failure seek error rate too high" },
 561  561          { 0x5d, 0x64, "firmware impending failure too many block reassigns" },
 562  562          { 0x5d, 0x65, "firmware impending failure access times too high" },
 563  563          { 0x5d, 0x66, "firmware impending failure start unit times too high" },
 564  564          { 0x5d, 0x67, "firmware impending failure channel parametrics" },
 565  565          { 0x5d, 0x68, "firmware impending failure controller detected" },
 566  566          { 0x5d, 0x69, "firmware impending failure throughput performance" },
 567  567          { 0x5d, 0x6a, "firmware impending failure seek time performance" },
 568  568          { 0x5d, 0x6b, "firmware impending failure spin-up retry count" },
 569  569          { 0x5d, 0x6c, "firmware impending failure drive calibration retry "
 570  570                  "count" },
 571  571          { 0x5d, 0xff, "failure prediction threshold exceeded (false)" },
 572  572          { 0x5e, 0x00, "low power condition active" },
 573  573          { 0x5e, 0x01, "idle condition activated by timer" },
 574  574          { 0x5e, 0x02, "standby condition activated by timer" },
 575  575          { 0x5e, 0x03, "idle condition activated by command" },
 576  576          { 0x5e, 0x04, "standby condition activated by command" },
 577  577          { 0x60, 0x00, "lamp failure" },
 578  578          { 0x61, 0x00, "video aquisition error" },
 579  579          { 0x62, 0x00, "scan head positioning error" },
 580  580          { 0x63, 0x00, "end of user area encountered on this track" },
 581  581          { 0x63, 0x01, "packet does not fit in available space" },
 582  582          { 0x64, 0x00, "illegal mode for this track" },
 583  583          { 0x64, 0x01, "invalid packet size" },
 584  584          { 0x65, 0x00, "voltage fault" },
 585  585          { 0x66, 0x00, "automatic document feeder cover up" },
 586  586          { 0x67, 0x00, "configuration failure" },
 587  587          { 0x67, 0x01, "configuration of incapable LUNs failed" },
 588  588          { 0x67, 0x02, "add LUN failed" },
 589  589          { 0x67, 0x03, "modification of LUN failed" },
 590  590          { 0x67, 0x04, "exchange of LUN failed" },
 591  591          { 0x67, 0x05, "remove of LUN failed" },
 592  592          { 0x67, 0x06, "attachment of LUN failed" },
 593  593          { 0x67, 0x07, "creation of LUN failed" },
 594  594          { 0x67, 0x08, "assign failure occurred" },
 595  595          { 0x67, 0x09, "multiply assigned LUN" },
 596  596          { 0x67, 0x0a, "set target port groups command failed" },
 597  597          { 0x68, 0x00, "logical unit not configured" },
 598  598          { 0x69, 0x00, "data loss on logical unit" },
 599  599          { 0x69, 0x01, "multiple LUN failures" },
 600  600          { 0x69, 0x02, "parity/data mismatch" },
 601  601          { 0x6a, 0x00, "informational, refer to log" },
 602  602          { 0x6b, 0x00, "state change has occured" },
 603  603          { 0x6b, 0x01, "redundancy level got better" },
 604  604          { 0x6b, 0x02, "redundancy level got worse" },
 605  605          { 0x6c, 0x00, "rebuild failure occured" },
 606  606          { 0x6d, 0x00, "recalculate failure occured" },
 607  607          { 0x6e, 0x00, "command to logical unit failed" },
 608  608          { 0x6f, 0x00, "copy protect key exchange failure authentication "
 609  609                  "failure" },
 610  610          { 0x6f, 0x01, "copy protect key exchange failure key not present" },
 611  611          { 0x6f, 0x02, "copy protect key exchange failure key not established" },
 612  612          { 0x6f, 0x03, "read of scrambled sector without authentication" },
 613  613          { 0x6f, 0x04, "media region code is mismatched to LUN region" },
 614  614          { 0x6f, 0x05, "drive region must be permanent/region reset count "
 615  615                  "error" },
 616  616          { 0x70, 0xffff, "decompression exception short algorithm id of ASCQ" },
 617  617          { 0x71, 0x00, "decompression exception long algorithm id" },
 618  618          { 0x72, 0x00, "session fixation error" },
 619  619          { 0x72, 0x01, "session fixation error writing lead-in" },
 620  620          { 0x72, 0x02, "session fixation error writing lead-out" },
 621  621          { 0x72, 0x03, "session fixation error - incomplete track in session" },
 622  622          { 0x72, 0x04, "empty or partially written reserved track" },
 623  623          { 0x72, 0x05, "no more track reservations allowed" },
 624  624          { 0x73, 0x00, "cd control error" },
 625  625          { 0x73, 0x01, "power calibration area almost full" },
 626  626          { 0x73, 0x02, "power calibration area is full" },
 627  627          { 0x73, 0x03, "power calibration area error" },
 628  628          { 0x73, 0x04, "program memory area update failure" },
 629  629          { 0x73, 0x05, "program memory area is full" },
 630  630          { 0x73, 0x06, "rma/pma is almost full" },
 631  631          { 0xffff, 0xffff, NULL }
 632  632  };
 633  633  
 634  634  /*
 635  635   * Given an asc (Additional Sense Code) and ascq (Additional Sense Code
 636  636   * Qualifier), return a string describing the error information.
 637  637   */
 638  638  static char *
 639  639  scsi_util_asc_ascq_name(uint_t asc, uint_t ascq, char *buf, int buflen)
 640  640  {
 641  641          int i = 0;
 642  642  
 643  643          while (extended_sense_list[i].asc != 0xffff) {
 644  644                  if ((asc == extended_sense_list[i].asc) &&
 645  645                      ((ascq == extended_sense_list[i].ascq) ||
 646  646                      (extended_sense_list[i].ascq == 0xffff))) {
 647  647                          return ((char *)extended_sense_list[i].message);
 648  648                  }
 649  649                  i++;
 650  650          }
 651  651          (void) snprintf(buf, buflen, "<vendor unique code 0x%x>", asc);
 652  652          return (buf);
 653  653  }
 654  654  
 655  655  /*
 656  656   * Dumps detailed information about a particular SCSI error condition.
 657  657   */
 658  658  static void
 659  659  scsi_printerr(struct uscsi_cmd *ucmd, struct scsi_extended_sense *rq, int rqlen)
 660  660  {
 661  661          diskaddr_t      blkno;
 662  662          struct scsi_descr_sense_hdr *sdsp = (struct scsi_descr_sense_hdr *)rq;
 663  663          char msgbuf[MSGBUFLEN];
 664  664  
 665  665          if (find_string(sensekey_strings, rq->es_key) == NULL)
 666  666                  dprintf("unknown error");
 667  667  
 668  668          dprintf("during %s:",
 669  669              find_string(scsi_cmdname_strings, ucmd->uscsi_cdb[0]));
 670  670  
 671  671          /*
 672  672           * Get asc, ascq and info field from sense data.  There are two
 673  673           * possible formats (fixed sense data and descriptor sense data)
 674  674           * depending on the value of es_code.
 675  675           */
 676  676          switch (rq->es_code) {
 677  677          case CODE_FMT_DESCR_CURRENT:
 678  678          case CODE_FMT_DESCR_DEFERRED:
 679  679                  blkno = (diskaddr_t)scsi_extract_sense_info_descr(sdsp, rqlen);
 680  680                  if (blkno != (diskaddr_t)-1)
 681  681                          dprintf(": block %lld (0x%llx)", blkno, blkno);
 682  682                  dprintf("\n");
 683  683                  dprintf("ASC: 0x%x   ASCQ: 0x%x    (%s)\n",
 684  684                      sdsp->ds_add_code, sdsp->ds_qual_code,
 685  685                      scsi_util_asc_ascq_name(sdsp->ds_add_code,
 686  686                      sdsp->ds_qual_code, msgbuf, MSGBUFLEN));
 687  687  
 688  688                  break;
 689  689  
 690  690          case CODE_FMT_FIXED_CURRENT:
 691  691          case CODE_FMT_FIXED_DEFERRED:
 692  692          default:
 693  693                  if (rq->es_valid) {
 694  694                          blkno = (rq->es_info_1 << 24) |
 695  695                              (rq->es_info_2 << 16) |
 696  696                              (rq->es_info_3 << 8) | rq->es_info_4;
 697  697                          dprintf(": block %lld (0x%llx)", blkno, blkno);
 698  698                  }
 699  699                  dprintf("\n");
 700  700                  if (rq->es_add_len >= 6) {
 701  701                          dprintf("ASC: 0x%x   ASCQ: 0x%x    (%s)\n",
 702  702                              rq->es_add_code,
 703  703                              rq->es_qual_code,
 704  704                              scsi_util_asc_ascq_name(rq->es_add_code,
 705  705                              rq->es_qual_code, msgbuf, MSGBUFLEN));
 706  706                  }
 707  707                  break;
 708  708          }
 709  709  
 710  710          if (rq->es_key == KEY_ILLEGAL_REQUEST) {
 711  711                  ddump("cmd:", (caddr_t)ucmd,
 712  712                      sizeof (struct uscsi_cmd));
 713  713                  ddump("cdb:", (caddr_t)ucmd->uscsi_cdb,
 714  714                      ucmd->uscsi_cdblen);
 715  715          }
 716  716          ddump("sense:", (caddr_t)rq, rqlen);
 717  717  
 718  718          switch (rq->es_code) {
 719  719          case CODE_FMT_DESCR_CURRENT:
 720  720          case CODE_FMT_DESCR_DEFERRED:
 721  721                  scsi_print_descr_sense(sdsp, rqlen);
 722  722                  break;
 723  723          case CODE_FMT_FIXED_CURRENT:
 724  724          case CODE_FMT_FIXED_DEFERRED:
 725  725          default:
 726  726                  scsi_print_extended_sense(rq, rqlen);
 727  727                  break;
 728  728          }
 729  729  }
 730  730  
 731  731  /*
 732  732   * Retrieve "information" field from descriptor format sense data.  Iterates
 733  733   * through each sense descriptor looking for the information descriptor and
 734  734   * returns the information field from that descriptor.
 735  735   */
 736  736  static diskaddr_t
 737  737  scsi_extract_sense_info_descr(struct scsi_descr_sense_hdr *sdsp, int rqlen)
 738  738  {
 739  739          diskaddr_t result;
 740  740          uint8_t *descr_offset;
 741  741          int valid_sense_length;
 742  742          struct scsi_information_sense_descr *isd;
 743  743  
 744  744          /*
 745  745           * Initialize result to -1 indicating there is no information
 746  746           * descriptor
 747  747           */
 748  748          result = (diskaddr_t)-1;
 749  749  
 750  750          /*
 751  751           * The first descriptor will immediately follow the header
 752  752           */
 753  753          descr_offset = (uint8_t *)(sdsp+1);
 754  754  
 755  755          /*
 756  756           * Calculate the amount of valid sense data
 757  757           */
 758  758          valid_sense_length =
 759  759              MIN((sizeof (struct scsi_descr_sense_hdr) +
 760  760              sdsp->ds_addl_sense_length), rqlen);
 761  761  
 762  762          /*
 763  763           * Iterate through the list of descriptors, stopping when we run out of
 764  764           * sense data
 765  765           */
 766  766          while ((descr_offset + sizeof (struct scsi_information_sense_descr)) <=
 767  767              (uint8_t *)sdsp + valid_sense_length) {
 768  768                  /*
 769  769                   * Check if this is an information descriptor.  We can use the
 770  770                   * scsi_information_sense_descr structure as a template since
 771  771                   * the first two fields are always the same
 772  772                   */
 773  773                  isd = (struct scsi_information_sense_descr *)descr_offset;
 774  774                  if (isd->isd_descr_type == DESCR_INFORMATION) {
 775  775                          /*
 776  776                           * Found an information descriptor.  Copy the
 777  777                           * information field.  There will only be one
 778  778                           * information descriptor so we can stop looking.
 779  779                           */
 780  780                          result =
 781  781                              (((diskaddr_t)isd->isd_information[0] << 56) |
 782  782                              ((diskaddr_t)isd->isd_information[1] << 48) |
 783  783                              ((diskaddr_t)isd->isd_information[2] << 40) |
 784  784                              ((diskaddr_t)isd->isd_information[3] << 32) |
 785  785                              ((diskaddr_t)isd->isd_information[4] << 24) |
 786  786                              ((diskaddr_t)isd->isd_information[5] << 16) |
 787  787                              ((diskaddr_t)isd->isd_information[6] << 8)  |
 788  788                              ((diskaddr_t)isd->isd_information[7]));
 789  789                          break;
 790  790                  }
 791  791  
 792  792                  /*
 793  793                   * Get pointer to the next descriptor.  The "additional length"
 794  794                   * field holds the length of the descriptor except for the
 795  795                   * "type" and "additional length" fields, so we need to add 2 to
 796  796                   * get the total length.
 797  797                   */
 798  798                  descr_offset += (isd->isd_addl_length + 2);
 799  799          }
 800  800  
 801  801          return (result);
 802  802  }
 803  803  
 804  804  /*
 805  805   * Display the full scsi_extended_sense as returned by the device
 806  806   */
 807  807  static void
 808  808  scsi_print_extended_sense(struct scsi_extended_sense *rq, int rqlen)
 809  809  {
 810  810          static char *scsi_extended_sense_labels[] = {
 811  811              "Request sense valid:             ",
 812  812              "Error class and code:            ",
 813  813              "Segment number:                  ",
 814  814              "Filemark:                        ",
 815  815              "End-of-medium:                   ",
 816  816              "Incorrect length indicator:      ",
 817  817              "Sense key:                       ",
 818  818              "Information field:               ",
 819  819              "Additional sense length:         ",
 820  820              "Command-specific information:    ",
 821  821              "Additional sense code:           ",
 822  822              "Additional sense code qualifier: ",
 823  823              "Field replaceable unit code:     ",
 824  824              "Sense-key specific:              ",
 825  825              "Additional sense bytes:          "
 826  826          };
 827  827  
 828  828          char **p = scsi_extended_sense_labels;
 829  829  
 830  830          if (rqlen < (sizeof (*rq) - 2) || !rq->es_valid) {
 831  831                  /*
 832  832                   * target should be capable of returning at least 18
 833  833                   * bytes of data, i.e upto rq->es_skey_specific field.
 834  834                   * The additional sense bytes (2 or more ...) are optional.
 835  835                   */
 836  836                  return;
 837  837          }
 838  838  
 839  839          dprintf("\n%s%s\n", *p++, rq->es_valid ? "yes" : "no");
 840  840          dprintf("%s0x%02x\n", *p++, (rq->es_class << 4) + rq->es_code);
 841  841          dprintf("%s%d\n", *p++, rq->es_segnum);
 842  842          dprintf("%s%s\n", *p++, rq->es_filmk ? "yes" : "no");
 843  843          dprintf("%s%s\n", *p++, rq->es_eom ? "yes" : "no");
 844  844          dprintf("%s%s\n", *p++, rq->es_ili ? "yes" : "no");
 845  845          dprintf("%s%d\n", *p++, rq->es_key);
 846  846  
 847  847          dprintf("%s0x%02x 0x%02x 0x%02x 0x%02x\n", *p++, rq->es_info_1,
 848  848              rq->es_info_2, rq->es_info_3, rq->es_info_4);
 849  849          dprintf("%s%d\n", *p++, rq->es_add_len);
 850  850          dprintf("%s0x%02x 0x%02x 0x%02x 0x%02x\n", *p++,
 851  851              rq->es_cmd_info[0], rq->es_cmd_info[1], rq->es_cmd_info[2],
 852  852              rq->es_cmd_info[3]);
 853  853          dprintf("%s0x%02x = %d\n", *p++, rq->es_add_code,
 854  854              rq->es_add_code);
 855  855          dprintf("%s0x%02x = %d\n", *p++, rq->es_qual_code,
 856  856              rq->es_qual_code);
 857  857          dprintf("%s%d\n", *p++, rq->es_fru_code);
 858  858          dprintf("%s0x%02x 0x%02x 0x%02x\n", *p++,
 859  859              rq->es_skey_specific[0], rq->es_skey_specific[1],
 860  860              rq->es_skey_specific[2]);
 861  861          if (rqlen >= sizeof (*rq)) {
 862  862                  dprintf("%s0x%02x 0x%02x%s\n", *p, rq->es_add_info[0],
 863  863                      rq->es_add_info[1], (rqlen > sizeof (*rq)) ? " ..." : "");
 864  864          }
 865  865  
 866  866          dprintf("\n");
 867  867  }
 868  868  
 869  869  /*
 870  870   * Display the full descriptor sense data as returned by the device
 871  871   */
 872  872  static void
 873  873  scsi_print_descr_sense(struct scsi_descr_sense_hdr *rq, int rqlen)
 874  874  {
 875  875          /*
 876  876           * Labels for the various fields of the scsi_descr_sense_hdr structure
 877  877           */
 878  878          static char *scsi_descr_sense_labels[] = {
 879  879              "Error class and code:            ",
 880  880              "Sense key:                       ",
 881  881              "Additional sense length:         ",
 882  882              "Additional sense code:           ",
 883  883              "Additional sense code qualifier: ",
 884  884              "Additional sense bytes:          "
 885  885          };
 886  886  
 887  887          struct scsi_information_sense_descr *isd;
 888  888          uint8_t *descr_offset;
 889  889          int valid_sense_length;
 890  890          char **p = scsi_descr_sense_labels;
 891  891  
 892  892          /* Target must return at least 8 bytes of data */
 893  893          if (rqlen < sizeof (struct scsi_descr_sense_hdr))
 894  894                  return;
 895  895  
 896  896          /* Print descriptor sense header */
 897  897          dprintf("%s0x%02x\n", *p++, (rq->ds_class << 4) + rq->ds_code);
 898  898          dprintf("%s%d\n", *p++, rq->ds_key);
 899  899  
 900  900          dprintf("%s%d\n", *p++, rq->ds_addl_sense_length);
 901  901          dprintf("%s0x%02x = %d\n", *p++, rq->ds_add_code,
 902  902              rq->ds_add_code);
 903  903          dprintf("%s0x%02x = %d\n", *p++, rq->ds_qual_code,
 904  904              rq->ds_qual_code);
 905  905          dprintf("\n");
 906  906  
 907  907          /*
 908  908           * Now print any sense descriptors.   The first descriptor will
 909  909           * immediately follow the header
 910  910           */
 911  911          descr_offset = (uint8_t *)(rq+1); /* Pointer arithmetic */
 912  912  
 913  913          /*
 914  914           * Calculate the amount of valid sense data
 915  915           */
 916  916          valid_sense_length =
 917  917              MIN((sizeof (struct scsi_descr_sense_hdr) +
 918  918              rq->ds_addl_sense_length), rqlen);
 919  919  
 920  920          /*
 921  921           * Iterate through the list of descriptors, stopping when we
 922  922           * run out of sense data.  Descriptor format is:
 923  923           *
 924  924           * <Descriptor type> <Descriptor length> <Descriptor data> ...
 925  925           */
 926  926          while ((descr_offset + *(descr_offset + 1)) <=
 927  927              (uint8_t *)rq + valid_sense_length) {
 928  928                  /*
 929  929                   * Determine descriptor type.  We can use the
 930  930                   * scsi_information_sense_descr structure as a
 931  931                   * template since the first two fields are always the
 932  932                   * same.
 933  933                   */
 934  934                  isd = (struct scsi_information_sense_descr *)descr_offset;
 935  935                  switch (isd->isd_descr_type) {
 936  936                  case DESCR_INFORMATION: {
 937  937                          uint64_t information;
 938  938  
 939  939                          information =
 940  940                              (((uint64_t)isd->isd_information[0] << 56) |
 941  941                              ((uint64_t)isd->isd_information[1] << 48) |
 942  942                              ((uint64_t)isd->isd_information[2] << 40) |
 943  943                              ((uint64_t)isd->isd_information[3] << 32) |
 944  944                              ((uint64_t)isd->isd_information[4] << 24) |
 945  945                              ((uint64_t)isd->isd_information[5] << 16) |
 946  946                              ((uint64_t)isd->isd_information[6] << 8)  |
 947  947                              ((uint64_t)isd->isd_information[7]));
 948  948                          dprintf("Information field:               "
 949  949                              "%0" PRIx64 "\n", information);
 950  950                          break;
 951  951                  }
 952  952                  case DESCR_COMMAND_SPECIFIC: {
 953  953                          struct scsi_cmd_specific_sense_descr *c =
 954  954                              (struct scsi_cmd_specific_sense_descr *)isd;
 955  955                          uint64_t cmd_specific;
 956  956  
 957  957                          cmd_specific =
 958  958                              (((uint64_t)c->css_cmd_specific_info[0] << 56) |
 959  959                              ((uint64_t)c->css_cmd_specific_info[1] << 48) |
 960  960                              ((uint64_t)c->css_cmd_specific_info[2] << 40) |
 961  961                              ((uint64_t)c->css_cmd_specific_info[3] << 32) |
 962  962                              ((uint64_t)c->css_cmd_specific_info[4] << 24) |
 963  963                              ((uint64_t)c->css_cmd_specific_info[5] << 16) |
 964  964                              ((uint64_t)c->css_cmd_specific_info[6] << 8)  |
 965  965                              ((uint64_t)c->css_cmd_specific_info[7]));
 966  966                          dprintf("Command-specific information:    "
 967  967                              "%0" PRIx64 "\n", cmd_specific);
 968  968                          break;
 969  969                  }
 970  970                  case DESCR_SENSE_KEY_SPECIFIC: {
 971  971                          struct scsi_sk_specific_sense_descr *ssd =
 972  972                              (struct scsi_sk_specific_sense_descr *)isd;
 973  973                          uint8_t *sk_spec_ptr = (uint8_t *)&ssd->sss_data;
 974  974                          dprintf("Sense-key specific:              "
 975  975                              "0x%02x 0x%02x 0x%02x\n", sk_spec_ptr[0],
 976  976                              sk_spec_ptr[1], sk_spec_ptr[2]);
 977  977                          break;
 978  978                  }
 979  979                  case DESCR_FRU: {
 980  980                          struct scsi_fru_sense_descr *fsd =
 981  981                              (struct scsi_fru_sense_descr *)isd;
 982  982                          dprintf("Field replaceable unit code:     "
 983  983                              "%d\n", fsd->fs_fru_code);
 984  984                          break;
 985  985                  }
 986  986                  case DESCR_BLOCK_COMMANDS: {
 987  987                          struct scsi_block_cmd_sense_descr *bsd =
 988  988                              (struct scsi_block_cmd_sense_descr *)isd;
 989  989                          dprintf("Incorrect length indicator:      "
 990  990                              "%s\n", bsd->bcs_ili ? "yes" : "no");
 991  991                          break;
 992  992                  }
 993  993                  default:
 994  994                          /* Ignore */
 995  995                          break;
 996  996                  }
 997  997  
 998  998                  /*
 999  999                   * Get pointer to the next descriptor.  The "additional
1000 1000                   * length" field holds the length of the descriptor except
1001 1001                   * for the "type" and "additional length" fields, so
1002 1002                   * we need to add 2 to get the total length.
1003 1003                   */
1004 1004                  descr_offset += (isd->isd_addl_length + 2);
1005 1005          }
1006 1006  
1007 1007          dprintf("\n");
1008 1008  }
1009 1009  
1010 1010  static int
1011 1011  uscsi_timeout(void)
1012 1012  {
1013 1013          const char *env = getenv("USCSI_TIMEOUT");
  
    | 
      ↓ open down ↓ | 
    1013 lines elided | 
    
      ↑ open up ↑ | 
  
1014 1014          static int timeo = -1;
1015 1015          int i;
1016 1016  
1017 1017          if (timeo > 0)
1018 1018                  return (timeo);
1019 1019  
1020 1020          if (env != NULL) {
1021 1021                  i = atoi(env);
1022 1022                  if (i > USCSI_TIMEOUT_MAX)
1023 1023                          i = USCSI_TIMEOUT_MAX;
1024      -                else if (i < 0)
     1024 +                else if (i <= 0)
1025 1025                          i = USCSI_DEFAULT_TIMEOUT;
1026 1026          } else
1027 1027                  i = USCSI_DEFAULT_TIMEOUT;
1028 1028  
1029 1029          timeo = i;
1030 1030          return (i);
1031 1031  }
1032 1032  
1033 1033  /*
1034 1034   * Execute a command and determine the result.  Uses the "uscsi" ioctl
1035 1035   * interface, which is fully supported.
1036 1036   *
1037 1037   * If the user wants request sense data to be returned in case of error then ,
1038 1038   * the "uscsi_cmd" structure should have the request sense buffer allocated in
1039 1039   * uscsi_rqbuf.
1040 1040   */
1041 1041  static int
1042 1042  uscsi_cmd(int fd, struct uscsi_cmd *ucmd, void *rqbuf, int *rqlen)
1043 1043  {
1044 1044          struct scsi_extended_sense *rq;
1045 1045          int status;
1046 1046  
1047 1047          /*
1048 1048           * Set function flags for driver.
1049 1049           */
1050 1050          ucmd->uscsi_flags = USCSI_ISOLATE;
1051 1051          if (!ds_debug)
1052 1052                  ucmd->uscsi_flags |= USCSI_SILENT;
1053 1053  
1054 1054          /*
1055 1055           * If this command will perform a read, set the USCSI_READ flag
1056 1056           */
1057 1057          if (ucmd->uscsi_buflen > 0) {
1058 1058                  /*
1059 1059                   * uscsi_cdb is declared as a caddr_t, so any CDB
1060 1060                   * command byte with the MSB set will result in a
1061 1061                   * compiler error unless we cast to an unsigned value.
1062 1062                   */
1063 1063                  switch ((uint8_t)ucmd->uscsi_cdb[0]) {
1064 1064                  case SCMD_MODE_SENSE:
1065 1065                  case SCMD_MODE_SENSE_G1:
1066 1066                  case SCMD_LOG_SENSE_G1:
1067 1067                  case SCMD_REQUEST_SENSE:
1068 1068                          ucmd->uscsi_flags |= USCSI_READ;
1069 1069                          break;
1070 1070  
1071 1071                  case SCMD_MODE_SELECT:
1072 1072                  case SCMD_MODE_SELECT_G1:
1073 1073                          /* LINTED */
1074 1074                          ucmd->uscsi_flags |= USCSI_WRITE;
1075 1075                          break;
1076 1076                  default:
1077 1077                          assert(0);
1078 1078                          break;
1079 1079                  }
1080 1080          }
1081 1081  
1082 1082          /* Set timeout */
1083 1083          ucmd->uscsi_timeout = uscsi_timeout();
1084 1084  
1085 1085          /*
1086 1086           * Set up Request Sense buffer
1087 1087           */
1088 1088  
1089 1089          if (ucmd->uscsi_rqbuf == NULL)  {
1090 1090                  ucmd->uscsi_rqbuf = rqbuf;
1091 1091                  ucmd->uscsi_rqlen = *rqlen;
1092 1092                  ucmd->uscsi_rqresid = *rqlen;
1093 1093          }
1094 1094          if (ucmd->uscsi_rqbuf)
1095 1095                  ucmd->uscsi_flags |= USCSI_RQENABLE;
1096 1096          ucmd->uscsi_rqstatus = IMPOSSIBLE_SCSI_STATUS;
1097 1097  
1098 1098          if (ucmd->uscsi_rqbuf != NULL && ucmd->uscsi_rqlen > 0)
1099 1099                  (void) memset(ucmd->uscsi_rqbuf, 0, ucmd->uscsi_rqlen);
1100 1100  
1101 1101          /*
1102 1102           * Execute the ioctl
1103 1103           */
1104 1104          status = ioctl(fd, USCSICMD, ucmd);
1105 1105          if (status == 0 && ucmd->uscsi_status == 0)
1106 1106                  return (status);
1107 1107  
1108 1108          /*
1109 1109           * If an automatic Request Sense gave us valid info about the error, we
1110 1110           * may be able to use that to print a reasonable error msg.
1111 1111           */
1112 1112          if (ucmd->uscsi_rqstatus == IMPOSSIBLE_SCSI_STATUS) {
1113 1113                  dprintf("No request sense for command %s\n",
1114 1114                      find_string(scsi_cmdname_strings,
1115 1115                      ucmd->uscsi_cdb[0]));
1116 1116                  return (-1);
1117 1117          }
1118 1118          if (ucmd->uscsi_rqstatus != STATUS_GOOD) {
1119 1119                  dprintf("Request sense status for command %s: 0x%x\n",
1120 1120                      find_string(scsi_cmdname_strings,
1121 1121                      ucmd->uscsi_cdb[0]),
1122 1122                      ucmd->uscsi_rqstatus);
1123 1123                  return (-1);
1124 1124          }
1125 1125  
1126 1126          rq = (struct scsi_extended_sense *)ucmd->uscsi_rqbuf;
1127 1127          *rqlen = ucmd->uscsi_rqlen - ucmd->uscsi_rqresid;
1128 1128  
1129 1129          if ((((int)rq->es_add_len) + 8) < MIN_REQUEST_SENSE_LEN ||
1130 1130              rq->es_class != CLASS_EXTENDED_SENSE ||
1131 1131              *rqlen < MIN_REQUEST_SENSE_LEN) {
1132 1132                  dprintf("Request sense for command %s failed\n",
1133 1133                      find_string(scsi_cmdname_strings,
1134 1134                      ucmd->uscsi_cdb[0]));
1135 1135  
1136 1136                  dprintf("Sense data:\n");
1137 1137                  ddump(NULL, (caddr_t)rqbuf, *rqlen);
1138 1138  
1139 1139                  return (-1);
1140 1140          }
1141 1141  
1142 1142          /*
1143 1143           * If the failed command is a Mode Select, and the
1144 1144           * target is indicating that it has rounded one of
1145 1145           * the mode select parameters, as defined in the SCSI-2
1146 1146           * specification, then we should accept the command
1147 1147           * as successful.
1148 1148           */
1149 1149          if (ucmd->uscsi_cdb[0] == SCMD_MODE_SELECT ||
1150 1150              ucmd->uscsi_cdb[0] == SCMD_MODE_SELECT_G1) {
1151 1151                  if (rq->es_key == KEY_RECOVERABLE_ERROR &&
1152 1152                      rq->es_add_code == ROUNDED_PARAMETER &&
1153 1153                      rq->es_qual_code == 0) {
1154 1154                          return (0);
1155 1155                  }
1156 1156          }
1157 1157  
1158 1158          if (ds_debug)
1159 1159                  scsi_printerr(ucmd, rq, *rqlen);
1160 1160          if (rq->es_key != KEY_RECOVERABLE_ERROR)
1161 1161                  return (-1);
1162 1162          return (0);
1163 1163  }
1164 1164  
1165 1165  int
1166 1166  uscsi_request_sense(int fd, caddr_t buf, int buflen, void *rqbuf, int *rqblen)
1167 1167  {
1168 1168          struct uscsi_cmd ucmd;
1169 1169          union scsi_cdb cdb;
1170 1170          int status;
1171 1171  
1172 1172          (void) memset(buf, 0, buflen);
1173 1173          (void) memset(&ucmd, 0, sizeof (ucmd));
1174 1174          (void) memset(&cdb, 0, sizeof (union scsi_cdb));
1175 1175          cdb.scc_cmd = SCMD_REQUEST_SENSE;
1176 1176          FORMG0COUNT(&cdb, (uchar_t)buflen);
1177 1177          ucmd.uscsi_cdb = (caddr_t)&cdb;
1178 1178          ucmd.uscsi_cdblen = CDB_GROUP0;
1179 1179          ucmd.uscsi_bufaddr = buf;
1180 1180          ucmd.uscsi_buflen = buflen;
1181 1181          status = uscsi_cmd(fd, &ucmd, rqbuf, rqblen);
1182 1182          if (status)
1183 1183                  dprintf("Request sense failed\n");
1184 1184          if (status == 0)
1185 1185                  ddump("Request Sense data:", buf, buflen);
1186 1186  
1187 1187          return (status);
1188 1188  }
1189 1189  
1190 1190  /*
1191 1191   * Execute a uscsi mode sense command.  This can only be used to return one page
1192 1192   * at a time.  Return the mode header/block descriptor and the actual page data
1193 1193   * separately - this allows us to support devices which return either 0 or 1
1194 1194   * block descriptors.  Whatever a device gives us in the mode header/block
1195 1195   * descriptor will be returned to it upon subsequent mode selects.
1196 1196   */
1197 1197  int
1198 1198  uscsi_mode_sense(int fd, int page_code, int page_control, caddr_t page_data,
1199 1199      int page_size, struct scsi_ms_header *header, void *rqbuf, int *rqblen)
1200 1200  {
1201 1201          caddr_t mode_sense_buf;
1202 1202          struct mode_header *hdr;
1203 1203          struct mode_page *pg;
1204 1204          int nbytes;
1205 1205          struct uscsi_cmd ucmd;
1206 1206          union scsi_cdb cdb;
1207 1207          int status;
1208 1208          int maximum;
1209 1209          char *pc;
1210 1210  
1211 1211          assert(page_size >= 0 && page_size < 256);
1212 1212          assert(page_control == PC_CURRENT || page_control == PC_CHANGEABLE ||
1213 1213              page_control == PC_DEFAULT || page_control == PC_SAVED);
1214 1214  
1215 1215          nbytes = sizeof (struct scsi_ms_header) + page_size;
1216 1216          mode_sense_buf = alloca((uint_t)nbytes);
1217 1217  
1218 1218          /*
1219 1219           * Build and execute the uscsi ioctl
1220 1220           */
1221 1221          (void) memset(mode_sense_buf, 0, nbytes);
1222 1222          (void) memset(&ucmd, 0, sizeof (ucmd));
1223 1223          (void) memset(&cdb, 0, sizeof (union scsi_cdb));
1224 1224          cdb.scc_cmd = SCMD_MODE_SENSE;
1225 1225          FORMG0COUNT(&cdb, (uchar_t)nbytes);
1226 1226          cdb.cdb_opaque[2] = page_control | page_code;
1227 1227          ucmd.uscsi_cdb = (caddr_t)&cdb;
1228 1228          ucmd.uscsi_cdblen = CDB_GROUP0;
1229 1229          ucmd.uscsi_bufaddr = mode_sense_buf;
1230 1230          ucmd.uscsi_buflen = nbytes;
1231 1231          status = uscsi_cmd(fd, &ucmd, rqbuf, rqblen);
1232 1232          if (status) {
1233 1233                  dprintf("Mode sense page 0x%x failed\n", page_code);
1234 1234                  return (-1);
1235 1235          }
1236 1236  
1237 1237          ddump("RAW MODE SENSE BUFFER", mode_sense_buf, nbytes);
1238 1238  
1239 1239          /*
1240 1240           * Verify that the returned data looks reasonable, find the actual page
1241 1241           * data, and copy it into the user's buffer.  Copy the mode_header and
1242 1242           * block_descriptor into the header structure, which can then be used to
1243 1243           * return the same data to the drive when issuing a mode select.
1244 1244           */
1245 1245          hdr = (struct mode_header *)mode_sense_buf;
1246 1246          (void) memset((caddr_t)header, 0, sizeof (struct scsi_ms_header));
1247 1247          if (hdr->bdesc_length != sizeof (struct block_descriptor) &&
1248 1248              hdr->bdesc_length != 0) {
1249 1249                  dprintf("\nMode sense page 0x%x: block descriptor "
1250 1250                      "length %d incorrect\n", page_code, hdr->bdesc_length);
1251 1251                  ddump("Mode sense:", mode_sense_buf, nbytes);
1252 1252                  return (-1);
1253 1253          }
1254 1254          (void) memcpy((caddr_t)header, mode_sense_buf,
1255 1255              (int)(MODE_HEADER_LENGTH + hdr->bdesc_length));
1256 1256          pg = (struct mode_page *)((ulong_t)mode_sense_buf +
1257 1257              MODE_HEADER_LENGTH + hdr->bdesc_length);
1258 1258  
1259 1259          if (page_code == MODEPAGE_ALLPAGES) {
1260 1260                  /* special case */
1261 1261  
1262 1262                  (void) memcpy(page_data, (caddr_t)pg,
1263 1263                      (hdr->length + sizeof (header->ms_header.length)) -
1264 1264                      (MODE_HEADER_LENGTH + hdr->bdesc_length));
1265 1265  
1266 1266                  pc = find_string(page_control_strings, page_control);
1267 1267                  dprintf("\nMode sense page 0x%x (%s):\n", page_code,
1268 1268                      pc != NULL ? pc : "");
1269 1269                  ddump("header:", (caddr_t)header,
1270 1270                      sizeof (struct scsi_ms_header));
1271 1271                  ddump("data:", page_data,
1272 1272                      (hdr->length +
1273 1273                      sizeof (header->ms_header.length)) -
1274 1274                      (MODE_HEADER_LENGTH + hdr->bdesc_length));
1275 1275  
1276 1276                  return (0);
1277 1277          }
1278 1278  
1279 1279          if (pg->code != page_code) {
1280 1280                  dprintf("\nMode sense page 0x%x: incorrect page code 0x%x\n",
1281 1281                      page_code, pg->code);
1282 1282                  ddump("Mode sense:", mode_sense_buf, nbytes);
1283 1283                  return (-1);
1284 1284          }
1285 1285  
1286 1286          /*
1287 1287           * Accept up to "page_size" bytes of mode sense data.  This allows us to
1288 1288           * accept both CCS and SCSI-2 structures, as long as we request the
1289 1289           * greater of the two.
1290 1290           */
1291 1291          maximum = page_size - sizeof (struct mode_page);
1292 1292          if (((int)pg->length) > maximum) {
1293 1293                  dprintf("Mode sense page 0x%x: incorrect page "
1294 1294                      "length %d - expected max %d\n",
1295 1295                      page_code, pg->length, maximum);
1296 1296                  ddump("Mode sense:", mode_sense_buf, nbytes);
1297 1297                  return (-1);
1298 1298          }
1299 1299  
1300 1300          (void) memcpy(page_data, (caddr_t)pg, MODESENSE_PAGE_LEN(pg));
1301 1301  
1302 1302          pc = find_string(page_control_strings, page_control);
1303 1303          dprintf("\nMode sense page 0x%x (%s):\n", page_code,
1304 1304              pc != NULL ? pc : "");
1305 1305          ddump("header:", (caddr_t)header, sizeof (struct scsi_ms_header));
1306 1306          ddump("data:", page_data, MODESENSE_PAGE_LEN(pg));
1307 1307  
1308 1308          return (0);
1309 1309  }
1310 1310  
1311 1311  /*
1312 1312   * Execute a uscsi MODE SENSE(10) command.  This can only be used to return one
1313 1313   * page at a time.  Return the mode header/block descriptor and the actual page
1314 1314   * data separately - this allows us to support devices which return either 0 or
1315 1315   * 1 block descriptors.  Whatever a device gives us in the mode header/block
1316 1316   * descriptor will be returned to it upon subsequent mode selects.
1317 1317   */
1318 1318  int
1319 1319  uscsi_mode_sense_10(int fd, int page_code, int page_control,
1320 1320      caddr_t page_data, int page_size, struct scsi_ms_header_g1 *header,
1321 1321      void *rqbuf, int *rqblen)
1322 1322  {
1323 1323          caddr_t mode_sense_buf;
1324 1324          struct mode_header_g1 *hdr;
1325 1325          struct mode_page *pg;
1326 1326          int nbytes;
1327 1327          struct uscsi_cmd ucmd;
1328 1328          union scsi_cdb cdb;
1329 1329          int status;
1330 1330          int maximum;
1331 1331          ushort_t length, bdesc_length;
1332 1332          char *pc;
1333 1333  
1334 1334          assert(page_size >= 0 && page_size < UINT16_MAX);
1335 1335          assert(page_control == PC_CURRENT || page_control == PC_CHANGEABLE ||
1336 1336              page_control == PC_DEFAULT || page_control == PC_SAVED);
1337 1337  
1338 1338          nbytes = sizeof (struct scsi_ms_header_g1) + page_size;
1339 1339          mode_sense_buf = alloca((uint_t)nbytes);
1340 1340  
1341 1341          (void) memset(mode_sense_buf, 0, nbytes);
1342 1342          (void) memset((char *)&ucmd, 0, sizeof (ucmd));
1343 1343          (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
1344 1344          cdb.scc_cmd = SCMD_MODE_SENSE_G1;
1345 1345          FORMG1COUNT(&cdb, (uint16_t)nbytes);
1346 1346          cdb.cdb_opaque[2] = page_control | page_code;
1347 1347          ucmd.uscsi_cdb = (caddr_t)&cdb;
1348 1348          ucmd.uscsi_cdblen = CDB_GROUP1;
1349 1349          ucmd.uscsi_bufaddr = mode_sense_buf;
1350 1350          ucmd.uscsi_buflen = nbytes;
1351 1351  
1352 1352          status = uscsi_cmd(fd, &ucmd, rqbuf, rqblen);
1353 1353          if (status) {
1354 1354                  dprintf("Mode sense(10) page 0x%x failed\n",
1355 1355                      page_code);
1356 1356                  return (-1);
1357 1357          }
1358 1358  
1359 1359          ddump("RAW MODE SENSE(10) BUFFER", mode_sense_buf, nbytes);
1360 1360  
1361 1361          /*
1362 1362           * Verify that the returned data looks reasonable, find the actual page
1363 1363           * data, and copy it into the user's buffer.  Copy the mode_header and
1364 1364           * block_descriptor into the header structure, which can then be used to
1365 1365           * return the same data to the drive when issuing a mode select.
1366 1366           */
1367 1367          /* LINTED */
1368 1368          hdr = (struct mode_header_g1 *)mode_sense_buf;
1369 1369  
1370 1370          length = BE_16(hdr->length);
1371 1371          bdesc_length = BE_16(hdr->bdesc_length);
1372 1372  
1373 1373          (void) memset((caddr_t)header, 0, sizeof (struct scsi_ms_header_g1));
1374 1374          if (bdesc_length != sizeof (struct block_descriptor) &&
1375 1375              bdesc_length != 0) {
1376 1376                  dprintf("\nMode sense(10) page 0x%x: block descriptor "
1377 1377                      "length %d incorrect\n", page_code, bdesc_length);
1378 1378                  ddump("Mode sense(10):", mode_sense_buf, nbytes);
1379 1379                  return (-1);
1380 1380          }
1381 1381          (void) memcpy((caddr_t)header, mode_sense_buf,
1382 1382              (int)(MODE_HEADER_LENGTH_G1 + bdesc_length));
1383 1383          pg = (struct mode_page *)((ulong_t)mode_sense_buf +
1384 1384              MODE_HEADER_LENGTH_G1 + bdesc_length);
1385 1385  
1386 1386          if (page_code == MODEPAGE_ALLPAGES) {
1387 1387                  /* special case */
1388 1388  
1389 1389                  (void) memcpy(page_data, (caddr_t)pg,
1390 1390                      (length + sizeof (header->ms_header.length)) -
1391 1391                      (MODE_HEADER_LENGTH_G1 + bdesc_length));
1392 1392  
1393 1393                  pc = find_string(page_control_strings, page_control);
1394 1394                  dprintf("\nMode sense(10) page 0x%x (%s):\n",
1395 1395                      page_code, pc != NULL ? pc : "");
1396 1396                  ddump("header:", (caddr_t)header,
1397 1397                      MODE_HEADER_LENGTH_G1 + bdesc_length);
1398 1398  
1399 1399                  ddump("data:", page_data,
1400 1400                      (length + sizeof (header->ms_header.length)) -
1401 1401                      (MODE_HEADER_LENGTH_G1 + bdesc_length));
1402 1402  
1403 1403                  return (0);
1404 1404          }
1405 1405  
1406 1406          if (pg->code != page_code) {
1407 1407                  dprintf("\nMode sense(10) page 0x%x: incorrect page "
1408 1408                      "code 0x%x\n", page_code, pg->code);
1409 1409                  ddump("Mode sense(10):", mode_sense_buf, nbytes);
1410 1410                  return (-1);
1411 1411          }
1412 1412  
1413 1413          /*
1414 1414           * Accept up to "page_size" bytes of mode sense data.  This allows us to
1415 1415           * accept both CCS and SCSI-2 structures, as long as we request the
1416 1416           * greater of the two.
1417 1417           */
1418 1418          maximum = page_size - sizeof (struct mode_page);
1419 1419          if (((int)pg->length) > maximum) {
1420 1420                  dprintf("Mode sense(10) page 0x%x: incorrect page "
1421 1421                      "length %d - expected max %d\n",
1422 1422                      page_code, pg->length, maximum);
1423 1423                  ddump("Mode sense(10):", mode_sense_buf,
1424 1424                      nbytes);
1425 1425                  return (-1);
1426 1426          }
1427 1427  
1428 1428          (void) memcpy(page_data, (caddr_t)pg, MODESENSE_PAGE_LEN(pg));
1429 1429  
1430 1430          pc = find_string(page_control_strings, page_control);
1431 1431          dprintf("\nMode sense(10) page 0x%x (%s):\n", page_code,
1432 1432              pc != NULL ? pc : "");
1433 1433          ddump("header:", (caddr_t)header,
1434 1434              sizeof (struct scsi_ms_header_g1));
1435 1435          ddump("data:", page_data, MODESENSE_PAGE_LEN(pg));
1436 1436  
1437 1437          return (0);
1438 1438  }
1439 1439  
1440 1440  /*
1441 1441   * Execute a uscsi mode select command.
1442 1442   */
1443 1443  int
1444 1444  uscsi_mode_select(int fd, int page_code, int options, caddr_t page_data,
1445 1445      int page_size, struct scsi_ms_header *header, void *rqbuf, int *rqblen)
1446 1446  {
1447 1447          caddr_t mode_select_buf;
1448 1448          int nbytes;
1449 1449          struct uscsi_cmd ucmd;
1450 1450          union scsi_cdb cdb;
1451 1451          int status;
1452 1452          char *s;
1453 1453  
1454 1454          assert(((struct mode_page *)page_data)->ps == 0);
1455 1455          assert(header->ms_header.length == 0);
1456 1456          assert(header->ms_header.device_specific == 0);
1457 1457          assert((options & ~(MODE_SELECT_SP|MODE_SELECT_PF)) == 0);
1458 1458  
1459 1459          nbytes = sizeof (struct scsi_ms_header) + page_size;
1460 1460          mode_select_buf = alloca((uint_t)nbytes);
1461 1461  
1462 1462          /*
1463 1463           * Build the mode select data out of the header and page data This
1464 1464           * allows us to support devices which return either 0 or 1 block
1465 1465           * descriptors.
1466 1466           */
1467 1467          (void) memset(mode_select_buf, 0, nbytes);
1468 1468          nbytes = MODE_HEADER_LENGTH;
1469 1469          if (header->ms_header.bdesc_length ==
1470 1470              sizeof (struct block_descriptor)) {
1471 1471                  nbytes += sizeof (struct block_descriptor);
1472 1472          }
1473 1473  
1474 1474          s = find_string(mode_select_strings,
1475 1475              options & (MODE_SELECT_SP|MODE_SELECT_PF));
1476 1476          dprintf("\nMode select page 0x%x%s:\n", page_code,
1477 1477              s != NULL ? s : "");
1478 1478          ddump("header:", (caddr_t)header, nbytes);
1479 1479          ddump("data:", (caddr_t)page_data, page_size);
1480 1480  
1481 1481          /*
1482 1482           * Put the header and data together
1483 1483           */
1484 1484          (void) memcpy(mode_select_buf, (caddr_t)header, nbytes);
1485 1485          (void) memcpy(mode_select_buf + nbytes, page_data, page_size);
1486 1486          nbytes += page_size;
1487 1487  
1488 1488          /*
1489 1489           * Build and execute the uscsi ioctl
1490 1490           */
1491 1491          (void) memset((char *)&ucmd, 0, sizeof (ucmd));
1492 1492          (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
1493 1493          cdb.scc_cmd = SCMD_MODE_SELECT;
1494 1494          FORMG0COUNT(&cdb, (uchar_t)nbytes);
1495 1495          cdb.cdb_opaque[1] = (uchar_t)options;
1496 1496          ucmd.uscsi_cdb = (caddr_t)&cdb;
1497 1497          ucmd.uscsi_cdblen = CDB_GROUP0;
1498 1498          ucmd.uscsi_bufaddr = mode_select_buf;
1499 1499          ucmd.uscsi_buflen = nbytes;
1500 1500          status = uscsi_cmd(fd, &ucmd, rqbuf, rqblen);
1501 1501  
1502 1502          if (status)
1503 1503                  dprintf("Mode select page 0x%x failed\n", page_code);
1504 1504  
1505 1505          return (status);
1506 1506  }
1507 1507  
1508 1508  /*
1509 1509   * Execute a uscsi mode select(10) command.
1510 1510   */
1511 1511  int
1512 1512  uscsi_mode_select_10(int fd, int page_code, int options,
1513 1513      caddr_t page_data, int page_size, struct scsi_ms_header_g1 *header,
1514 1514      void *rqbuf, int *rqblen)
1515 1515  {
1516 1516          caddr_t                         mode_select_buf;
1517 1517          int                             nbytes;
1518 1518          struct uscsi_cmd                ucmd;
1519 1519          union scsi_cdb                  cdb;
1520 1520          int                             status;
1521 1521          char                            *s;
1522 1522  
1523 1523          assert(((struct mode_page *)page_data)->ps == 0);
1524 1524          assert(header->ms_header.length == 0);
1525 1525          assert(header->ms_header.device_specific == 0);
1526 1526          assert((options & ~(MODE_SELECT_SP|MODE_SELECT_PF)) == 0);
1527 1527  
1528 1528          nbytes = sizeof (struct scsi_ms_header_g1) + page_size;
1529 1529          mode_select_buf = alloca((uint_t)nbytes);
1530 1530  
1531 1531          /*
1532 1532           * Build the mode select data out of the header and page data
1533 1533           * This allows us to support devices which return either
1534 1534           * 0 or 1 block descriptors.
1535 1535           */
1536 1536          (void) memset(mode_select_buf, 0, nbytes);
1537 1537          nbytes = sizeof (struct mode_header_g1);
1538 1538          if (BE_16(header->ms_header.bdesc_length) ==
1539 1539              sizeof (struct block_descriptor)) {
1540 1540                  nbytes += sizeof (struct block_descriptor);
1541 1541          }
1542 1542  
1543 1543          /*
1544 1544           * Dump the structures
1545 1545           */
1546 1546          s = find_string(mode_select_strings,
1547 1547              options & (MODE_SELECT_SP|MODE_SELECT_PF));
1548 1548          dprintf("\nMode select(10) page 0x%x%s:\n", page_code,
1549 1549              s != NULL ? s : "");
1550 1550          ddump("header:", (caddr_t)header, nbytes);
1551 1551          ddump("data:", (caddr_t)page_data, page_size);
1552 1552  
1553 1553          /*
1554 1554           * Put the header and data together
1555 1555           */
1556 1556          (void) memcpy(mode_select_buf, (caddr_t)header, nbytes);
1557 1557          (void) memcpy(mode_select_buf + nbytes, page_data, page_size);
1558 1558          nbytes += page_size;
1559 1559  
1560 1560          /*
1561 1561           * Build and execute the uscsi ioctl
1562 1562           */
1563 1563          (void) memset((char *)&ucmd, 0, sizeof (ucmd));
1564 1564          (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
1565 1565          cdb.scc_cmd = SCMD_MODE_SELECT_G1;
1566 1566          FORMG1COUNT(&cdb, (uint16_t)nbytes);
1567 1567          cdb.cdb_opaque[1] = (uchar_t)options;
1568 1568          ucmd.uscsi_cdb = (caddr_t)&cdb;
1569 1569          ucmd.uscsi_cdblen = CDB_GROUP1;
1570 1570          ucmd.uscsi_bufaddr = mode_select_buf;
1571 1571          ucmd.uscsi_buflen = nbytes;
1572 1572          status = uscsi_cmd(fd, &ucmd, rqbuf, rqblen);
1573 1573  
1574 1574          if (status)
1575 1575                  dprintf("Mode select(10) page 0x%x failed\n", page_code);
1576 1576  
1577 1577          return (status);
1578 1578  }
1579 1579  
1580 1580  int
1581 1581  uscsi_log_sense(int fd, int page_code, int page_control, caddr_t page_data,
1582 1582      int page_size, void *rqbuf, int *rqblen)
1583 1583  {
1584 1584          caddr_t log_sense_buf;
1585 1585          scsi_log_header_t *hdr;
1586 1586          struct uscsi_cmd ucmd;
1587 1587          union scsi_cdb cdb;
1588 1588          int status;
1589 1589          ushort_t len;
1590 1590          char *pc;
1591 1591  
1592 1592          assert(page_size >= 0 && page_size < UINT16_MAX);
1593 1593          assert(page_control == PC_CURRENT || page_control == PC_CHANGEABLE ||
1594 1594              page_control == PC_DEFAULT || page_control == PC_SAVED);
1595 1595  
1596 1596          if (page_size < sizeof (scsi_log_header_t))
1597 1597                  return (-1);
1598 1598  
1599 1599          log_sense_buf = alloca((uint_t)page_size);
1600 1600  
1601 1601          /*
1602 1602           * Build and execute the uscsi ioctl
1603 1603           */
1604 1604          (void) memset(log_sense_buf, 0, page_size);
1605 1605          (void) memset((char *)&ucmd, 0, sizeof (ucmd));
1606 1606          (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
1607 1607          cdb.scc_cmd = SCMD_LOG_SENSE_G1;
1608 1608          FORMG1COUNT(&cdb, (uint16_t)page_size);
1609 1609          cdb.cdb_opaque[2] = page_control | page_code;
1610 1610          ucmd.uscsi_cdb = (caddr_t)&cdb;
1611 1611          ucmd.uscsi_cdblen = CDB_GROUP1;
1612 1612          ucmd.uscsi_bufaddr = log_sense_buf;
1613 1613          ucmd.uscsi_buflen = page_size;
1614 1614          status = uscsi_cmd(fd, &ucmd, rqbuf, rqblen);
1615 1615          if (status) {
1616 1616                  dprintf("Log sense page 0x%x failed\n", page_code);
1617 1617                  return (-1);
1618 1618          }
1619 1619  
1620 1620          /*
1621 1621           * Verify that the returned data looks reasonable, then copy it into the
1622 1622           * user's buffer.
1623 1623           */
1624 1624          hdr = (scsi_log_header_t *)log_sense_buf;
1625 1625  
1626 1626          /*
1627 1627           * Ensure we have a host-understandable length field
1628 1628           */
1629 1629          len = BE_16(hdr->lh_length);
1630 1630  
1631 1631          if (hdr->lh_code != page_code) {
1632 1632                  dprintf("\nLog sense page 0x%x: incorrect page code 0x%x\n",
1633 1633                      page_code, hdr->lh_code);
1634 1634                  ddump("Log sense:", log_sense_buf, page_size);
1635 1635                  return (-1);
1636 1636          }
1637 1637  
1638 1638          ddump("LOG SENSE RAW OUTPUT", log_sense_buf,
1639 1639              sizeof (scsi_log_header_t) + len);
1640 1640  
1641 1641          /*
1642 1642           * Accept up to "page_size" bytes of mode sense data.  This allows us to
1643 1643           * accept both CCS and SCSI-2 structures, as long as we request the
1644 1644           * greater of the two.
1645 1645           */
1646 1646          (void) memcpy(page_data, (caddr_t)hdr, len +
1647 1647              sizeof (scsi_log_header_t));
1648 1648  
1649 1649          pc = find_string(page_control_strings, page_control);
1650 1650          dprintf("\nLog sense page 0x%x (%s):\n", page_code,
1651 1651              pc != NULL ? pc : "");
1652 1652          ddump("header:", (caddr_t)hdr,
1653 1653              sizeof (scsi_log_header_t));
1654 1654          ddump("data:", (caddr_t)hdr +
1655 1655              sizeof (scsi_log_header_t), len);
1656 1656  
1657 1657          return (0);
1658 1658  }
  
    | 
      ↓ open down ↓ | 
    624 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX