mirror of
https://github.com/freebsd/freebsd-src.git
synced 2026-11-07 04:36:52 -10:00
camcontrol: Add support for NVMe namespace Identify
Add a -N argument to camcontrol identify. This will fetch and display namespace Identify data for NVMe drives, using nvme_print_namespace() from nvmecontrol(8). This gets the namespace Identify data via XPT_DEV_ADVINFO (i.e. data cached in the kernel) like the standard NVMe identify command does, and so works even on NVMe devices that do not support NVMe Namespace Management. sbin/camcontrol/camcontrol.c: Add a -N argument to camcontrol identify. Rename nvme_get_cdata() to nvme_get_data(), and give it the ability to fetch controller or namespace Identify data. While here, improve its error reporting with cam_error_print(), and only look at the CAM status bits of the returned CCB. Change identify(), ataidentify(), and nvmeidentify() to handle the extra arguments. Give nvmeidentify() the ability to fetch and print NVMe namespace data, using nvme_print_namespace() from nvmecontrol(8). sbin/camcontrol/camcontrol.h: Add the nvme_get_data() prototype, for use by future NVMe subcommands living outside camcontrol.c. sbin/camcontrol/camcontrol.8: Document camcontrol identify -N. Make it clear that the NVMe data is from data cached in the kernel. Add a cross reference to nvmecontrol(8). Co-authored-by: Claude Fable 5 <[email protected]> Reviewed by: imp MFC after: 1 week Sponsored by: Spectra Logic Differential Revision: https://reviews.freebsd.org/D59533
This commit is contained in:
1 parent
9814633f63
commit
961fa195b3
3 files changed
+101
-28
No files matched your search
@@ -25,7 +25,7 @@
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd December 28, 2023
|
||||
.Dd August 21, 2026
|
||||
.Dt CAMCONTROL 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
@@ -67,6 +67,7 @@
|
||||
.Ic identify
|
||||
.Op device id
|
||||
.Op generic args
|
||||
.Op Fl N
|
||||
.Op Fl v
|
||||
.Nm
|
||||
.Ic reportluns
|
||||
@@ -524,7 +525,15 @@ This is to aid in script writing.
|
||||
Print out transfer rate information.
|
||||
.El
|
||||
.It Ic identify
|
||||
Send an ATA identify command (0xec) to a device.
|
||||
Send a ATA identify command (0xec) or NVMe identify command to a device.
|
||||
For NVMe devices, this displays Identify data cached in the kernel, and
|
||||
does not send commands to the drive.
|
||||
.Bl -tag -width 8n
|
||||
.It Fl N
|
||||
Display NVMe Identify Namespace data.
|
||||
This shows the capacity of the namespace (CAM peripheral drivers are attached
|
||||
to a NVMe namespace) as opposed to the entire drive.
|
||||
.El
|
||||
.It Ic reportluns
|
||||
Send the SCSI REPORT LUNS (0xA0) command to the given device.
|
||||
By default,
|
||||
@@ -2935,6 +2944,7 @@ camcontrol timestamp sa0 -s -f "%a, %d %b %Y %T %z" \e
|
||||
.Xr pass 4 ,
|
||||
.Xr xpt 4 ,
|
||||
.Xr diskinfo 8 ,
|
||||
.Xr nvmecontrol 8 ,
|
||||
.Xr trim 8 ,
|
||||
.Xr zonectl 8
|
||||
.Sh HISTORY
|
||||
|
||||
@@ -185,7 +185,7 @@ static char pwd_opt;
|
||||
static struct camcontrol_opts option_table[] = {
|
||||
{"tur", CAM_CMD_TUR, CAM_ARG_NONE, NULL},
|
||||
{"inquiry", CAM_CMD_INQUIRY, CAM_ARG_NONE, "DSR"},
|
||||
{"identify", CAM_CMD_IDENTIFY, CAM_ARG_NONE, NULL},
|
||||
{"identify", CAM_CMD_IDENTIFY, CAM_ARG_NONE, "N"},
|
||||
{"start", CAM_CMD_STARTSTOP, CAM_ARG_START_UNIT, NULL},
|
||||
{"stop", CAM_CMD_STARTSTOP, CAM_ARG_NONE, NULL},
|
||||
{"load", CAM_CMD_STARTSTOP, CAM_ARG_START_UNIT | CAM_ARG_EJECT, NULL},
|
||||
@@ -779,12 +779,35 @@ print_dev_mmcsd(struct device_match_result *dev_result, char *tmpstr)
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
nvme_get_cdata(struct cam_device *dev, struct nvme_controller_data *cdata)
|
||||
int
|
||||
nvme_get_data(struct cam_device *dev, int nvme_data_type, void *data,
|
||||
size_t data_len)
|
||||
{
|
||||
union ccb *ccb;
|
||||
struct nvme_controller_data *cdata;
|
||||
struct nvme_namespace_data *nsdata;
|
||||
struct ccb_dev_advinfo *advi;
|
||||
|
||||
switch (nvme_data_type) {
|
||||
case CDAI_TYPE_NVME_CNTRL:
|
||||
if (data_len != sizeof(*cdata)) {
|
||||
warnx("%s: supplied data length %zu != controller data "
|
||||
"length %zu", __func__, data_len, sizeof(*nsdata));
|
||||
goto bailout_error;
|
||||
}
|
||||
break;
|
||||
case CDAI_TYPE_NVME_NS:
|
||||
if (data_len != sizeof(*nsdata)) {
|
||||
warnx("%s: supplied data length %zu != namespace data "
|
||||
"length %zu", __func__, data_len, sizeof(*nsdata));
|
||||
goto bailout_error;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
warnx("Unknown NVMe data type %d", nvme_data_type);
|
||||
goto bailout_error;
|
||||
}
|
||||
|
||||
ccb = cam_getccb(dev);
|
||||
if (ccb == NULL) {
|
||||
warnx("couldn't allocate CCB");
|
||||
@@ -792,28 +815,31 @@ nvme_get_cdata(struct cam_device *dev, struct nvme_controller_data *cdata)
|
||||
return (1);
|
||||
}
|
||||
|
||||
CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->cdai);
|
||||
advi = &ccb->cdai;
|
||||
advi->ccb_h.flags = CAM_DIR_IN;
|
||||
advi->ccb_h.func_code = XPT_DEV_ADVINFO;
|
||||
advi->flags = CDAI_FLAG_NONE;
|
||||
advi->buftype = CDAI_TYPE_NVME_CNTRL;
|
||||
advi->bufsiz = sizeof(struct nvme_controller_data);
|
||||
advi->buf = (uint8_t *)cdata;
|
||||
advi->buftype = nvme_data_type;
|
||||
advi->bufsiz = data_len;
|
||||
advi->buf = data;
|
||||
|
||||
if (cam_send_ccb(dev, ccb) < 0) {
|
||||
warn("error sending XPT_DEV_ADVINFO CCB");
|
||||
warn("%s: error sending XPT_DEV_ADVINFO CCB", __func__);
|
||||
cam_freeccb(ccb);
|
||||
cam_close_device(dev);
|
||||
return(1);
|
||||
goto bailout_error;
|
||||
}
|
||||
if (advi->ccb_h.status != CAM_REQ_CMP) {
|
||||
warnx("got CAM error %#x", advi->ccb_h.status);
|
||||
if ((advi->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
|
||||
cam_error_print(dev, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr);
|
||||
cam_freeccb(ccb);
|
||||
cam_close_device(dev);
|
||||
return(1);
|
||||
goto bailout_error;
|
||||
}
|
||||
cam_freeccb(ccb);
|
||||
return 0;
|
||||
|
||||
bailout_error:
|
||||
cam_close_device(dev);
|
||||
return (1);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -830,7 +856,7 @@ print_dev_nvme(struct device_match_result *dev_result, char *tmpstr)
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (nvme_get_cdata(dev, &cdata))
|
||||
if (nvme_get_data(dev, CDAI_TYPE_NVME_CNTRL, &cdata, sizeof(cdata)))
|
||||
return (1);
|
||||
|
||||
cam_strvis(vendor, cdata.mn, sizeof(cdata.mn), sizeof(vendor));
|
||||
@@ -2470,7 +2496,8 @@ retry:
|
||||
|
||||
|
||||
static int
|
||||
ataidentify(struct cam_device *device, int retry_count, int timeout)
|
||||
ataidentify(struct cam_device *device, int argc __unused, char **argv __unused,
|
||||
char *combinedopt __unused, int retry_count, int timeout)
|
||||
{
|
||||
union ccb *ccb;
|
||||
struct ata_params *ident_buf;
|
||||
@@ -2515,19 +2542,47 @@ ataidentify(struct cam_device *device, int retry_count, int timeout)
|
||||
}
|
||||
|
||||
static int
|
||||
nvmeidentify(struct cam_device *device, int retry_count __unused, int timeout __unused)
|
||||
nvmeidentify(struct cam_device *device, int argc, char **argv,
|
||||
char *combinedopt, int retry_count __unused, int timeout __unused)
|
||||
{
|
||||
struct nvme_controller_data cdata;
|
||||
int ns_identify = 0;
|
||||
int c;
|
||||
|
||||
if (nvme_get_cdata(device, &cdata))
|
||||
return (1);
|
||||
nvme_print_controller(&cdata);
|
||||
|
||||
while ((c = getopt(argc, argv, combinedopt)) != -1) {
|
||||
switch (c) {
|
||||
case 'N':
|
||||
ns_identify = 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ns_identify == 0) {
|
||||
struct nvme_controller_data cdata;
|
||||
|
||||
if (nvme_get_data(device, CDAI_TYPE_NVME_CNTRL, &cdata,
|
||||
sizeof(cdata)))
|
||||
return (1);
|
||||
|
||||
nvme_print_controller(&cdata);
|
||||
} else {
|
||||
struct nvme_namespace_data ns_data;
|
||||
|
||||
if (nvme_get_data(device, CDAI_TYPE_NVME_NS, &ns_data,
|
||||
sizeof(ns_data)))
|
||||
return (1);
|
||||
|
||||
nvme_print_namespace(&ns_data);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
identify(struct cam_device *device, int retry_count, int timeout)
|
||||
identify(struct cam_device *device, int argc, char **argv, char *combinedopt,
|
||||
int retry_count, int timeout)
|
||||
{
|
||||
struct ccb_pathinq cpi;
|
||||
|
||||
@@ -2537,9 +2592,12 @@ identify(struct cam_device *device, int retry_count, int timeout)
|
||||
}
|
||||
|
||||
if (cpi.protocol == PROTO_NVME) {
|
||||
return (nvmeidentify(device, retry_count, timeout));
|
||||
return (nvmeidentify(device, argc, argv, combinedopt,
|
||||
retry_count, timeout));
|
||||
} else {
|
||||
return (ataidentify(device, argc, argv, combinedopt,
|
||||
retry_count, timeout));
|
||||
}
|
||||
return (ataidentify(device, retry_count, timeout));
|
||||
}
|
||||
|
||||
|
||||
@@ -10030,7 +10088,7 @@ usage(int printlong)
|
||||
" 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 identify [dev_id][generic args] [-N] [-v]\n"
|
||||
" camcontrol reportluns [dev_id][generic args] [-c] [-l] [-r report]\n"
|
||||
" camcontrol readcap [dev_id][generic args] [-b] [-h] [-H] [-N]\n"
|
||||
" [-q] [-s] [-l]\n"
|
||||
@@ -10120,7 +10178,7 @@ usage(int printlong)
|
||||
"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"
|
||||
"identify send a ATA or NVMe identify command to the named device\n"
|
||||
"reportluns send a SCSI report luns command to the device\n"
|
||||
"readcap send a SCSI read capacity command to the device\n"
|
||||
"start send a Start Unit command to the device\n"
|
||||
@@ -10189,6 +10247,8 @@ usage(int printlong)
|
||||
"-D get the standard inquiry data\n"
|
||||
"-S get the serial number\n"
|
||||
"-R get the transfer rate, etc.\n"
|
||||
"identify arguments:\n"
|
||||
"-N send identify to the NVMe namespace\n"
|
||||
"reportluns arguments:\n"
|
||||
"-c only report a count of available LUNs\n"
|
||||
"-l only print out luns, and not a count\n"
|
||||
@@ -10668,7 +10728,8 @@ main(int argc, char **argv)
|
||||
task_attr, retry_count, timeout);
|
||||
break;
|
||||
case CAM_CMD_IDENTIFY:
|
||||
error = identify(cam_dev, retry_count, timeout);
|
||||
error = identify(cam_dev, argc, argv, combinedopt, retry_count,
|
||||
timeout);
|
||||
break;
|
||||
case CAM_CMD_STARTSTOP:
|
||||
error = scsistart(cam_dev, arglist & CAM_ARG_START_UNIT,
|
||||
|
||||
@@ -75,6 +75,8 @@ int build_ata_cmd(union ccb *ccb, uint32_t retry_count, uint32_t flags,
|
||||
int get_ata_status(struct cam_device *dev, union ccb *ccb, uint8_t *error,
|
||||
uint16_t *count, uint64_t *lba, uint8_t *device,
|
||||
uint8_t *status);
|
||||
int nvme_get_data(struct cam_device *dev, int nvme_data_type, void *data,
|
||||
size_t data_len);
|
||||
int camxferrate(struct cam_device *device);
|
||||
int fwdownload(struct cam_device *device, int argc, char **argv,
|
||||
char *combinedopt, int printerrors, int task_attr,
|
||||
|
||||
Reference in new issue
Block a user