summaryrefslogtreecommitdiffstats
path: root/sbin
diff options
context:
space:
mode:
authorken <ken@FreeBSD.org>2017-02-24 20:51:39 +0000
committerken <ken@FreeBSD.org>2017-02-24 20:51:39 +0000
commita82b72965ec560f35cabeb478a39f6683cc8ff5f (patch)
tree74507b5d4eabdbaf6a001856faedc606745fdf5c /sbin
parent81e6bddfc9a08fc84f3231b648ec2ae209bca843 (diff)
downloadFreeBSD-src-a82b72965ec560f35cabeb478a39f6683cc8ff5f.zip
FreeBSD-src-a82b72965ec560f35cabeb478a39f6683cc8ff5f.tar.gz
MFC r313893
------------------------------------------------------------------------ r313893 | ken | 2017-02-17 13:04:22 -0700 (Fri, 17 Feb 2017) | 48 lines Add task attribute support to camcontrol(8). Users can use the new generic argument, -Q task_attr, to specify a task attribute (simple, ordered, head of queue, aca) for the commands issued. The the default is simple, which works with all SCSI devices that support tagged queueing. This will mostly be useful for debugging target behavior in certain situations. You can try it out by compiling CTL with CTL_IO_DELAY turned on (in sys/cam/ctl/ctl_io.h) and then do something like this with one of the CTL LUNs: ctladm delay 0:0 -l done -t 10 camcontrol tur da34 -v And at then before the 10 second timer is up, in another terminal: camcontrol inquiry da34 -Q ordered -v The Inquiry should complete just after the TUR completes. Ordinarily it would complete first because of the delay injection, but because the task attribute is set to ordered in this case, CTL holds it up until the previous command has completed. sbin/camcontrol/camcontrol.c: Add the new generic argument, -Q, which allows the user to specify a SCSI task attribute. The user can specify task attributes by name or numerically. Add a new task_attr arguments to SCSI sub-functions. sbin/camcontrol/attrib.c, sbin/camcontrol/camcontrol.h, sbin/camcontrol/fwdownload.c, sbin/camcontrol/modeedit.c, sbin/camcontrol/persist.c, sbin/camcontrol/timestamp.c, sbin/camcontrol/zone.c: Add the new task_attr argument to SCSI sub-functions. sbin/camcontrol/camcontrol.8: Document the new -Q option, and add an example. Sponsored by: Spectra Logic ------------------------------------------------------------------------
Diffstat (limited to 'sbin')
-rw-r--r--sbin/camcontrol/attrib.c5
-rw-r--r--sbin/camcontrol/camcontrol.818
-rw-r--r--sbin/camcontrol/camcontrol.c241
-rw-r--r--sbin/camcontrol/camcontrol.h35
-rw-r--r--sbin/camcontrol/fwdownload.c14
-rw-r--r--sbin/camcontrol/modeedit.c44
-rw-r--r--sbin/camcontrol/persist.c7
7 files changed, 231 insertions, 133 deletions
diff --git a/sbin/camcontrol/attrib.c b/sbin/camcontrol/attrib.c
index 7ff2c42..5c3c009 100644
--- a/sbin/camcontrol/attrib.c
+++ b/sbin/camcontrol/attrib.c
@@ -106,7 +106,8 @@ static struct scsi_nv output_format_map[] = {
int
scsiattrib(struct cam_device *device, int argc, char **argv, char *combinedopt,
- int retry_count, int timeout, int verbosemode, int err_recover)
+ int task_attr, int retry_count, int timeout, int verbosemode,
+ int err_recover)
{
union ccb *ccb = NULL;
int attr_num = -1;
@@ -317,7 +318,7 @@ scsiattrib(struct cam_device *device, int argc, char **argv, char *combinedopt,
scsi_read_attribute(&ccb->csio,
/*retries*/ retry_count,
/*cbfcnp*/ NULL,
- /*tag_action*/ MSG_SIMPLE_Q_TAG,
+ /*tag_action*/ task_attr,
/*service_action*/ read_service_action,
/*element*/ element_address,
/*elem_type*/ element_type,
diff --git a/sbin/camcontrol/camcontrol.8 b/sbin/camcontrol/camcontrol.8
index 87ea011..7163bed 100644
--- a/sbin/camcontrol/camcontrol.8
+++ b/sbin/camcontrol/camcontrol.8
@@ -27,7 +27,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd January 6, 2017
+.Dd February 17, 2017
.Dt CAMCONTROL 8
.Os
.Sh NAME
@@ -397,6 +397,17 @@ It may take some other actions, depending upon the sense code returned from
the command.
.It Fl n Ar dev_name
Specify the device type to operate on, e.g.\& "da", "cd".
+.It Fl Q Ar task_attr
+.Tn SCSI
+task attribute for the command, if it is a
+.Tn SCSI
+command.
+This may be ordered, simple, head, or aca.
+In most cases this is not needed.
+The default is simple, which works with all
+.Tn SCSI
+devices.
+The task attribute may also be specified numerically.
.It Fl t Ar timeout
SCSI command timeout in seconds.
This overrides the default timeout for
@@ -2143,7 +2154,7 @@ information if the command fails since the
.Fl v
switch was not specified.
.Bd -literal -offset indent
-camcontrol tur da1 -E -C 4 -t 50 -v
+camcontrol tur da1 -E -C 4 -t 50 -Q head -v
.Ed
.Pp
Send a test unit ready command to da1.
@@ -2156,6 +2167,9 @@ flag) if the command fails.
Since error recovery is turned on, the
disk will be spun up if it is not currently spinning.
The
+.Tn SCSI
+task attribute for the command will be set to Head of Queue.
+The
.Nm
utility will report whether the disk is ready.
.Bd -literal -offset indent
diff --git a/sbin/camcontrol/camcontrol.c b/sbin/camcontrol/camcontrol.c
index 0050c3b..3ba1e74 100644
--- a/sbin/camcontrol/camcontrol.c
+++ b/sbin/camcontrol/camcontrol.c
@@ -168,6 +168,14 @@ struct ata_set_max_pwd
u_int16_t reserved2[239];
};
+static struct scsi_nv task_attrs[] = {
+ { "simple", MSG_SIMPLE_Q_TAG },
+ { "head", MSG_HEAD_OF_Q_TAG },
+ { "ordered", MSG_ORDERED_Q_TAG },
+ { "iwr", MSG_IGN_WIDE_RESIDUE },
+ { "aca", MSG_ACA_TASK }
+};
+
static const char scsicmd_opts[] = "a:c:dfi:o:r";
static const char readdefect_opts[] = "f:GPqsS:X";
static const char negotiate_opts[] = "acD:M:O:qR:T:UW:";
@@ -259,12 +267,14 @@ static int getdevlist(struct cam_device *device);
#endif /* MINIMALISTIC */
static int getdevtree(int argc, char **argv, char *combinedopt);
#ifndef MINIMALISTIC
-static int testunitready(struct cam_device *device, int retry_count,
- int timeout, int quiet);
+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,
- int retry_count, int timeout);
-static int scsiinquiry(struct cam_device *device, int retry_count, int timeout);
-static int scsiserial(struct cam_device *device, int retry_count, int timeout);
+ int task_attr, int retry_count, int timeout);
+static int scsiinquiry(struct cam_device *device, int task_attr,
+ int retry_count, int timeout);
+static int scsiserial(struct cam_device *device, int task_attr,
+ int retry_count, int timeout);
#endif /* MINIMALISTIC */
static int parse_btl(char *tstr, path_id_t *bus, target_id_t *target,
lun_id_t *lun, cam_argmask *arglst);
@@ -274,11 +284,14 @@ static int scanlun_or_reset_dev(path_id_t bus, target_id_t target,
lun_id_t lun, int scan);
#ifndef MINIMALISTIC
static int readdefects(struct cam_device *device, int argc, char **argv,
- char *combinedopt, int retry_count, int timeout);
+ char *combinedopt, int task_attr, int retry_count,
+ int timeout);
static void modepage(struct cam_device *device, int argc, char **argv,
- char *combinedopt, int retry_count, int timeout);
+ char *combinedopt, int task_attr, int retry_count,
+ int timeout);
static int scsicmd(struct cam_device *device, int argc, char **argv,
- char *combinedopt, int retry_count, int timeout);
+ char *combinedopt, int task_attr, int retry_count,
+ int timeout);
static int smpcmd(struct cam_device *device, int argc, char **argv,
char *combinedopt, int retry_count, int timeout);
static int smpreportgeneral(struct cam_device *device, int argc, char **argv,
@@ -303,16 +316,21 @@ static int get_cpi(struct cam_device *device, struct ccb_pathinq *cpi);
static int get_cgd(struct cam_device *device, struct ccb_getdev *cgd);
static int get_print_cts(struct cam_device *device, int user_settings,
int quiet, struct ccb_trans_settings *cts);
-static int ratecontrol(struct cam_device *device, int retry_count,
- int timeout, int argc, char **argv, char *combinedopt);
+static int ratecontrol(struct cam_device *device, int task_attr,
+ int retry_count, int timeout, int argc, char **argv,
+ char *combinedopt);
static int scsiformat(struct cam_device *device, int argc, char **argv,
- char *combinedopt, int retry_count, int timeout);
+ char *combinedopt, int task_attr, int retry_count,
+ int timeout);
static int scsisanitize(struct cam_device *device, int argc, char **argv,
- char *combinedopt, int retry_count, int timeout);
+ char *combinedopt, int task_attr, int retry_count,
+ int timeout);
static int scsireportluns(struct cam_device *device, int argc, char **argv,
- char *combinedopt, int retry_count, int timeout);
+ char *combinedopt, int task_attr, int retry_count,
+ int timeout);
static int scsireadcapacity(struct cam_device *device, int argc, char **argv,
- char *combinedopt, int retry_count, int timeout);
+ char *combinedopt, int task_attr, int retry_count,
+ int timeout);
static int atapm(struct cam_device *device, int argc, char **argv,
char *combinedopt, int retry_count, int timeout);
static int atasecurity(struct cam_device *device, int retry_count, int timeout,
@@ -325,8 +343,8 @@ static int scsiprintoneopcode(struct cam_device *device, int req_opcode,
static int scsiprintopcodes(struct cam_device *device, int td_req, uint8_t *buf,
uint32_t valid_len);
static int scsiopcodes(struct cam_device *device, int argc, char **argv,
- char *combinedopt, int retry_count, int timeout,
- int verbose);
+ char *combinedopt, int task_attr, int retry_count,
+ int timeout, int verbose);
static int scsireprobe(struct cam_device *device);
#endif /* MINIMALISTIC */
@@ -644,8 +662,8 @@ getdevtree(int argc, char **argv, char *combinedopt)
#ifndef MINIMALISTIC
static int
-testunitready(struct cam_device *device, int retry_count, int timeout,
- int quiet)
+testunitready(struct cam_device *device, int task_attr, int retry_count,
+ int timeout, int quiet)
{
int error = 0;
union ccb *ccb;
@@ -655,7 +673,7 @@ testunitready(struct cam_device *device, int retry_count, int timeout,
scsi_test_unit_ready(&ccb->csio,
/* retries */ retry_count,
/* cbfcnp */ NULL,
- /* tag_action */ MSG_SIMPLE_Q_TAG,
+ /* tag_action */ task_attr,
/* sense_len */ SSD_FULL_SIZE,
/* timeout */ timeout ? timeout : 5000);
@@ -699,7 +717,7 @@ testunitready(struct cam_device *device, int retry_count, int timeout,
static int
scsistart(struct cam_device *device, int startstop, int loadeject,
- int retry_count, int timeout)
+ int task_attr, int retry_count, int timeout)
{
union ccb *ccb;
int error = 0;
@@ -710,13 +728,19 @@ scsistart(struct cam_device *device, int startstop, int loadeject,
* If we're stopping, send an ordered tag so the drive in question
* will finish any previously queued writes before stopping. If
* the device isn't capable of tagged queueing, or if tagged
- * queueing is turned off, the tag action is a no-op.
+ * queueing is turned off, the tag action is a no-op. We override
+ * the default simple tag, although this also has the effect of
+ * overriding the user's wishes if he wanted to specify a simple
+ * tag.
*/
+ if ((startstop == 0)
+ && (task_attr == MSG_SIMPLE_Q_TAG))
+ task_attr = MSG_ORDERED_Q_TAG;
+
scsi_start_stop(&ccb->csio,
/* retries */ retry_count,
/* cbfcnp */ NULL,
- /* tag_action */ startstop ? MSG_SIMPLE_Q_TAG :
- MSG_ORDERED_Q_TAG,
+ /* tag_action */ task_attr,
/* start/stop */ startstop,
/* load_eject */ loadeject,
/* immediate */ 0,
@@ -777,7 +801,7 @@ scsistart(struct cam_device *device, int startstop, int loadeject,
int
scsidoinquiry(struct cam_device *device, int argc, char **argv,
- char *combinedopt, int retry_count, int timeout)
+ char *combinedopt, int task_attr, int retry_count, int timeout)
{
int c;
int error = 0;
@@ -806,13 +830,13 @@ scsidoinquiry(struct cam_device *device, int argc, char **argv,
arglist |= CAM_ARG_INQ_MASK;
if (arglist & CAM_ARG_GET_STDINQ)
- error = scsiinquiry(device, retry_count, timeout);
+ error = scsiinquiry(device, task_attr, retry_count, timeout);
if (error != 0)
return(error);
if (arglist & CAM_ARG_GET_SERIAL)
- scsiserial(device, retry_count, timeout);
+ scsiserial(device, task_attr, retry_count, timeout);
if (arglist & CAM_ARG_GET_XFERRATE)
error = camxferrate(device);
@@ -821,7 +845,8 @@ scsidoinquiry(struct cam_device *device, int argc, char **argv,
}
static int
-scsiinquiry(struct cam_device *device, int retry_count, int timeout)
+scsiinquiry(struct cam_device *device, int task_attr, int retry_count,
+ int timeout)
{
union ccb *ccb;
struct scsi_inquiry_data *inq_buf;
@@ -883,7 +908,7 @@ scsiinquiry(struct cam_device *device, int retry_count, int timeout)
scsi_inquiry(&ccb->csio,
/* retries */ retry_count,
/* cbfcnp */ NULL,
- /* tag_action */ MSG_SIMPLE_Q_TAG,
+ /* tag_action */ task_attr,
/* inq_buf */ (u_int8_t *)inq_buf,
/* inq_len */ SHORT_INQUIRY_LENGTH,
/* evpd */ 0,
@@ -935,7 +960,8 @@ scsiinquiry(struct cam_device *device, int retry_count, int timeout)
}
static int
-scsiserial(struct cam_device *device, int retry_count, int timeout)
+scsiserial(struct cam_device *device, int task_attr, int retry_count,
+ int timeout)
{
union ccb *ccb;
struct scsi_vpd_unit_serial_number *serial_buf;
@@ -964,7 +990,7 @@ scsiserial(struct cam_device *device, int retry_count, int timeout)
scsi_inquiry(&ccb->csio,
/*retries*/ retry_count,
/*cbfcnp*/ NULL,
- /* tag_action */ MSG_SIMPLE_Q_TAG,
+ /* tag_action */ task_attr,
/* inq_buf */ (u_int8_t *)serial_buf,
/* inq_len */ sizeof(*serial_buf),
/* evpd */ 1,
@@ -3400,7 +3426,7 @@ static struct scsi_nv defect_list_type_map[] = {
static int
readdefects(struct cam_device *device, int argc, char **argv,
- char *combinedopt, int retry_count, int timeout)
+ char *combinedopt, int task_attr, int retry_count, int timeout)
{
union ccb *ccb = NULL;
struct scsi_read_defect_data_hdr_10 *hdr10 = NULL;
@@ -3542,7 +3568,7 @@ next_batch:
scsi_read_defects(&ccb->csio,
/*retries*/ retry_count,
/*cbfcnp*/ NULL,
- /*tag_action*/ MSG_SIMPLE_Q_TAG,
+ /*tag_action*/ task_attr,
/*list_format*/ list_format,
/*addr_desc_index*/ starting_offset,
/*data_ptr*/ defect_list,
@@ -3980,7 +4006,8 @@ reassignblocks(struct cam_device *device, u_int32_t *blocks, int num_blocks)
#ifndef MINIMALISTIC
void
mode_sense(struct cam_device *device, int dbd, int pc, int page, int subpage,
- int retry_count, int timeout, u_int8_t *data, int datalen)
+ int task_attr, int retry_count, int timeout, u_int8_t *data,
+ int datalen)
{
union ccb *ccb;
int retval;
@@ -3995,7 +4022,7 @@ mode_sense(struct cam_device *device, int dbd, int pc, int page, int subpage,
scsi_mode_sense_subpage(&ccb->csio,
/* retries */ retry_count,
/* cbfcnp */ NULL,
- /* tag_action */ MSG_SIMPLE_Q_TAG,
+ /* tag_action */ task_attr,
/* dbd */ dbd,
/* pc */ pc << 6,
/* page */ page,
@@ -4030,8 +4057,8 @@ mode_sense(struct cam_device *device, int dbd, int pc, int page, int subpage,
}
void
-mode_select(struct cam_device *device, int save_pages, int retry_count,
- int timeout, u_int8_t *data, int datalen)
+mode_select(struct cam_device *device, int save_pages, int task_attr,
+ int retry_count, int timeout, u_int8_t *data, int datalen)
{
union ccb *ccb;
int retval;
@@ -4046,7 +4073,7 @@ mode_select(struct cam_device *device, int save_pages, int retry_count,
scsi_mode_select(&ccb->csio,
/* retries */ retry_count,
/* cbfcnp */ NULL,
- /* tag_action */ MSG_SIMPLE_Q_TAG,
+ /* tag_action */ task_attr,
/* scsi_page_fmt */ 1,
/* save_pages */ save_pages,
/* param_buf */ data,
@@ -4081,7 +4108,7 @@ mode_select(struct cam_device *device, int save_pages, int retry_count,
void
modepage(struct cam_device *device, int argc, char **argv, char *combinedopt,
- int retry_count, int timeout)
+ int task_attr, int retry_count, int timeout)
{
char *str_subpage;
int c, page = -1, subpage = -1, pc = 0;
@@ -4128,16 +4155,17 @@ modepage(struct cam_device *device, int argc, char **argv, char *combinedopt,
errx(1, "you must specify a mode page!");
if (list != 0) {
- mode_list(device, dbd, pc, list > 1, retry_count, timeout);
+ mode_list(device, dbd, pc, list > 1, task_attr, retry_count,
+ timeout);
} else {
mode_edit(device, dbd, pc, page, subpage, edit, binary,
- retry_count, timeout);
+ task_attr, retry_count, timeout);
}
}
static int
scsicmd(struct cam_device *device, int argc, char **argv, char *combinedopt,
- int retry_count, int timeout)
+ int task_attr, int retry_count, int timeout)
{
union ccb *ccb;
u_int32_t flags = CAM_DIR_NONE;
@@ -4382,7 +4410,7 @@ scsicmd(struct cam_device *device, int argc, char **argv, char *combinedopt,
/*retries*/ retry_count,
/*cbfcnp*/ NULL,
/*flags*/ flags,
- /*tag_action*/ MSG_SIMPLE_Q_TAG,
+ /*tag_action*/ task_attr,
/*data_ptr*/ data_ptr,
/*dxfer_len*/ data_bytes,
/*sense_len*/ SSD_FULL_SIZE,
@@ -5333,8 +5361,8 @@ get_print_cts_bailout:
}
static int
-ratecontrol(struct cam_device *device, int retry_count, int timeout,
- int argc, char **argv, char *combinedopt)
+ratecontrol(struct cam_device *device, int task_attr, int retry_count,
+ int timeout, int argc, char **argv, char *combinedopt)
{
int c;
union ccb *ccb;
@@ -5664,7 +5692,7 @@ ratecontrol(struct cam_device *device, int retry_count, int timeout,
}
}
if (send_tur) {
- retval = testunitready(device, retry_count, timeout,
+ retval = testunitready(device, task_attr, retry_count, timeout,
(arglist & CAM_ARG_VERBOSE) ? 0 : 1);
/*
* If the TUR didn't succeed, just bail.
@@ -5689,7 +5717,7 @@ ratecontrol_bailout:
static int
scsiformat(struct cam_device *device, int argc, char **argv,
- char *combinedopt, int retry_count, int timeout)
+ char *combinedopt, int task_attr, int retry_count, int timeout)
{
union ccb *ccb;
int c;
@@ -5738,7 +5766,7 @@ scsiformat(struct cam_device *device, int argc, char **argv,
"following device:\n");
error = scsidoinquiry(device, argc, argv, combinedopt,
- retry_count, timeout);
+ task_attr, retry_count, timeout);
if (error != 0) {
warnx("scsiformat: error sending inquiry");
@@ -5810,7 +5838,7 @@ scsiformat(struct cam_device *device, int argc, char **argv,
scsi_format_unit(&ccb->csio,
/* retries */ retry_count,
/* cbfcnp */ NULL,
- /* tag_action */ MSG_SIMPLE_Q_TAG,
+ /* tag_action */ task_attr,
/* byte2 */ byte2,
/* ileave */ 0,
/* data_ptr */ data_ptr,
@@ -5869,7 +5897,7 @@ doreport:
scsi_test_unit_ready(&ccb->csio,
/* retries */ 0,
/* cbfcnp */ NULL,
- /* tag_action */ MSG_SIMPLE_Q_TAG,
+ /* tag_action */ task_attr,
/* sense_len */ SSD_FULL_SIZE,
/* timeout */ 5000);
@@ -5979,7 +6007,7 @@ scsiformat_bailout:
static int
scsisanitize(struct cam_device *device, int argc, char **argv,
- char *combinedopt, int retry_count, int timeout)
+ char *combinedopt, int task_attr, int retry_count, int timeout)
{
union ccb *ccb;
u_int8_t action = 0;
@@ -6144,7 +6172,7 @@ scsisanitize(struct cam_device *device, int argc, char **argv,
"following device:\n");
error = scsidoinquiry(device, argc, argv, combinedopt,
- retry_count, timeout);
+ task_attr, retry_count, timeout);
if (error != 0) {
warnx("scsisanitize: error sending inquiry");
@@ -6202,7 +6230,7 @@ scsisanitize(struct cam_device *device, int argc, char **argv,
scsi_sanitize(&ccb->csio,
/* retries */ retry_count,
/* cbfcnp */ NULL,
- /* tag_action */ MSG_SIMPLE_Q_TAG,
+ /* tag_action */ task_attr,
/* byte2 */ byte2,
/* control */ 0,
/* data_ptr */ data_ptr,
@@ -6277,7 +6305,7 @@ doreport:
scsi_test_unit_ready(&ccb->csio,
/* retries */ 0,
/* cbfcnp */ NULL,
- /* tag_action */ MSG_SIMPLE_Q_TAG,
+ /* tag_action */ task_attr,
/* sense_len */ SSD_FULL_SIZE,
/* timeout */ 5000);
@@ -6389,7 +6417,7 @@ scsisanitize_bailout:
static int
scsireportluns(struct cam_device *device, int argc, char **argv,
- char *combinedopt, int retry_count, int timeout)
+ char *combinedopt, int task_attr, int retry_count, int timeout)
{
union ccb *ccb;
int c, countonly, lunsonly;
@@ -6466,7 +6494,7 @@ retry:
scsi_report_luns(&ccb->csio,
/*retries*/ retry_count,
/*cbfcnp*/ NULL,
- /*tag_action*/ MSG_SIMPLE_Q_TAG,
+ /*tag_action*/ task_attr,
/*select_report*/ report_type,
/*rpl_buf*/ lundata,
/*alloc_len*/ alloc_len,
@@ -6631,7 +6659,7 @@ bailout:
static int
scsireadcapacity(struct cam_device *device, int argc, char **argv,
- char *combinedopt, int retry_count, int timeout)
+ char *combinedopt, int task_attr, int retry_count, int timeout)
{
union ccb *ccb;
int blocksizeonly, humanize, numblocks, quiet, sizeonly, baseten;
@@ -6717,7 +6745,7 @@ scsireadcapacity(struct cam_device *device, int argc, char **argv,
scsi_read_capacity(&ccb->csio,
/*retries*/ retry_count,
/*cbfcnp*/ NULL,
- /*tag_action*/ MSG_SIMPLE_Q_TAG,
+ /*tag_action*/ task_attr,
&rcap,
SSD_FULL_SIZE,
/*timeout*/ timeout ? timeout : 5000);
@@ -6759,7 +6787,7 @@ scsireadcapacity(struct cam_device *device, int argc, char **argv,
scsi_read_capacity_16(&ccb->csio,
/*retries*/ retry_count,
/*cbfcnp*/ NULL,
- /*tag_action*/ MSG_SIMPLE_Q_TAG,
+ /*tag_action*/ task_attr,
/*lba*/ 0,
/*reladdr*/ 0,
/*pmi*/ 0,
@@ -8200,8 +8228,8 @@ ataaxm(struct cam_device *device, int argc, char **argv,
int
scsigetopcodes(struct cam_device *device, int opcode_set, int opcode,
int show_sa_errors, int sa_set, int service_action,
- int timeout_desc, int retry_count, int timeout, int verbosemode,
- uint32_t *fill_len, uint8_t **data_ptr)
+ int timeout_desc, int task_attr, int retry_count, int timeout,
+ int verbosemode, uint32_t *fill_len, uint8_t **data_ptr)
{
union ccb *ccb = NULL;
uint8_t *buf = NULL;
@@ -8268,7 +8296,7 @@ retry_alloc:
scsi_report_supported_opcodes(&ccb->csio,
/*retries*/ retry_count,
/*cbfcnp*/ NULL,
- /*tag_action*/ MSG_SIMPLE_Q_TAG,
+ /*tag_action*/ task_attr,
/*options*/ options,
/*req_opcode*/ opcode,
/*req_service_action*/ service_action,
@@ -8568,7 +8596,8 @@ bailout:
static int
scsiopcodes(struct cam_device *device, int argc, char **argv,
- char *combinedopt, int retry_count, int timeout, int verbosemode)
+ char *combinedopt, int task_attr, int retry_count, int timeout,
+ int verbosemode)
{
int c;
uint32_t opcode = 0, service_action = 0;
@@ -8632,8 +8661,9 @@ scsiopcodes(struct cam_device *device, int argc, char **argv,
goto bailout;
}
retval = scsigetopcodes(device, opcode_set, opcode, show_sa_errors,
- sa_set, service_action, td_set, retry_count,
- timeout, verbosemode, &valid_len, &buf);
+ sa_set, service_action, td_set, task_attr,
+ retry_count, timeout, verbosemode, &valid_len,
+ &buf);
if (retval != 0)
goto bailout;
@@ -8816,6 +8846,7 @@ usage(int printlong)
"-u unit specify unit number, e.g. \"0\", \"5\"\n"
"-E have the kernel attempt to perform SCSI error recovery\n"
"-C count specify the SCSI command retry count (needs -E to work)\n"
+"-Q task_attr specify ordered, simple or head tag type for SCSI cmds\n"
"modepage arguments:\n"
"-l list all available mode pages\n"
"-m page specify the mode page to view or edit\n"
@@ -8988,10 +9019,11 @@ main(int argc, char **argv)
int timeout = 0, retry_count = 1;
camcontrol_optret optreturn;
char *tstr;
- const char *mainopt = "C:En:t:u:v";
+ const char *mainopt = "C:En:Q:t:u:v";
const char *subopt = NULL;
char combinedopt[256];
int error = 0, optstart = 2;
+ int task_attr = MSG_SIMPLE_Q_TAG;
int devopen = 1;
#ifndef MINIMALISTIC
path_id_t bus;
@@ -9145,6 +9177,40 @@ main(int argc, char **argv)
tstr++;
device = (char *)strdup(tstr);
break;
+ case 'Q': {
+ char *endptr;
+ int table_entry = 0;
+
+ tstr = optarg;
+ while (isspace(*tstr) && (*tstr != '\0'))
+ tstr++;
+ if (isdigit(*tstr)) {
+ task_attr = strtol(tstr, &endptr, 0);
+ if (*endptr != '\0') {
+ errx(1, "Invalid queue option "
+ "%s", tstr);
+ }
+ } else {
+ size_t table_size;
+ scsi_nv_status status;
+
+ table_size = sizeof(task_attrs) /
+ sizeof(task_attrs[0]);
+ status = scsi_get_nv(task_attrs,
+ table_size, tstr, &table_entry,
+ SCSI_NV_FLAG_IG_CASE);
+ if (status == SCSI_NV_FOUND)
+ task_attr = task_attrs[
+ table_entry].value;
+ else {
+ errx(1, "%s option %s",
+ (status == SCSI_NV_AMBIGUOUS)?
+ "ambiguous" : "invalid",
+ tstr);
+ }
+ }
+ break;
+ }
case 't':
timeout = strtol(optarg, NULL, 0);
if (timeout < 0)
@@ -9210,19 +9276,20 @@ main(int argc, char **argv)
break;
#ifndef MINIMALISTIC
case CAM_CMD_TUR:
- error = testunitready(cam_dev, retry_count, timeout, 0);
+ error = testunitready(cam_dev, task_attr, retry_count,
+ timeout, 0);
break;
case CAM_CMD_INQUIRY:
error = scsidoinquiry(cam_dev, argc, argv, combinedopt,
- retry_count, timeout);
+ task_attr, retry_count, timeout);
break;
case CAM_CMD_IDENTIFY:
error = ataidentify(cam_dev, retry_count, timeout);
break;
case CAM_CMD_STARTSTOP:
error = scsistart(cam_dev, arglist & CAM_ARG_START_UNIT,
- arglist & CAM_ARG_EJECT, retry_count,
- timeout);
+ arglist & CAM_ARG_EJECT, task_attr,
+ retry_count, timeout);
break;
#endif /* MINIMALISTIC */
case CAM_CMD_RESCAN:
@@ -9234,15 +9301,15 @@ main(int argc, char **argv)
#ifndef MINIMALISTIC
case CAM_CMD_READ_DEFECTS:
error = readdefects(cam_dev, argc, argv, combinedopt,
- retry_count, timeout);
+ task_attr, retry_count, timeout);
break;
case CAM_CMD_MODE_PAGE:
modepage(cam_dev, argc, argv, combinedopt,
- retry_count, timeout);
+ task_attr, retry_count, timeout);
break;
case CAM_CMD_SCSI_CMD:
error = scsicmd(cam_dev, argc, argv, combinedopt,
- retry_count, timeout);
+ task_attr, retry_count, timeout);
break;
case CAM_CMD_SMP_CMD:
error = smpcmd(cam_dev, argc, argv, combinedopt,
@@ -9272,22 +9339,23 @@ main(int argc, char **argv)
error = tagcontrol(cam_dev, argc, argv, combinedopt);
break;
case CAM_CMD_RATE:
- error = ratecontrol(cam_dev, retry_count, timeout,
- argc, argv, combinedopt);
+ error = ratecontrol(cam_dev, task_attr, retry_count,
+ timeout, argc, argv, combinedopt);
break;
case CAM_CMD_FORMAT:
error = scsiformat(cam_dev, argc, argv,
- combinedopt, retry_count, timeout);
+ combinedopt, task_attr, retry_count,
+ timeout);
break;
case CAM_CMD_REPORTLUNS:
error = scsireportluns(cam_dev, argc, argv,
- combinedopt, retry_count,
- timeout);
+ combinedopt, task_attr,
+ retry_count, timeout);
break;
case CAM_CMD_READCAP:
error = scsireadcapacity(cam_dev, argc, argv,
- combinedopt, retry_count,
- timeout);
+ combinedopt, task_attr,
+ retry_count, timeout);
break;
case CAM_CMD_IDLE:
case CAM_CMD_STANDBY:
@@ -9306,25 +9374,30 @@ main(int argc, char **argv)
break;
case CAM_CMD_DOWNLOAD_FW:
error = fwdownload(cam_dev, argc, argv, combinedopt,
- arglist & CAM_ARG_VERBOSE, retry_count, timeout);
+ arglist & CAM_ARG_VERBOSE, task_attr, retry_count,
+ timeout);
break;
case CAM_CMD_SANITIZE:
error = scsisanitize(cam_dev, argc, argv,
- combinedopt, retry_count, timeout);
+ combinedopt, task_attr,
+ retry_count, timeout);
break;
case CAM_CMD_PERSIST:
error = scsipersist(cam_dev, argc, argv, combinedopt,
- retry_count, timeout, arglist & CAM_ARG_VERBOSE,
+ task_attr, retry_count, timeout,
+ arglist & CAM_ARG_VERBOSE,
arglist & CAM_ARG_ERR_RECOVER);
break;
case CAM_CMD_ATTRIB:
error = scsiattrib(cam_dev, argc, argv, combinedopt,
- retry_count, timeout, arglist & CAM_ARG_VERBOSE,
+ task_attr, retry_count, timeout,
+ arglist & CAM_ARG_VERBOSE,
arglist & CAM_ARG_ERR_RECOVER);
break;
case CAM_CMD_OPCODES:
error = scsiopcodes(cam_dev, argc, argv, combinedopt,
- retry_count, timeout, arglist & CAM_ARG_VERBOSE);
+ task_attr, retry_count, timeout,
+ arglist & CAM_ARG_VERBOSE);
break;
case CAM_CMD_REPROBE:
error = scsireprobe(cam_dev);
diff --git a/sbin/camcontrol/camcontrol.h b/sbin/camcontrol/camcontrol.h
index 3d6b98d..d4b76b5 100644
--- a/sbin/camcontrol/camcontrol.h
+++ b/sbin/camcontrol/camcontrol.h
@@ -71,29 +71,32 @@ void build_ata_cmd(union ccb *ccb, uint32_t retry_count, uint32_t flags,
camcontrol_devtype devtype);
int camxferrate(struct cam_device *device);
int fwdownload(struct cam_device *device, int argc, char **argv,
- char *combinedopt, int printerrors, int retry_count,
- int timeout);
+ char *combinedopt, int printerrors, int task_attr,
+ int retry_count, int timeout);
void mode_sense(struct cam_device *device, int dbd, int pc, int page,
- int subpage, int retry_count, int timeout, uint8_t *data,
- int datalen);
-void mode_select(struct cam_device *device, int save_pages, int retry_count,
- int timeout, u_int8_t *data, int datalen);
-void mode_edit(struct cam_device *device, int dbd, int pc, int page, int subpage,
- int edit, int binary, int retry_count, int timeout);
-void mode_list(struct cam_device *device, int dbd, int pc, int subpages,
+ int subpage, int task_attr, int retry_count, int timeout,
+ uint8_t *data, int datalen);
+void mode_select(struct cam_device *device, int save_pages, int task_attr,
+ int retry_count, int timeout, u_int8_t *data, int datalen);
+void mode_edit(struct cam_device *device, int dbd, int pc, int page,
+ int subpage, int edit, int binary, int task_attr,
int retry_count, int timeout);
+void mode_list(struct cam_device *device, int dbd, int pc, int subpages,
+ int task_attr, int retry_count, int timeout);
int scsidoinquiry(struct cam_device *device, int argc, char **argv,
- char *combinedopt, int retry_count, int timeout);
+ char *combinedopt, int task_attr, int retry_count,
+ int timeout);
int scsigetopcodes(struct cam_device *device, int opcode_set, int opcode,
int show_sa_errors, int sa_set, int service_action,
- int timeout_desc, int retry_count, int timeout,
- int verbosemode, uint32_t *fill_len, uint8_t **data_ptr);
+ int timeout_desc, int task_attr, int retry_count,
+ int timeout, int verbosemode, uint32_t *fill_len,
+ uint8_t **data_ptr);
int scsipersist(struct cam_device *device, int argc, char **argv,
- char *combinedopt, int retry_count, int timeout, int verbose,
- int err_recover);
+ char *combinedopt, int task_attr, int retry_count,
+ int timeout, int verbose, int err_recover);
int scsiattrib(struct cam_device *device, int argc, char **argv,
- char *combinedopt, int retry_count, int timeout, int verbose,
- int err_recover);
+ char *combinedopt, int task_attr, int retry_count, int timeout,
+ int verbose, int err_recover);
char *cget(void *hook, char *name);
int iget(void *hook, char *name);
void arg_put(void *hook, int letter, void *arg, int count, char *name);
diff --git a/sbin/camcontrol/fwdownload.c b/sbin/camcontrol/fwdownload.c
index 205cfd3..d587414 100644
--- a/sbin/camcontrol/fwdownload.c
+++ b/sbin/camcontrol/fwdownload.c
@@ -263,7 +263,7 @@ static const struct fw_timeout_desc fw_timeout_desc_table[] = {
static struct fw_vendor *fw_get_vendor(struct cam_device *cam_dev,
struct ata_params *ident_buf);
static int fw_get_timeout(struct cam_device *cam_dev, struct fw_vendor *vp,
- int retry_count, int timeout);
+ int task_attr, int retry_count, int timeout);
static int fw_validate_ibm(struct cam_device *dev, int retry_count,
int timeout, int fd, char *buf,
const char *fw_img_path, int quiet);
@@ -317,7 +317,7 @@ fw_get_vendor(struct cam_device *cam_dev, struct ata_params *ident_buf)
static int
fw_get_timeout(struct cam_device *cam_dev, struct fw_vendor *vp,
- int retry_count, int timeout)
+ int task_attr, int retry_count, int timeout)
{
struct scsi_report_supported_opcodes_one *one;
struct scsi_report_supported_opcodes_timeout *td;
@@ -349,6 +349,7 @@ fw_get_timeout(struct cam_device *cam_dev, struct fw_vendor *vp,
/*sa_set*/ 0,
/*service_action*/ 0,
/*timeout_desc*/ 1,
+ /*task_attr*/ task_attr,
/*retry_count*/ retry_count,
/*timeout*/ 10000,
/*verbose*/ 0,
@@ -901,7 +902,8 @@ bailout:
int
fwdownload(struct cam_device *device, int argc, char **argv,
- char *combinedopt, int printerrors, int retry_count, int timeout)
+ char *combinedopt, int printerrors, int task_attr, int retry_count,
+ int timeout)
{
struct fw_vendor *vp;
char *fw_img_path = NULL;
@@ -976,7 +978,7 @@ fwdownload(struct cam_device *device, int argc, char **argv,
&& (devtype == CC_DT_SCSI))
errx(1, "Unsupported device");
- retval = fw_get_timeout(device, vp, retry_count, timeout);
+ retval = fw_get_timeout(device, vp, task_attr, retry_count, timeout);
if (retval != 0) {
warnx("Unable to get a firmware download timeout value");
goto bailout;
@@ -994,8 +996,8 @@ fwdownload(struct cam_device *device, int argc, char **argv,
" into the following device:\n",
fw_img_path);
if (devtype == CC_DT_SCSI) {
- if (scsidoinquiry(device, argc, argv, combinedopt, 0,
- 5000) != 0) {
+ if (scsidoinquiry(device, argc, argv, combinedopt,
+ MSG_SIMPLE_Q_TAG, 0, 5000) != 0) {
warnx("Error sending inquiry");
retval = 1;
goto bailout;
diff --git a/sbin/camcontrol/modeedit.c b/sbin/camcontrol/modeedit.c
index 90862db..b636515 100644
--- a/sbin/camcontrol/modeedit.c
+++ b/sbin/camcontrol/modeedit.c
@@ -106,10 +106,11 @@ static int editentry_set(char *name, char *newvalue,
int editonly);
static void editlist_populate(struct cam_device *device, int dbd,
int pc, int page, int subpage,
- int retries, int timeout);
+ int task_attr, int retries,
+ int timeout);
static void editlist_save(struct cam_device *device, int dbd,
int pc, int page, int subpage,
- int retries, int timeout);
+ int task_attr, int retries, int timeout);
static void nameentry_create(int page, int subpage, char *name);
static struct pagename *nameentry_lookup(int page, int subpage);
static int load_format(const char *pagedb_path, int lpage,
@@ -118,8 +119,8 @@ static int modepage_write(FILE *file, int editonly);
static int modepage_read(FILE *file);
static void modepage_edit(void);
static void modepage_dump(struct cam_device *device, int dbd,
- int pc, int page, int subpage, int retries,
- int timeout);
+ int pc, int page, int subpage, int task_attr,
+ int retries, int timeout);
static void cleanup_editfile(void);
@@ -550,7 +551,7 @@ load_format(const char *pagedb_path, int lpage, int lsubpage)
static void
editlist_populate(struct cam_device *device, int dbd, int pc, int page,
- int subpage, int retries, int timeout)
+ int subpage, int task_attr, int retries, int timeout)
{
u_int8_t data[MAX_COMMAND_SIZE];/* Buffer to hold sense data. */
u_int8_t *mode_pars; /* Pointer to modepage params. */
@@ -562,8 +563,8 @@ editlist_populate(struct cam_device *device, int dbd, int pc, int page,
STAILQ_INIT(&editlist);
/* Fetch changeable values; use to build initial editlist. */
- mode_sense(device, dbd, 1, page, subpage, retries, timeout, data,
- sizeof(data));
+ mode_sense(device, dbd, 1, page, subpage, task_attr, retries, timeout,
+ data, sizeof(data));
mh = (struct scsi_mode_header_6 *)data;
mph = MODE_PAGE_HEADER(mh);
@@ -581,14 +582,14 @@ editlist_populate(struct cam_device *device, int dbd, int pc, int page,
buff_decode_visit(mode_pars, len, format, editentry_create, 0);
/* Fetch the current/saved values; use to set editentry values. */
- mode_sense(device, dbd, pc, page, subpage, retries, timeout,
+ mode_sense(device, dbd, pc, page, subpage, task_attr, retries, timeout,
data, sizeof(data));
buff_decode_visit(mode_pars, len, format, editentry_update, 0);
}
static void
editlist_save(struct cam_device *device, int dbd, int pc, int page,
- int subpage, int retries, int timeout)
+ int subpage, int task_attr, int retries, int timeout)
{
u_int8_t data[MAX_COMMAND_SIZE];/* Buffer to hold sense data. */
u_int8_t *mode_pars; /* Pointer to modepage params. */
@@ -602,7 +603,7 @@ editlist_save(struct cam_device *device, int dbd, int pc, int page,
return;
/* Preload the CDB buffer with the current mode page data. */
- mode_sense(device, dbd, pc, page, subpage, retries, timeout,
+ mode_sense(device, dbd, pc, page, subpage, task_attr, retries, timeout,
data, sizeof(data));
/* Initial headers & offsets. */
@@ -639,7 +640,8 @@ editlist_save(struct cam_device *device, int dbd, int pc, int page,
* recorded.
*/
mode_select(device, (pc << PAGE_CTRL_SHIFT == SMS_PAGE_CTRL_SAVED),
- retries, timeout, (u_int8_t *)mh, sizeof(*mh) + hlen + len);
+ task_attr, retries, timeout, (u_int8_t *)mh,
+ sizeof(*mh) + hlen + len);
}
static int
@@ -809,7 +811,7 @@ modepage_edit(void)
static void
modepage_dump(struct cam_device *device, int dbd, int pc, int page, int subpage,
- int retries, int timeout)
+ int task_attr, int retries, int timeout)
{
u_int8_t data[MAX_COMMAND_SIZE];/* Buffer to hold sense data. */
u_int8_t *mode_pars; /* Pointer to modepage params. */
@@ -818,7 +820,7 @@ modepage_dump(struct cam_device *device, int dbd, int pc, int page, int subpage,
struct scsi_mode_page_header_sp *mphsp;
size_t indx, len;
- mode_sense(device, dbd, pc, page, subpage, retries, timeout,
+ mode_sense(device, dbd, pc, page, subpage, task_attr, retries, timeout,
data, sizeof(data));
mh = (struct scsi_mode_header_6 *)data;
@@ -853,7 +855,7 @@ cleanup_editfile(void)
void
mode_edit(struct cam_device *device, int dbd, int pc, int page, int subpage,
- int edit, int binary, int retry_count, int timeout)
+ int edit, int binary, int task_attr, int retry_count, int timeout)
{
const char *pagedb_path; /* Path to modepage database. */
@@ -884,8 +886,8 @@ mode_edit(struct cam_device *device, int dbd, int pc, int page, int subpage,
exit(EX_OSFILE);
}
- editlist_populate(device, dbd, pc, page, subpage, retry_count,
- timeout);
+ editlist_populate(device, dbd, pc, page, subpage, task_attr,
+ retry_count, timeout);
}
if (edit) {
@@ -894,10 +896,12 @@ mode_edit(struct cam_device *device, int dbd, int pc, int page, int subpage,
errx(EX_USAGE, "it only makes sense to edit page 0 "
"(current) or page 3 (saved values)");
modepage_edit();
- editlist_save(device, dbd, pc, page, subpage, retry_count, timeout);
+ editlist_save(device, dbd, pc, page, subpage, task_attr,
+ retry_count, timeout);
} else if (binary || STAILQ_EMPTY(&editlist)) {
/* Display without formatting information. */
- modepage_dump(device, dbd, pc, page, subpage, retry_count, timeout);
+ modepage_dump(device, dbd, pc, page, subpage, task_attr,
+ retry_count, timeout);
} else {
/* Display with format. */
modepage_write(stdout, 0);
@@ -906,7 +910,7 @@ mode_edit(struct cam_device *device, int dbd, int pc, int page, int subpage,
void
mode_list(struct cam_device *device, int dbd, int pc, int subpages,
- int retry_count, int timeout)
+ int task_attr, int retry_count, int timeout)
{
u_int8_t data[MAX_COMMAND_SIZE];/* Buffer to hold sense data. */
struct scsi_mode_header_6 *mh; /* Location of mode header. */
@@ -927,7 +931,7 @@ mode_list(struct cam_device *device, int dbd, int pc, int subpages,
/* Build the list of all mode pages by querying the "all pages" page. */
mode_sense(device, dbd, pc, SMS_ALL_PAGES_PAGE,
subpages ? SMS_SUBPAGE_ALL : 0,
- retry_count, timeout, data, sizeof(data));
+ task_attr, retry_count, timeout, data, sizeof(data));
mh = (struct scsi_mode_header_6 *)data;
len = sizeof(*mh) + mh->blk_desc_len; /* Skip block descriptors. */
diff --git a/sbin/camcontrol/persist.c b/sbin/camcontrol/persist.c
index 089216f..812c524 100644
--- a/sbin/camcontrol/persist.c
+++ b/sbin/camcontrol/persist.c
@@ -423,7 +423,8 @@ persist_print_full(struct scsi_per_res_in_header *hdr, uint32_t valid_len)
int
scsipersist(struct cam_device *device, int argc, char **argv, char *combinedopt,
- int retry_count, int timeout, int verbosemode, int err_recover)
+ int task_attr, int retry_count, int timeout, int verbosemode,
+ int err_recover)
{
union ccb *ccb = NULL;
int c, in = 0, out = 0;
@@ -756,7 +757,7 @@ retry:
scsi_persistent_reserve_in(&ccb->csio,
/*retries*/ retry_count,
/*cbfcnp*/ NULL,
- /*tag_action*/ MSG_SIMPLE_Q_TAG,
+ /*tag_action*/ task_attr,
/*service_action*/ action,
/*data_ptr*/ res_buf,
/*dxfer_len*/ res_len,
@@ -838,7 +839,7 @@ retry:
scsi_persistent_reserve_out(&ccb->csio,
/*retries*/ retry_count,
/*cbfcnp*/ NULL,
- /*tag_action*/ MSG_SIMPLE_Q_TAG,
+ /*tag_action*/ task_attr,
/*service_action*/ action,
/*scope*/ scope,
/*res_type*/ res_type,
OpenPOWER on IntegriCloud