From owner-freebsd-scsi@FreeBSD.ORG Mon Sep 26 11:07:10 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 8FAD5106566B for ; Mon, 26 Sep 2011 11:07:10 +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 7DF048FC08 for ; Mon, 26 Sep 2011 11:07:10 +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 p8QB7AkW088264 for ; Mon, 26 Sep 2011 11:07:10 GMT (envelope-from owner-bugmaster@FreeBSD.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.4/8.14.4/Submit) id p8QB79cA088261 for freebsd-scsi@FreeBSD.org; Mon, 26 Sep 2011 11:07:09 GMT (envelope-from owner-bugmaster@FreeBSD.org) Date: Mon, 26 Sep 2011 11:07:09 GMT Message-Id: <201109261107.p8QB79cA088261@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, 26 Sep 2011 11:07:10 -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 Mon Sep 26 14:36:59 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 9B7381065670 for ; Mon, 26 Sep 2011 14:36:59 +0000 (UTC) (envelope-from freebsd-scsi@m.gmane.org) Received: from lo.gmane.org (lo.gmane.org [80.91.229.12]) by mx1.freebsd.org (Postfix) with ESMTP id 29EE78FC15 for ; Mon, 26 Sep 2011 14:36:59 +0000 (UTC) Received: from list by lo.gmane.org with local (Exim 4.69) (envelope-from ) id 1R8C4D-0007qX-NC for freebsd-scsi@freebsd.org; Mon, 26 Sep 2011 16:21:57 +0200 Received: from lara.cc.fer.hr ([161.53.72.113]) by main.gmane.org with esmtp (Gmexim 0.1 (Debian)) id 1AlnuQ-0007hv-00 for ; Mon, 26 Sep 2011 16:21:57 +0200 Received: from ivoras by lara.cc.fer.hr with local (Gmexim 0.1 (Debian)) id 1AlnuQ-0007hv-00 for ; Mon, 26 Sep 2011 16:21:57 +0200 X-Injected-Via-Gmane: http://gmane.org/ To: freebsd-scsi@freebsd.org From: Ivan Voras Date: Mon, 26 Sep 2011 16:21:36 +0200 Lines: 57 Message-ID: Mime-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="------------enigBFB57A5C66CCCC0E3DAF7A07" X-Complaints-To: usenet@dough.gmane.org X-Gmane-NNTP-Posting-Host: lara.cc.fer.hr User-Agent: Mozilla/5.0 (X11; FreeBSD amd64; rv:6.0.1) Gecko/20110907 Thunderbird/6.0.1 X-Enigmail-Version: 1.1.2 Subject: isp(4) WWPN 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, 26 Sep 2011 14:36:59 -0000 This is an OpenPGP/MIME signed message (RFC 2440 and 3156) --------------enigBFB57A5C66CCCC0E3DAF7A07 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable I'm trying to find out the port names on the isp controller, and the the isp(4) page says: SYSCTL OPTIONS =2E.. dev.isp.N.wwnn This is the readonly World Wide Node Name value for this por= t. dev.isp.N.wwpn This is the readonly World Wide Port Name value for this por= t. However, this looks unimplemented: ~# sysctl dev.isp dev.isp.0.%desc: Qlogic ISP 2432 PCI FC-AL Adapter dev.isp.0.%driver: isp dev.isp.0.%location: slot=3D0 function=3D0 handle=3D\_SB_.PCI0.PT06.PES2 dev.isp.0.%pnpinfo: vendor=3D0x1077 device=3D0x2432 subvendor=3D0x103c subdevice=3D0x1705 class=3D0x0c0400 dev.isp.0.%parent: pci19 dev.isp.1.%desc: Qlogic ISP 2432 PCI FC-AL Adapter dev.isp.1.%driver: isp dev.isp.1.%location: slot=3D0 function=3D1 handle=3D\_SB_.PCI0.PT06.PE21 dev.isp.1.%pnpinfo: vendor=3D0x1077 device=3D0x2432 subvendor=3D0x103c subdevice=3D0x1705 class=3D0x0c0400 dev.isp.1.%parent: pci19 ~# sysctl dev.isp.0.wwpn sysctl: unknown oid 'dev.isp.0.wwpn' Any ideas how to work around it? This is 8-stable amd64. --------------enigBFB57A5C66CCCC0E3DAF7A07 Content-Type: application/pgp-signature; name="signature.asc" Content-Description: OpenPGP digital signature Content-Disposition: attachment; filename="signature.asc" -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.18 (FreeBSD) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAk6AincACgkQldnAQVacBciV8gCeKqrhGdOkQn7gNtG1pHaZwpJw SuUAnRWK65z2xryLsSvMPo9lOlVFCW3U =RmvO -----END PGP SIGNATURE----- --------------enigBFB57A5C66CCCC0E3DAF7A07-- From owner-freebsd-scsi@FreeBSD.ORG Mon Sep 26 16:18:31 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 E32DE1065675 for ; Mon, 26 Sep 2011 16:18:31 +0000 (UTC) (envelope-from mj@feral.com) Received: from ns1.feral.com (ns1.feral.com [192.67.166.1]) by mx1.freebsd.org (Postfix) with ESMTP id B0EFC8FC0A for ; Mon, 26 Sep 2011 16:18:31 +0000 (UTC) Received: from [192.168.135.104] (c-24-7-47-62.hsd1.ca.comcast.net [24.7.47.62]) (authenticated bits=0) by ns1.feral.com (8.14.4/8.14.4) with ESMTP id p8QGIUtQ022187 (version=TLSv1/SSLv3 cipher=DHE-RSA-CAMELLIA256-SHA bits=256 verify=NO) for ; Mon, 26 Sep 2011 09:18:30 -0700 (PDT) (envelope-from mj@feral.com) Message-ID: <4E80A5D1.3020605@feral.com> Date: Mon, 26 Sep 2011 09:18:25 -0700 From: Matthew Jacob User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0.2) Gecko/20110902 Thunderbird/6.0.2 MIME-Version: 1.0 To: freebsd-scsi@freebsd.org References: In-Reply-To: Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-Greylist: Sender succeeded SMTP AUTH, not delayed by milter-greylist-4.2.7 (ns1.feral.com [192.67.166.1]); Mon, 26 Sep 2011 09:18:30 -0700 (PDT) Subject: Re: isp(4) WWPN 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, 26 Sep 2011 16:18:32 -0000 On 9/26/2011 7:21 AM, Ivan Voras wrote: > I'm trying to find out the port names on the isp controller, and the the > isp(4) page says: > > SYSCTL OPTIONS > ... > dev.isp.N.wwnn > This is the readonly World Wide Node Name value for this port. > > dev.isp.N.wwpn > This is the readonly World Wide Port Name value for this port. > > However, this looks unimplemented: > Bug. Use the ioctls in ispioctl as a temp workaround until I get around to fixing it. Here's some tools that make use: http://people.freebsd.org/~mjacob/isp_tools.tgz From owner-freebsd-scsi@FreeBSD.ORG Mon Sep 26 16:26:39 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 CFC391065672 for ; Mon, 26 Sep 2011 16:26:39 +0000 (UTC) (envelope-from mj@feral.com) Received: from ns1.feral.com (ns1.feral.com [192.67.166.1]) by mx1.freebsd.org (Postfix) with ESMTP id 85F218FC08 for ; Mon, 26 Sep 2011 16:26:39 +0000 (UTC) Received: from [192.168.135.104] (c-24-7-47-62.hsd1.ca.comcast.net [24.7.47.62]) (authenticated bits=0) by ns1.feral.com (8.14.4/8.14.4) with ESMTP id p8QGQcTV022333 (version=TLSv1/SSLv3 cipher=DHE-RSA-CAMELLIA256-SHA bits=256 verify=NO) for ; Mon, 26 Sep 2011 09:26:38 -0700 (PDT) (envelope-from mj@feral.com) Message-ID: <4E80A7B9.6080701@feral.com> Date: Mon, 26 Sep 2011 09:26:33 -0700 From: Matthew Jacob User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0.2) Gecko/20110902 Thunderbird/6.0.2 MIME-Version: 1.0 To: freebsd-scsi@freebsd.org References: <4E80A5D1.3020605@feral.com> In-Reply-To: <4E80A5D1.3020605@feral.com> Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-Greylist: Sender succeeded SMTP AUTH, not delayed by milter-greylist-4.2.7 (ns1.feral.com [192.67.166.1]); Mon, 26 Sep 2011 09:26:38 -0700 (PDT) Subject: Re: isp(4) WWPN 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, 26 Sep 2011 16:26:39 -0000 >> > > Bug. > > Use the ioctls in ispioctl as a temp workaround until I get around to > fixing it. Here's some tools that make use: > > http://people.freebsd.org/~mjacob/isp_tools.tgz > This info is also available at the CAM/XPT level as well for FC transports. From owner-freebsd-scsi@FreeBSD.ORG Fri Sep 30 23:40:05 2011 Return-Path: Delivered-To: freebsd-scsi@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 5D230106566C for ; Fri, 30 Sep 2011 23:40:05 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:4f8:fff6::28]) by mx1.freebsd.org (Postfix) with ESMTP id 2AAB98FC0A for ; Fri, 30 Sep 2011 23:40:05 +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 p8UNe4K7026339 for ; Fri, 30 Sep 2011 23:40:04 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.4/8.14.4/Submit) id p8UNe4FU026338; Fri, 30 Sep 2011 23:40:04 GMT (envelope-from gnats) Date: Fri, 30 Sep 2011 23:40:04 GMT Message-Id: <201109302340.p8UNe4FU026338@freefall.freebsd.org> To: freebsd-scsi@FreeBSD.org From: David Cc: Subject: Re: kern/154432: [xpt] run_interrupt_driven_hooks: still waiting after 60-300 seconds for xpt_config X-BeenThere: freebsd-scsi@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: David List-Id: SCSI subsystem List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 30 Sep 2011 23:40:05 -0000 The following reply was made to PR kern/154432; it has been noted by GNATS. From: David To: bug-followup@FreeBSD.org, robert@bsd.hu Cc: Subject: Re: kern/154432: [xpt] run_interrupt_driven_hooks: still waiting after 60-300 seconds for xpt_config Date: Fri, 30 Sep 2011 19:20:54 -0400 --=-ZVLAFB154UrOwKLn5r6o Content-Type: text/plain; charset=utf-8 Content-ID: <1317424853.4260.27.camel@Nokia-N900> Content-Transfer-Encoding: 7bit Same result seen in HP HDX-18t Notebook computer during installition attempt of PC-BSD (containing FreeBSD). YouTube video of entire installation attempt for this model can be seen here in 1080P: http://www.youtube.com/watch?v=Jn2WAc8b_GE . Hardware for this computer is as follows: Quanta 3610 Motherboard Bios - HP branded 8GB DDR2 dual channel @ 800MHz (6/6/6/18) 1.8V Intel Penryn Core 2 Duo P8600 2.4GHz PCI-Express graphics interface NVidia Geforce 9600M GT Synaptics PS/2 Port Touchpad Generic Plug and Play monitor (1920x1080p) Realtek RTL8168C(P) NIC (PCI-E) Intel WIFI Link 5100 AGN Sony BlueRay Comp drive Firewire Port Other assorted basics (if it makes a difference feel free to ask me - I'm happy to provide any info you need). David Monkeyman_Stones@Comcast.net --=-ZVLAFB154UrOwKLn5r6o Content-Type: text/html; charset=utf-8 Content-ID: <1317424853.4260.29.camel@Nokia-N900> Content-Transfer-Encoding: 7bit

Same result seen in HP HDX-18t Notebook computer during installition attempt of PC-BSD (containing FreeBSD).
YouTube video of entire installation attempt for this model can be seen here in 1080P: http://www.youtube.com/watch?v=Jn2WAc8b_GE .
Hardware for this computer is as follows:
Quanta 3610 Motherboard
Bios - HP branded
8GB DDR2 dual channel @ 800MHz (6/6/6/18) 1.8V
Intel Penryn Core 2 Duo P8600 2.4GHz
PCI-Express graphics interface
NVidia Geforce 9600M GT
Synaptics PS/2 Port Touchpad
Generic Plug and Play monitor (1920x1080p)
Realtek RTL8168C(P) NIC (PCI-E)
Intel WIFI Link 5100 AGN
Sony BlueRay Comp drive
Firewire Port
Other assorted basics (if it makes a difference feel free to ask me - I'm happy to provide any info you need).

David
Monkeyman_Stones@Comcast.net

--=-ZVLAFB154UrOwKLn5r6o-- From owner-freebsd-scsi@FreeBSD.ORG Sat Oct 1 05:19:44 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 D0F3E1065A3B; Sat, 1 Oct 2011 05:19:23 +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 2A2F38FC15; Sat, 1 Oct 2011 05:19:21 +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 p915JF6Y027348; Fri, 30 Sep 2011 23:19:15 -0600 (MDT) (envelope-from ken@nargothrond.kdm.org) Received: (from ken@localhost) by nargothrond.kdm.org (8.14.2/8.14.2/Submit) id p915JFh3027347; Fri, 30 Sep 2011 23:19:15 -0600 (MDT) (envelope-from ken) Date: Fri, 30 Sep 2011 23:19:14 -0600 From: "Kenneth D. Merry" To: scsi@freebsd.org, current@freebsd.org Message-ID: <20111001051914.GA25534@nargothrond.kdm.org> References: <20110922193305.GA24939@nargothrond.kdm.org> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="MGYHOYXEY6WxJCY8" Content-Disposition: inline In-Reply-To: <20110922193305.GA24939@nargothrond.kdm.org> User-Agent: Mutt/1.4.2i Cc: Fabian Keil 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: Sat, 01 Oct 2011 05:19:44 -0000 --MGYHOYXEY6WxJCY8 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline I have attached a new version of the patches, with a number of changes. One issue that has cropped up is that the previous sense code and my new descriptor sense changes never paid any attention to the actual length of the sense data returned by the controller. I have changed all of the error recovery code and sense printing code to honor the sense data length in the CAM CCB. One other problem related to that is that many controller drivers don't set the sense residual field in struct ccb_scsiio properly, or don't set it at all. This patch includes changes to the isp, mps, mpt, umass, and ciss drivers to set the sense_resid field properly. There are lots of other drivers in the system, however, that haven't been audited, and may or may not set the sense residual correctly. I also fixed an issue reported by Fabian Keil that showed up with the ahci driver. In reverting a change I have in my local tree to switch to a 2 byte length field in the SCSI inquiry CDB, I accidently shortened the CDB to 5 bytes. Oops. I'd really appreciate more feedback; Fabian is the only person to report testing the previous patch. Thanks, Ken On Thu, Sep 22, 2011 at 13:33:05 -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. > > 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 -- Kenneth Merry ken@FreeBSD.ORG --MGYHOYXEY6WxJCY8 Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="scsi_descriptor_sense.20110930.6.txt" Index: sbin/camcontrol/camcontrol.c =================================================================== --- sbin/camcontrol/camcontrol.c (revision 225891) +++ sbin/camcontrol/camcontrol.c (working copy) @@ -1907,7 +1907,9 @@ readdefects(struct cam_device *device, int argc, c int error_code, sense_key, asc, ascq; sense = &ccb->csio.sense_data; - scsi_extract_sense(sense, &error_code, &sense_key, &asc, &ascq); + scsi_extract_sense_len(sense, ccb->csio.sense_len - + ccb->csio.sense_resid, &error_code, &sense_key, &asc, + &ascq, /*show_errors*/ 1); /* * According to the SCSI spec, if the disk doesn't support @@ -3798,8 +3800,9 @@ doreport: int error_code, sense_key, asc, ascq; sense = &ccb->csio.sense_data; - scsi_extract_sense(sense, &error_code, &sense_key, - &asc, &ascq); + scsi_extract_sense_len(sense, ccb->csio.sense_len - + ccb->csio.sense_resid, &error_code, &sense_key, + &asc, &ascq, /*show_errors*/ 1); /* * According to the SCSI-2 and SCSI-3 specs, a @@ -3810,15 +3813,15 @@ doreport: */ 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, ccb->csio.sense_len - + ccb->csio.sense_resid, 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 225891) +++ 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 225891) +++ share/examples/scsi_target/scsi_cmds.c (working copy) @@ -242,22 +242,22 @@ tcmd_sense(u_int init_id, struct ccb_scsiio *ctio, 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 @@ tcmd_inquiry(struct ccb_accept_tio *atio, struct c 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 @@ tcmd_inquiry(struct ccb_accept_tio *atio, struct c * 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 @@ static int 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 @@ tcmd_req_sense(struct ccb_accept_tio *atio, struct 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 @@ tcmd_req_sense(struct ccb_accept_tio *atio, struct } 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 @@ tcmd_rdwr(struct ccb_accept_tio *atio, struct ccb_ 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 225891) +++ share/examples/scsi_target/scsi_target.c (working copy) @@ -651,7 +651,7 @@ work_atio(struct ccb_accept_tio *atio) * 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 @@ work_inot(struct ccb_immed_notify *inot) /* 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 225891) +++ sys/powerpc/ps3/ps3cdrom.c (working copy) @@ -506,21 +506,19 @@ ps3cdrom_intr(void *arg) 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 @@ ps3cdrom_transfer(void *arg, bus_dma_segment_t *se } 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 @@ ps3cdrom_transfer(void *arg, bus_dma_segment_t *se 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 225891) +++ sys/cam/cam_periph.c (working copy) @@ -1085,7 +1085,6 @@ camperiphsensedone(struct cam_periph *periph, unio 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,22 +1100,25 @@ camperiphsensedone(struct cam_periph *periph, unio switch (status) { case CAM_REQ_CMP: { + int error_code, sense_key, asc, ascq; + + scsi_extract_sense_len(&saved_ccb->csio.sense_data, + saved_ccb->csio.sense_len - + saved_ccb->csio.sense_resid, + &error_code, &sense_key, &asc, &ascq, + /*show_errors*/ 1); /* * 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; + if ((sense_key != -1) + && (sense_key != SSD_KEY_NO_SENSE)) { + saved_ccb->ccb_h.status |= CAM_AUTOSNS_VALID; } else { - saved_ccb->ccb_h.status &= - ~CAM_STATUS_MASK; - saved_ccb->ccb_h.status |= - CAM_AUTOSENSE_FAIL; + saved_ccb->ccb_h.status &= ~CAM_STATUS_MASK; + saved_ccb->ccb_h.status |= CAM_AUTOSENSE_FAIL; } saved_ccb->csio.sense_resid = done_ccb->csio.resid; bcopy(saved_ccb, done_ccb, sizeof(union ccb)); @@ -1198,12 +1200,15 @@ camperiphdone(struct cam_periph *periph, union ccb if (status & CAM_AUTOSNS_VALID) { struct ccb_getdev cgd; struct scsi_sense_data *sense; - int error_code, sense_key, asc, ascq; + int error_code, sense_key, asc, ascq, sense_len; scsi_sense_action err_action; sense = &done_ccb->csio.sense_data; - scsi_extract_sense(sense, &error_code, - &sense_key, &asc, &ascq); + sense_len = done_ccb->csio.sense_len - + done_ccb->csio.sense_resid; + scsi_extract_sense_len(sense, sense_len, &error_code, + &sense_key, &asc, &ascq, + /*show_errors*/ 1); /* * Grab the inquiry data for this device. */ Index: sys/cam/cam_ccb.h =================================================================== --- sys/cam/cam_ccb.h (revision 225891) +++ sys/cam/cam_ccb.h (working copy) @@ -539,7 +539,7 @@ struct ccb_dev_match { /* * 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 225891) +++ sys/cam/scsi/scsi_all.h (working copy) @@ -25,6 +25,7 @@ #define _SCSI_SCSI_ALL_H 1 #include +#include #ifdef _KERNEL /* @@ -171,7 +172,8 @@ struct scsi_inquiry { 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; @@ -200,7 +202,9 @@ struct scsi_mode_sense_6 #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 +213,10 @@ struct scsi_mode_sense_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 +269,120 @@ struct scsi_mode_block_descr 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 +457,16 @@ struct scsi_control_page { 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 +497,41 @@ struct scsi_cache_page { 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 +570,49 @@ struct scsi_reserve { 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 +628,61 @@ struct scsi_sync_cache { 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 +700,7 @@ struct scsi_read_buffer 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 +771,40 @@ struct scsi_rw_16 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 +814,14 @@ struct scsi_start_stop_unit 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 +846,18 @@ struct ata_pass_12 { 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 +903,7 @@ struct ata_pass_16 { #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 +912,16 @@ struct ata_pass_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 +930,7 @@ struct ata_pass_16 { #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 +1041,12 @@ struct scsi_inquiry_data 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 +1056,7 @@ struct scsi_inquiry_data #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 +1116,10 @@ struct scsi_inquiry_data 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 +1163,11 @@ struct scsi_vpd_device_id 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 +1183,13 @@ struct scsi_vpd_id_descriptor #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 +1202,9 @@ struct scsi_vpd_id_descriptor #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 +1305,23 @@ struct scsi_vpd_id_scsi_name 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 +1364,11 @@ struct scsi_report_luns 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 +1381,17 @@ struct scsi_report_luns #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 +1432,9 @@ struct scsi_target_port_group_descriptor { 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 +1454,49 @@ struct scsi_target_group_data_extended { }; +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 +1520,7 @@ struct scsi_sense_data #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 +1535,315 @@ struct scsi_sense_data #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) +#define SSD_FIXED_IS_PRESENT(sense, length, field) \ + ((length >= (offsetof(struct scsi_sense_data_fixed, field) + \ + sizeof(sense->field))) ? 1 :0) +#define SSD_FIXED_IS_FILLED(sense, field) \ + ((((offsetof(struct scsi_sense_data_fixed, field) + \ + sizeof(sense->field)) - \ + (offsetof(struct scsi_sense_data_fixed, extra_len) + \ + sizeof(sense->extra_len))) <= sense->extra_len) ? 1 : 0) }; +/* + * 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]; +#define SSD_DESC_IS_PRESENT(sense, length, field) \ + ((length >= (offsetof(struct scsi_sense_data_desc, field) + \ + sizeof(sense->field))) ? 1 :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 +1864,20 @@ struct scsi_mode_header_10 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 +1980,84 @@ scsi_sense_action scsi_error_action(struct ccb_scs struct scsi_inquiry_data *inq_data, u_int32_t sense_flags); const char * scsi_status_string(struct ccb_scsiio *csio); + +void scsi_desc_iterate(struct scsi_sense_data_desc *sense, u_int sense_len, + int (*iter_func)(struct scsi_sense_data_desc *sense, + u_int, struct scsi_sense_desc_header *, + void *), void *arg); +uint8_t *scsi_find_desc(struct scsi_sense_data_desc *sense, u_int sense_len, + 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_get_sense_info(struct scsi_sense_data *sense_data, u_int sense_len, + uint8_t info_type, uint64_t *info, + int64_t *signed_info); +int scsi_get_sks(struct scsi_sense_data *sense_data, u_int sense_len, + uint8_t *sks); +int scsi_get_block_info(struct scsi_sense_data *sense_data, u_int sense_len, + struct scsi_inquiry_data *inq_data, + uint8_t *block_bits); +int scsi_get_stream_info(struct scsi_sense_data *sense_data, u_int sense_len, + struct scsi_inquiry_data *inq_data, + uint8_t *stream_bits); +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, + u_int sense_len, 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, + u_int sense_len, 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, + u_int sense_len, 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, + u_int sense_len, 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, + u_int sense_len, 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, + u_int sense_len, 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, + u_int sense_len, 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, + u_int sense_len, 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, + u_int sense_len, 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, u_int sense_len, + 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, @@ -1497,31 +2263,29 @@ int scsi_static_inquiry_match(caddr_t inqbuffer, int scsi_devid_match(uint8_t *rhs, size_t rhs_len, uint8_t *lhs, size_t lhs_len); -static __inline void scsi_extract_sense(struct scsi_sense_data *sense, - int *error_code, int *sense_key, - int *asc, int *ascq); +void scsi_extract_sense(struct scsi_sense_data *sense, int *error_code, + int *sense_key, int *asc, int *ascq); +void scsi_extract_sense_len(struct scsi_sense_data *sense, + u_int sense_len, int *error_code, int *sense_key, + int *asc, int *ascq, int show_errors); +int scsi_get_sense_key(struct scsi_sense_data *sense, u_int sense_len, + int show_errors); +int scsi_get_asc(struct scsi_sense_data *sense, u_int sense_len, + int show_errors); +int scsi_get_ascq(struct scsi_sense_data *sense, u_int sense_len, + int show_errors); 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, - 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; -} - static __inline void scsi_ulto2b(u_int32_t val, u_int8_t *bytes) { @@ -1563,20 +2327,20 @@ scsi_u64to8b(u_int64_t val, u_int8_t *bytes) 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 +2349,9 @@ scsi_u64to8b(u_int64_t val, u_int8_t *bytes) } 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 +2359,10 @@ static __inline int32_t 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 +2372,7 @@ static __inline int32_t } static __inline uint64_t -scsi_8btou64(uint8_t *bytes) +scsi_8btou64(const uint8_t *bytes) { uint64_t rv; Index: sys/cam/scsi/scsi_cd.c =================================================================== --- sys/cam/scsi/scsi_cd.c (revision 225891) +++ sys/cam/scsi/scsi_cd.c (working copy) @@ -1691,9 +1691,10 @@ cddone(struct cam_periph *periph, union ccb *done_ if (have_sense) { sense = &csio->sense_data; - scsi_extract_sense(sense, &error_code, - &sense_key, - &asc, &ascq); + scsi_extract_sense_len(sense, + csio->sense_len - csio->sense_resid, + &error_code, &sense_key, &asc, + &ascq, /*show_errors*/ 1); } /* * Attach to anything that claims to be a @@ -3126,8 +3127,9 @@ cderror(union ccb *ccb, u_int32_t cam_flags, u_int && ((ccb->ccb_h.flags & CAM_SENSE_PTR) == 0)) { int sense_key, error_code, asc, ascq; - scsi_extract_sense(&ccb->csio.sense_data, - &error_code, &sense_key, &asc, &ascq); + scsi_extract_sense_len(&ccb->csio.sense_data, + ccb->csio.sense_len - ccb->csio.sense_resid, &error_code, + &sense_key, &asc, &ascq, /*show_errors*/ 1); if (sense_key == SSD_KEY_ILLEGAL_REQUEST) error = cd6byteworkaround(ccb); } Index: sys/cam/scsi/scsi_sa.c =================================================================== --- sys/cam/scsi/scsi_sa.c (revision 225891) +++ sys/cam/scsi/scsi_sa.c (working copy) @@ -235,10 +235,10 @@ struct sa_softc { */ 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 @@ -849,8 +849,10 @@ saioctl(struct cdev *dev, u_long cmd, caddr_t arg, */ if ((periph->flags & CAM_PERIPH_LOCKED) == 0) { error = cam_periph_hold(periph, PRIBIO|PCATCH); - if (error != 0) + if (error != 0) { + cam_periph_unlock(periph); return (error); + } didlockperiph = 1; } break; @@ -884,12 +886,15 @@ saioctl(struct cdev *dev, u_long cmd, caddr_t arg, * access to data structures. */ error = cam_periph_hold(periph, PRIBIO|PCATCH); - if (error != 0) + if (error != 0) { + cam_periph_unlock(periph); return (error); + } didlockperiph = 1; break; default: + cam_periph_unlock(periph); return (EINVAL); } } @@ -2322,17 +2327,28 @@ saerror(union ccb *ccb, u_int32_t cflgs, u_int32_t 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; + int sense_len; + 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; + sense_len = csio->sense_len - csio->sense_resid; + scsi_extract_sense_len(sense, sense_len, &error_code, &sense_key, + &asc, &ascq, /*show_errors*/ 1); + if (asc != -1 && ascq != -1) + aqvalid = 1; + else + aqvalid = 0; + if (scsi_get_stream_info(sense, sense_len, NULL, &stream_bits) == 0) + stream_valid = 1; + else + stream_valid = 0; error = 0; status = csio->ccb_h.status & CAM_STATUS_MASK; @@ -2343,9 +2359,8 @@ saerror(union ccb *ccb, u_int32_t cflgs, u_int32_t * 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, sense_len, SSD_DESC_INFO, &resid, + &info) == 0) { if ((softc->flags & SA_FLAG_FIXED) != 0) resid *= softc->media_blksize; } else { @@ -2372,10 +2387,11 @@ saerror(union ccb *ccb, u_int32_t cflgs, u_int32_t 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 +2447,7 @@ saerror(union ccb *ccb, u_int32_t cflgs, u_int32_t 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 +2466,7 @@ saerror(union ccb *ccb, u_int32_t cflgs, u_int32_t } 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 +2486,7 @@ saerror(union ccb *ccb, u_int32_t cflgs, u_int32_t /* * 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 +2501,8 @@ saerror(union ccb *ccb, u_int32_t cflgs, u_int32_t * 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 225891) +++ sys/cam/scsi/scsi_targ_bh.c (working copy) @@ -112,20 +112,20 @@ static struct scsi_inquiry_data no_lun_inq_data = /* 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 @@ targbhdone(struct cam_periph *periph, union ccb *d * 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 @@ targbhdone(struct cam_periph *periph, union ccb *d /* 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_da.c =================================================================== --- sys/cam/scsi/scsi_da.c (revision 225891) +++ sys/cam/scsi/scsi_da.c (working copy) @@ -753,10 +753,10 @@ daclose(struct disk *dp) int asc, ascq; int sense_key, error_code; - scsi_extract_sense(&ccb->csio.sense_data, - &error_code, - &sense_key, - &asc, &ascq); + scsi_extract_sense_len(&ccb->csio.sense_data, + ccb->csio.sense_len - ccb->csio.sense_resid, + &error_code, &sense_key, &asc, &ascq, + /*show_errors*/ 1); if (sense_key != SSD_KEY_ILLEGAL_REQUEST) scsi_sense_print(&ccb->csio); } else { @@ -916,10 +916,10 @@ dadump(void *arg, void *virtual, vm_offset_t physi int asc, ascq; int sense_key, error_code; - scsi_extract_sense(&csio.sense_data, - &error_code, - &sense_key, - &asc, &ascq); + scsi_extract_sense_len(&csio.sense_data, + csio.sense_len - csio.sense_resid, + &error_code, &sense_key, &asc, &ascq, + /*show_errors*/ 1); if (sense_key != SSD_KEY_ILLEGAL_REQUEST) scsi_sense_print(&csio); } else { @@ -1802,9 +1802,10 @@ dadone(struct cam_periph *periph, union ccb *done_ if (have_sense) { sense = &csio->sense_data; - scsi_extract_sense(sense, &error_code, - &sense_key, - &asc, &ascq); + scsi_extract_sense_len(sense, + csio->sense_len - csio->sense_resid, + &error_code, &sense_key, &asc, + &ascq, /*show_errors*/ 1); } /* * Attach to anything that claims to be a Index: sys/cam/scsi/scsi_low.c =================================================================== --- sys/cam/scsi/scsi_low.c (revision 225891) +++ sys/cam/scsi/scsi_low.c (working copy) @@ -2577,12 +2577,16 @@ resume: #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 225891) +++ sys/cam/scsi/scsi_all.c (working copy) @@ -31,6 +31,8 @@ __FBSDID("$FreeBSD$"); #include +#include +#include #ifdef _KERNEL #include @@ -54,6 +56,7 @@ __FBSDID("$FreeBSD$"); #include #ifndef _KERNEL #include +#include #ifndef FALSE #define FALSE 0 @@ -608,14 +611,24 @@ scsi_op_desc(u_int16_t opcode, struct scsi_inquiry 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 @@ const struct sense_key_table_entry sense_key_table { 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, "COMPLETED" } }; const int sense_key_table_size = @@ -1062,25 +1075,25 @@ static struct asc_table_entry asc_table[] = { { 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 @@ static struct asc_table_entry asc_table[] = { { 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, @@ -2790,7 +2803,10 @@ scsi_sense_desc(int sense_key, int asc, int ascq, &sense_entry, &asc_entry); - *sense_key_desc = sense_entry->desc; + if (sense_entry != NULL) + *sense_key_desc = sense_entry->desc; + else + *sense_key_desc = "Invalid Sense Key"; if (asc_entry != NULL) *asc_desc = asc_entry->desc; @@ -2816,10 +2832,12 @@ scsi_error_action(struct ccb_scsiio *csio, struct int error_code, sense_key, asc, ascq; scsi_sense_action action; - scsi_extract_sense(&csio->sense_data, &error_code, - &sense_key, &asc, &ascq); + scsi_extract_sense_len(&csio->sense_data, csio->sense_len - + csio->sense_resid, &error_code, + &sense_key, &asc, &ascq, /*show_errors*/ 1); - 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 @@ -2857,8 +2875,10 @@ scsi_error_action(struct ccb_scsiio *csio, struct if (asc_entry != NULL && (asc != 0 || ascq != 0)) action = asc_entry->action; + else if (sense_entry != NULL) + action = sense_entry->action; else - action = sense_entry->action; + action = SS_RETRY|SSQ_DECREMENT_COUNT|SSQ_PRINT_SENSE; if (sense_key == SSD_KEY_RECOVERED_ERROR) { /* @@ -3040,8 +3060,1348 @@ scsi_command_string(struct cam_device *device, str return(0); } +/* + * Iterate over sense descriptors. Each descriptor is passed into iter_func(). + * If iter_func() returns 0, list traversal continues. If iter_func() + * returns non-zero, list traversal is stopped. + */ +void +scsi_desc_iterate(struct scsi_sense_data_desc *sense, u_int sense_len, + int (*iter_func)(struct scsi_sense_data_desc *sense, + u_int, struct scsi_sense_desc_header *, + void *), void *arg) +{ + int cur_pos; + int desc_len; + /* + * First make sure the extra length field is present. + */ + if (SSD_DESC_IS_PRESENT(sense, sense_len, extra_len) == 0) + return; + + /* + * The length of data actually returned may be different than the + * extra_len recorded in the sturcture. + */ + desc_len = sense_len -offsetof(struct scsi_sense_data_desc, sense_desc); + + /* + * Limit this further by the extra length reported, and the maximum + * allowed extra length. + */ + desc_len = MIN(desc_len, MIN(sense->extra_len, SSD_EXTRA_MAX)); + + /* + * Subtract the size of the header from the descriptor length. + * This is to ensure that we have at least the header left, so we + * don't have to check that inside the loop. This can wind up + * being a negative value. + */ + desc_len -= sizeof(struct scsi_sense_desc_header); + + for (cur_pos = 0; cur_pos < desc_len;) { + struct scsi_sense_desc_header *header; + + header = (struct scsi_sense_desc_header *) + &sense->sense_desc[cur_pos]; + + /* + * Check to make sure we have the entire descriptor. We + * don't call iter_func() unless we do. + * + * Note that although cur_pos is at the beginning of the + * descriptor, desc_len already has the header length + * subtracted. So the comparison of the length in the + * header (which does not include the header itself) to + * desc_len - cur_pos is correct. + */ + if (header->length > (desc_len - cur_pos)) + break; + + if (iter_func(sense, sense_len, header, arg) != 0) + break; + + cur_pos += sizeof(*header) + header->length; + } +} + +struct scsi_find_desc_info { + uint8_t desc_type; + struct scsi_sense_desc_header *header; +}; + +static int +scsi_find_desc_func(struct scsi_sense_data_desc *sense, u_int sense_len, + struct scsi_sense_desc_header *header, void *arg) +{ + struct scsi_find_desc_info *desc_info; + + desc_info = (struct scsi_find_desc_info *)arg; + + if (header->desc_type == desc_info->desc_type) { + desc_info->header = header; + + /* We found the descriptor, tell the iterator to stop. */ + return (1); + } else + 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. + */ +uint8_t * +scsi_find_desc(struct scsi_sense_data_desc *sense, u_int sense_len, + uint8_t desc_type) +{ + struct scsi_find_desc_info desc_info; + + desc_info.desc_type = desc_type; + desc_info.header = NULL; + + scsi_desc_iterate(sense, sense_len, scsi_find_desc_func, &desc_info); + + return ((uint8_t *)desc_info.header); +} + +/* + * 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_CURRENT_ERROR; + else + sense->error_code = 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]; + /* + * We're setting the info field, so + * set the valid bit. + */ + sense->error_code |= SSD_ERRCODE_VALID; + } + + /* + * 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); +} + +/* + * Get sense information for three similar sense data types. + */ +int +scsi_get_sense_info(struct scsi_sense_data *sense_data, u_int sense_len, + uint8_t info_type, uint64_t *info, int64_t *signed_info) +{ + scsi_sense_data_type sense_type; + + if (sense_len == 0) + goto bailout; + + 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, sense_len, 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; + + if (SSD_FIXED_IS_PRESENT(sense, sense_len, info) == 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 ((SSD_FIXED_IS_PRESENT(sense, sense_len, + cmd_spec_info) == 0) + || (SSD_FIXED_IS_FILLED(sense, cmd_spec_info) == 0)) + 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 ((SSD_FIXED_IS_PRESENT(sense, sense_len, fru) == 0) + || (SSD_FIXED_IS_FILLED(sense, fru) == 0)) + goto bailout; + + if (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, u_int sense_len, uint8_t *sks) +{ + scsi_sense_data_type sense_type; + + if (sense_len == 0) + goto bailout; + + 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, sense_len, + SSD_DESC_SKS); + if (desc == NULL) + goto bailout; + + /* + * No need to check the SKS valid bit for descriptor sense. + * If the descriptor is present, it is valid. + */ + 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 ((SSD_FIXED_IS_PRESENT(sense, sense_len, sense_key_spec)== 0) + || (SSD_FIXED_IS_FILLED(sense, sense_key_spec) == 0)) + goto bailout; + + if ((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, u_int sense_len, + 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, + sense_len, 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 (SSD_FIXED_IS_PRESENT(sense, sense_len, flags) == 0) + goto bailout; + + 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, u_int sense_len, + 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, + sense_len, 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 (SSD_FIXED_IS_PRESENT(sense, sense_len, flags) == 0) + goto bailout; + + 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, + u_int sense_len, 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, + u_int sense_len, 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, + u_int sense_len, 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_len(sense, sense_len, &error_code, &sense_key, + &asc, &ascq, /*show_errors*/ 1); + + scsi_sks_sbuf(sb, sense_key, sks->sense_key_spec); +} + +void +scsi_sense_fru_sbuf(struct sbuf *sb, struct scsi_sense_data *sense, + u_int sense_len, 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, + u_int sense_len, 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, sense_len, 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, + u_int sense_len, 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, sense_len, 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, + u_int sense_len, 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, + u_int sense_len, 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, + u_int sense_len, 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, + u_int sense_len, 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, sense_len, cdb, cdb_len, + inq_data, header); + + return; + } + + /* + * No specific printing routine, so use the generic routine. + */ + scsi_sense_generic_sbuf(sb, sense, sense_len, 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); +} + +struct scsi_print_sense_info { + struct sbuf *sb; + char *path_str; + uint8_t *cdb; + int cdb_len; + struct scsi_inquiry_data *inq_data; +}; + +static int +scsi_print_desc_func(struct scsi_sense_data_desc *sense, u_int sense_len, + struct scsi_sense_desc_header *header, void *arg) +{ + struct scsi_print_sense_info *print_info; + + print_info = (struct scsi_print_sense_info *)arg; + + switch (header->desc_type) { + case SSD_DESC_INFO: + case SSD_DESC_FRU: + case SSD_DESC_COMMAND: + case SSD_DESC_SKS: + case SSD_DESC_BLOCK: + case SSD_DESC_STREAM: + /* + * We have already printed these descriptors, if they are + * present. + */ + break; + default: { + sbuf_printf(print_info->sb, "%s", print_info->path_str); + scsi_sense_desc_sbuf(print_info->sb, + (struct scsi_sense_data *)sense, sense_len, + print_info->cdb, print_info->cdb_len, + print_info->inq_data, header); + sbuf_printf(print_info->sb, "\n"); + break; + } + } + + /* + * Tell the iterator that we want to see more descriptors if they + * are present. + */ + return (0); +} + +void +scsi_sense_only_sbuf(struct scsi_sense_data *sense, u_int sense_len, + 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_len(sense, sense_len, &error_code, &sense_key, + &asc, &ascq, /*show_errors*/ 1); + + 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; + struct scsi_print_sense_info print_info; + const char *sense_key_desc; + const char *asc_desc; + uint8_t sks[3]; + uint64_t val; + int info_valid; + + /* + * Get descriptions for the sense key, ASC, and ASCQ. If + * these aren't present in the sense data (i.e. the sense + * data isn't long enough), the -1 values that + * scsi_extract_sense_len() returns will yield default + * or error descriptions. + */ + 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, sense_len, 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, sense_len, 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, sense_len, + 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, sense_len, 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, sense_len, 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, sense_len, 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; + + print_info.sb = sb; + print_info.path_str = path_str; + print_info.cdb = cdb; + print_info.cdb_len = cdb_len; + print_info.inq_data = inq_data; + + /* + * Print any sense descriptors that we have not already printed. + */ + scsi_desc_iterate(desc_sense, sense_len, scsi_print_desc_func, + &print_info); + break; + + } + case -1: + /* + * scsi_extract_sense_len() sets values to -1 if the + * show_errors flag is set and they aren't present in the + * sense data. This means that sense_len is 0. + */ + sbuf_printf(sb, "No sense data present\n"); + 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; + + fixed_sense = (struct scsi_sense_data_fixed *)sense; + + if (SSD_FIXED_IS_PRESENT(fixed_sense, sense_len, info)){ + uint32_t info; + + info = scsi_4btoul(fixed_sense->info); + + sbuf_printf(sb, " at block no. %d (decimal)", + info); + } + } + sbuf_printf(sb, "\n"); + break; + } + } +} + +/* * scsi_sense_sbuf() returns 0 for success and -1 for failure. */ #ifdef _KERNEL @@ -3059,11 +4419,8 @@ scsi_sense_sbuf(struct cam_device *device, struct #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 +4518,14 @@ scsi_sense_sbuf(struct cam_device *device, struct 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, csio->sense_len - csio->sense_resid, sb, + path_str, inq_data, cdb, csio->cdb_len); + #ifdef _KERNEL xpt_free_ccb((union ccb*)cgd); #endif /* _KERNEL/!_KERNEL */ @@ -3355,6 +4597,135 @@ scsi_sense_print(struct cam_device *device, struct #endif /* _KERNEL/!_KERNEL */ /* + * Extract basic sense information. This is backward-compatible with the + * previous implementation. For new implementations, + * scsi_extract_sense_len() is recommended. + */ +void +scsi_extract_sense(struct scsi_sense_data *sense_data, int *error_code, + int *sense_key, int *asc, int *ascq) +{ + scsi_extract_sense_len(sense_data, sizeof(*sense_data), error_code, + sense_key, asc, ascq, /*show_errors*/ 0); +} + +/* + * Extract basic sense information. If show_errors is set, sense values + * will be set to -1 if they are not present. + */ +void +scsi_extract_sense_len(struct scsi_sense_data *sense_data, u_int sense_len, + int *error_code, int *sense_key, int *asc, int *ascq, + int show_errors) +{ + /* + * If we have no length, we have no sense. + */ + if (sense_len == 0) { + if (show_errors == 0) { + *error_code = 0; + *sense_key = 0; + *asc = 0; + *ascq = 0; + } else { + *error_code = -1; + *sense_key = -1; + *asc = -1; + *ascq = -1; + } + return; + } + + *error_code = sense_data->error_code & SSD_ERRCODE; + + switch (*error_code) { + case SSD_DESC_CURRENT_ERROR: + case SSD_DESC_DEFERRED_ERROR: { + struct scsi_sense_data_desc *sense; + + sense = (struct scsi_sense_data_desc *)sense_data; + + if (SSD_DESC_IS_PRESENT(sense, sense_len, sense_key)) + *sense_key = sense->sense_key & SSD_KEY; + else + *sense_key = (show_errors) ? -1 : 0; + + if (SSD_DESC_IS_PRESENT(sense, sense_len, add_sense_code)) + *asc = sense->add_sense_code; + else + *asc = (show_errors) ? -1 : 0; + + if (SSD_DESC_IS_PRESENT(sense, sense_len, add_sense_code_qual)) + *ascq = sense->add_sense_code_qual; + else + *ascq = (show_errors) ? -1 : 0; + break; + } + case SSD_CURRENT_ERROR: + case SSD_DEFERRED_ERROR: + default: { + struct scsi_sense_data_fixed *sense; + + sense = (struct scsi_sense_data_fixed *)sense_data; + + if (SSD_FIXED_IS_PRESENT(sense, sense_len, flags)) + *sense_key = sense->flags & SSD_KEY; + else + *sense_key = (show_errors) ? -1 : 0; + + if ((SSD_FIXED_IS_PRESENT(sense, sense_len, add_sense_code)) + && (SSD_FIXED_IS_FILLED(sense, add_sense_code))) + *asc = sense->add_sense_code; + else + *asc = (show_errors) ? -1 : 0; + + if ((SSD_FIXED_IS_PRESENT(sense, sense_len,add_sense_code_qual)) + && (SSD_FIXED_IS_FILLED(sense, add_sense_code_qual))) + *ascq = sense->add_sense_code_qual; + else + *ascq = (show_errors) ? -1 : 0; + break; + } + } +} + +int +scsi_get_sense_key(struct scsi_sense_data *sense_data, u_int sense_len, + int show_errors) +{ + int error_code, sense_key, asc, ascq; + + scsi_extract_sense_len(sense_data, sense_len, &error_code, + &sense_key, &asc, &ascq, show_errors); + + return (sense_key); +} + +int +scsi_get_asc(struct scsi_sense_data *sense_data, u_int sense_len, + int show_errors) +{ + int error_code, sense_key, asc, ascq; + + scsi_extract_sense_len(sense_data, sense_len, &error_code, + &sense_key, &asc, &ascq, show_errors); + + return (asc); +} + +int +scsi_get_ascq(struct scsi_sense_data *sense_data, u_int sense_len, + int show_errors) +{ + int error_code, sense_key, asc, ascq; + + scsi_extract_sense_len(sense_data, sense_len, &error_code, + &sense_key, &asc, &ascq, show_errors); + + return (ascq); +} + +/* * This function currently requires at least 36 bytes, or * SHORT_INQUIRY_LENGTH, worth of data to function properly. If this * function needs more or less data in the future, another length should be Index: sys/cam/scsi/smp_all.h =================================================================== --- sys/cam/scsi/smp_all.h (revision 225891) +++ 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 225891) +++ sys/dev/mly/mly.c (working copy) @@ -1294,10 +1294,12 @@ mly_complete_event(struct mly_command *mc) 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 225891) +++ 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,12 @@ sbp_targ_send_status(struct orb_info *orbi, union { 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; + int sense_len; if (debug) printf("%s: STATUS %d\n", __func__, @@ -659,36 +666,76 @@ sbp_targ_send_status(struct orb_info *orbi, union #endif #endif - if ((sense->error_code & SSD_ERRCODE) == SSD_CURRENT_ERROR) + sense_len = ccb->csio.sense_len - ccb->csio.sense_resid; + scsi_extract_sense_len(sense, sense_len, &error_code, + &sense_key, &asc, &ascq, /*show_errors*/ 0); + + 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, sense_len, 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, sense_len, 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, sense_len, 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, sense_len, 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, sense_len, 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 225891) +++ sys/dev/firewire/sbp.c (working copy) @@ -1515,10 +1515,10 @@ static void 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 225891) +++ sys/dev/ciss/ciss.c (working copy) @@ -3249,13 +3249,17 @@ ciss_cam_complete(struct ciss_request *cr) ce->sense_length, ce->residual_count); bzero(&csio->sense_data, SSD_FULL_SIZE); bcopy(&ce->sense_info[0], &csio->sense_data, ce->sense_length); - csio->sense_len = ce->sense_length; + if (csio->sense_len > ce->sense_length) + csio->sense_resid = csio->sense_len - ce->sense_length; + else + csio->sense_resid = 0; csio->resid = ce->residual_count; csio->ccb_h.status |= CAM_SCSI_STATUS_ERROR | CAM_AUTOSNS_VALID; #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, csio->sense_len - + csio->sense_resid, /*show_errors*/ 1)); } #endif break; Index: sys/dev/mps/mps_sas.c =================================================================== --- sys/dev/mps/mps_sas.c (revision 225891) +++ sys/dev/mps/mps_sas.c (working copy) @@ -1490,7 +1490,6 @@ mpssas_scsiio_complete(struct mps_softc *sc, struc MPI2_SCSI_IO_REPLY *rep; union ccb *ccb; struct mpssas_softc *sassc; - u_int sense_len; int dir = 0; mps_dprint(sc, MPS_TRACE, "%s\n", __func__); @@ -1666,10 +1665,16 @@ mpssas_scsiio_complete(struct mps_softc *sc, struc } if (rep->SCSIState & MPI2_SCSI_STATE_AUTOSENSE_VALID) { - sense_len = MIN(rep->SenseCount, - sizeof(struct scsi_sense_data)); - if (sense_len < rep->SenseCount) - ccb->csio.sense_resid = rep->SenseCount - sense_len; + int sense_len; + + if (rep->SenseCount < ccb->csio.sense_len) + ccb->csio.sense_resid = ccb->csio.sense_len - + rep->SenseCount; + else + ccb->csio.sense_resid = 0; + + sense_len = min(rep->SenseCount, ccb->csio.sense_len - + ccb->csio.sense_resid); bcopy(cm->cm_sense, &ccb->csio.sense_data, sense_len); ccb->ccb_h.status |= CAM_AUTOSNS_VALID; } Index: sys/dev/mpt/mpt_cam.c =================================================================== --- sys/dev/mpt/mpt_cam.c (revision 225891) +++ sys/dev/mpt/mpt_cam.c (working copy) @@ -3167,12 +3167,19 @@ mpt_scsi_reply_frame_handler(struct mpt_softc *mpt if ((sstate & MPI_SCSI_STATE_AUTOSENSE_VALID) != 0 && (ccb->ccb_h.flags & (CAM_SENSE_PHYS | CAM_SENSE_PTR)) == 0) { + uint32_t sense_returned; + ccb->ccb_h.status |= CAM_AUTOSNS_VALID; - ccb->csio.sense_resid = - ccb->csio.sense_len - le32toh(scsi_io_reply->SenseCount); + + sense_returned = le32toh(scsi_io_reply->SenseCount); + if (sense_returned < ccb->csio.sense_len) + ccb->csio.sense_resid = ccb->csio.sense_len - + sense_returned; + else + ccb->csio.sense_resid = 0; + bcopy(req->sense_vbuf, &ccb->csio.sense_data, - min(ccb->csio.sense_len, - le32toh(scsi_io_reply->SenseCount))); + min(ccb->csio.sense_len, sense_returned)); } if ((sstate & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) != 0) { Index: sys/dev/iir/iir.c =================================================================== --- sys/dev/iir/iir.c (revision 225891) +++ sys/dev/iir/iir.c (working copy) @@ -1839,13 +1839,20 @@ gdt_sync_event(struct gdt_softc *gdt, int service, } 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 225891) +++ sys/dev/iscsi/initiator/iscsi_subr.c (working copy) @@ -153,6 +153,7 @@ getSenseData(u_int status, union ccb *ccb, pduq_t 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,14 @@ getSenseData(u_int status, union ccb *ccb, pduq_t scsi->sense_resid = 0; if(cmd->flag & (BIT(1)|BIT(2))) scsi->sense_resid = ntohl(pp->ipdu.scsi_rsp.rcnt); + + scsi_extract_sense_len(sense, scsi->sense_len - scsi->sense_resid, + &error_code, &sense_key, &asc, &ascq, /*show_errors*/ 1); + 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 225891) +++ sys/dev/usb/storage/umass.c (working copy) @@ -2344,14 +2344,14 @@ umass_cam_action(struct cam_sim *sim, union ccb *c */ 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,24 @@ umass_cam_sense_cb(struct umass_softc *sc, union c 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 key, sense_len; + ccb->csio.sense_resid = residue; + sense_len = ccb->csio.sense_len - ccb->csio.sense_resid; + key = scsi_get_sense_key(&ccb->csio.sense_data, sense_len, + /*show_errors*/ 1); + 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 +2707,7 @@ umass_cam_sense_cb(struct umass_softc *sc, union c } 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 225891) +++ sys/dev/isp/isp_freebsd.h (working copy) @@ -438,11 +438,19 @@ default: \ #define XS_SNSP(ccb) (&(ccb)->sense_data) #define XS_SNSLEN(ccb) \ - imin((sizeof((ccb)->sense_data)), ccb->sense_len) + imin((sizeof((ccb)->sense_data)), ccb->sense_len - ccb->sense_resid) -#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, \ + ccb->sense_len - ccb->sense_resid, \ + /*show_errors*/ 1)) + +#define XS_SNSASC(ccb) (scsi_get_asc(&(ccb)->sense_data, \ + ccb->sense_len - ccb->sense_resid, \ + /*show_errors*/ 1)) + +#define XS_SNSASCQ(ccb) (scsi_get_ascq(&(ccb)->sense_data, \ + ccb->sense_len - ccb->sense_resid, \ + /*show_errors*/ 1)) #define XS_TAG_P(ccb) \ (((ccb)->ccb_h.flags & CAM_TAG_ACTION_VALID) && \ (ccb)->tag_action != CAM_TAG_ACTION_NONE) @@ -476,9 +484,13 @@ default: \ #define XS_INITERR(ccb) \ XS_SETERR(ccb, CAM_REQ_INPROG), (ccb)->ccb_h.spriv_field0 = 0 -#define XS_SAVE_SENSE(xs, sense_ptr, sense_len) \ - (xs)->ccb_h.status |= CAM_AUTOSNS_VALID; \ - memcpy(&(xs)->sense_data, sense_ptr, imin(XS_SNSLEN(xs), sense_len)) +#define XS_SAVE_SENSE(xs, sense_ptr, slen) do { \ + (xs)->ccb_h.status |= CAM_AUTOSNS_VALID; \ + memcpy(&(xs)->sense_data, sense_ptr, imin(XS_SNSLEN(xs),\ + slen)); \ + if (slen < (xs)->sense_len) \ + (xs)->sense_resid = (xs)->sense_len - slen; \ + } while (0); #define XS_SENSE_VALID(xs) (((xs)->ccb_h.status & CAM_AUTOSNS_VALID) != 0) --MGYHOYXEY6WxJCY8--