From owner-freebsd-scsi@FreeBSD.ORG Mon Sep 19 11:07:13 2011 Return-Path: Delivered-To: freebsd-scsi@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id C1D0E106564A for ; Mon, 19 Sep 2011 11:07:13 +0000 (UTC) (envelope-from owner-bugmaster@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:4f8:fff6::28]) by mx1.freebsd.org (Postfix) with ESMTP id A69AE8FC08 for ; Mon, 19 Sep 2011 11:07:13 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.4/8.14.4) with ESMTP id p8JB7DXa073619 for ; Mon, 19 Sep 2011 11:07:13 GMT (envelope-from owner-bugmaster@FreeBSD.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.4/8.14.4/Submit) id p8JB7DZ0073617 for freebsd-scsi@FreeBSD.org; Mon, 19 Sep 2011 11:07:13 GMT (envelope-from owner-bugmaster@FreeBSD.org) Date: Mon, 19 Sep 2011 11:07:13 GMT Message-Id: <201109191107.p8JB7DZ0073617@freefall.freebsd.org> X-Authentication-Warning: freefall.freebsd.org: gnats set sender to owner-bugmaster@FreeBSD.org using -f From: FreeBSD bugmaster To: freebsd-scsi@FreeBSD.org Cc: Subject: Current problem reports assigned to freebsd-scsi@FreeBSD.org X-BeenThere: freebsd-scsi@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SCSI subsystem List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 19 Sep 2011 11:07:13 -0000 Note: to view an individual PR, use: http://www.freebsd.org/cgi/query-pr.cgi?pr=(number). The following is a listing of current problems submitted by FreeBSD users. These represent problem reports covering all versions including experimental development code and obsolete releases. S Tracker Resp. Description -------------------------------------------------------------------------------- o kern/159412 scsi [ciss] 7.3 RELEASE: ciss0 ADAPTER HEARTBEAT FAILED err o kern/157770 scsi [iscsi] [panic] iscsi_initiator panic o kern/154432 scsi [xpt] run_interrupt_driven_hooks: still waiting after o kern/153514 scsi [cam] [panic] CAM related panic o kern/153361 scsi [ciss] Smart Array 5300 boot/detect drive problem o kern/152250 scsi [ciss] [patch] Kernel panic when hw.ciss.expose_hidden o kern/151564 scsi [ciss] ciss(4) should increase CISS_MAX_LOGICAL to 10 o docs/151336 scsi Missing documentation of scsi_ and ata_ functions in c s kern/149927 scsi [cam] hard drive not stopped before removing power dur o kern/148083 scsi [aac] Strange device reporting o kern/147704 scsi [mpt] sys/dev/mpt: new chip revision, partially unsupp o kern/146287 scsi [ciss] ciss(4) cannot see more than one SmartArray con o kern/145768 scsi [mpt] can't perform I/O on SAS based SAN disk in freeb o kern/144648 scsi [aac] Strange values of speed and bus width in dmesg o kern/144301 scsi [ciss] [hang] HP proliant server locks when using ciss o kern/142351 scsi [mpt] LSILogic driver performance problems o kern/141934 scsi [cam] [patch] add support for SEAGATE DAT Scopion 130 o kern/134488 scsi [mpt] MPT SCSI driver probes max. 8 LUNs per device o kern/132250 scsi [ciss] ciss driver does not support more then 15 drive o kern/132206 scsi [mpt] system panics on boot when mirroring and 2nd dri o kern/130621 scsi [mpt] tranfer rate is inscrutable slow when use lsi213 o kern/129602 scsi [ahd] ahd(4) gets confused and wedges SCSI bus o kern/128452 scsi [sa] [panic] Accessing SCSI tape drive randomly crashe o kern/128245 scsi [scsi] "inquiry data fails comparison at DV1 step" [re o kern/127927 scsi [isp] isp(4) target driver crashes kernel when set up o kern/127717 scsi [ata] [patch] [request] - support write cache toggling o kern/124667 scsi [amd] [panic] FreeBSD-7 kernel page faults at amd-scsi o kern/123674 scsi [ahc] ahc driver dumping o kern/123520 scsi [ahd] unable to boot from net while using ahd o sparc/121676 scsi [iscsi] iscontrol do not connect iscsi-target on sparc o kern/120487 scsi [sg] scsi_sg incompatible with scanners o kern/120247 scsi [mpt] FreeBSD 6.3 and LSI Logic 1030 = only 3.300MB/s o kern/114597 scsi [sym] System hangs at SCSI bus reset with dual HBAs o kern/110847 scsi [ahd] Tyan U320 onboard problem with more than 3 disks o kern/99954 scsi [ahc] reading from DVD failes on 6.x [regression] o kern/92798 scsi [ahc] SCSI problem with timeouts o kern/90282 scsi [sym] SCSI bus resets cause loss of ch device o kern/76178 scsi [ahd] Problem with ahd and large SCSI Raid system o kern/74627 scsi [ahc] [hang] Adaptec 2940U2W Can't boot 5.3 s kern/61165 scsi [panic] kernel page fault after calling cam_send_ccb o kern/60641 scsi [sym] Sporadic SCSI bus resets with 53C810 under load o kern/60598 scsi wire down of scsi devices conflicts with config s kern/57398 scsi [mly] Current fails to install on mly(4) based RAID di o bin/57088 scsi [cam] [patch] for a possible fd leak in libcam.c o kern/52638 scsi [panic] SCSI U320 on SMP server won't run faster than o kern/44587 scsi dev/dpt/dpt.h is missing defines required for DPT_HAND o kern/39388 scsi ncr/sym drivers fail with 53c810 and more than 256MB m o kern/35234 scsi World access to /dev/pass? (for scanner) requires acce 48 problems total. From owner-freebsd-scsi@FreeBSD.ORG Thu Sep 22 20:08:06 2011 Return-Path: Delivered-To: scsi@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 1E7DD106564A; Thu, 22 Sep 2011 20:08:06 +0000 (UTC) (envelope-from ken@kdm.org) Received: from nargothrond.kdm.org (nargothrond.kdm.org [70.56.43.81]) by mx1.freebsd.org (Postfix) with ESMTP id BA8898FC1F; Thu, 22 Sep 2011 20:08:04 +0000 (UTC) Received: from nargothrond.kdm.org (localhost [127.0.0.1]) by nargothrond.kdm.org (8.14.2/8.14.2) with ESMTP id p8MJX5sO037452; Thu, 22 Sep 2011 13:33:05 -0600 (MDT) (envelope-from ken@nargothrond.kdm.org) Received: (from ken@localhost) by nargothrond.kdm.org (8.14.2/8.14.2/Submit) id p8MJX5Op037451; Thu, 22 Sep 2011 13:33:05 -0600 (MDT) (envelope-from ken) Date: Thu, 22 Sep 2011 13:33:05 -0600 From: "Kenneth D. Merry" To: scsi@freebsd.org, current@freebsd.org Message-ID: <20110922193305.GA24939@nargothrond.kdm.org> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="ibTvN161/egqYuK8" Content-Disposition: inline User-Agent: Mutt/1.4.2i Cc: Subject: SCSI descriptor sense changes, testing needed X-BeenThere: freebsd-scsi@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SCSI subsystem List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 22 Sep 2011 20:08:06 -0000 --ibTvN161/egqYuK8 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline I have attached a set of patches against head that implement SCSI descriptor sense support for CAM. Descriptor sense is a new sense (SCSI error) format introduced in the SPC-3 spec in 2006. FreeBSD doesn't currently support it. Seagate's new 3TB SAS drives come with descriptor sense enabled by default, and it's possible that other newer drives do as well. Because all the sense key, additional sense code, and additional sense code qualifier fields are in different places, the CAM error recovery code will not do the right thing when it gets descriptor sense. These patches do bump up the size of struct scsi_sense_data, and so I have incremented CAM_VERSION as well. I have discussed this with re@, and it looks like we'll be putting the changes in before 9.0, so it ships with support for newer SCSI devices. A number of things have changed in these patches, but in particular, it would be good to test the following: - The sa(4) (SCSI tape) driver. The residual handling code, which looks at the sense data, has changed. - The Playstation 3 CDROM driver. - Firewire target mode. - umass devices with the NO_INQUIRY_EVPD quirk. Also, please let me know if you see any anomalies with the sense printing code. In the common cases the output should look identical to the old code, but in some cases it will be a little different. e.g.: # camcontrol inquiry da40 -v pass47: Fixed Direct Access SCSI-6 device pass47: Serial Number 9XK0GAJ70000S125XDNU pass47: 300.000MB/s transfers, Command Queueing Enabled (Seagate 3TB drive) # camcontrol modepage da40 -m 10 |grep D_SENSE D_SENSE: 1 (Descriptor sense is enabled) # camcontrol modepage da40 -m 15 -v (pass47:mps1:0:47:0): MODE SENSE(6). CDB: 1a 0 4f 0 ff 0 (pass47:mps1:0:47:0): CAM status: SCSI Status Error (pass47:mps1:0:47:0): SCSI status: Check Condition (pass47:mps1:0:47:0): SCSI sense: ILLEGAL REQUEST asc:24,0 (Invalid field in CDB) (pass47:mps1:0:47:0): Field Replaceable Unit: 1 (pass47:mps1:0:47:0): Command byte 2 bit 5 is invalid (pass47:mps1:0:47:0): Descriptor 0x80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 camcontrol: error sending mode sense command (The FRU and Sense Key Specific entries are on separate lines, and a vendor-specific sense descriptor is printed out in hex format.) Anyway, I'd appreciate any testing and feedback on these changes. As I said, they will probably be in 9.0, so if there are any issues it would be better to find them now. :) Thanks, Ken -- Kenneth Merry ken@FreeBSD.ORG --ibTvN161/egqYuK8 Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="scsi_descriptor_sense.20110920.4.txt" Index: sbin/camcontrol/camcontrol.c =================================================================== --- sbin/camcontrol/camcontrol.c (revision 225710) +++ sbin/camcontrol/camcontrol.c (working copy) @@ -3810,15 +3810,14 @@ */ if ((sense_key == SSD_KEY_NOT_READY) && (asc == 0x04) && (ascq == 0x04)) { - if ((sense->extra_len >= 10) - && ((sense->sense_key_spec[0] & - SSD_SCS_VALID) != 0) + uint8_t sks[3]; + + if ((scsi_get_sks(sense, sks) == 0) && (quiet == 0)) { int val; u_int64_t percentage; - val = scsi_2btoul( - &sense->sense_key_spec[1]); + val = scsi_2btoul(&sks[1]); percentage = 10000 * val; fprintf(stdout, Index: share/misc/scsi_modes =================================================================== --- share/misc/scsi_modes (revision 225710) +++ share/misc/scsi_modes (working copy) @@ -50,19 +50,32 @@ # ALL DEVICE TYPES 0x0a "Control Mode Page" { - {Reserved} *t7 + {TST} t3 + {TMF_ONLY} t1 + {DPICZ} t1 + {D_SENSE} t1 + {GLTSD} t1 {RLEC} t1 {Queue Algorithm Modifier} t4 - {Reserved} *t2 - {QErr} t1 + {NUAR} t1 + {QErr} t2 {DQue} t1 {EECA} t1 - {Reserved} *t4 + {RAC} t1 + {UA_INTLCK_CTRL} t2 + {SWP} t1 {RAENP} t1 {UAAENP} t1 {EAENP} t1 - {Reserved} *i1 + {ATO} t1 + {TAS} t1 + {ATMPE} t1 + {RWWP} t1 + {Reserved} *t1 + {Autoload Mode} t3 {Ready AEN Holdoff Period} i2 + {Busy Timeout Period} i2 + {Extended Self-Test Completion Time} i2 } 0x02 "Disconnect-Reconnect Page" { Index: share/examples/scsi_target/scsi_cmds.c =================================================================== --- share/examples/scsi_target/scsi_cmds.c (revision 225710) +++ share/examples/scsi_target/scsi_cmds.c (working copy) @@ -242,22 +242,22 @@ u_int8_t asc, u_int8_t ascq) { struct initiator_state *istate; - struct scsi_sense_data *sense; + struct scsi_sense_data_fixed *sense; /* Set our initiator's istate */ istate = tcmd_get_istate(init_id); if (istate == NULL) return; istate->pending_ca |= CA_CMD_SENSE; /* XXX set instead of or? */ - sense = &istate->sense_data; + sense = (struct scsi_sense_data_fixed *)&istate->sense_data; bzero(sense, sizeof(*sense)); sense->error_code = SSD_CURRENT_ERROR; sense->flags = flags; sense->add_sense_code = asc; sense->add_sense_code_qual = ascq; sense->extra_len = - offsetof(struct scsi_sense_data, sense_key_spec[2]) - - offsetof(struct scsi_sense_data, extra_len); + offsetof(struct scsi_sense_data_fixed, sense_key_spec[2]) - + offsetof(struct scsi_sense_data_fixed, extra_len); /* Fill out the supplied CTIO */ if (ctio != NULL) { @@ -298,7 +298,7 @@ struct scsi_inquiry *inq; struct atio_descr *a_descr; struct initiator_state *istate; - struct scsi_sense_data *sense; + struct scsi_sense_data_fixed *sense; a_descr = (struct atio_descr *)atio->ccb_h.targ_descr; inq = (struct scsi_inquiry *)a_descr->cdb; @@ -310,7 +310,7 @@ * complain if EVPD or CMDDT is set. */ istate = tcmd_get_istate(ctio->init_id); - sense = &istate->sense_data; + sense = (struct scsi_sense_data_fixed *)&istate->sense_data; if ((inq->byte2 & SI_EVPD) != 0) { tcmd_illegal_req(atio, ctio); sense->sense_key_spec[0] = SSD_SCS_VALID | SSD_FIELDPTR_CMD | @@ -376,7 +376,7 @@ tcmd_req_sense(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio) { struct scsi_request_sense *rsense; - struct scsi_sense_data *sense; + struct scsi_sense_data_fixed *sense; struct initiator_state *istate; size_t dlen; struct atio_descr *a_descr; @@ -385,7 +385,7 @@ rsense = (struct scsi_request_sense *)a_descr->cdb; istate = tcmd_get_istate(ctio->init_id); - sense = &istate->sense_data; + sense = (struct scsi_sense_data_fixed *)&istate->sense_data; if (debug) { cdb_debug(a_descr->cdb, "REQ SENSE from %u: ", atio->init_id); @@ -400,7 +400,7 @@ } bcopy(sense, ctio->data_ptr, sizeof(struct scsi_sense_data)); - dlen = offsetof(struct scsi_sense_data, extra_len) + + dlen = offsetof(struct scsi_sense_data_fixed, extra_len) + sense->extra_len + 1; ctio->dxfer_len = min(dlen, SCSI_CDB6_LEN(rsense->length)); ctio->ccb_h.flags |= CAM_DIR_IN | CAM_SEND_STATUS; @@ -482,7 +482,7 @@ c_descr = (struct ctio_descr *)ctio->ccb_h.targ_descr; /* Command needs to be decoded */ - if ((a_descr->flags & CAM_DIR_MASK) == CAM_DIR_RESV) { + if ((a_descr->flags & CAM_DIR_MASK) == CAM_DIR_BOTH) { if (debug) warnx("Calling rdwr_decode"); ret = tcmd_rdwr_decode(atio, ctio); Index: share/examples/scsi_target/scsi_target.c =================================================================== --- share/examples/scsi_target/scsi_target.c (revision 225710) +++ share/examples/scsi_target/scsi_target.c (working copy) @@ -651,7 +651,7 @@ * receiving this ATIO. */ if (atio->sense_len != 0) { - struct scsi_sense_data *sense; + struct scsi_sense_data_fixed *sense; if (debug) { warnx("ATIO with %u bytes sense received", @@ -825,9 +825,9 @@ /* If there is sense data, use it */ if (sense != 0) { - struct scsi_sense_data *sense; + struct scsi_sense_data_fixed *sense; - sense = &inot->sense_data; + sense = (struct scsi_sense_data_fixed *)&inot->sense_data; tcmd_sense(inot->initiator_id, NULL, sense->flags, sense->add_sense_code, sense->add_sense_code_qual); if (debug) Index: sys/powerpc/ps3/ps3cdrom.c =================================================================== --- sys/powerpc/ps3/ps3cdrom.c (revision 225710) +++ sys/powerpc/ps3/ps3cdrom.c (working copy) @@ -506,21 +506,19 @@ if (!ps3cdrom_decode_lv1_status(status, &sense_key, &asc, &ascq)) { - struct scsi_sense_data sense_data; CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("sense key 0x%02x asc 0x%02x ascq 0x%02x\n", sense_key, asc, ascq)); - bzero(&sense_data, sizeof(sense_data)); - sense_data.error_code = SSD_CURRENT_ERROR; - sense_data.flags |= sense_key; - sense_data.extra_len = 0xa; - sense_data.add_sense_code = asc; - sense_data.add_sense_code_qual = ascq; - ccb->csio.sense_len = sizeof(sense_data); - bcopy(&sense_data, &ccb->csio.sense_data, - ccb->csio.sense_len); + scsi_set_sense_data(&ccb->csio.sense_data, + /*sense_format*/ SSD_TYPE_NONE, + /*current_error*/ 1, + sense_key, + asc, + ascq, + SSD_ELEM_NONE); + ccb->csio.sense_len = SSD_FULL_SIZE; ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR | CAM_AUTOSNS_VALID; } @@ -643,8 +641,6 @@ } if (err) { - struct scsi_sense_data sense_data; - device_printf(dev, "ATAPI command 0x%02x failed (%d)\n", cdb[0], err); @@ -653,11 +649,18 @@ xp->x_ccb = NULL; TAILQ_INSERT_TAIL(&sc->sc_free_xferq, xp, x_queue); - bzero(&sense_data, sizeof(sense_data)); - sense_data.error_code = SSD_CURRENT_ERROR; - sense_data.flags |= SSD_KEY_ILLEGAL_REQUEST; - ccb->csio.sense_len = sizeof(sense_data); - bcopy(&sense_data, &ccb->csio.sense_data, ccb->csio.sense_len); + bzero(&ccb->csio.sense_data, sizeof(ccb->csio.sense_data)); + /* Invalid field in parameter list */ + scsi_set_sense_data(&ccb->csio.sense_data, + /*sense_format*/ SSD_TYPE_NONE, + /*current_error*/ 1, + /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST, + /*asc*/ 0x26, + /*ascq*/ 0x00, + SSD_ELEM_NONE); + + ccb->csio.sense_len = SSD_FULL_SIZE; + ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND; ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR | CAM_AUTOSNS_VALID; xpt_done(ccb); } else { Index: sys/cam/cam_periph.c =================================================================== --- sys/cam/cam_periph.c (revision 225710) +++ sys/cam/cam_periph.c (working copy) @@ -1085,7 +1085,6 @@ union ccb *saved_ccb = (union ccb *)done_ccb->ccb_h.saved_ccb_ptr; cam_status status; int frozen = 0; - u_int sense_key; int depth = done_ccb->ccb_h.recovery_depth; status = done_ccb->ccb_h.status; @@ -1101,14 +1100,16 @@ switch (status) { case CAM_REQ_CMP: { + int error_code, sense_key, asc, ascq; + + scsi_extract_sense(&saved_ccb->csio.sense_data, &error_code, + &sense_key, &asc, &ascq); /* * If we manually retrieved sense into a CCB and got * something other than "NO SENSE" send the updated CCB * back to the client via xpt_done() to be processed via * the error recovery code again. */ - sense_key = saved_ccb->csio.sense_data.flags; - sense_key &= SSD_KEY; if (sense_key != SSD_KEY_NO_SENSE) { saved_ccb->ccb_h.status |= CAM_AUTOSNS_VALID; Index: sys/cam/cam_ccb.h =================================================================== --- sys/cam/cam_ccb.h (revision 225710) +++ sys/cam/cam_ccb.h (working copy) @@ -539,7 +539,7 @@ /* * Definitions for the path inquiry CCB fields. */ -#define CAM_VERSION 0x15 /* Hex value for current version */ +#define CAM_VERSION 0x16 /* Hex value for current version */ typedef enum { PI_MDP_ABLE = 0x80, /* Supports MDP message */ Index: sys/cam/scsi/scsi_all.h =================================================================== --- sys/cam/scsi/scsi_all.h (revision 225710) +++ sys/cam/scsi/scsi_all.h (working copy) @@ -25,6 +25,7 @@ #define _SCSI_SCSI_ALL_H 1 #include +#include #ifdef _KERNEL /* @@ -171,9 +172,9 @@ { u_int8_t opcode; u_int8_t byte2; -#define SI_EVPD 0x01 +#define SI_EVPD 0x01 +#define SI_CMDDT 0x02 u_int8_t page_code; - u_int8_t reserved; u_int8_t length; u_int8_t control; }; @@ -200,7 +201,9 @@ #define SMS_PAGE_CTRL_CHANGEABLE 0x40 #define SMS_PAGE_CTRL_DEFAULT 0x80 #define SMS_PAGE_CTRL_SAVED 0xC0 - u_int8_t unused; + u_int8_t subpage; +#define SMS_SUBPAGE_PAGE_0 0x00 +#define SMS_SUBPAGE_ALL 0xff u_int8_t length; u_int8_t control; }; @@ -209,8 +212,10 @@ { u_int8_t opcode; u_int8_t byte2; /* same bits as small version */ +#define SMS10_LLBAA 0x10 u_int8_t page; /* same bits as small version */ - u_int8_t unused[4]; + u_int8_t subpage; + u_int8_t unused[3]; u_int8_t length[2]; u_int8_t control; }; @@ -263,6 +268,120 @@ u_int8_t block_len[3]; }; +struct scsi_per_res_in +{ + u_int8_t opcode; + u_int8_t action; +#define SPRI_RK 0x00 +#define SPRI_RR 0x01 +#define SPRI_RC 0x02 +#define SPRI_RS 0x03 + u_int8_t reserved[5]; + u_int8_t length[2]; + u_int8_t control; +}; + +struct scsi_per_res_in_header +{ + u_int8_t generation[4]; + u_int8_t length[4]; +}; + +struct scsi_per_res_key +{ + u_int8_t key[8]; +}; + +struct scsi_per_res_in_keys +{ + struct scsi_per_res_in_header header; + struct scsi_per_res_key keys[0]; +}; + +struct scsi_per_res_cap +{ + uint8_t length[2]; + uint8_t flags1; +#define SPRI_CRH 0x10 +#define SPRI_SIP_C 0x08 +#define SPRI_ATP_C 0x04 +#define SPRI_PTPL_C 0x01 + uint8_t flags2; +#define SPRI_TMV 0x80 +#define SPRI_PTPL_A 0x01 + uint8_t type_mask[2]; +#define SPRI_TM_WR_EX_AR 0x8000 +#define SPRI_TM_EX_AC_RO 0x4000 +#define SPRI_TM_WR_EX_RO 0x2000 +#define SPRI_TM_EX_AC 0x0800 +#define SPRI_TM_WR_EX 0x0200 +#define SPRI_TM_EX_AC_AR 0x0001 + uint8_t reserved[2]; +}; + +struct scsi_per_res_in_rsrv_data +{ + uint8_t reservation[8]; + uint8_t obsolete1[4]; + uint8_t reserved; + uint8_t scopetype; +#define SPRT_WE 0x01 +#define SPRT_EA 0x03 +#define SPRT_WERO 0x05 +#define SPRT_EARO 0x06 +#define SPRT_WEAR 0x07 +#define SPRT_EAAR 0x08 + uint8_t obsolete2[2]; +}; + +struct scsi_per_res_in_rsrv +{ + struct scsi_per_res_in_header header; + struct scsi_per_res_in_rsrv_data data; +}; + +struct scsi_per_res_out +{ + u_int8_t opcode; + u_int8_t action; +#define SPRO_REGISTER 0x00 +#define SPRO_RESERVE 0x01 +#define SPRO_RELEASE 0x02 +#define SPRO_CLEAR 0x03 +#define SPRO_PREEMPT 0x04 +#define SPRO_PRE_ABO 0x05 +#define SPRO_REG_IGNO 0x06 +#define SPRO_REG_MOVE 0x07 +#define SPRO_ACTION_MASK 0x1f + u_int8_t scope_type; +#define SPR_SCOPE_MASK 0xf0 +#define SPR_LU_SCOPE 0x00 +#define SPR_TYPE_MASK 0x0f +#define SPR_TYPE_WR_EX 0x01 +#define SPR_TYPE_EX_AC 0x03 +#define SPR_TYPE_WR_EX_RO 0x05 +#define SPR_TYPE_EX_AC_RO 0x06 +#define SPR_TYPE_WR_EX_AR 0x07 +#define SPR_TYPE_EX_AC_AR 0x08 + u_int8_t reserved[2]; + u_int8_t length[4]; + u_int8_t control; +}; + +struct scsi_per_res_out_parms +{ + struct scsi_per_res_key res_key; + u_int8_t serv_act_res_key[8]; + u_int8_t obsolete1[4]; + u_int8_t flags; +#define SPR_SPEC_I_PT 0x08 +#define SPR_ALL_TG_PT 0x04 +#define SPR_APTPL 0x01 + u_int8_t reserved1; + u_int8_t obsolete2[2]; +}; + + struct scsi_log_sense { u_int8_t opcode; @@ -337,7 +456,16 @@ u_int8_t page_code; u_int8_t page_length; u_int8_t rlec; -#define SCB_RLEC 0x01 /*Report Log Exception Cond*/ +#define SCP_RLEC 0x01 /*Report Log Exception Cond*/ +#define SCP_GLTSD 0x02 /*Global Logging target + save disable */ +#define SCP_DSENSE 0x04 /*Descriptor Sense */ +#define SCP_DPICZ 0x08 /*Disable Prot. Info Check + if Prot. Field is Zero */ +#define SCP_TMF_ONLY 0x10 /*TM Functions Only*/ +#define SCP_TST_MASK 0xE0 /*Task Set Type Mask*/ +#define SCP_TST_ONE 0x00 /*One Task Set*/ +#define SCP_TST_SEPARATE 0x20 /*Separate Task Sets*/ u_int8_t queue_flags; #define SCP_QUEUE_ALG_MASK 0xF0 #define SCP_QUEUE_ALG_RESTRICTED 0x00 @@ -368,6 +496,41 @@ u_int8_t max_prefetch_ceil[2]; }; +/* + * XXX KDM + * Updated version of the cache page, as of SBC. Update this to SBC-3 and + * rationalize the two. + */ +struct scsi_caching_page { + uint8_t page_code; +#define SMS_CACHING_PAGE 0x08 + uint8_t page_length; + uint8_t flags1; +#define SCP_IC 0x80 +#define SCP_ABPF 0x40 +#define SCP_CAP 0x20 +#define SCP_DISC 0x10 +#define SCP_SIZE 0x08 +#define SCP_WCE 0x04 +#define SCP_MF 0x02 +#define SCP_RCD 0x01 + uint8_t ret_priority; + uint8_t disable_pf_transfer_len[2]; + uint8_t min_prefetch[2]; + uint8_t max_prefetch[2]; + uint8_t max_pf_ceiling[2]; + uint8_t flags2; +#define SCP_FSW 0x80 +#define SCP_LBCSS 0x40 +#define SCP_DRA 0x20 +#define SCP_VS1 0x10 +#define SCP_VS2 0x08 + uint8_t cache_segments; + uint8_t cache_seg_size[2]; + uint8_t reserved; + uint8_t non_cache_seg_size[3]; +}; + struct scsi_info_exceptions_page { u_int8_t page_code; #define SIEP_PAGE_SAVABLE 0x80 /* Page is savable */ @@ -406,20 +569,49 @@ { u_int8_t opcode; u_int8_t byte2; - u_int8_t unused[2]; - u_int8_t length; +#define SR_EXTENT 0x01 +#define SR_ID_MASK 0x0e +#define SR_3RDPTY 0x10 +#define SR_LUN_MASK 0xe0 + u_int8_t resv_id; + u_int8_t length[2]; u_int8_t control; }; +struct scsi_reserve_10 { + uint8_t opcode; + uint8_t byte2; +#define SR10_3RDPTY 0x10 +#define SR10_LONGID 0x02 +#define SR10_EXTENT 0x01 + uint8_t resv_id; + uint8_t thirdparty_id; + uint8_t reserved[3]; + uint8_t length[2]; + uint8_t control; +}; + + struct scsi_release { u_int8_t opcode; u_int8_t byte2; - u_int8_t unused[2]; + u_int8_t resv_id; + u_int8_t unused[1]; u_int8_t length; u_int8_t control; }; +struct scsi_release_10 { + uint8_t opcode; + uint8_t byte2; + uint8_t resv_id; + uint8_t thirdparty_id; + uint8_t reserved[3]; + uint8_t length[2]; + uint8_t control; +}; + struct scsi_prevent { u_int8_t opcode; @@ -435,13 +627,61 @@ { u_int8_t opcode; u_int8_t byte2; +#define SSC_IMMED 0x02 +#define SSC_RELADR 0x01 u_int8_t begin_lba[4]; u_int8_t reserved; u_int8_t lb_count[2]; u_int8_t control; }; +struct scsi_sync_cache_16 +{ + uint8_t opcode; + uint8_t byte2; + uint8_t begin_lba[8]; + uint8_t lb_count[4]; + uint8_t reserved; + uint8_t control; +}; +struct scsi_format { + uint8_t opcode; + uint8_t byte2; +#define SF_LONGLIST 0x20 +#define SF_FMTDATA 0x10 +#define SF_CMPLIST 0x08 +#define SF_FORMAT_MASK 0x07 +#define SF_FORMAT_BLOCK 0x00 +#define SF_FORMAT_LONG_BLOCK 0x03 +#define SF_FORMAT_BFI 0x04 +#define SF_FORMAT_PHYS 0x05 + uint8_t vendor; + uint8_t interleave[2]; + uint8_t control; +}; + +struct scsi_format_header_short { + uint8_t reserved; +#define SF_DATA_FOV 0x80 +#define SF_DATA_DPRY 0x40 +#define SF_DATA_DCRT 0x20 +#define SF_DATA_STPF 0x10 +#define SF_DATA_IP 0x08 +#define SF_DATA_DSP 0x04 +#define SF_DATA_IMMED 0x02 +#define SF_DATA_VS 0x01 + uint8_t byte2; + uint8_t defect_list_len[2]; +}; + +struct scsi_format_header_long { + uint8_t reserved; + uint8_t byte2; + uint8_t reserved2[2]; + uint8_t defect_list_len[4]; +}; + struct scsi_changedef { u_int8_t opcode; @@ -459,6 +699,7 @@ u_int8_t byte2; #define RWB_MODE 0x07 #define RWB_MODE_HDR_DATA 0x00 +#define RWB_MODE_VENDOR 0x01 #define RWB_MODE_DATA 0x02 #define RWB_MODE_DOWNLOAD 0x04 #define RWB_MODE_DOWNLOAD_SAVE 0x05 @@ -529,6 +770,40 @@ u_int8_t control; }; +struct scsi_write_verify_10 +{ + uint8_t opcode; + uint8_t byte2; +#define SWV_BYTCHK 0x02 +#define SWV_DPO 0x10 +#define SWV_WRPROECT_MASK 0xe0 + uint8_t addr[4]; + uint8_t group; + uint8_t length[2]; + uint8_t control; +}; + +struct scsi_write_verify_12 +{ + uint8_t opcode; + uint8_t byte2; + uint8_t addr[4]; + uint8_t length[4]; + uint8_t group; + uint8_t control; +}; + +struct scsi_write_verify_16 +{ + uint8_t opcode; + uint8_t byte2; + uint8_t addr[8]; + uint8_t length[4]; + uint8_t group; + uint8_t control; +}; + + struct scsi_start_stop_unit { u_int8_t opcode; @@ -538,6 +813,14 @@ u_int8_t how; #define SSS_START 0x01 #define SSS_LOEJ 0x02 +#define SSS_PC_MASK 0xf0 +#define SSS_PC_START_VALID 0x00 +#define SSS_PC_ACTIVE 0x10 +#define SSS_PC_IDLE 0x20 +#define SSS_PC_STANDBY 0x30 +#define SSS_PC_LU_CONTROL 0x70 +#define SSS_PC_FORCE_IDLE_0 0xa0 +#define SSS_PC_FORCE_STANDBY_0 0xb0 u_int8_t control; }; @@ -562,6 +845,18 @@ u_int8_t control; }; +struct scsi_maintenance_in +{ + uint8_t opcode; + uint8_t byte2; +#define SERVICE_ACTION_MASK 0x1f +#define SA_RPRT_TRGT_GRP 0x0a + uint8_t reserved[4]; + uint8_t length[4]; + uint8_t reserved1; + uint8_t control; +}; + struct ata_pass_16 { u_int8_t opcode; u_int8_t protocol; @@ -607,6 +902,7 @@ #define READ_10 0x28 #define WRITE_10 0x2A #define POSITION_TO_ELEMENT 0x2B +#define WRITE_VERIFY_10 0x2E #define SYNCHRONIZE_CACHE 0x35 #define READ_DEFECT_DATA_10 0x37 #define WRITE_BUFFER 0x3B @@ -615,10 +911,16 @@ #define LOG_SELECT 0x4C #define LOG_SENSE 0x4D #define MODE_SELECT_10 0x55 +#define RESERVE_10 0x56 +#define RELEASE_10 0x57 #define MODE_SENSE_10 0x5A +#define PERSISTENT_RES_IN 0x5E +#define PERSISTENT_RES_OUT 0x5F #define ATA_PASS_16 0x85 #define READ_16 0x88 #define WRITE_16 0x8A +#define WRITE_VERIFY_16 0x8E +#define SYNCHRONIZE_CACHE_16 0x91 #define SERVICE_ACTION_IN 0x9E #define REPORT_LUNS 0xA0 #define ATA_PASS_12 0xA1 @@ -627,6 +929,7 @@ #define MOVE_MEDIUM 0xA5 #define READ_12 0xA8 #define WRITE_12 0xAA +#define WRITE_VERIFY_12 0xAE #define READ_ELEMENT_STATUS 0xB8 /* Maintenance In Service Action Codes */ @@ -737,10 +1040,12 @@ u_int8_t response_format; #define SID_AENC 0x80 #define SID_TrmIOP 0x40 +#define SID_NormACA 0x20 +#define SID_HiSup 0x10 u_int8_t additional_length; #define SID_ADDITIONAL_LENGTH(iqd) \ ((iqd)->additional_length + \ - offsetof(struct scsi_inquiry_data, additional_length) + 1) + __offsetof(struct scsi_inquiry_data, additional_length) + 1) u_int8_t spc3_flags; #define SPC3_SID_PROTECT 0x01 #define SPC3_SID_3PC 0x08 @@ -750,6 +1055,7 @@ #define SPC3_SID_ACC 0x40 #define SPC3_SID_SCCS 0x80 u_int8_t spc2_flags; +#define SPC2_SID_ADDR16 0x01 #define SPC2_SID_MChngr 0x08 #define SPC2_SID_MultiP 0x10 #define SPC2_SID_EncServ 0x40 @@ -809,6 +1115,10 @@ u_int8_t vendor_specific1[SID_VENDOR_SPECIFIC_1_SIZE]; }; +/* + * This structure is more suited to initiator operation, because the + * maximum number of supported pages is already allocated. + */ struct scsi_vpd_supported_page_list { u_int8_t device; @@ -852,11 +1162,11 @@ u_int8_t device; u_int8_t page_code; #define SVPD_DEVICE_ID 0x83 -#define SVPD_DEVICE_ID_MAX_SIZE 0xffff -#define SVPD_DEVICE_ID_HDR_LEN 4 -#define SVPD_DEVICE_ID_DESC_HDR_LEN 4 +#define SVPD_DEVICE_ID_MAX_SIZE 252 +#define SVPD_DEVICE_ID_HDR_LEN \ + __offsetof(struct scsi_vpd_device_id, desc_list) u_int8_t length[2]; - u_int8_t desc_list[0]; + u_int8_t desc_list[]; }; struct scsi_vpd_id_descriptor @@ -872,11 +1182,13 @@ #define SVPD_ID_PROTO_SHIFT 4 #define SVPD_ID_CODESET_BINARY 0x01 #define SVPD_ID_CODESET_ASCII 0x02 +#define SVPD_ID_CODESET_MASK 0x0f u_int8_t id_type; #define SVPD_ID_PIV 0x80 #define SVPD_ID_ASSOC_LUN 0x00 #define SVPD_ID_ASSOC_PORT 0x10 #define SVPD_ID_ASSOC_TARGET 0x20 +#define SVPD_ID_ASSOC_MASK 0x30 #define SVPD_ID_TYPE_VENDOR 0x00 #define SVPD_ID_TYPE_T10 0x01 #define SVPD_ID_TYPE_EUI64 0x02 @@ -889,7 +1201,9 @@ #define SVPD_ID_TYPE_MASK 0x0f u_int8_t reserved; u_int8_t length; - u_int8_t identifier[0]; +#define SVPD_DEVICE_ID_DESC_HDR_LEN \ + __offsetof(struct scsi_vpd_id_descriptor, identifier) + u_int8_t identifier[]; }; struct scsi_vpd_id_t10 @@ -990,12 +1304,23 @@ uint8_t name_string[256]; }; +struct scsi_service_action_in +{ + uint8_t opcode; + uint8_t service_action; + uint8_t action_dependent[13]; + uint8_t control; +}; + struct scsi_read_capacity { u_int8_t opcode; u_int8_t byte2; +#define SRC_RELADR 0x01 u_int8_t addr[4]; - u_int8_t unused[3]; + u_int8_t unused[2]; + u_int8_t pmi; +#define SRC_PMI 0x01 u_int8_t control; }; @@ -1038,18 +1363,11 @@ uint8_t control; }; -struct scsi_report_luns_data { - u_int8_t length[4]; /* length of LUN inventory, in bytes */ - u_int8_t reserved[4]; /* unused */ - /* - * LUN inventory- we only support the type zero form for now. - */ - struct { - u_int8_t lundata[8]; - } luns[0]; -}; +struct scsi_report_luns_lundata { + uint8_t lundata[8]; #define RPL_LUNDATA_PERIPH_BUS_MASK 0x3f #define RPL_LUNDATA_FLAT_LUN_MASK 0x3f +#define RPL_LUNDATA_FLAT_LUN_BITS 0x06 #define RPL_LUNDATA_LUN_TARG_MASK 0x3f #define RPL_LUNDATA_LUN_BUS_MASK 0xe0 #define RPL_LUNDATA_LUN_LUN_MASK 0x1f @@ -1062,7 +1380,17 @@ #define RPL_LUNDATA_ATYP_FLAT 0x40 #define RPL_LUNDATA_ATYP_LUN 0x80 #define RPL_LUNDATA_ATYP_EXTLUN 0xc0 +}; +struct scsi_report_luns_data { + u_int8_t length[4]; /* length of LUN inventory, in bytes */ + u_int8_t reserved[4]; /* unused */ + /* + * LUN inventory- we only support the type zero form for now. + */ + struct scsi_report_luns_lundata luns[0]; +}; + struct scsi_target_group { uint8_t opcode; @@ -1103,6 +1431,9 @@ uint8_t target_port_group[2]; uint8_t reserved; uint8_t status; +#define TPG_UNAVLBL 0 +#define TPG_SET_BY_STPG 0x01 +#define TPG_IMPLICIT 0x02 uint8_t vendor_specific; uint8_t target_port_count; struct scsi_target_port_descriptor descriptors[]; @@ -1122,8 +1453,49 @@ }; +typedef enum { + SSD_TYPE_NONE, + SSD_TYPE_FIXED, + SSD_TYPE_DESC +} scsi_sense_data_type; + +typedef enum { + SSD_ELEM_NONE, + SSD_ELEM_SKIP, + SSD_ELEM_DESC, + SSD_ELEM_SKS, + SSD_ELEM_COMMAND, + SSD_ELEM_INFO, + SSD_ELEM_FRU, + SSD_ELEM_STREAM, + SSD_ELEM_MAX +} scsi_sense_elem_type; + + struct scsi_sense_data { + uint8_t error_code; + /* + * SPC-4 says that the maximum length of sense data is 252 bytes. + * So this structure is exactly 252 bytes log. + */ +#define SSD_FULL_SIZE 252 + uint8_t sense_buf[SSD_FULL_SIZE - 1]; + /* + * XXX KDM is this still a reasonable minimum size? + */ +#define SSD_MIN_SIZE 18 + /* + * Maximum value for the extra_len field in the sense data. + */ +#define SSD_EXTRA_MAX 244 +}; + +/* + * Fixed format sense data. + */ +struct scsi_sense_data_fixed +{ u_int8_t error_code; #define SSD_ERRCODE 0x7F #define SSD_CURRENT_ERROR 0x70 @@ -1147,7 +1519,7 @@ #define SSD_KEY_EQUAL 0x0c #define SSD_KEY_VOLUME_OVERFLOW 0x0d #define SSD_KEY_MISCOMPARE 0x0e -#define SSD_KEY_RESERVED 0x0f +#define SSD_KEY_COMPLETED 0x0f #define SSD_ILI 0x20 #define SSD_EOM 0x40 #define SSD_FILEMARK 0x80 @@ -1162,11 +1534,304 @@ #define SSD_FIELDPTR_CMD 0x40 #define SSD_BITPTR_VALID 0x08 #define SSD_BITPTR_VALUE 0x07 -#define SSD_MIN_SIZE 18 u_int8_t extra_bytes[14]; -#define SSD_FULL_SIZE sizeof(struct scsi_sense_data) }; +/* + * Descriptor format sense data definitions. + * Introduced in SPC-3. + */ +struct scsi_sense_data_desc +{ + uint8_t error_code; +#define SSD_DESC_CURRENT_ERROR 0x72 +#define SSD_DESC_DEFERRED_ERROR 0x73 + uint8_t sense_key; + uint8_t add_sense_code; + uint8_t add_sense_code_qual; + uint8_t reserved[3]; + /* + * Note that SPC-4, section 4.5.2.1 says that the extra_len field + * must be less than or equal to 244. + */ + uint8_t extra_len; + uint8_t sense_desc[0]; +}; + +struct scsi_sense_desc_header +{ + uint8_t desc_type; + uint8_t length; +}; +/* + * The information provide in the Information descriptor is device type or + * command specific information, and defined in a command standard. + * + * Note that any changes to the field names or positions in this structure, + * even reserved fields, should be accompanied by an examination of the + * code in ctl_set_sense() that uses them. + * + * Maximum descriptors allowed: 1 (as of SPC-4) + */ +struct scsi_sense_info +{ + uint8_t desc_type; +#define SSD_DESC_INFO 0x00 + uint8_t length; + uint8_t byte2; +#define SSD_INFO_VALID 0x80 + uint8_t reserved; + uint8_t info[8]; +}; + +/* + * Command-specific information depends on the command for which the + * reported condition occured. + * + * Note that any changes to the field names or positions in this structure, + * even reserved fields, should be accompanied by an examination of the + * code in ctl_set_sense() that uses them. + * + * Maximum descriptors allowed: 1 (as of SPC-4) + */ +struct scsi_sense_command +{ + uint8_t desc_type; +#define SSD_DESC_COMMAND 0x01 + uint8_t length; + uint8_t reserved[2]; + uint8_t command_info[8]; +}; + +/* + * Sense key specific descriptor. The sense key specific data format + * depends on the sense key in question. + * + * Maximum descriptors allowed: 1 (as of SPC-4) + */ +struct scsi_sense_sks +{ + uint8_t desc_type; +#define SSD_DESC_SKS 0x02 + uint8_t length; + uint8_t reserved1[2]; + uint8_t sense_key_spec[3]; +#define SSD_SKS_VALID 0x80 + uint8_t reserved2; +}; + +/* + * This is used for the Illegal Request sense key (0x05) only. + */ +struct scsi_sense_sks_field +{ + uint8_t byte0; +#define SSD_SKS_FIELD_VALID 0x80 +#define SSD_SKS_FIELD_CMD 0x40 +#define SSD_SKS_BPV 0x08 +#define SSD_SKS_BIT_VALUE 0x07 + uint8_t field[2]; +}; + + +/* + * This is used for the Hardware Error (0x04), Medium Error (0x03) and + * Recovered Error (0x01) sense keys. + */ +struct scsi_sense_sks_retry +{ + uint8_t byte0; +#define SSD_SKS_RETRY_VALID 0x80 + uint8_t actual_retry_count[2]; +}; + +/* + * Used with the NO Sense (0x00) or Not Ready (0x02) sense keys. + */ +struct scsi_sense_sks_progress +{ + uint8_t byte0; +#define SSD_SKS_PROGRESS_VALID 0x80 + uint8_t progress[2]; +#define SSD_SKS_PROGRESS_DENOM 0x10000 +}; + +/* + * Used with the Copy Aborted (0x0a) sense key. + */ +struct scsi_sense_sks_segment +{ + uint8_t byte0; +#define SSD_SKS_SEGMENT_VALID 0x80 +#define SSD_SKS_SEGMENT_SD 0x20 +#define SSD_SKS_SEGMENT_BPV 0x08 +#define SSD_SKS_SEGMENT_BITPTR 0x07 + uint8_t field[2]; +}; + +/* + * Used with the Unit Attention (0x06) sense key. + * + * This is currently used to indicate that the unit attention condition + * queue has overflowed (when the overflow bit is set). + */ +struct scsi_sense_sks_overflow +{ + uint8_t byte0; +#define SSD_SKS_OVERFLOW_VALID 0x80 +#define SSD_SKS_OVERFLOW_SET 0x01 + uint8_t reserved[2]; +}; + +/* + * This specifies which component is associated with the sense data. There + * is no standard meaning for the fru value. + * + * Maximum descriptors allowed: 1 (as of SPC-4) + */ +struct scsi_sense_fru +{ + uint8_t desc_type; +#define SSD_DESC_FRU 0x03 + uint8_t length; + uint8_t reserved; + uint8_t fru; +}; + +/* + * Used for Stream commands, defined in SSC-4. + * + * Maximum descriptors allowed: 1 (as of SPC-4) + */ + +struct scsi_sense_stream +{ + uint8_t desc_type; +#define SSD_DESC_STREAM 0x04 + uint8_t length; + uint8_t reserved; + uint8_t byte3; +#define SSD_DESC_STREAM_FM 0x80 +#define SSD_DESC_STREAM_EOM 0x40 +#define SSD_DESC_STREAM_ILI 0x20 +}; + +/* + * Used for Block commands, defined in SBC-3. + * + * This is currently (as of SBC-3) only used for the Incorrect Length + * Indication (ILI) bit, which says that the data length requested in the + * READ LONG or WRITE LONG command did not match the length of the logical + * block. + * + * Maximum descriptors allowed: 1 (as of SPC-4) + */ +struct scsi_sense_block +{ + uint8_t desc_type; +#define SSD_DESC_BLOCK 0x05 + uint8_t length; + uint8_t reserved; + uint8_t byte3; +#define SSD_DESC_BLOCK_ILI 0x20 +}; + +/* + * Used for Object-Based Storage Devices (OSD-3). + * + * Maximum descriptors allowed: 1 (as of SPC-4) + */ +struct scsi_sense_osd_objid +{ + uint8_t desc_type; +#define SSD_DESC_OSD_OBJID 0x06 + uint8_t length; + uint8_t reserved[6]; + /* + * XXX KDM provide the bit definitions here? There are a lot of + * them, and we don't have an OSD driver yet. + */ + uint8_t not_init_cmds[4]; + uint8_t completed_cmds[4]; + uint8_t partition_id[8]; + uint8_t object_id[8]; +}; + +/* + * Used for Object-Based Storage Devices (OSD-3). + * + * Maximum descriptors allowed: 1 (as of SPC-4) + */ +struct scsi_sense_osd_integrity +{ + uint8_t desc_type; +#define SSD_DESC_OSD_INTEGRITY 0x07 + uint8_t length; + uint8_t integ_check_val[32]; +}; + +/* + * Used for Object-Based Storage Devices (OSD-3). + * + * Maximum descriptors allowed: 1 (as of SPC-4) + */ +struct scsi_sense_osd_attr_id +{ + uint8_t desc_type; +#define SSD_DESC_OSD_ATTR_ID 0x08 + uint8_t length; + uint8_t reserved[2]; + uint8_t attr_desc[0]; +}; + +/* + * Used with Sense keys No Sense (0x00) and Not Ready (0x02). + * + * Maximum descriptors allowed: 32 (as of SPC-4) + */ +struct scsi_sense_progress +{ + uint8_t desc_type; +#define SSD_DESC_PROGRESS 0x0a + uint8_t length; + uint8_t sense_key; + uint8_t add_sense_code; + uint8_t add_sense_code_qual; + uint8_t reserved; + uint8_t progress[2]; +}; + +/* + * This is typically forwarded as the result of an EXTENDED COPY command. + * + * Maximum descriptors allowed: 2 (as of SPC-4) + */ +struct scsi_sense_forwarded +{ + uint8_t desc_type; +#define SSD_DESC_FORWARDED 0x0c + uint8_t length; + uint8_t byte2; +#define SSD_FORWARDED_FSDT 0x80 +#define SSD_FORWARDED_SDS_MASK 0x0f +#define SSD_FORWARDED_SDS_UNK 0x00 +#define SSD_FORWARDED_SDS_EXSRC 0x01 +#define SSD_FORWARDED_SDS_EXDST 0x02 +}; + +/* + * Vendor-specific sense descriptor. The desc_type field will be in the + * range bewteen MIN and MAX inclusive. + */ +struct scsi_sense_vendor +{ + uint8_t desc_type; +#define SSD_DESC_VENDOR_MIN 0x80 +#define SSD_DESC_VENDOR_MAX 0xff + uint8_t length; + uint8_t data[0]; +}; + struct scsi_mode_header_6 { u_int8_t data_length; /* Sense data length */ @@ -1187,9 +1852,20 @@ struct scsi_mode_page_header { u_int8_t page_code; +#define SMPH_PS 0x80 +#define SMPH_SPF 0x40 +#define SMPH_PC_MASK 0x3f u_int8_t page_length; }; +struct scsi_mode_page_header_sp +{ + uint8_t page_code; + uint8_t subpage; + uint8_t page_length[2]; +}; + + struct scsi_mode_blk_desc { u_int8_t density; @@ -1292,6 +1968,81 @@ struct scsi_inquiry_data *inq_data, u_int32_t sense_flags); const char * scsi_status_string(struct ccb_scsiio *csio); + +uint8_t *scsi_find_desc(struct scsi_sense_data_desc *sense, uint8_t desc_type); +void scsi_set_sense_data(struct scsi_sense_data *sense_data, + scsi_sense_data_type sense_format, int current_error, + int sense_key, int asc, int ascq, ...) ; +void scsi_set_sense_data_va(struct scsi_sense_data *sense_data, + scsi_sense_data_type sense_format, + int current_error, int sense_key, int asc, + int ascq, va_list ap); +int scsi_asc_ascq_valid(struct scsi_sense_data *sense, int ascq); +int scsi_get_sense_info(struct scsi_sense_data *sense_data, uint8_t info_type, + uint64_t *info, int64_t *signed_info); +int scsi_get_sks(struct scsi_sense_data *sense_data, uint8_t *sks); +int scsi_get_block_info(struct scsi_sense_data *sense_data, + struct scsi_inquiry_data *inq_data, + uint8_t *block_bits); +int scsi_get_stream_info(struct scsi_sense_data *sense_data, + struct scsi_inquiry_data *inq_data, + uint8_t *stream_bits); +/* + * XXX KDM consider removing some of these routines once ctl_scsi_all.c + * has been refactored. + */ +void scsi_info_sbuf(struct sbuf *sb, uint8_t *cdb, int cdb_len, + struct scsi_inquiry_data *inq_data, uint64_t info); +void scsi_command_sbuf(struct sbuf *sb, uint8_t *cdb, int cdb_len, + struct scsi_inquiry_data *inq_data, uint64_t csi); +void scsi_progress_sbuf(struct sbuf *sb, uint16_t progress); +int scsi_sks_sbuf(struct sbuf *sb, int sense_key, uint8_t *sks); +void scsi_fru_sbuf(struct sbuf *sb, uint64_t fru); +void scsi_stream_sbuf(struct sbuf *sb, uint8_t stream_bits, uint64_t info); +void scsi_block_sbuf(struct sbuf *sb, uint8_t block_bits, uint64_t info); +void scsi_sense_info_sbuf(struct sbuf *sb, struct scsi_sense_data *sense, + uint8_t *cdb, int cdb_len, + struct scsi_inquiry_data *inq_data, + struct scsi_sense_desc_header *header); + +void scsi_sense_command_sbuf(struct sbuf *sb, struct scsi_sense_data *sense, + uint8_t *cdb, int cdb_len, + struct scsi_inquiry_data *inq_data, + struct scsi_sense_desc_header *header); +void scsi_sense_sks_sbuf(struct sbuf *sb, struct scsi_sense_data *sense, + uint8_t *cdb, int cdb_len, + struct scsi_inquiry_data *inq_data, + struct scsi_sense_desc_header *header); +void scsi_sense_fru_sbuf(struct sbuf *sb, struct scsi_sense_data *sense, + uint8_t *cdb, int cdb_len, + struct scsi_inquiry_data *inq_data, + struct scsi_sense_desc_header *header); +void scsi_sense_stream_sbuf(struct sbuf *sb, struct scsi_sense_data *sense, + uint8_t *cdb, int cdb_len, + struct scsi_inquiry_data *inq_data, + struct scsi_sense_desc_header *header); +void scsi_sense_block_sbuf(struct sbuf *sb, struct scsi_sense_data *sense, + uint8_t *cdb, int cdb_len, + struct scsi_inquiry_data *inq_data, + struct scsi_sense_desc_header *header); +void scsi_sense_progress_sbuf(struct sbuf *sb, struct scsi_sense_data *sense, + uint8_t *cdb, int cdb_len, + struct scsi_inquiry_data *inq_data, + struct scsi_sense_desc_header *header); +void scsi_sense_generic_sbuf(struct sbuf *sb, struct scsi_sense_data *sense, + uint8_t *cdb, int cdb_len, + struct scsi_inquiry_data *inq_data, + struct scsi_sense_desc_header *header); +void scsi_sense_desc_sbuf(struct sbuf *sb, struct scsi_sense_data *sense, + uint8_t *cdb, int cdb_len, + struct scsi_inquiry_data *inq_data, + struct scsi_sense_desc_header *header); +scsi_sense_data_type scsi_sense_type(struct scsi_sense_data *sense_data); + +void scsi_sense_only_sbuf(struct scsi_sense_data *sense, struct sbuf *sb, + char *path_str, struct scsi_inquiry_data *inq_data, + uint8_t *cdb, int cdb_len); + #ifdef _KERNEL int scsi_command_string(struct ccb_scsiio *csio, struct sbuf *sb); int scsi_sense_sbuf(struct ccb_scsiio *csio, struct sbuf *sb, @@ -1500,28 +2251,80 @@ static __inline void scsi_extract_sense(struct scsi_sense_data *sense, int *error_code, int *sense_key, int *asc, int *ascq); +static __inline int scsi_get_sense_key(struct scsi_sense_data *sense); +static __inline int scsi_get_asc(struct scsi_sense_data *sense); +static __inline int scsi_get_ascq(struct scsi_sense_data *sense); static __inline void scsi_ulto2b(u_int32_t val, u_int8_t *bytes); static __inline void scsi_ulto3b(u_int32_t val, u_int8_t *bytes); static __inline void scsi_ulto4b(u_int32_t val, u_int8_t *bytes); static __inline void scsi_u64to8b(u_int64_t val, u_int8_t *bytes); -static __inline u_int32_t scsi_2btoul(u_int8_t *bytes); -static __inline u_int32_t scsi_3btoul(u_int8_t *bytes); -static __inline int32_t scsi_3btol(u_int8_t *bytes); -static __inline u_int32_t scsi_4btoul(u_int8_t *bytes); -static __inline u_int64_t scsi_8btou64(u_int8_t *bytes); +static __inline uint32_t scsi_2btoul(const uint8_t *bytes); +static __inline uint32_t scsi_3btoul(const uint8_t *bytes); +static __inline int32_t scsi_3btol(const uint8_t *bytes); +static __inline uint32_t scsi_4btoul(const uint8_t *bytes); +static __inline uint64_t scsi_8btou64(const uint8_t *bytes); static __inline void *find_mode_page_6(struct scsi_mode_header_6 *mode_header); static __inline void *find_mode_page_10(struct scsi_mode_header_10 *mode_header); -static __inline void scsi_extract_sense(struct scsi_sense_data *sense, +static __inline void scsi_extract_sense(struct scsi_sense_data *sense_data, int *error_code, int *sense_key, int *asc, int *ascq) { - *error_code = sense->error_code & SSD_ERRCODE; - *sense_key = sense->flags & SSD_KEY; - *asc = (sense->extra_len >= 5) ? sense->add_sense_code : 0; - *ascq = (sense->extra_len >= 6) ? sense->add_sense_code_qual : 0; + switch (sense_data->error_code & SSD_ERRCODE) { + case SSD_DESC_CURRENT_ERROR: + case SSD_DESC_DEFERRED_ERROR: { + struct scsi_sense_data_desc *sense; + + sense = (struct scsi_sense_data_desc *)sense_data; + *error_code = sense->error_code & SSD_ERRCODE; + *sense_key = sense->sense_key & SSD_KEY; + *asc = sense->add_sense_code; + *ascq = sense->add_sense_code_qual; + break; + } + case SSD_CURRENT_ERROR: + case SSD_DEFERRED_ERROR: + default: { + struct scsi_sense_data_fixed *sense; + + sense = (struct scsi_sense_data_fixed *)sense_data; + *error_code = sense->error_code & SSD_ERRCODE; + *sense_key = sense->flags & SSD_KEY; + *asc = (sense->extra_len >= 5) ? sense->add_sense_code : 0; + *ascq = (sense->extra_len >= 6) ?sense->add_sense_code_qual : 0; + break; + } + } } +static __inline int scsi_get_sense_key(struct scsi_sense_data *sense_data) +{ + int error_code, sense_key, asc, ascq; + + scsi_extract_sense(sense_data, &error_code, &sense_key, &asc, &ascq); + + return (sense_key); +} + +static __inline int scsi_get_asc(struct scsi_sense_data *sense_data) +{ + int error_code, sense_key, asc, ascq; + + scsi_extract_sense(sense_data, &error_code, &sense_key, &asc, &ascq); + + return (asc); +} + +static __inline int scsi_get_ascq(struct scsi_sense_data *sense_data) +{ + int error_code, sense_key, asc, ascq; + + scsi_extract_sense(sense_data, &error_code, &sense_key, &asc, &ascq); + + return (ascq); +} + + static __inline void scsi_ulto2b(u_int32_t val, u_int8_t *bytes) { @@ -1563,20 +2366,20 @@ bytes[7] = val & 0xff; } -static __inline u_int32_t -scsi_2btoul(u_int8_t *bytes) +static __inline uint32_t +scsi_2btoul(const uint8_t *bytes) { - u_int32_t rv; + uint32_t rv; rv = (bytes[0] << 8) | bytes[1]; return (rv); } -static __inline u_int32_t -scsi_3btoul(u_int8_t *bytes) +static __inline uint32_t +scsi_3btoul(const uint8_t *bytes) { - u_int32_t rv; + uint32_t rv; rv = (bytes[0] << 16) | (bytes[1] << 8) | @@ -1585,9 +2388,9 @@ } static __inline int32_t -scsi_3btol(u_int8_t *bytes) +scsi_3btol(const uint8_t *bytes) { - u_int32_t rc = scsi_3btoul(bytes); + uint32_t rc = scsi_3btoul(bytes); if (rc & 0x00800000) rc |= 0xff000000; @@ -1595,10 +2398,10 @@ return (int32_t) rc; } -static __inline u_int32_t -scsi_4btoul(u_int8_t *bytes) +static __inline uint32_t +scsi_4btoul(const uint8_t *bytes) { - u_int32_t rv; + uint32_t rv; rv = (bytes[0] << 24) | (bytes[1] << 16) | @@ -1608,7 +2411,7 @@ } static __inline uint64_t -scsi_8btou64(uint8_t *bytes) +scsi_8btou64(const uint8_t *bytes) { uint64_t rv; Index: sys/cam/scsi/scsi_sa.c =================================================================== --- sys/cam/scsi/scsi_sa.c (revision 225710) +++ sys/cam/scsi/scsi_sa.c (working copy) @@ -235,10 +235,10 @@ */ struct { struct scsi_sense_data _last_io_sense; - u_int32_t _last_io_resid; + u_int64_t _last_io_resid; u_int8_t _last_io_cdb[CAM_MAX_CDBLEN]; struct scsi_sense_data _last_ctl_sense; - u_int32_t _last_ctl_resid; + u_int64_t _last_ctl_resid; u_int8_t _last_ctl_cdb[CAM_MAX_CDBLEN]; #define last_io_sense errinfo._last_io_sense #define last_io_resid errinfo._last_io_resid @@ -2322,17 +2322,22 @@ struct sa_softc *softc; struct ccb_scsiio *csio; struct scsi_sense_data *sense; - u_int32_t resid = 0; - int32_t info = 0; + uint64_t resid = 0; + int64_t info = 0; cam_status status; - int error_code, sense_key, asc, ascq, error, aqvalid; + int error_code, sense_key, asc, ascq, error, aqvalid, stream_valid; + uint8_t stream_bits; periph = xpt_path_periph(ccb->ccb_h.path); softc = (struct sa_softc *)periph->softc; csio = &ccb->csio; sense = &csio->sense_data; scsi_extract_sense(sense, &error_code, &sense_key, &asc, &ascq); - aqvalid = sense->extra_len >= 6; + aqvalid = scsi_asc_ascq_valid(sense, /*ascq*/ 1); + if (scsi_get_stream_info(sense, NULL, &stream_bits) == 0) + stream_valid = 1; + else + stream_valid = 0; error = 0; status = csio->ccb_h.status & CAM_STATUS_MASK; @@ -2343,9 +2348,8 @@ * unit. */ if (status == CAM_SCSI_STATUS_ERROR) { - if ((sense->error_code & SSD_ERRCODE_VALID) != 0) { - info = (int32_t) scsi_4btoul(sense->info); - resid = info; + if (scsi_get_sense_info(sense, SSD_DESC_INFO, &resid, + &info) == 0) { if ((softc->flags & SA_FLAG_FIXED) != 0) resid *= softc->media_blksize; } else { @@ -2372,10 +2376,11 @@ softc->last_resid_was_io = 0; } CAM_DEBUG(periph->path, CAM_DEBUG_INFO, ("CDB[0]=0x%x Key 0x%x " - "ASC/ASCQ 0x%x/0x%x CAM STATUS 0x%x flags 0x%x resid %d " + "ASC/ASCQ 0x%x/0x%x CAM STATUS 0x%x flags 0x%x resid %jd " "dxfer_len %d\n", csio->cdb_io.cdb_bytes[0] & 0xff, sense_key, asc, ascq, status, - sense->flags & ~SSD_KEY_RESERVED, resid, csio->dxfer_len)); + (stream_valid) ? stream_bits : 0, (intmax_t)resid, + csio->dxfer_len)); } else { CAM_DEBUG(periph->path, CAM_DEBUG_INFO, ("Cam Status 0x%x\n", status)); @@ -2431,7 +2436,7 @@ if (sense_key == SSD_KEY_VOLUME_OVERFLOW) { csio->resid = resid; error = ENOSPC; - } else if (sense->flags & SSD_EOM) { + } else if ((stream_valid != 0) && (stream_bits & SSD_EOM)) { softc->flags |= SA_FLAG_EOM_PENDING; /* * Grotesque as it seems, the few times @@ -2450,7 +2455,7 @@ } else { error = EIO; } - } else if (sense->flags & SSD_FILEMARK) { + } else if ((stream_valid != 0) && (stream_bits & SSD_FILEMARK)){ if (softc->flags & SA_FLAG_FIXED) { error = -1; softc->flags |= SA_FLAG_EOF_PENDING; @@ -2470,7 +2475,7 @@ /* * Incorrect Length usually applies to read, but can apply to writes. */ - if (error == 0 && (sense->flags & SSD_ILI)) { + if (error == 0 && (stream_valid != 0) && (stream_bits & SSD_ILI)) { if (info < 0) { xpt_print(csio->ccb_h.path, toobig, csio->dxfer_len - info); @@ -2485,7 +2490,8 @@ * Bump the block number if we hadn't seen a filemark. * Do this independent of errors (we've moved anyway). */ - if ((sense->flags & SSD_FILEMARK) == 0) { + if ((stream_valid == 0) || + (stream_bits & SSD_FILEMARK) == 0) { if (softc->blkno != (daddr_t) -1) { softc->blkno++; csio->ccb_h.ccb_pflags |= Index: sys/cam/scsi/scsi_targ_bh.c =================================================================== --- sys/cam/scsi/scsi_targ_bh.c (revision 225710) +++ sys/cam/scsi/scsi_targ_bh.c (working copy) @@ -112,20 +112,20 @@ /* version */2, /* format version */2 }; -static struct scsi_sense_data no_lun_sense_data = +static struct scsi_sense_data_fixed no_lun_sense_data = { SSD_CURRENT_ERROR|SSD_ERRCODE_VALID, 0, SSD_KEY_NOT_READY, { 0, 0, 0, 0 }, - /*extra_len*/offsetof(struct scsi_sense_data, fru) - - offsetof(struct scsi_sense_data, extra_len), + /*extra_len*/offsetof(struct scsi_sense_data_fixed, fru) + - offsetof(struct scsi_sense_data_fixed, extra_len), { 0, 0, 0, 0 }, /* Logical Unit Not Supported */ /*ASC*/0x25, /*ASCQ*/0 }; -static const int request_sense_size = offsetof(struct scsi_sense_data, fru); +static const int request_sense_size = offsetof(struct scsi_sense_data_fixed, fru); static periph_init_t targbhinit; static void targbhasync(void *callback_arg, u_int32_t code, @@ -587,7 +587,9 @@ * This needs to have other than a * no_lun_sense_data response. */ - atio->sense_data = no_lun_sense_data; + bcopy(&no_lun_sense_data, &atio->sense_data, + min(sizeof(no_lun_sense_data), + sizeof(atio->sense_data))); atio->sense_len = sizeof(no_lun_sense_data); descr->data_resid = 0; descr->data_increment = 0; @@ -630,7 +632,9 @@ /* Direction is always relative to the initator */ atio->ccb_h.flags &= ~CAM_DIR_MASK; atio->ccb_h.flags |= CAM_DIR_NONE; - atio->sense_data = no_lun_sense_data; + bcopy(&no_lun_sense_data, &atio->sense_data, + min(sizeof(no_lun_sense_data), + sizeof(atio->sense_data))); atio->sense_len = sizeof (no_lun_sense_data); descr->data_resid = 0; descr->data_increment = 0; Index: sys/cam/scsi/scsi_low.c =================================================================== --- sys/cam/scsi/scsi_low.c (revision 225710) +++ sys/cam/scsi/scsi_low.c (working copy) @@ -2577,12 +2577,16 @@ #ifdef SCSI_LOW_DEBUG if (scsi_low_debug & SCSI_LOW_DEBUG_SENSE) { - printf("SENSE: [%x][%x][%x][%x][%x]\n", - (u_int) cb->ccb_sense.error_code, - (u_int) cb->ccb_sense.segment, - (u_int) cb->ccb_sense.flags, - (u_int) cb->ccb_sense.add_sense_code, - (u_int) cb->ccb_sense.add_sense_code_qual); + int error_code, sense_key, asc, ascq; + + scsi_extract_sense(&cb->ccb_sense, + &error_code, + &sense_key, + &asc, + &ascq); + printf("SENSE: [%x][%x][%x][%x]\n", + error_code, sense_key, asc, + ascq); } #endif /* SCSI_LOW_DEBUG */ } Index: sys/cam/scsi/scsi_all.c =================================================================== --- sys/cam/scsi/scsi_all.c (revision 225710) +++ sys/cam/scsi/scsi_all.c (working copy) @@ -31,6 +31,8 @@ __FBSDID("$FreeBSD$"); #include +#include +#include #ifdef _KERNEL #include @@ -54,6 +56,7 @@ #include #ifndef _KERNEL #include +#include #ifndef FALSE #define FALSE 0 @@ -608,14 +611,24 @@ struct op_table_entry *table[2]; int num_tables; - pd_type = SID_TYPE(inq_data); + /* + * If we've got inquiry data, use it to determine what type of + * device we're dealing with here. Otherwise, assume direct + * access. + */ + if (inq_data == NULL) { + pd_type = T_DIRECT; + match = NULL; + } else { + pd_type = SID_TYPE(inq_data); - match = cam_quirkmatch((caddr_t)inq_data, - (caddr_t)scsi_op_quirk_table, - sizeof(scsi_op_quirk_table)/ - sizeof(*scsi_op_quirk_table), - sizeof(*scsi_op_quirk_table), - scsi_inquiry_match); + match = cam_quirkmatch((caddr_t)inq_data, + (caddr_t)scsi_op_quirk_table, + sizeof(scsi_op_quirk_table)/ + sizeof(*scsi_op_quirk_table), + sizeof(*scsi_op_quirk_table), + scsi_inquiry_match); + } if (match != NULL) { table[0] = ((struct scsi_op_quirk_entry *)match)->op_table; @@ -699,7 +712,7 @@ { SSD_KEY_EQUAL, SS_NOP, "EQUAL" }, { SSD_KEY_VOLUME_OVERFLOW, SS_FATAL|EIO, "VOLUME OVERFLOW" }, { SSD_KEY_MISCOMPARE, SS_NOP, "MISCOMPARE" }, - { SSD_KEY_RESERVED, SS_FATAL|EIO, "RESERVED" } + { SSD_KEY_COMPLETED, SS_NOP, "RESERVED" } }; const int sense_key_table_size = @@ -1062,25 +1075,25 @@ { SST(0x10, 0x03, SS_RDEF, /* XXX TBD */ "Logical block reference tag check failed") }, /* DT WRO BK */ - { SST(0x11, 0x00, SS_RDEF, + { SST(0x11, 0x00, SS_FATAL|EIO, "Unrecovered read error") }, /* DT WRO BK */ - { SST(0x11, 0x01, SS_RDEF, + { SST(0x11, 0x01, SS_FATAL|EIO, "Read retries exhausted") }, /* DT WRO BK */ - { SST(0x11, 0x02, SS_RDEF, + { SST(0x11, 0x02, SS_FATAL|EIO, "Error too long to correct") }, /* DT W O BK */ - { SST(0x11, 0x03, SS_RDEF, + { SST(0x11, 0x03, SS_FATAL|EIO, "Multiple read errors") }, /* D W O BK */ - { SST(0x11, 0x04, SS_RDEF, + { SST(0x11, 0x04, SS_FATAL|EIO, "Unrecovered read error - auto reallocate failed") }, /* WRO B */ - { SST(0x11, 0x05, SS_RDEF, + { SST(0x11, 0x05, SS_FATAL|EIO, "L-EC uncorrectable error") }, /* WRO B */ - { SST(0x11, 0x06, SS_RDEF, + { SST(0x11, 0x06, SS_FATAL|EIO, "CIRC unrecovered error") }, /* W O B */ { SST(0x11, 0x07, SS_RDEF, @@ -1095,10 +1108,10 @@ { SST(0x11, 0x0A, SS_RDEF, "Miscorrected error") }, /* D W O BK */ - { SST(0x11, 0x0B, SS_RDEF, + { SST(0x11, 0x0B, SS_FATAL|EIO, "Unrecovered read error - recommend reassignment") }, /* D W O BK */ - { SST(0x11, 0x0C, SS_RDEF, + { SST(0x11, 0x0C, SS_FATAL|EIO, "Unrecovered read error - recommend rewrite the data") }, /* DT WRO B */ { SST(0x11, 0x0D, SS_RDEF, @@ -2819,7 +2832,8 @@ scsi_extract_sense(&csio->sense_data, &error_code, &sense_key, &asc, &ascq); - if (error_code == SSD_DEFERRED_ERROR) { + if ((error_code == SSD_DEFERRED_ERROR) + || (error_code == SSD_DESC_DEFERRED_ERROR)) { /* * XXX dufault@FreeBSD.org * This error doesn't relate to the command associated @@ -3040,8 +3054,1232 @@ return(0); } +/* + * Given a descriptor type, return a pointer to it if it is in the sense + * data and not truncated. Avoiding truncating sense data will simplify + * things significantly for the caller. + * + * We shouldn't run into truncated data very often, since we specify full + * sized sense data in most every case. + */ +uint8_t * +scsi_find_desc(struct scsi_sense_data_desc *sense, uint8_t desc_type) +{ + int cur_pos; + for (cur_pos = 0; cur_pos < MIN(sense->extra_len, SSD_EXTRA_MAX);) { + struct scsi_sense_desc_header *header; + + header = (struct scsi_sense_desc_header *) + &sense->sense_desc[cur_pos]; + if (header->desc_type == desc_type) { + if (header->length > (sense->extra_len - cur_pos)) + return (NULL); + else + return (uint8_t *)header; + } + cur_pos += sizeof(*header) + header->length; + } + + return (NULL); +} + /* + * Fill in SCSI sense data with the specified parameters. This routine can + * fill in either fixed or descriptor type sense data. + */ +void +scsi_set_sense_data_va(struct scsi_sense_data *sense_data, + scsi_sense_data_type sense_format, int current_error, + int sense_key, int asc, int ascq, va_list ap) +{ + int descriptor_sense; + scsi_sense_elem_type elem_type; + + /* + * Determine whether to return fixed or descriptor format sense + * data. If the user specifies SSD_TYPE_NONE for some reason, + * they'll just get fixed sense data. + */ + if (sense_format == SSD_TYPE_DESC) + descriptor_sense = 1; + else + descriptor_sense = 0; + + /* + * Zero the sense data, so that we don't pass back any garbage data + * to the user. + */ + memset(sense_data, 0, sizeof(*sense_data)); + + if (descriptor_sense != 0) { + struct scsi_sense_data_desc *sense; + + sense = (struct scsi_sense_data_desc *)sense_data; + /* + * The descriptor sense format eliminates the use of the + * valid bit. + */ + if (current_error != 0) + sense->error_code = SSD_DESC_CURRENT_ERROR; + else + sense->error_code = SSD_DESC_DEFERRED_ERROR; + sense->sense_key = sense_key; + sense->add_sense_code = asc; + sense->add_sense_code_qual = ascq; + /* + * Start off with no extra length, since the above data + * fits in the standard descriptor sense information. + */ + sense->extra_len = 0; + while ((elem_type = (scsi_sense_elem_type)va_arg(ap, + scsi_sense_elem_type)) != SSD_ELEM_NONE) { + int sense_len, len_to_copy; + uint8_t *data; + + if (elem_type >= SSD_ELEM_MAX) { + printf("%s: invalid sense type %d\n", __func__, + elem_type); + break; + } + + sense_len = (int)va_arg(ap, int); + len_to_copy = MIN(sense_len, SSD_EXTRA_MAX - + sense->extra_len); + data = (uint8_t *)va_arg(ap, uint8_t *); + + /* + * We've already consumed the arguments for this one. + */ + if (elem_type == SSD_ELEM_SKIP) + continue; + + switch (elem_type) { + case SSD_ELEM_DESC: { + + /* + * This is a straight descriptor. All we + * need to do is copy the data in. + */ + bcopy(data, &sense->sense_desc[ + sense->extra_len], len_to_copy); + sense->extra_len += len_to_copy; + break; + } + case SSD_ELEM_SKS: { + struct scsi_sense_sks sks; + + bzero(&sks, sizeof(sks)); + + /* + * This is already-formatted sense key + * specific data. We just need to fill out + * the header and copy everything in. + */ + bcopy(data, &sks.sense_key_spec, + MIN(len_to_copy, + sizeof(sks.sense_key_spec))); + + sks.desc_type = SSD_DESC_SKS; + sks.length = sizeof(sks) - + offsetof(struct scsi_sense_sks, reserved1); + bcopy(&sks,&sense->sense_desc[sense->extra_len], + sizeof(sks)); + sense->extra_len += sizeof(sks); + break; + } + case SSD_ELEM_INFO: + case SSD_ELEM_COMMAND: { + struct scsi_sense_command cmd; + struct scsi_sense_info info; + uint8_t *data_dest; + uint8_t *descriptor; + int descriptor_size, i, copy_len; + + bzero(&cmd, sizeof(cmd)); + bzero(&info, sizeof(info)); + + /* + * Command or information data. The + * operate in pretty much the same way. + */ + if (elem_type == SSD_ELEM_COMMAND) { + len_to_copy = MIN(len_to_copy, + sizeof(cmd.command_info)); + descriptor = (uint8_t *)&cmd; + descriptor_size = sizeof(cmd); + data_dest =(uint8_t *)&cmd.command_info; + cmd.desc_type = SSD_DESC_COMMAND; + cmd.length = sizeof(cmd) - + offsetof(struct scsi_sense_command, + reserved); + } else { + len_to_copy = MIN(len_to_copy, + sizeof(info.info)); + descriptor = (uint8_t *)&info; + descriptor_size = sizeof(cmd); + data_dest = (uint8_t *)&info.info; + info.desc_type = SSD_DESC_INFO; + info.byte2 = SSD_INFO_VALID; + info.length = sizeof(info) - + offsetof(struct scsi_sense_info, + byte2); + } + + /* + * Copy this in reverse because the spec + * (SPC-4) says that when 4 byte quantities + * are stored in this 8 byte field, the + * first four bytes shall be 0. + * + * So we fill the bytes in from the end, and + * if we have less than 8 bytes to copy, + * the initial, most significant bytes will + * be 0. + */ + for (i = sense_len - 1; i >= 0 && + len_to_copy > 0; i--, len_to_copy--) + data_dest[len_to_copy - 1] = data[i]; + + /* + * This calculation looks much like the + * initial len_to_copy calculation, but + * we have to do it again here, because + * we're looking at a larger amount that + * may or may not fit. It's not only the + * data the user passed in, but also the + * rest of the descriptor. + */ + copy_len = MIN(descriptor_size, + SSD_EXTRA_MAX - sense->extra_len); + bcopy(descriptor, &sense->sense_desc[ + sense->extra_len], copy_len); + sense->extra_len += copy_len; + break; + } + case SSD_ELEM_FRU: { + struct scsi_sense_fru fru; + int copy_len; + + bzero(&fru, sizeof(fru)); + + fru.desc_type = SSD_DESC_FRU; + fru.length = sizeof(fru) - + offsetof(struct scsi_sense_fru, reserved); + fru.fru = *data; + + copy_len = MIN(sizeof(fru), SSD_EXTRA_MAX - + sense->extra_len); + bcopy(&fru, &sense->sense_desc[ + sense->extra_len], copy_len); + sense->extra_len += copy_len; + break; + } + case SSD_ELEM_STREAM: { + struct scsi_sense_stream stream_sense; + int copy_len; + + bzero(&stream_sense, sizeof(stream_sense)); + stream_sense.desc_type = SSD_DESC_STREAM; + stream_sense.length = sizeof(stream_sense) - + offsetof(struct scsi_sense_stream, reserved); + stream_sense.byte3 = *data; + + copy_len = MIN(sizeof(stream_sense), + SSD_EXTRA_MAX - sense->extra_len); + bcopy(&stream_sense, &sense->sense_desc[ + sense->extra_len], copy_len); + sense->extra_len += copy_len; + break; + } + default: + /* + * We shouldn't get here, but if we do, do + * nothing. We've already consumed the + * arguments above. + */ + break; + } + } + } else { + struct scsi_sense_data_fixed *sense; + + sense = (struct scsi_sense_data_fixed *)sense_data; + + if (current_error != 0) + sense->error_code = SSD_ERRCODE_VALID | + SSD_CURRENT_ERROR; + else + sense->error_code = SSD_ERRCODE_VALID | + SSD_DEFERRED_ERROR; + sense->flags = sense_key; + sense->add_sense_code = asc; + sense->add_sense_code_qual = ascq; + /* + * We've set the ASC and ASCQ, so we have 6 more bytes of + * valid data. If we wind up setting any of the other + * fields, we'll bump this to 10 extra bytes. + */ + sense->extra_len = 6; + + while ((elem_type = (scsi_sense_elem_type)va_arg(ap, + scsi_sense_elem_type)) != SSD_ELEM_NONE) { + int sense_len, len_to_copy; + uint8_t *data; + + if (elem_type >= SSD_ELEM_MAX) { + printf("%s: invalid sense type %d\n", __func__, + elem_type); + break; + } + /* + * If we get in here, just bump the extra length to + * 10 bytes. That will encompass anything we're + * going to set here. + */ + sense->extra_len = 10; + sense_len = (int)va_arg(ap, int); + len_to_copy = MIN(sense_len, SSD_EXTRA_MAX - + sense->extra_len); + data = (uint8_t *)va_arg(ap, uint8_t *); + + switch (elem_type) { + case SSD_ELEM_SKS: + /* + * The user passed in pre-formatted sense + * key specific data. + */ + bcopy(data, &sense->sense_key_spec[0], + MIN(sizeof(sense->sense_key_spec), + sense_len)); + break; + case SSD_ELEM_INFO: + case SSD_ELEM_COMMAND: { + uint8_t *data_dest; + int i; + + if (elem_type == SSD_ELEM_COMMAND) + data_dest = &sense->cmd_spec_info[0]; + else + data_dest = &sense->info[0]; + + /* + * Copy this in reverse so that if we have + * less than 4 bytes to fill, the least + * significant bytes will be at the end. + * If we have more than 4 bytes, only the + * least significant bytes will be included. + */ + for (i = sense_len - 1; i >= 0 && + len_to_copy > 0; i--, len_to_copy--) + data_dest[len_to_copy - 1] = data[i]; + + break; + } + case SSD_ELEM_FRU: + sense->fru = *data; + break; + case SSD_ELEM_STREAM: + sense->flags |= *data; + break; + case SSD_ELEM_DESC: + default: + + /* + * If the user passes in descriptor sense, + * we can't handle that in fixed format. + * So just skip it, and any unknown argument + * types. + */ + break; + } + } + } +} + +void +scsi_set_sense_data(struct scsi_sense_data *sense_data, + scsi_sense_data_type sense_format, int current_error, + int sense_key, int asc, int ascq, ...) +{ + va_list ap; + + va_start(ap, ascq); + scsi_set_sense_data_va(sense_data, sense_format, current_error, + sense_key, asc, ascq, ap); + va_end(ap); +} + +/* + * Returns 1 if the ASC or ASCQ is valid, 0 if it is not valid. + */ +int +scsi_asc_ascq_valid(struct scsi_sense_data *sense, int ascq) +{ + switch (scsi_sense_type(sense)) { + case SSD_TYPE_DESC: + /* + * For descriptor sense, the ASC and ASCQ are always valid. + */ + return (1); + break; + case SSD_TYPE_FIXED: { + struct scsi_sense_data_fixed *fixed_sense; + + fixed_sense = (struct scsi_sense_data_fixed *)sense; + + /* + * For fixed sense, the ASC and ASCQ are only valid if + * extra_len is large enough to include them. + */ + if (fixed_sense->extra_len >= 6) + return (1); + else if ((ascq == 0) + && (fixed_sense->extra_len >= 5)) + return (1); + else + return (0); + break; + } + default: + return (0); + break; + } +} + +/* + * Get sense information for three similar sense data types. + */ +int +scsi_get_sense_info(struct scsi_sense_data *sense_data, uint8_t info_type, + uint64_t *info, int64_t *signed_info) +{ + scsi_sense_data_type sense_type; + + sense_type = scsi_sense_type(sense_data); + + switch (sense_type) { + case SSD_TYPE_DESC: { + struct scsi_sense_data_desc *sense; + uint8_t *desc; + + sense = (struct scsi_sense_data_desc *)sense_data; + + desc = scsi_find_desc(sense, info_type); + if (desc == NULL) + goto bailout; + + switch (info_type) { + case SSD_DESC_INFO: { + struct scsi_sense_info *info_desc; + + info_desc = (struct scsi_sense_info *)desc; + *info = scsi_8btou64(info_desc->info); + if (signed_info != NULL) + *signed_info = *info; + break; + } + case SSD_DESC_COMMAND: { + struct scsi_sense_command *cmd_desc; + + cmd_desc = (struct scsi_sense_command *)desc; + + *info = scsi_8btou64(cmd_desc->command_info); + if (signed_info != NULL) + *signed_info = *info; + break; + } + case SSD_DESC_FRU: { + struct scsi_sense_fru *fru_desc; + + fru_desc = (struct scsi_sense_fru *)desc; + + *info = fru_desc->fru; + if (signed_info != NULL) + *signed_info = (int8_t)fru_desc->fru; + break; + } + default: + goto bailout; + break; + } + break; + } + case SSD_TYPE_FIXED: { + struct scsi_sense_data_fixed *sense; + + sense = (struct scsi_sense_data_fixed *)sense_data; + + switch (info_type) { + case SSD_DESC_INFO: { + uint32_t info_val; + + if ((sense->error_code & SSD_ERRCODE_VALID) == 0) + goto bailout; + + info_val = scsi_4btoul(sense->info); + + *info = info_val; + if (signed_info != NULL) + *signed_info = (int32_t)info_val; + break; + } + case SSD_DESC_COMMAND: { + uint32_t cmd_val; + + if (sense->extra_len < 4) + goto bailout; + + cmd_val = scsi_4btoul(sense->cmd_spec_info); + if (cmd_val == 0) + goto bailout; + + *info = cmd_val; + if (signed_info != NULL) + *signed_info = (int32_t)cmd_val; + break; + } + case SSD_DESC_FRU: + if ((sense->extra_len < 7) + || (sense->fru == 0)) + goto bailout; + + *info = sense->fru; + if (signed_info != NULL) + *signed_info = (int8_t)sense->fru; + break; + default: + goto bailout; + break; + } + break; + } + default: + goto bailout; + break; + } + + return (0); +bailout: + return (1); +} + +int +scsi_get_sks(struct scsi_sense_data *sense_data, uint8_t *sks) +{ + scsi_sense_data_type sense_type; + + sense_type = scsi_sense_type(sense_data); + + switch (sense_type) { + case SSD_TYPE_DESC: { + struct scsi_sense_data_desc *sense; + struct scsi_sense_sks *desc; + + sense = (struct scsi_sense_data_desc *)sense_data; + + desc = (struct scsi_sense_sks *)scsi_find_desc(sense, + SSD_DESC_SKS); + if (desc == NULL) + goto bailout; + + bcopy(desc->sense_key_spec, sks, sizeof(desc->sense_key_spec)); + break; + } + case SSD_TYPE_FIXED: { + struct scsi_sense_data_fixed *sense; + + sense = (struct scsi_sense_data_fixed *)sense_data; + + if ((sense->extra_len < 10) + || ((sense->sense_key_spec[0] & SSD_SCS_VALID) == 0)) + goto bailout; + bcopy(sense->sense_key_spec, sks,sizeof(sense->sense_key_spec)); + break; + } + default: + goto bailout; + break; + } + return (0); +bailout: + return (1); +} + +/* + * Provide a common interface for fixed and descriptor sense to detect + * whether we have block-specific sense information. It is clear by the + * presence of the block descriptor in descriptor mode, but we have to + * infer from the inquiry data and ILI bit in fixed mode. + */ +int +scsi_get_block_info(struct scsi_sense_data *sense_data, + struct scsi_inquiry_data *inq_data, uint8_t *block_bits) +{ + scsi_sense_data_type sense_type; + + if (inq_data != NULL) { + switch (SID_TYPE(inq_data)) { + case T_DIRECT: + case T_RBC: + break; + default: + goto bailout; + break; + } + } + + sense_type = scsi_sense_type(sense_data); + + switch (sense_type) { + case SSD_TYPE_DESC: { + struct scsi_sense_data_desc *sense; + struct scsi_sense_block *block; + + sense = (struct scsi_sense_data_desc *)sense_data; + + block = (struct scsi_sense_block *)scsi_find_desc(sense, + SSD_DESC_BLOCK); + if (block == NULL) + goto bailout; + + *block_bits = block->byte3; + break; + } + case SSD_TYPE_FIXED: { + struct scsi_sense_data_fixed *sense; + + sense = (struct scsi_sense_data_fixed *)sense_data; + + if ((sense->flags & SSD_ILI) == 0) + goto bailout; + + *block_bits = sense->flags & SSD_ILI; + break; + } + default: + goto bailout; + break; + } + return (0); +bailout: + return (1); +} + +int +scsi_get_stream_info(struct scsi_sense_data *sense_data, + struct scsi_inquiry_data *inq_data, uint8_t *stream_bits) +{ + scsi_sense_data_type sense_type; + + if (inq_data != NULL) { + switch (SID_TYPE(inq_data)) { + case T_SEQUENTIAL: + break; + default: + goto bailout; + break; + } + } + + sense_type = scsi_sense_type(sense_data); + + switch (sense_type) { + case SSD_TYPE_DESC: { + struct scsi_sense_data_desc *sense; + struct scsi_sense_stream *stream; + + sense = (struct scsi_sense_data_desc *)sense_data; + + stream = (struct scsi_sense_stream *)scsi_find_desc(sense, + SSD_DESC_STREAM); + if (stream == NULL) + goto bailout; + + *stream_bits = stream->byte3; + break; + } + case SSD_TYPE_FIXED: { + struct scsi_sense_data_fixed *sense; + + sense = (struct scsi_sense_data_fixed *)sense_data; + + if ((sense->flags & (SSD_ILI|SSD_EOM|SSD_FILEMARK)) == 0) + goto bailout; + + *stream_bits = sense->flags & (SSD_ILI|SSD_EOM|SSD_FILEMARK); + break; + } + default: + goto bailout; + break; + } + return (0); +bailout: + return (1); +} + +void +scsi_info_sbuf(struct sbuf *sb, uint8_t *cdb, int cdb_len, + struct scsi_inquiry_data *inq_data, uint64_t info) +{ + sbuf_printf(sb, "Info: %#jx", info); +} + +void +scsi_command_sbuf(struct sbuf *sb, uint8_t *cdb, int cdb_len, + struct scsi_inquiry_data *inq_data, uint64_t csi) +{ + sbuf_printf(sb, "Command Specific Info: %#jx", csi); +} + + +void +scsi_progress_sbuf(struct sbuf *sb, uint16_t progress) +{ + sbuf_printf(sb, "Progress: %d%% (%d/%d) complete", + (progress * 100) / SSD_SKS_PROGRESS_DENOM, + progress, SSD_SKS_PROGRESS_DENOM); +} + +/* + * Returns 1 for failure (i.e. SKS isn't valid) and 0 for success. + */ +int +scsi_sks_sbuf(struct sbuf *sb, int sense_key, uint8_t *sks) +{ + if ((sks[0] & SSD_SKS_VALID) == 0) + return (1); + + switch (sense_key) { + case SSD_KEY_ILLEGAL_REQUEST: { + struct scsi_sense_sks_field *field; + int bad_command; + char tmpstr[40]; + + /*Field Pointer*/ + field = (struct scsi_sense_sks_field *)sks; + + if (field->byte0 & SSD_SKS_FIELD_CMD) + bad_command = 1; + else + bad_command = 0; + + tmpstr[0] = '\0'; + + /* Bit pointer is valid */ + if (field->byte0 & SSD_SKS_BPV) + snprintf(tmpstr, sizeof(tmpstr), "bit %d ", + field->byte0 & SSD_SKS_BIT_VALUE); + + sbuf_printf(sb, "%s byte %d %sis invalid", + bad_command ? "Command" : "Data", + scsi_2btoul(field->field), tmpstr); + break; + } + case SSD_KEY_UNIT_ATTENTION: { + struct scsi_sense_sks_overflow *overflow; + + overflow = (struct scsi_sense_sks_overflow *)sks; + + /*UA Condition Queue Overflow*/ + sbuf_printf(sb, "Unit Attention Condition Queue %s", + (overflow->byte0 & SSD_SKS_OVERFLOW_SET) ? + "Overflowed" : "Did Not Overflow??"); + break; + } + case SSD_KEY_RECOVERED_ERROR: + case SSD_KEY_HARDWARE_ERROR: + case SSD_KEY_MEDIUM_ERROR: { + struct scsi_sense_sks_retry *retry; + + /*Actual Retry Count*/ + retry = (struct scsi_sense_sks_retry *)sks; + + sbuf_printf(sb, "Actual Retry Count: %d", + scsi_2btoul(retry->actual_retry_count)); + break; + } + case SSD_KEY_NO_SENSE: + case SSD_KEY_NOT_READY: { + struct scsi_sense_sks_progress *progress; + int progress_val; + + /*Progress Indication*/ + progress = (struct scsi_sense_sks_progress *)sks; + progress_val = scsi_2btoul(progress->progress); + + scsi_progress_sbuf(sb, progress_val); + break; + } + case SSD_KEY_COPY_ABORTED: { + struct scsi_sense_sks_segment *segment; + char tmpstr[40]; + + /*Segment Pointer*/ + segment = (struct scsi_sense_sks_segment *)sks; + + tmpstr[0] = '\0'; + + if (segment->byte0 & SSD_SKS_SEGMENT_BPV) + snprintf(tmpstr, sizeof(tmpstr), "bit %d ", + segment->byte0 & SSD_SKS_SEGMENT_BITPTR); + + sbuf_printf(sb, "%s byte %d %sis invalid", (segment->byte0 & + SSD_SKS_SEGMENT_SD) ? "Segment" : "Data", + scsi_2btoul(segment->field), tmpstr); + break; + } + default: + sbuf_printf(sb, "Sense Key Specific: %#x,%#x", sks[0], + scsi_2btoul(&sks[1])); + break; + } + + return (0); +} + +void +scsi_fru_sbuf(struct sbuf *sb, uint64_t fru) +{ + sbuf_printf(sb, "Field Replaceable Unit: %d", (int)fru); +} + +void +scsi_stream_sbuf(struct sbuf *sb, uint8_t stream_bits, uint64_t info) +{ + int need_comma; + + need_comma = 0; + /* + * XXX KDM this needs more descriptive decoding. + */ + if (stream_bits & SSD_DESC_STREAM_FM) { + sbuf_printf(sb, "Filemark"); + need_comma = 1; + } + + if (stream_bits & SSD_DESC_STREAM_EOM) { + sbuf_printf(sb, "%sEOM", (need_comma) ? "," : ""); + need_comma = 1; + } + + if (stream_bits & SSD_DESC_STREAM_ILI) + sbuf_printf(sb, "%sILI", (need_comma) ? "," : ""); + + sbuf_printf(sb, ": Info: %#jx", (uintmax_t) info); +} + +void +scsi_block_sbuf(struct sbuf *sb, uint8_t block_bits, uint64_t info) +{ + if (block_bits & SSD_DESC_BLOCK_ILI) + sbuf_printf(sb, "ILI: residue %#jx", (uintmax_t) info); +} + +void +scsi_sense_info_sbuf(struct sbuf *sb, struct scsi_sense_data *sense, + uint8_t *cdb, int cdb_len, + struct scsi_inquiry_data *inq_data, + struct scsi_sense_desc_header *header) +{ + struct scsi_sense_info *info; + + info = (struct scsi_sense_info *)header; + + scsi_info_sbuf(sb, cdb, cdb_len, inq_data, scsi_8btou64(info->info)); +} + +void +scsi_sense_command_sbuf(struct sbuf *sb, struct scsi_sense_data *sense, + uint8_t *cdb, int cdb_len, + struct scsi_inquiry_data *inq_data, + struct scsi_sense_desc_header *header) +{ + struct scsi_sense_command *command; + + command = (struct scsi_sense_command *)header; + + scsi_command_sbuf(sb, cdb, cdb_len, inq_data, + scsi_8btou64(command->command_info)); +} + +void +scsi_sense_sks_sbuf(struct sbuf *sb, struct scsi_sense_data *sense, + uint8_t *cdb, int cdb_len, + struct scsi_inquiry_data *inq_data, + struct scsi_sense_desc_header *header) +{ + struct scsi_sense_sks *sks; + int error_code, sense_key, asc, ascq; + + sks = (struct scsi_sense_sks *)header; + + scsi_extract_sense(sense, &error_code, &sense_key, &asc, &ascq); + + scsi_sks_sbuf(sb, sense_key, sks->sense_key_spec); +} + +void +scsi_sense_fru_sbuf(struct sbuf *sb, struct scsi_sense_data *sense, + uint8_t *cdb, int cdb_len, + struct scsi_inquiry_data *inq_data, + struct scsi_sense_desc_header *header) +{ + struct scsi_sense_fru *fru; + + fru = (struct scsi_sense_fru *)header; + + scsi_fru_sbuf(sb, (uint64_t)fru->fru); +} + +void +scsi_sense_stream_sbuf(struct sbuf *sb, struct scsi_sense_data *sense, + uint8_t *cdb, int cdb_len, + struct scsi_inquiry_data *inq_data, + struct scsi_sense_desc_header *header) +{ + struct scsi_sense_stream *stream; + uint64_t info; + + stream = (struct scsi_sense_stream *)header; + info = 0; + + scsi_get_sense_info(sense, SSD_DESC_INFO, &info, NULL); + + scsi_stream_sbuf(sb, stream->byte3, info); +} + +void +scsi_sense_block_sbuf(struct sbuf *sb, struct scsi_sense_data *sense, + uint8_t *cdb, int cdb_len, + struct scsi_inquiry_data *inq_data, + struct scsi_sense_desc_header *header) +{ + struct scsi_sense_block *block; + uint64_t info; + + block = (struct scsi_sense_block *)header; + info = 0; + + scsi_get_sense_info(sense, SSD_DESC_INFO, &info, NULL); + + scsi_block_sbuf(sb, block->byte3, info); +} + +void +scsi_sense_progress_sbuf(struct sbuf *sb, struct scsi_sense_data *sense, + uint8_t *cdb, int cdb_len, + struct scsi_inquiry_data *inq_data, + struct scsi_sense_desc_header *header) +{ + struct scsi_sense_progress *progress; + const char *sense_key_desc; + const char *asc_desc; + int progress_val; + + progress = (struct scsi_sense_progress *)header; + + /* + * Get descriptions for the sense key, ASC, and ASCQ in the + * progress descriptor. These could be different than the values + * in the overall sense data. + */ + scsi_sense_desc(progress->sense_key, progress->add_sense_code, + progress->add_sense_code_qual, inq_data, + &sense_key_desc, &asc_desc); + + progress_val = scsi_2btoul(progress->progress); + + /* + * The progress indicator is for the operation described by the + * sense key, ASC, and ASCQ in the descriptor. + */ + sbuf_cat(sb, sense_key_desc); + sbuf_printf(sb, " asc:%x,%x (%s): ", progress->add_sense_code, + progress->add_sense_code_qual, asc_desc); + scsi_progress_sbuf(sb, progress_val); +} + +/* + * Generic sense descriptor printing routine. This is used when we have + * not yet implemented a specific printing routine for this descriptor. + */ +void +scsi_sense_generic_sbuf(struct sbuf *sb, struct scsi_sense_data *sense, + uint8_t *cdb, int cdb_len, + struct scsi_inquiry_data *inq_data, + struct scsi_sense_desc_header *header) +{ + int i; + uint8_t *buf_ptr; + + sbuf_printf(sb, "Descriptor %#x:", header->desc_type); + + buf_ptr = (uint8_t *)&header[1]; + + for (i = 0; i < header->length; i++, buf_ptr++) + sbuf_printf(sb, " %02x", *buf_ptr); +} + +/* + * Keep this list in numeric order. This speeds the array traversal. + */ +struct scsi_sense_desc_printer { + uint8_t desc_type; + /* + * The function arguments here are the superset of what is needed + * to print out various different descriptors. Command and + * information descriptors need inquiry data and command type. + * Sense key specific descriptors need the sense key. + * + * The sense, cdb, and inquiry data arguments may be NULL, but the + * information printed may not be fully decoded as a result. + */ + void (*print_func)(struct sbuf *sb, struct scsi_sense_data *sense, + uint8_t *cdb, int cdb_len, + struct scsi_inquiry_data *inq_data, + struct scsi_sense_desc_header *header); +} scsi_sense_printers[] = { + {SSD_DESC_INFO, scsi_sense_info_sbuf}, + {SSD_DESC_COMMAND, scsi_sense_command_sbuf}, + {SSD_DESC_SKS, scsi_sense_sks_sbuf}, + {SSD_DESC_FRU, scsi_sense_fru_sbuf}, + {SSD_DESC_STREAM, scsi_sense_stream_sbuf}, + {SSD_DESC_BLOCK, scsi_sense_block_sbuf}, + {SSD_DESC_PROGRESS, scsi_sense_progress_sbuf} +}; + +void +scsi_sense_desc_sbuf(struct sbuf *sb, struct scsi_sense_data *sense, + uint8_t *cdb, int cdb_len, + struct scsi_inquiry_data *inq_data, + struct scsi_sense_desc_header *header) +{ + int i, found; + + for (i = 0, found = 0; i < (sizeof(scsi_sense_printers) / + sizeof(scsi_sense_printers[0])); i++) { + struct scsi_sense_desc_printer *printer; + + printer = &scsi_sense_printers[i]; + + /* + * The list is sorted, so quit if we've passed our + * descriptor number. + */ + if (printer->desc_type > header->desc_type) + break; + + if (printer->desc_type != header->desc_type) + continue; + + printer->print_func(sb, sense, cdb, cdb_len, inq_data, header); + + return; + } + + /* + * No specific printing routine, so use the generic routine. + */ + scsi_sense_generic_sbuf(sb, sense, cdb, cdb_len, inq_data, header); +} + +scsi_sense_data_type +scsi_sense_type(struct scsi_sense_data *sense_data) +{ + switch (sense_data->error_code & SSD_ERRCODE) { + case SSD_DESC_CURRENT_ERROR: + case SSD_DESC_DEFERRED_ERROR: + return (SSD_TYPE_DESC); + break; + case SSD_CURRENT_ERROR: + case SSD_DEFERRED_ERROR: + return (SSD_TYPE_FIXED); + break; + default: + break; + } + + return (SSD_TYPE_NONE); +} + +void +scsi_sense_only_sbuf(struct scsi_sense_data *sense, struct sbuf *sb, + char *path_str, struct scsi_inquiry_data *inq_data, + uint8_t *cdb, int cdb_len) +{ + int error_code, sense_key, asc, ascq; + + sbuf_cat(sb, path_str); + + scsi_extract_sense(sense, &error_code, &sense_key, &asc, &ascq); + + sbuf_printf(sb, "SCSI sense: "); + switch (error_code) { + case SSD_DEFERRED_ERROR: + case SSD_DESC_DEFERRED_ERROR: + sbuf_printf(sb, "Deferred error: "); + + /* FALLTHROUGH */ + case SSD_CURRENT_ERROR: + case SSD_DESC_CURRENT_ERROR: + { + struct scsi_sense_data_desc *desc_sense; + const char *sense_key_desc; + const char *asc_desc; + uint8_t sks[3]; + uint64_t val; + int cur_pos; + int info_valid; + + /* + * Get descriptions for the sense key, ASC, and ASCQ. + */ + scsi_sense_desc(sense_key, asc, ascq, inq_data, + &sense_key_desc, &asc_desc); + + /* + * We first print the sense key and ASC/ASCQ. + */ + sbuf_cat(sb, sense_key_desc); + sbuf_printf(sb, " asc:%x,%x (%s)\n", asc, ascq, asc_desc); + + /* + * Get the info field if it is valid. + */ + if (scsi_get_sense_info(sense, SSD_DESC_INFO, &val, NULL) == 0) + info_valid = 1; + else + info_valid = 0; + + if (info_valid != 0) { + uint8_t bits; + + /* + * Determine whether we have any block or stream + * device-specific information. + */ + if (scsi_get_block_info(sense, inq_data, &bits) == 0) { + sbuf_cat(sb, path_str); + scsi_block_sbuf(sb, bits, val); + sbuf_printf(sb, "\n"); + } else if (scsi_get_stream_info(sense, inq_data, + &bits) == 0) { + sbuf_cat(sb, path_str); + scsi_stream_sbuf(sb, bits, val); + sbuf_printf(sb, "\n"); + } else if (val != 0) { + /* + * The information field can be valid but 0. + * If the block or stream bits aren't set, + * and this is 0, it isn't terribly useful + * to print it out. + */ + sbuf_cat(sb, path_str); + scsi_info_sbuf(sb, cdb, cdb_len, inq_data, val); + sbuf_printf(sb, "\n"); + } + } + + /* + * Print the FRU. + */ + if (scsi_get_sense_info(sense, SSD_DESC_FRU, &val, NULL) == 0) { + sbuf_cat(sb, path_str); + scsi_fru_sbuf(sb, val); + sbuf_printf(sb, "\n"); + } + + /* + * Print any command-specific information. + */ + if (scsi_get_sense_info(sense, SSD_DESC_COMMAND, &val, + NULL) == 0) { + sbuf_cat(sb, path_str); + scsi_command_sbuf(sb, cdb, cdb_len, inq_data, val); + sbuf_printf(sb, "\n"); + } + + /* + * Print out any sense-key-specific information. + */ + if (scsi_get_sks(sense, sks) == 0) { + sbuf_cat(sb, path_str); + scsi_sks_sbuf(sb, sense_key, sks); + sbuf_printf(sb, "\n"); + } + + /* + * If this is fixed sense, we're done. If we have + * descriptor sense, we might have more information + * available. + */ + if (scsi_sense_type(sense) != SSD_TYPE_DESC) + break; + + desc_sense = (struct scsi_sense_data_desc *)sense; + + /* + * If we have descriptor sense, print out any remaining + * descriptors. + */ + for (cur_pos = 0; cur_pos < MIN(desc_sense->extra_len, + SSD_EXTRA_MAX);) { + struct scsi_sense_desc_header *header; + + header = (struct scsi_sense_desc_header *) + &desc_sense->sense_desc[cur_pos]; + switch (header->desc_type) { + case SSD_DESC_INFO: + case SSD_DESC_FRU: + case SSD_DESC_COMMAND: + case SSD_DESC_SKS: + /* + * We have already printed these + * descriptors, if they are present. + */ + break; + default: { + /* + * We only send a descriptor for printing + * if we have the entire descriptor. This + * simplifies things for the printing + * routines. + */ + if (header->length > + (desc_sense->extra_len - cur_pos)) + break; + sbuf_printf(sb, "%s", path_str); + scsi_sense_desc_sbuf(sb, sense, cdb, + cdb_len, inq_data, header); + sbuf_printf(sb, "\n"); + break; + } + } + cur_pos += sizeof(*header) + header->length; + } + break; + + } + default: { + sbuf_printf(sb, "Error code 0x%x", error_code); + if (sense->error_code & SSD_ERRCODE_VALID) { + struct scsi_sense_data_fixed *fixed_sense; + uint32_t info; + + fixed_sense = (struct scsi_sense_data_fixed *)sense; + + sbuf_printf(sb, " at block no. %d (decimal)", + info = scsi_4btoul(fixed_sense->info)); + } + sbuf_printf(sb, "\n"); + break; + } + } +} + +/* * scsi_sense_sbuf() returns 0 for success and -1 for failure. */ #ifdef _KERNEL @@ -3059,11 +4297,8 @@ #ifdef _KERNEL struct ccb_getdev *cgd; #endif /* _KERNEL */ - u_int32_t info; - int error_code; - int sense_key; - int asc, ascq; char path_str[64]; + uint8_t *cdb; #ifndef _KERNEL if (device == NULL) @@ -3161,129 +4396,13 @@ sense = &csio->sense_data; } + if (csio->ccb_h.flags & CAM_CDB_POINTER) + cdb = csio->cdb_io.cdb_ptr; + else + cdb = csio->cdb_io.cdb_bytes; - sbuf_cat(sb, path_str); - - error_code = sense->error_code & SSD_ERRCODE; - sense_key = sense->flags & SSD_KEY; - - sbuf_printf(sb, "SCSI sense: "); - switch (error_code) { - case SSD_DEFERRED_ERROR: - sbuf_printf(sb, "Deferred error: "); - - /* FALLTHROUGH */ - case SSD_CURRENT_ERROR: - { - const char *sense_key_desc; - const char *asc_desc; - - asc = (sense->extra_len >= 5) ? sense->add_sense_code : 0; - ascq = (sense->extra_len >= 6) ? sense->add_sense_code_qual : 0; - scsi_sense_desc(sense_key, asc, ascq, inq_data, - &sense_key_desc, &asc_desc); - sbuf_cat(sb, sense_key_desc); - - info = scsi_4btoul(sense->info); - - if (sense->error_code & SSD_ERRCODE_VALID) { - - switch (sense_key) { - case SSD_KEY_NOT_READY: - case SSD_KEY_ILLEGAL_REQUEST: - case SSD_KEY_UNIT_ATTENTION: - case SSD_KEY_DATA_PROTECT: - break; - case SSD_KEY_BLANK_CHECK: - sbuf_printf(sb, " req sz: %d (decimal)", info); - break; - default: - if (info) { - if (sense->flags & SSD_ILI) { - sbuf_printf(sb, " ILI (length " - "mismatch): %d", info); - - } else { - sbuf_printf(sb, " info:%x", - info); - } - } - } - } else if (info) { - sbuf_printf(sb, " info?:%x", info); - } - - if (sense->extra_len >= 4) { - if (bcmp(sense->cmd_spec_info, "\0\0\0\0", 4)) { - sbuf_printf(sb, " csi:%x,%x,%x,%x", - sense->cmd_spec_info[0], - sense->cmd_spec_info[1], - sense->cmd_spec_info[2], - sense->cmd_spec_info[3]); - } - } - - sbuf_printf(sb, " asc:%x,%x (%s)", asc, ascq, asc_desc); - - if (sense->extra_len >= 7 && sense->fru) { - sbuf_printf(sb, " field replaceable unit: %x", - sense->fru); - } - - if ((sense->extra_len >= 10) - && (sense->sense_key_spec[0] & SSD_SCS_VALID) != 0) { - switch(sense_key) { - case SSD_KEY_ILLEGAL_REQUEST: { - int bad_command; - char tmpstr2[40]; - - if (sense->sense_key_spec[0] & 0x40) - bad_command = 1; - else - bad_command = 0; - - tmpstr2[0] = '\0'; - - /* Bit pointer is valid */ - if (sense->sense_key_spec[0] & 0x08) - snprintf(tmpstr2, sizeof(tmpstr2), - "bit %d ", - sense->sense_key_spec[0] & 0x7); - sbuf_printf(sb, ": %s byte %d %sis invalid", - bad_command ? "Command" : "Data", - scsi_2btoul( - &sense->sense_key_spec[1]), - tmpstr2); - break; - } - case SSD_KEY_RECOVERED_ERROR: - case SSD_KEY_HARDWARE_ERROR: - case SSD_KEY_MEDIUM_ERROR: - sbuf_printf(sb, " actual retry count: %d", - scsi_2btoul( - &sense->sense_key_spec[1])); - break; - default: - sbuf_printf(sb, " sks:%#x,%#x", - sense->sense_key_spec[0], - scsi_2btoul( - &sense->sense_key_spec[1])); - break; - } - } - break; - - } - default: - sbuf_printf(sb, "Error code 0x%x", sense->error_code); - if (sense->error_code & SSD_ERRCODE_VALID) { - sbuf_printf(sb, " at block no. %d (decimal)", - info = scsi_4btoul(sense->info)); - } - } - - sbuf_printf(sb, "\n"); - + scsi_sense_only_sbuf(sense, sb, path_str, inq_data, cdb, csio->cdb_len); + #ifdef _KERNEL xpt_free_ccb((union ccb*)cgd); #endif /* _KERNEL/!_KERNEL */ Index: sys/cam/scsi/smp_all.h =================================================================== --- sys/cam/scsi/smp_all.h (revision 225710) +++ sys/cam/scsi/smp_all.h (working copy) @@ -27,7 +27,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/users/kenm/FreeBSD-test/sys/cam/scsi/smp_all.h#4 $ + * $Id$ * $FreeBSD$ */ Index: sys/dev/mly/mly.c =================================================================== --- sys/dev/mly/mly.c (revision 225710) +++ sys/dev/mly/mly.c (working copy) @@ -1294,10 +1294,12 @@ static void mly_process_event(struct mly_softc *sc, struct mly_event *me) { - struct scsi_sense_data *ssd = (struct scsi_sense_data *)&me->sense[0]; - char *fp, *tp; - int bus, target, event, class, action; + struct scsi_sense_data_fixed *ssd; + char *fp, *tp; + int bus, target, event, class, action; + ssd = (struct scsi_sense_data_fixed *)&me->sense[0]; + /* * Errors can be reported using vendor-unique sense data. In this case, the * event code will be 0x1c (Request sense data present), the sense key will Index: sys/dev/firewire/sbp_targ.c =================================================================== --- sys/dev/firewire/sbp_targ.c (revision 225710) +++ sys/dev/firewire/sbp_targ.c (working copy) @@ -41,6 +41,7 @@ #include #include #include +#include #if __FreeBSD_version < 500000 #include #endif @@ -632,6 +633,11 @@ { struct sbp_cmd_status *sbp_cmd_status; struct scsi_sense_data *sense; + int error_code, sense_key, asc, ascq; + uint8_t stream_bits; + uint8_t sks[3]; + uint64_t info; + int64_t sinfo; if (debug) printf("%s: STATUS %d\n", __func__, @@ -659,36 +665,75 @@ #endif #endif - if ((sense->error_code & SSD_ERRCODE) == SSD_CURRENT_ERROR) + scsi_extract_sense(sense, &error_code, &sense_key, &asc, + &ascq); + + switch (error_code) { + case SSD_CURRENT_ERROR: + case SSD_DESC_CURRENT_ERROR: sbp_cmd_status->sfmt = SBP_SFMT_CURR; - else + break; + default: sbp_cmd_status->sfmt = SBP_SFMT_DEFER; + break; + } - sbp_cmd_status->valid = (sense->error_code & SSD_ERRCODE_VALID) - ? 1 : 0; - sbp_cmd_status->s_key = sense->flags & SSD_KEY; - sbp_cmd_status->mark = (sense->flags & SSD_FILEMARK)? 1 : 0; - sbp_cmd_status->eom = (sense->flags & SSD_EOM) ? 1 : 0; - sbp_cmd_status->ill_len = (sense->flags & SSD_ILI) ? 1 : 0; + if (scsi_get_sense_info(sense, SSD_DESC_INFO, &info, + &sinfo) == 0) { + uint32_t info_trunc; + sbp_cmd_status->valid = 1; + info_trunc = info; - bcopy(&sense->info[0], &sbp_cmd_status->info, 4); + sbp_cmd_status->info = htobe32(info_trunc); + } else { + sbp_cmd_status->valid = 0; + } - if (sense->extra_len <= 6) - /* add_sense_code(_qual), info, cmd_spec_info */ - sbp_status->len = 4; - else - /* fru, sense_key_spec */ + sbp_cmd_status->s_key = sense_key; + + if (scsi_get_stream_info(sense, NULL, &stream_bits) == 0) { + sbp_cmd_status->mark = + (stream_bits & SSD_FILEMARK) ? 1 : 0; + sbp_cmd_status->eom = + (stream_bits & SSD_EOM) ? 1 : 0; + sbp_cmd_status->ill_len = + (stream_bits & SSD_ILI) ? 1 : 0; + } else { + sbp_cmd_status->mark = 0; + sbp_cmd_status->eom = 0; + sbp_cmd_status->ill_len = 0; + } + + + /* add_sense_code(_qual), info, cmd_spec_info */ + sbp_status->len = 4; + + if (scsi_get_sense_info(sense, SSD_DESC_COMMAND, &info, + &sinfo) == 0) { + uint32_t cmdspec_trunc; + + cmdspec_trunc = info; + + sbp_cmd_status->cdb = htobe32(cmdspec_trunc); + + } + + sbp_cmd_status->s_code = asc; + sbp_cmd_status->s_qlfr = ascq; + + if (scsi_get_sense_info(sense, SSD_DESC_FRU, &info, + &sinfo) == 0) { + sbp_cmd_status->fru = (uint8_t)info; sbp_status->len = 5; - - bcopy(&sense->cmd_spec_info[0], &sbp_cmd_status->cdb, 4); + } else { + sbp_cmd_status->fru = 0; + } - sbp_cmd_status->s_code = sense->add_sense_code; - sbp_cmd_status->s_qlfr = sense->add_sense_code_qual; - sbp_cmd_status->fru = sense->fru; + if (scsi_get_sks(sense, sks) == 0) { + bcopy(sks, &sbp_cmd_status->s_keydep[0], sizeof(sks)); + sbp_status->len = 5; + } - bcopy(&sense->sense_key_spec[0], - &sbp_cmd_status->s_keydep[0], 3); - break; } default: Index: sys/dev/firewire/sbp.c =================================================================== --- sys/dev/firewire/sbp.c (revision 225710) +++ sys/dev/firewire/sbp.c (working copy) @@ -1515,10 +1515,10 @@ sbp_scsi_status(struct sbp_status *sbp_status, struct sbp_ocb *ocb) { struct sbp_cmd_status *sbp_cmd_status; - struct scsi_sense_data *sense; + struct scsi_sense_data_fixed *sense; sbp_cmd_status = (struct sbp_cmd_status *)sbp_status->data; - sense = &ocb->ccb->csio.sense_data; + sense = (struct scsi_sense_data_fixed *)&ocb->ccb->csio.sense_data; SBP_DEBUG(0) sbp_print_scsi_cmd(ocb); Index: sys/dev/ciss/ciss.c =================================================================== --- sys/dev/ciss/ciss.c (revision 225710) +++ sys/dev/ciss/ciss.c (working copy) @@ -3255,7 +3255,7 @@ #ifdef CISS_DEBUG { struct scsi_sense_data *sns = (struct scsi_sense_data *)&ce->sense_info[0]; - debug(0, "sense key %x", sns->flags & SSD_KEY); + debug(0, "sense key %x", scsi_get_sense_key(sns)); } #endif break; Index: sys/dev/iir/iir.c =================================================================== --- sys/dev/iir/iir.c (revision 225710) +++ sys/dev/iir/iir.c (working copy) @@ -1839,13 +1839,20 @@ } else { /* error */ if (gccb->gc_service == GDT_CACHESERVICE) { + struct scsi_sense_data *sense; + ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR | CAM_AUTOSNS_VALID; ccb->ccb_h.status &= ~CAM_SIM_QUEUED; ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND; bzero(&ccb->csio.sense_data, ccb->csio.sense_len); - ccb->csio.sense_data.error_code = - SSD_CURRENT_ERROR | SSD_ERRCODE_VALID; - ccb->csio.sense_data.flags = SSD_KEY_NOT_READY; + sense = &ccb->csio.sense_data; + scsi_set_sense_data(sense, + /*sense_format*/ SSD_TYPE_NONE, + /*current_error*/ 1, + /*sense_key*/ SSD_KEY_NOT_READY, + /*asc*/ 0x4, + /*ascq*/ 0x01, + SSD_ELEM_NONE); gdt->sc_dvr.size = sizeof(gdt->sc_dvr.eu.sync); gdt->sc_dvr.eu.sync.ionode = gdt->sc_hanum; Index: sys/dev/iscsi/initiator/iscsi_subr.c =================================================================== --- sys/dev/iscsi/initiator/iscsi_subr.c (revision 225710) +++ sys/dev/iscsi/initiator/iscsi_subr.c (working copy) @@ -153,6 +153,7 @@ scsi_rsp_t *cmd = &pp->ipdu.scsi_rsp; caddr_t bp; int sense_len, mustfree = 0; + int error_code, sense_key, asc, ascq; bp = mtod(pq->mp, caddr_t); if((sense_len = scsi_2btoul(bp)) == 0) @@ -174,10 +175,13 @@ scsi->sense_resid = 0; if(cmd->flag & (BIT(1)|BIT(2))) scsi->sense_resid = ntohl(pp->ipdu.scsi_rsp.rcnt); + + scsi_extract_sense(sense, &error_code, &sense_key, &asc, &ascq); + debug(3, "sense_len=%d rcnt=%d sense_resid=%d dsl=%d error_code=%x flags=%x", sense_len, ntohl(pp->ipdu.scsi_rsp.rcnt), scsi->sense_resid, - pp->ds_len, sense->error_code, sense->flags); + pp->ds_len, error_code, sense_key); if(mustfree) free(bp, M_ISCSI); Index: sys/dev/usb/storage/umass.c =================================================================== --- sys/dev/usb/storage/umass.c (revision 225710) +++ sys/dev/usb/storage/umass.c (working copy) @@ -2344,14 +2344,14 @@ */ if ((sc->sc_quirks & (NO_INQUIRY_EVPD | NO_INQUIRY)) && (sc->sc_transfer.cmd_data[1] & SI_EVPD)) { - struct scsi_sense_data *sense; - sense = &ccb->csio.sense_data; - bzero(sense, sizeof(*sense)); - sense->error_code = SSD_CURRENT_ERROR; - sense->flags = SSD_KEY_ILLEGAL_REQUEST; - sense->add_sense_code = 0x24; - sense->extra_len = 10; + scsi_set_sense_data(&ccb->csio.sense_data, + /*sense_format*/ SSD_TYPE_NONE, + /*current_error*/ 1, + /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST, + /*asc*/ 0x24, + /*ascq*/ 0x00, + /*extra args*/ SSD_ELEM_NONE); ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND; ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR | CAM_AUTOSNS_VALID; @@ -2631,21 +2631,22 @@ uint8_t status) { uint8_t *cmd; - uint8_t key; switch (status) { case STATUS_CMD_OK: case STATUS_CMD_UNKNOWN: - case STATUS_CMD_FAILED: + case STATUS_CMD_FAILED: { + int error_code, key, asc, ascq; + scsi_extract_sense(&ccb->csio.sense_data, &error_code, + &key, &asc, &ascq); + if (ccb->csio.ccb_h.flags & CAM_CDB_POINTER) { cmd = (uint8_t *)(ccb->csio.cdb_io.cdb_ptr); } else { cmd = (uint8_t *)(ccb->csio.cdb_io.cdb_bytes); } - key = (ccb->csio.sense_data.flags & SSD_KEY); - /* * Getting sense data always succeeds (apart from wire * failures): @@ -2704,7 +2705,7 @@ } xpt_done(ccb); break; - + } default: DPRINTF(sc, UDMASS_SCSI, "Autosense failed, " "status %d\n", status); Index: sys/dev/isp/isp_freebsd.h =================================================================== --- sys/dev/isp/isp_freebsd.h (revision 225710) +++ sys/dev/isp/isp_freebsd.h (working copy) @@ -440,9 +440,9 @@ #define XS_SNSLEN(ccb) \ imin((sizeof((ccb)->sense_data)), ccb->sense_len) -#define XS_SNSKEY(ccb) ((ccb)->sense_data.flags & 0xf) -#define XS_SNSASC(ccb) ((ccb)->sense_data.add_sense_code) -#define XS_SNSASCQ(ccb) ((ccb)->sense_data.add_sense_code_qual) +#define XS_SNSKEY(ccb) (scsi_get_sense_key(&(ccb)->sense_data)) +#define XS_SNSASC(ccb) (scsi_get_asc(&(ccb)->sense_data)) +#define XS_SNSASCQ(ccb) (scsi_get_ascq(&(ccb)->sense_data)) #define XS_TAG_P(ccb) \ (((ccb)->ccb_h.flags & CAM_TAG_ACTION_VALID) && \ (ccb)->tag_action != CAM_TAG_ACTION_NONE) --ibTvN161/egqYuK8-- From owner-freebsd-scsi@FreeBSD.ORG Fri Sep 23 15:08:43 2011 Return-Path: Delivered-To: scsi@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id DF4041065810; Fri, 23 Sep 2011 15:08:43 +0000 (UTC) (envelope-from marius@alchemy.franken.de) Received: from alchemy.franken.de (alchemy.franken.de [194.94.249.214]) by mx1.freebsd.org (Postfix) with ESMTP id 62C3D8FC18; Fri, 23 Sep 2011 15:08:42 +0000 (UTC) Received: from alchemy.franken.de (localhost [127.0.0.1]) by alchemy.franken.de (8.14.4/8.14.4/ALCHEMY.FRANKEN.DE) with ESMTP id p8NEue3I006337; Fri, 23 Sep 2011 16:56:40 +0200 (CEST) (envelope-from marius@alchemy.franken.de) Received: (from marius@localhost) by alchemy.franken.de (8.14.4/8.14.4/Submit) id p8NEuehx006336; Fri, 23 Sep 2011 16:56:40 +0200 (CEST) (envelope-from marius) Date: Fri, 23 Sep 2011 16:56:40 +0200 From: Marius Strobl To: "Kenneth D. Merry" Message-ID: <20110923145640.GA6316@alchemy.franken.de> References: <20110922193305.GA24939@nargothrond.kdm.org> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20110922193305.GA24939@nargothrond.kdm.org> User-Agent: Mutt/1.4.2.3i Cc: current@freebsd.org, scsi@freebsd.org Subject: Re: SCSI descriptor sense changes, testing needed X-BeenThere: freebsd-scsi@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SCSI subsystem List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 23 Sep 2011 15:08:44 -0000 On Thu, Sep 22, 2011 at 01:33:05PM -0600, Kenneth D. Merry wrote: > > I have attached a set of patches against head that implement SCSI > descriptor sense support for CAM. > > Descriptor sense is a new sense (SCSI error) format introduced in the SPC-3 > spec in 2006. FreeBSD doesn't currently support it. > > Seagate's new 3TB SAS drives come with descriptor sense enabled by default, > and it's possible that other newer drives do as well. Because all the > sense key, additional sense code, and additional sense code qualifier > fields are in different places, the CAM error recovery code will not do the > right thing when it gets descriptor sense. > > These patches do bump up the size of struct scsi_sense_data, and so I have > incremented CAM_VERSION as well. I have discussed this with re@, and it > looks like we'll be putting the changes in before 9.0, so it ships with > support for newer SCSI devices. Hi Ken, as far as I understand this also requires consumers of scsi_sense_data and SSD_FULL_SIZE etc in userland to be recompiled. So while you are at breaking the API and ABI of CAM anyway, could you please take the opportunity to change CAM_XPT_PATH_ID and CAM_BUS_WILDCARD to not use the same value so incorrect uses will fail? Currently, there seems to be a lot of confusion when to use which one, including camcontrol(8) just encoding this as -1: /* * We don't want to rescan or reset the xpt bus. * See above. */ if ((int)bus_result->path_id == -1) continue; Moreover, AFAICT CAM_XPT_PATH_ID corresponds to what the ANSI CAM Draft refers to as "XPT Path ID" and specifies a value of 0xff for. Marius