The branch main has been updated by ken:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=40a492d38ee10ecf9d9a099c5cdecc072e24d2d1

commit 40a492d38ee10ecf9d9a099c5cdecc072e24d2d1
Author:     Kenneth D. Merry <k...@freebsd.org>
AuthorDate: 2023-12-28 21:23:16 +0000
Commit:     Kenneth D. Merry <k...@freebsd.org>
CommitDate: 2023-12-28 21:23:16 +0000

    camcontrol: Add a sense subcommand
    
    As the name suggests, this sends a SCSI REQUEST SENSE to a device,
    and prints out decoded sense information.  It can also print out a
    hexdump of the sense data.
    
    sbin/camcontrol/camcontrol.c:
            Add the new sense subcommand.
    
    sbin/camcontrol/camcontrol.8:
            Document camcontrol sense.
    
    Sponsored by:   Spectra Logic
    Reviewed by:    mav
    MFC after:      3 days
    Differential Revision:  https://reviews.freebsd.org/D43225
---
 sbin/camcontrol/camcontrol.8 |  17 +++++-
 sbin/camcontrol/camcontrol.c | 122 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 138 insertions(+), 1 deletion(-)

diff --git a/sbin/camcontrol/camcontrol.8 b/sbin/camcontrol/camcontrol.8
index 2113c4fb2aab..0151376ff39f 100644
--- a/sbin/camcontrol/camcontrol.8
+++ b/sbin/camcontrol/camcontrol.8
@@ -25,7 +25,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd June 1, 2023
+.Dd December 28, 2023
 .Dt CAMCONTROL 8
 .Os
 .Sh NAME
@@ -51,6 +51,12 @@
 .Op device id
 .Op generic args
 .Nm
+.Ic sense
+.Op device id
+.Op generic args
+.Op Fl D
+.Op Fl x
+.Nm
 .Ic inquiry
 .Op device id
 .Op generic args
@@ -488,6 +494,15 @@ Send the SCSI test unit ready (0x00) command to the given 
device.
 The
 .Nm
 utility will report whether the device is ready or not.
+.It Ic sense
+Send a SCSI REQUEST SENSE command (0x03) to a device.
+The decoded sense (or hexdump) is printed to stdout.
+.Bl -tag -width 4n
+.It Fl D
+Request descriptor sense instead of fixed sense.
+.It Fl x
+Do a hexdump of the returned sense data.
+.El
 .It Ic inquiry
 Send a SCSI inquiry command (0x12) to a device.
 By default,
diff --git a/sbin/camcontrol/camcontrol.c b/sbin/camcontrol/camcontrol.c
index 9417943afcb3..555a67001443 100644
--- a/sbin/camcontrol/camcontrol.c
+++ b/sbin/camcontrol/camcontrol.c
@@ -111,6 +111,7 @@ typedef enum {
        CAM_CMD_DEVTYPE,
        CAM_CMD_AMA,
        CAM_CMD_DEPOP,
+       CAM_CMD_REQSENSE
 } cam_cmd;
 
 typedef enum {
@@ -233,6 +234,7 @@ static struct camcontrol_opts option_table[] = {
        {"epc", CAM_CMD_EPC, CAM_ARG_NONE, "c:dDeHp:Pr:sS:T:"},
        {"timestamp", CAM_CMD_TIMESTAMP, CAM_ARG_NONE, "f:mrsUT:"},
        {"depop", CAM_CMD_DEPOP, CAM_ARG_NONE, "ac:de:ls"},
+       {"sense", CAM_CMD_REQSENSE, CAM_ARG_NONE, "Dx"},
        {"help", CAM_CMD_USAGE, CAM_ARG_NONE, NULL},
        {"-?", CAM_CMD_USAGE, CAM_ARG_NONE, NULL},
        {"-h", CAM_CMD_USAGE, CAM_ARG_NONE, NULL},
@@ -279,6 +281,9 @@ static int print_dev_mmcsd(struct device_match_result 
*dev_result,
 #ifdef WITH_NVME
 static int print_dev_nvme(struct device_match_result *dev_result, char 
*tmpstr);
 #endif
+static int requestsense(struct cam_device *device, int argc, char **argv,
+                       char *combinedopt, int task_attr, int retry_count,
+                       int timeout);
 static int testunitready(struct cam_device *device, int task_attr,
                         int retry_count, int timeout, int quiet);
 static int scsistart(struct cam_device *device, int startstop, int loadeject,
@@ -840,6 +845,114 @@ print_dev_nvme(struct device_match_result *dev_result, 
char *tmpstr)
 }
 #endif
 
+static int
+requestsense(struct cam_device *device, int argc, char **argv,
+            char *combinedopt, int task_attr, int retry_count, int timeout)
+{
+       int c;
+       int descriptor_sense = 0;
+       int do_hexdump = 0;
+       struct scsi_sense_data sense;
+       union ccb *ccb = NULL;
+       int error = 0;
+       size_t returned_bytes;
+
+       while ((c = getopt(argc, argv, combinedopt)) != -1) {
+               switch (c) {
+               case 'D':
+                       descriptor_sense = 1;
+                       break;
+               case 'x':
+                       do_hexdump = 1;
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       ccb = cam_getccb(device);
+       if (ccb == NULL) {
+               warnx("couldn't allocate CCB");
+               return (1);
+       }
+
+       /* cam_getccb cleans up the header, caller has to zero the payload */
+       CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->csio);
+
+       bzero(&sense, sizeof(sense));
+
+       scsi_request_sense(&ccb->csio,
+                          /*retries*/ retry_count,
+                          /*cbfcnp*/ NULL,
+                          /*data_ptr*/ (void *)&sense,
+                          /*dxfer_len*/ sizeof(sense),
+                          /*tag_action*/ task_attr,
+                          /*sense_len*/ SSD_FULL_SIZE,
+                          /*timeout*/ timeout ? timeout : 60000);
+
+       if (descriptor_sense != 0) {
+               struct scsi_request_sense *cdb;
+
+               cdb = (struct scsi_request_sense *)&ccb->csio.cdb_io.cdb_bytes;
+               cdb->byte2 |= SRS_DESC;
+       }
+
+       ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
+
+       if (arglist & CAM_ARG_ERR_RECOVER)
+               ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
+
+       if (cam_send_ccb(device, ccb) < 0) {
+               warn("error sending REQUEST SENSE command");
+               cam_freeccb(ccb);
+               error = 1;
+               goto bailout;
+       }
+
+       /*
+        * REQUEST SENSE is not generally supposed to fail.  But there can
+        * be transport or other errors that might cause it to fail.  It
+        * may also fail if the user asks for descriptor sense and the
+        * device doesn't support it.  So we check the CCB status here to see.
+        */
+       if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
+               warnx("REQUEST SENSE failed");
+               cam_error_print(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr);
+               error = 1;
+               goto bailout;
+       }
+
+       returned_bytes = ccb->csio.dxfer_len - ccb->csio.resid;
+
+       if (do_hexdump != 0) {
+               hexdump(&sense, returned_bytes, NULL, 0);
+       } else {
+               char path_str[80];
+               struct sbuf *sb;
+
+               cam_path_string(device, path_str, sizeof(path_str));
+               sb = sbuf_new_auto();
+               if (sb == NULL) {
+                       warnx("%s: cannot allocate sbuf", __func__);
+                       error = 1;
+                       goto bailout;
+               }
+
+               scsi_sense_only_sbuf(&sense, returned_bytes, sb, path_str,
+                   &device->inq_data, scsiio_cdb_ptr(&ccb->csio),
+                   ccb->csio.cdb_len);
+
+               sbuf_finish(sb);
+               printf("%s", sbuf_data(sb));
+               sbuf_delete(sb);
+       }
+bailout:
+       if (ccb != NULL)
+               cam_freeccb(ccb);
+
+       return (error);
+}
+
 static int
 testunitready(struct cam_device *device, int task_attr, int retry_count,
              int timeout, int quiet)
@@ -9869,6 +9982,7 @@ usage(int printlong)
 "        camcontrol devlist    [-b] [-v]\n"
 "        camcontrol periphlist [dev_id][-n dev_name] [-u unit]\n"
 "        camcontrol tur        [dev_id][generic args]\n"
+"        camcontrol sense      [dev_id][generic args][-D][-x]\n"
 "        camcontrol inquiry    [dev_id][generic args] [-D] [-S] [-R]\n"
 "        camcontrol identify   [dev_id][generic args] [-v]\n"
 "        camcontrol reportluns [dev_id][generic args] [-c] [-l] [-r report]\n"
@@ -9957,6 +10071,7 @@ usage(int printlong)
 "Specify one of the following options:\n"
 "devlist     list all CAM devices\n"
 "periphlist  list all CAM peripheral drivers attached to a device\n"
+"sense       send a request sense command to the named device\n"
 "tur         send a test unit ready to the named device\n"
 "inquiry     send a SCSI inquiry command to the named device\n"
 "identify    send a ATA identify command to the named device\n"
@@ -10021,6 +10136,9 @@ usage(int printlong)
 "-f format         specify defect list format (block, bfi or phys)\n"
 "-G                get the grown defect list\n"
 "-P                get the permanent defect list\n"
+"sense arguments:\n"
+"-D                request descriptor sense data\n"
+"-x                do a hexdump of the sense data\n"
 "inquiry arguments:\n"
 "-D                get the standard inquiry data\n"
 "-S                get the serial number\n"
@@ -10491,6 +10609,10 @@ main(int argc, char **argv)
        case CAM_CMD_DEVTYPE:
                error = getdevtype(cam_dev);
                break;
+       case CAM_CMD_REQSENSE:
+               error = requestsense(cam_dev, argc, argv, combinedopt,
+                   task_attr, retry_count, timeout);
+               break;
        case CAM_CMD_TUR:
                error = testunitready(cam_dev, task_attr, retry_count,
                    timeout, 0);

Reply via email to