git: 40a492d38ee1 - main - camcontrol: Add a sense subcommand
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Thu, 28 Dec 2023 21:24:09 UTC
The branch main has been updated by ken: URL: https://cgit.FreeBSD.org/src/commit/?id=40a492d38ee10ecf9d9a099c5cdecc072e24d2d1 commit 40a492d38ee10ecf9d9a099c5cdecc072e24d2d1 Author: Kenneth D. Merry <ken@FreeBSD.org> AuthorDate: 2023-12-28 21:23:16 +0000 Commit: Kenneth D. Merry <ken@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);