Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 17 Feb 2017 20:04:23 +0000 (UTC)
From:      "Kenneth D. Merry" <ken@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r313893 - head/sbin/camcontrol
Message-ID:  <201702172004.v1HK4NWl087687@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: ken
Date: Fri Feb 17 20:04:22 2017
New Revision: 313893
URL: https://svnweb.freebsd.org/changeset/base/313893

Log:
  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
  MFC after:	1 week

Modified:
  head/sbin/camcontrol/attrib.c
  head/sbin/camcontrol/camcontrol.8
  head/sbin/camcontrol/camcontrol.c
  head/sbin/camcontrol/camcontrol.h
  head/sbin/camcontrol/fwdownload.c
  head/sbin/camcontrol/modeedit.c
  head/sbin/camcontrol/persist.c
  head/sbin/camcontrol/timestamp.c
  head/sbin/camcontrol/zone.c

Modified: head/sbin/camcontrol/attrib.c
==============================================================================
--- head/sbin/camcontrol/attrib.c	Fri Feb 17 20:02:40 2017	(r313892)
+++ head/sbin/camcontrol/attrib.c	Fri Feb 17 20:04:22 2017	(r313893)
@@ -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, in
 		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,

Modified: head/sbin/camcontrol/camcontrol.8
==============================================================================
--- head/sbin/camcontrol/camcontrol.8	Fri Feb 17 20:02:40 2017	(r313892)
+++ head/sbin/camcontrol/camcontrol.8	Fri Feb 17 20:04:22 2017	(r313893)
@@ -27,7 +27,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd January 20, 2017
+.Dd February 17, 2017
 .Dt CAMCONTROL 8
 .Os
 .Sh NAME
@@ -422,6 +422,17 @@ It may take some other actions, dependin
 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
@@ -2523,7 +2534,7 @@ information if the command fails since t
 .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.
@@ -2536,6 +2547,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

Modified: head/sbin/camcontrol/camcontrol.c
==============================================================================
--- head/sbin/camcontrol/camcontrol.c	Fri Feb 17 20:02:40 2017	(r313892)
+++ head/sbin/camcontrol/camcontrol.c	Fri Feb 17 20:04:22 2017	(r313893)
@@ -171,6 +171,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:";
@@ -265,12 +273,14 @@ static int getdevlist(struct cam_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);
@@ -280,11 +290,14 @@ static int scanlun_or_reset_dev(path_id_
     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,
@@ -309,16 +322,21 @@ static int get_cpi(struct cam_device *de
 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,
@@ -331,8 +349,8 @@ static int scsiprintoneopcode(struct cam
 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 */
@@ -650,8 +668,8 @@ getdevtree(int argc, char **argv, char *
 
 #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;
@@ -661,7 +679,7 @@ testunitready(struct cam_device *device,
 	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);
 
@@ -705,7 +723,7 @@ testunitready(struct cam_device *device,
 
 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;
@@ -716,13 +734,19 @@ scsistart(struct cam_device *device, int
 	 * 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,
@@ -783,7 +807,7 @@ scsistart(struct cam_device *device, int
 
 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;
@@ -812,13 +836,13 @@ scsidoinquiry(struct cam_device *device,
 		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);
@@ -827,7 +851,8 @@ scsidoinquiry(struct cam_device *device,
 }
 
 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;
@@ -889,7 +914,7 @@ scsiinquiry(struct cam_device *device, i
 	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,
@@ -941,7 +966,8 @@ scsiinquiry(struct cam_device *device, i
 }
 
 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;
@@ -970,7 +996,7 @@ scsiserial(struct cam_device *device, in
 	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,
@@ -3405,7 +3431,7 @@ static struct scsi_nv defect_list_type_m
 
 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;
@@ -3547,7 +3573,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,
@@ -3985,7 +4011,8 @@ reassignblocks(struct cam_device *device
 #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;
@@ -4000,7 +4027,7 @@ mode_sense(struct cam_device *device, in
 	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,
@@ -4035,8 +4062,8 @@ mode_sense(struct cam_device *device, in
 }
 
 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;
@@ -4051,7 +4078,7 @@ mode_select(struct cam_device *device, i
 	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,
@@ -4086,7 +4113,7 @@ mode_select(struct cam_device *device, i
 
 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;
@@ -4133,16 +4160,17 @@ modepage(struct cam_device *device, int 
 		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;
@@ -4387,7 +4415,7 @@ scsicmd(struct cam_device *device, int a
 		      /*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,
@@ -5498,8 +5526,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;
@@ -5829,7 +5857,7 @@ ratecontrol(struct cam_device *device, i
 		}
 	}
 	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.
@@ -5854,7 +5882,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;
@@ -5903,7 +5931,7 @@ scsiformat(struct cam_device *device, in
 			"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");
@@ -5975,7 +6003,7 @@ scsiformat(struct cam_device *device, in
 	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,
@@ -6034,7 +6062,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);
 
@@ -6144,7 +6172,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;
@@ -6309,7 +6337,7 @@ scsisanitize(struct cam_device *device, 
 			"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");
@@ -6367,7 +6395,7 @@ scsisanitize(struct cam_device *device, 
 	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,
@@ -6442,7 +6470,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);
 
@@ -6554,7 +6582,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;
@@ -6631,7 +6659,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,
@@ -6796,7 +6824,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;
@@ -6882,7 +6910,7 @@ scsireadcapacity(struct cam_device *devi
 	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);
@@ -6924,7 +6952,7 @@ scsireadcapacity(struct cam_device *devi
 	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,
@@ -8365,8 +8393,8 @@ ataaxm(struct cam_device *device, int ar
 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;
@@ -8433,7 +8461,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,
@@ -8733,7 +8761,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;
@@ -8797,8 +8826,9 @@ scsiopcodes(struct cam_device *device, i
 		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;
 
@@ -8992,6 +9022,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"
@@ -9196,10 +9227,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;
@@ -9353,6 +9385,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)
@@ -9418,19 +9484,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:
@@ -9442,15 +9509,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,
@@ -9480,22 +9547,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:
@@ -9514,32 +9582,38 @@ 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);
 			break;
 		case CAM_CMD_ZONE:
 			error = zone(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_EPC:
 			error = epc(cam_dev, argc, argv, combinedopt,
@@ -9547,7 +9621,8 @@ main(int argc, char **argv)
 			break;
 		case CAM_CMD_TIMESTAMP:
 			error = timestamp(cam_dev, argc, argv, combinedopt,
-			    retry_count, timeout, arglist & CAM_ARG_VERBOSE);
+			    task_attr, retry_count, timeout,
+			    arglist & CAM_ARG_VERBOSE);
 			break;
 #endif /* MINIMALISTIC */
 		case CAM_CMD_USAGE:

Modified: head/sbin/camcontrol/camcontrol.h
==============================================================================
--- head/sbin/camcontrol/camcontrol.h	Fri Feb 17 20:02:40 2017	(r313892)
+++ head/sbin/camcontrol/camcontrol.h	Fri Feb 17 20:04:22 2017	(r313893)
@@ -75,36 +75,39 @@ int get_ata_status(struct cam_device *de
 		   uint8_t *status);
 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);
 int zone(struct cam_device *device, int argc, char **argv, char *combinedopt,
-	 int retry_count, int timeout, int verbosemode);
+	 int task_attr, int retry_count, int timeout, int verbosemode);
 int epc(struct cam_device *device, int argc, char **argv, char *combinedopt,
 	int retry_count, int timeout, int verbosemode);
 int timestamp(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 verbosemode);
 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);

Modified: head/sbin/camcontrol/fwdownload.c
==============================================================================
--- head/sbin/camcontrol/fwdownload.c	Fri Feb 17 20:02:40 2017	(r313892)
+++ head/sbin/camcontrol/fwdownload.c	Fri Feb 17 20:04:22 2017	(r313893)
@@ -263,7 +263,7 @@ static const struct fw_timeout_desc fw_t
 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
 
 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_de
 				/*sa_set*/ 0,
 				/*service_action*/ 0,
 				/*timeout_desc*/ 1,
+				/*task_attr*/ task_attr,
 				/*retry_count*/ retry_count,
 				/*timeout*/ 10000,
 				/*verbose*/ 0,
@@ -919,7 +920,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;
@@ -994,7 +996,7 @@ fwdownload(struct cam_device *device, in
 	 && (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;
@@ -1012,8 +1014,8 @@ fwdownload(struct cam_device *device, in
 		    " 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;

Modified: head/sbin/camcontrol/modeedit.c
==============================================================================
--- head/sbin/camcontrol/modeedit.c	Fri Feb 17 20:02:40 2017	(r313892)
+++ head/sbin/camcontrol/modeedit.c	Fri Feb 17 20:04:22 2017	(r313893)
@@ -106,10 +106,11 @@ static int		 editentry_set(char *name, c
 				       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, 
 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
 
 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 *dev
 	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 *dev
 	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,
 		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,
 	 * 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,
 	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
 				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
 			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);

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201702172004.v1HK4NWl087687>