svn commit: r217947 - in projects/graid/7: lib/libcam sbin/camcontrol sys/cam sys/cam/ata sys/cam/scsi sys/conf sys/dev/ahci sys/dev/ata sys/dev/ata/chipsets sys/dev/siis sys/modules/cam

Alexander Motin mav at FreeBSD.org
Thu Jan 27 16:47:33 UTC 2011


Author: mav
Date: Thu Jan 27 16:47:33 2011
New Revision: 217947
URL: http://svn.freebsd.org/changeset/base/217947

Log:
  Resync ATA and CAM stuff with HEAD.

Modified:
  projects/graid/7/lib/libcam/Makefile
  projects/graid/7/sbin/camcontrol/camcontrol.8
  projects/graid/7/sbin/camcontrol/camcontrol.c
  projects/graid/7/sys/cam/ata/ata_xpt.c
  projects/graid/7/sys/cam/cam.c
  projects/graid/7/sys/cam/cam.h
  projects/graid/7/sys/cam/cam_ccb.h
  projects/graid/7/sys/cam/cam_periph.c
  projects/graid/7/sys/cam/cam_xpt.c
  projects/graid/7/sys/cam/cam_xpt_internal.h
  projects/graid/7/sys/cam/scsi/scsi_all.c
  projects/graid/7/sys/cam/scsi/scsi_all.h
  projects/graid/7/sys/cam/scsi/scsi_low.h
  projects/graid/7/sys/cam/scsi/scsi_pass.c
  projects/graid/7/sys/cam/scsi/scsi_target.c
  projects/graid/7/sys/cam/scsi/scsi_xpt.c
  projects/graid/7/sys/conf/files
  projects/graid/7/sys/dev/ahci/ahci.c
  projects/graid/7/sys/dev/ata/ata-all.c
  projects/graid/7/sys/dev/ata/ata-all.h
  projects/graid/7/sys/dev/ata/ata-disk.c
  projects/graid/7/sys/dev/ata/ata-dma.c
  projects/graid/7/sys/dev/ata/ata-lowlevel.c
  projects/graid/7/sys/dev/ata/ata-pci.h
  projects/graid/7/sys/dev/ata/ata-sata.c
  projects/graid/7/sys/dev/ata/chipsets/ata-ahci.c
  projects/graid/7/sys/dev/ata/chipsets/ata-cyrix.c
  projects/graid/7/sys/dev/ata/chipsets/ata-intel.c
  projects/graid/7/sys/dev/ata/chipsets/ata-marvell.c
  projects/graid/7/sys/dev/ata/chipsets/ata-national.c
  projects/graid/7/sys/dev/ata/chipsets/ata-promise.c
  projects/graid/7/sys/dev/ata/chipsets/ata-serverworks.c
  projects/graid/7/sys/dev/ata/chipsets/ata-siliconimage.c
  projects/graid/7/sys/dev/ata/chipsets/ata-via.c
  projects/graid/7/sys/dev/siis/siis.c
  projects/graid/7/sys/dev/siis/siis.h
  projects/graid/7/sys/modules/cam/Makefile

Modified: projects/graid/7/lib/libcam/Makefile
==============================================================================
--- projects/graid/7/lib/libcam/Makefile	Thu Jan 27 16:10:25 2011	(r217946)
+++ projects/graid/7/lib/libcam/Makefile	Thu Jan 27 16:47:33 2011	(r217947)
@@ -3,7 +3,7 @@
 LIB=		cam
 SHLIBDIR?=	/lib
 SRCS=		camlib.c scsi_cmdparse.c scsi_all.c scsi_da.c scsi_sa.c cam.c \
-		ata_all.c
+		ata_all.c smp_all.c
 INCS=		camlib.h
 
 DPADD=		${LIBSBUF}

Modified: projects/graid/7/sbin/camcontrol/camcontrol.8
==============================================================================
--- projects/graid/7/sbin/camcontrol/camcontrol.8	Thu Jan 27 16:10:25 2011	(r217946)
+++ projects/graid/7/sbin/camcontrol/camcontrol.8	Thu Jan 27 16:47:33 2011	(r217947)
@@ -27,7 +27,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd July 1, 2010
+.Dd November 30, 2010
 .Dt CAMCONTROL 8
 .Os
 .Sh NAME
@@ -131,6 +131,43 @@
 .Op Fl r Ar fmt
 .Ek
 .Nm
+.Ic smpcmd
+.Op device id
+.Op generic args
+.Aq Fl r Ar len Ar fmt Op args
+.Aq Fl R Ar len Ar fmt Op args
+.Nm
+.Ic smprg
+.Op device id
+.Op generic args
+.Op Fl l
+.Nm
+.Ic smppc
+.Op device id
+.Op generic args
+.Aq Fl p Ar phy
+.Op Fl l
+.Op Fl o Ar operation
+.Op Fl d Ar name
+.Op Fl m Ar rate
+.Op Fl M Ar rate
+.Op Fl T Ar pp_timeout
+.Op Fl a Ar enable|disable
+.Op Fl A Ar enable|disable
+.Op Fl s Ar enable|disable
+.Op Fl S Ar enable|disable
+.Nm
+.Ic smpphylist
+.Op device id
+.Op generic args
+.Op Fl l
+.Op Fl q
+.Nm
+.Ic smpmaninfo
+.Op device id
+.Op generic args
+.Op Fl l
+.Nm
 .Ic debug
 .Op Fl I
 .Op Fl P
@@ -207,9 +244,6 @@ A device identifier can take one of thre
 .Bl -tag -width 14n
 .It deviceUNIT
 Specify a device name and unit number combination, like "da5" or "cd3".
-Note that character device node names (e.g.\& /dev/da0) are
-.Em not
-allowed here.
 .It bus:target
 Specify a bus number and target id.
 The bus number can be determined from
@@ -557,6 +591,177 @@ If the format is
 .Sq - ,
 11 result registers will be written to standard output in hex.
 .El
+.It Ic smpcmd
+Allows the user to send an arbitrary Serial 
+Management Protocol (SMP) command to a device.
+The
+.Ic smpcmd
+function requires the
+.Fl r
+argument to specify the SMP request to be sent, and the
+.Fl R
+argument to specify the format of the SMP response.
+The syntax for the SMP request and response arguments is documented in
+.Xr cam_cdbparse 3 .
+.Pp
+Note that SAS adapters that support SMP passthrough (at least the currently
+known adapters) do not accept CRC bytes from the user in the request and do
+not pass CRC bytes back to the user in the response.
+Therefore users should not include the CRC bytes in the length of the
+request and not expect CRC bytes to be returned in the response.
+.Bl -tag -width 17n
+.It Fl r Ar len Ar fmt Op args
+This specifies the size of the SMP request, without the CRC bytes, and the
+SMP request format.  If the format is
+.Sq - ,
+.Ar len
+bytes of data will be read from standard input and written as the SMP
+request.
+.It Fl R Ar len Ar fmt Op args
+This specifies the size of the buffer allocated for the SMP response, and
+the SMP response format.
+If the format is
+.Sq - ,
+.Ar len
+bytes of data will be allocated for the response and the response will be
+written to standard output.
+.El
+.It Ic smprg
+Allows the user to send the Serial Management Protocol (SMP) Report General
+command to a device.
+.Nm
+will display the data returned by the Report General command.
+If the SMP target supports the long response format, the additional data
+will be requested and displayed automatically.
+.Bl -tag -width 8n
+.It Fl l
+Request the long response format only.
+Not all SMP targets support the long response format.
+This option causes
+.Nm
+to skip sending the initial report general request without the long bit set
+and only issue a report general request with the long bit set.
+.El
+.It Ic smppc
+Allows the user to issue the Serial Management Protocol (SMP) PHY Control
+command to a device.
+This function should be used with some caution, as it can render devices
+inaccessible, and could potentially cause data corruption as well.
+The
+.Fl p
+argument is required to specify the PHY to operate on.
+.Bl -tag -width 17n
+.It Fl p Ar phy
+Specify the PHY to operate on.
+This argument is required. 
+.It Fl l
+Request the long request/response format.
+Not all SMP targets support the long response format.
+For the PHY Control command, this currently only affects whether the
+request length is set to a value other than 0.
+.It Fl o Ar operation
+Specify a PHY control operation.
+Only one
+.Fl o
+operation may be specified.
+The operation may be specified numerically (in decimal, hexadecimal, or octal)
+or one of the following operation names may be specified:
+.Bl -tag -width 16n
+.It nop
+No operation.
+It is not necessary to specify this argument.
+.It linkreset
+Send the LINK RESET command to the phy.
+.It hardreset
+Send the HARD RESET command to the phy.
+.It disable
+Send the DISABLE command to the phy.
+Note that the LINK RESET or HARD RESET commands should re-enable the phy.
+.It clearerrlog
+Send the CLEAR ERROR LOG command.
+This clears the error log counters for the specified phy.
+.It clearaffiliation
+Send the CLEAR AFFILIATION command.
+This clears the affiliation from the STP initiator port with the same SAS
+address as the SMP initiator that requests the clear operation.
+.It sataportsel
+Send the TRANSMIT SATA PORT SELECTION SIGNAL command to the phy.
+This will cause a SATA port selector to use the given phy as its active phy
+and make the other phy inactive.
+.It clearitnl
+Send the CLEAR STP I_T NEXUS LOSS command to the PHY.
+.It setdevname
+Send the SET ATTACHED DEVICE NAME command to the PHY.
+This requires the
+.Fl d
+argument to specify the device name.
+.El
+.It Fl d Ar name
+Specify the attached device name.
+This option is needed with the
+.Fl o Ar setdevname
+phy operation.
+The name is a 64-bit number, and can be specified in decimal, hexadecimal
+or octal format.
+.It Fl m Ar rate
+Set the minimum physical link rate for the phy.
+This is a numeric argument.
+Currently known link rates are:
+.Bl -tag -width 5n
+.It 0x0
+Do not change current value.
+.It 0x8
+1.5 Gbps
+.It 0x9
+3 Gbps
+.It 0xa
+6 Gbps
+.El
+.Pp
+Other values may be specified for newer physical link rates.
+.It Fl M Ar rate
+Set the maximum physical link rate for the phy.
+This is a numeric argument.
+See the
+.Fl m
+argument description for known link rate arguments.
+.It Fl T Ar pp_timeout
+Set the partial pathway timeout value, in microseconds.
+See the
+.Tn ANSI
+.Tn SAS
+Protcol Layer (SPL)
+specification for more information on this field.
+.It Fl a Ar enable|disable
+Enable or disable SATA slumber phy power conditions.
+.It Fl A Ar enable|disable
+Enable or disable SATA partial power conditions.
+.It Fl s Ar enable|disable
+Enable or disable SAS slumber phy power conditions.
+.It Fl S Ar enable|disable
+Enable or disable SAS partial phy power conditions.
+.El
+.It Ic smpphylist
+List phys attached to a SAS expander, the address of the end device
+attached to the phy, and the inquiry data for that device and peripheral
+devices attached to that device.
+The inquiry data and peripheral devices are displayed if available.
+.Bl -tag -width 5n
+.It Fl l
+Turn on the long response format for the underlying SMP commands used for
+this command.
+.It Fl q
+Only print out phys that are attached to a device in the CAM EDT (Existing
+Device Table).
+.El
+.It Ic smpmaninfo
+Send the SMP Report Manufacturer Information command to the device and
+display the response.
+.Bl -tag -width 5n
+.It Fl l
+Turn on the long response format for the underlying SMP commands used for
+this command.
+.El
 .It Ic debug
 Turn on CAM debugging printfs in the kernel.
 This requires options CAMDEBUG
@@ -800,7 +1005,6 @@ The
 and
 .Fl y
 arguments can be useful for scripts.
-.Pp
 .Bl -tag -width 6n
 .It Fl q
 Be quiet, do not print any status messages.
@@ -893,7 +1097,6 @@ utility will report whether the disk is 
 information if the command fails since the
 .Fl v
 switch was not specified.
-.Pp
 .Bd -literal -offset indent
 camcontrol tur da1 -E -C 4 -t 50 -v
 .Ed
@@ -920,7 +1123,6 @@ Display the buffer size of cd1,
 and display the first 10 bytes from the cache on cd1.
 Display SCSI sense
 information if the command fails.
-.Pp
 .Bd -literal -offset indent
 camcontrol cmd -n cd -u 1 -v -c "3B 00 00 00 00 00 00 00 0e 00" \e
 	-o 14 "00 00 00 00 1 2 3 4 5 6 v v v v" 7 8 9 8
@@ -933,7 +1135,6 @@ Print out sense information if
 the command fails.
 Be very careful with this command, improper use may
 cause data corruption.
-.Pp
 .Bd -literal -offset indent
 camcontrol modepage da3 -m 1 -e -P 3
 .Ed
@@ -960,13 +1161,11 @@ changed.
 .Dl camcontrol tags da5 -N 24
 .Pp
 Set the number of concurrent transactions for da5 to 24.
-.Pp
 .Bd -literal -offset indent
 camcontrol negotiate -n da -u 4 -T disable
 .Ed
 .Pp
 Disable tagged queueing for da4.
-.Pp
 .Bd -literal -offset indent
 camcontrol negotiate -n da -u 3 -R 20.000 -O 15 -a
 .Ed
@@ -974,6 +1173,14 @@ camcontrol negotiate -n da -u 3 -R 20.00
 Negotiate a sync rate of 20MHz and an offset of 15 with da3.
 Then send a
 Test Unit Ready command to make the settings take effect.
+.Pp
+.Bd -literal -offset indent
+camcontrol smpcmd ses0 -v -r 4 "40 0 00 0" -R 1020 "s9 i1"
+.Ed
+.Pp
+Send the SMP REPORT GENERAL command to ses0, and display the number of PHYs
+it contains.
+Display SMP errors if the command fails.
 .Sh SEE ALSO
 .Xr cam 3 ,
 .Xr cam_cdbparse 3 ,

Modified: projects/graid/7/sbin/camcontrol/camcontrol.c
==============================================================================
--- projects/graid/7/sbin/camcontrol/camcontrol.c	Thu Jan 27 16:10:25 2011	(r217946)
+++ projects/graid/7/sbin/camcontrol/camcontrol.c	Thu Jan 27 16:47:33 2011	(r217947)
@@ -33,11 +33,14 @@ __FBSDID("$FreeBSD$");
 #include <sys/stdint.h>
 #include <sys/types.h>
 #include <sys/endian.h>
+#include <sys/sbuf.h>
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <inttypes.h>
+#include <limits.h>
 #include <fcntl.h>
 #include <ctype.h>
 #include <err.h>
@@ -50,6 +53,7 @@ __FBSDID("$FreeBSD$");
 #include <cam/scsi/scsi_da.h>
 #include <cam/scsi/scsi_pass.h>
 #include <cam/scsi/scsi_message.h>
+#include <cam/scsi/smp_all.h>
 #include <cam/ata/ata_all.h>
 #include <camlib.h>
 #include "camcontrol.h"
@@ -77,7 +81,12 @@ typedef enum {
 	CAM_CMD_IDENTIFY	= 0x00000013,
 	CAM_CMD_IDLE		= 0x00000014,
 	CAM_CMD_STANDBY		= 0x00000015,
-	CAM_CMD_SLEEP		= 0x00000016
+	CAM_CMD_SLEEP		= 0x00000016,
+	CAM_CMD_SMP_CMD		= 0x00000017,
+	CAM_CMD_SMP_RG		= 0x00000018,
+	CAM_CMD_SMP_PC		= 0x00000019,
+	CAM_CMD_SMP_PHYLIST	= 0x0000001a,
+	CAM_CMD_SMP_MANINFO	= 0x0000001b
 } cam_cmdmask;
 
 typedef enum {
@@ -117,7 +126,7 @@ typedef enum {
 
 struct camcontrol_opts {
 	const char	*optname;
-	cam_cmdmask	cmdnum;
+	uint32_t	cmdnum;
 	cam_argmask	argnum;
 	const char	*subopt;
 };
@@ -126,6 +135,9 @@ struct camcontrol_opts {
 static const char scsicmd_opts[] = "a:c:dfi:o:r";
 static const char readdefect_opts[] = "f:GP";
 static const char negotiate_opts[] = "acD:M:O:qR:T:UW:";
+static const char smprg_opts[] = "l";
+static const char smppc_opts[] = "a:A:d:lm:M:o:p:s:S:T:";
+static const char smpphylist_opts[] = "lq";
 #endif
 
 struct camcontrol_opts option_table[] = {
@@ -145,6 +157,14 @@ struct camcontrol_opts option_table[] = 
 #ifndef MINIMALISTIC
 	{"cmd", CAM_CMD_SCSI_CMD, CAM_ARG_NONE, scsicmd_opts},
 	{"command", CAM_CMD_SCSI_CMD, CAM_ARG_NONE, scsicmd_opts},
+	{"smpcmd", CAM_CMD_SMP_CMD, CAM_ARG_NONE, "r:R:"},
+	{"smprg", CAM_CMD_SMP_RG, CAM_ARG_NONE, smprg_opts},
+	{"smpreportgeneral", CAM_CMD_SMP_RG, CAM_ARG_NONE, smprg_opts},
+	{"smppc", CAM_CMD_SMP_PC, CAM_ARG_NONE, smppc_opts},
+	{"smpphycontrol", CAM_CMD_SMP_PC, CAM_ARG_NONE, smppc_opts},
+	{"smpplist", CAM_CMD_SMP_PHYLIST, CAM_ARG_NONE, smpphylist_opts},
+	{"smpphylist", CAM_CMD_SMP_PHYLIST, CAM_ARG_NONE, smpphylist_opts},
+	{"smpmaninfo", CAM_CMD_SMP_MANINFO, CAM_ARG_NONE, "l"},
 	{"defects", CAM_CMD_READ_DEFECTS, CAM_ARG_NONE, readdefect_opts},
 	{"defectlist", CAM_CMD_READ_DEFECTS, CAM_ARG_NONE, readdefect_opts},
 #endif /* MINIMALISTIC */
@@ -173,11 +193,25 @@ typedef enum {
 	CC_OR_FOUND
 } camcontrol_optret;
 
+struct cam_devitem {
+	struct device_match_result dev_match;
+	int num_periphs;
+	struct periph_match_result *periph_matches;
+	struct scsi_vpd_device_id *device_id;
+	int device_id_len;
+	STAILQ_ENTRY(cam_devitem) links;
+};
+
+struct cam_devlist {
+	STAILQ_HEAD(, cam_devitem) dev_queue;
+	path_id_t path_id;
+};
+
 cam_cmdmask cmdlist;
 cam_argmask arglist;
 
-
-camcontrol_optret getoption(char *arg, cam_cmdmask *cmdnum, cam_argmask *argnum,
+camcontrol_optret getoption(struct camcontrol_opts *table, char *arg,
+			    uint32_t *cmdnum, cam_argmask *argnum,
 			    const char **subopt);
 #ifndef MINIMALISTIC
 static int getdevlist(struct cam_device *device);
@@ -206,6 +240,21 @@ static void modepage(struct cam_device *
 		     char *combinedopt, int retry_count, int timeout);
 static int scsicmd(struct cam_device *device, int argc, char **argv,
 		   char *combinedopt, 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,
+			    char *combinedopt, int retry_count, int timeout);
+static int smpphycontrol(struct cam_device *device, int argc, char **argv,
+			 char *combinedopt, int retry_count, int timeout);
+static int smpmaninfo(struct cam_device *device, int argc, char **argv,
+		      char *combinedopt, int retry_count, int timeout);
+static int getdevid(struct cam_devitem *item);
+static int buildbusdevlist(struct cam_devlist *devlist);
+static void freebusdevlist(struct cam_devlist *devlist);
+static struct cam_devitem *findsasdevice(struct cam_devlist *devlist,
+					 uint64_t sasaddr);
+static int smpphylist(struct cam_device *device, int argc, char **argv,
+		      char *combinedopt, int retry_count, int timeout);
 static int tagcontrol(struct cam_device *device, int argc, char **argv,
 		      char *combinedopt);
 static void cts_print(struct cam_device *device,
@@ -234,13 +283,13 @@ static int atapm(struct cam_device *devi
 #endif
 
 camcontrol_optret
-getoption(char *arg, cam_cmdmask *cmdnum, cam_argmask *argnum,
-	  const char **subopt)
+getoption(struct camcontrol_opts *table, char *arg, uint32_t *cmdnum,
+	  cam_argmask *argnum, const char **subopt)
 {
 	struct camcontrol_opts *opts;
 	int num_matches = 0;
 
-	for (opts = option_table; (opts != NULL) && (opts->optname != NULL);
+	for (opts = table; (opts != NULL) && (opts->optname != NULL);
 	     opts++) {
 		if (strncmp(opts->optname, arg, strlen(arg)) == 0) {
 			*cmdnum = opts->cmdnum;
@@ -1526,6 +1575,7 @@ rescan_or_reset_bus(int bus, int rescan)
 	bzero(&(&matchccb.ccb_h)[1],
 	      sizeof(struct ccb_dev_match) - sizeof(struct ccb_hdr));
 	matchccb.ccb_h.func_code = XPT_DEV_MATCH;
+	matchccb.ccb_h.path_id = CAM_BUS_WILDCARD;
 	bufsize = sizeof(struct dev_match_result) * 20;
 	matchccb.cdm.match_buf_len = bufsize;
 	matchccb.cdm.matches=(struct dev_match_result *)malloc(bufsize);
@@ -2454,10 +2504,12 @@ scsicmd(struct cam_device *device, int a
 
 	if (((retval = cam_send_ccb(device, ccb)) < 0)
 	 || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
+		const char *warnstr = "error sending command";
+
 		if (retval < 0)
-			warn("error sending command");
+			warn(warnstr);
 		else
-			warnx("error sending command");
+			warnx(warnstr);
 
 		if (arglist & CAM_ARG_VERBOSE) {
 			cam_error_print(device, ccb, CAM_ESF_ALL,
@@ -4273,121 +4325,1359 @@ bailout:
 }
 
 static int
-atapm(struct cam_device *device, int argc, char **argv,
-		 char *combinedopt, int retry_count, int timeout)
+smpcmd(struct cam_device *device, int argc, char **argv, char *combinedopt,
+       int retry_count, int timeout)
 {
+	int c, error;
 	union ccb *ccb;
-	int retval = 0;
-	int t = -1;
-	int c;
-	u_char cmd, sc;
+	uint8_t *smp_request = NULL, *smp_response = NULL;
+	int request_size = 0, response_size = 0;
+	int fd_request = 0, fd_response = 0;
+	char *datastr = NULL;
+	struct get_hook hook;
+	int retval;
+	int flags = 0;
 
+	/*
+	 * Note that at the moment we don't support sending SMP CCBs to
+	 * devices that aren't probed by CAM.
+	 */
 	ccb = cam_getccb(device);
-
 	if (ccb == NULL) {
-		warnx("%s: error allocating ccb", __func__);
+		warnx("%s: error allocating CCB", __func__);
 		return (1);
 	}
 
+	bzero(&(&ccb->ccb_h)[1],
+	      sizeof(union ccb) - sizeof(struct ccb_hdr));
+
 	while ((c = getopt(argc, argv, combinedopt)) != -1) {
 		switch (c) {
-		case 't':
-			t = atoi(optarg);
+		case 'R':
+			arglist |= CAM_ARG_CMD_IN;
+			response_size = strtol(optarg, NULL, 0);
+			if (response_size <= 0) {
+				warnx("invalid number of response bytes %d",
+				      response_size);
+				error = 1;
+				goto smpcmd_bailout;
+			}
+			hook.argc = argc - optind;
+			hook.argv = argv + optind;
+			hook.got = 0;
+			optind++;
+			datastr = cget(&hook, NULL);
+			/*
+			 * If the user supplied "-" instead of a format, he
+			 * wants the data to be written to stdout.
+			 */
+			if ((datastr != NULL)
+			 && (datastr[0] == '-'))
+				fd_response = 1;
+
+			smp_response = (u_int8_t *)malloc(response_size);
+			if (smp_response == NULL) {
+				warn("can't malloc memory for SMP response");
+				error = 1;
+				goto smpcmd_bailout;
+			}
+			break;
+		case 'r':
+			arglist |= CAM_ARG_CMD_OUT;
+			request_size = strtol(optarg, NULL, 0);
+			if (request_size <= 0) {
+				warnx("invalid number of request bytes %d",
+				      request_size);
+				error = 1;
+				goto smpcmd_bailout;
+			}
+			hook.argc = argc - optind;
+			hook.argv = argv + optind;
+			hook.got = 0;
+			datastr = cget(&hook, NULL);
+			smp_request = (u_int8_t *)malloc(request_size);
+			if (smp_request == NULL) {
+				warn("can't malloc memory for SMP request");
+				error = 1;
+				goto smpcmd_bailout;
+			}
+			bzero(smp_request, request_size);
+			/*
+			 * If the user supplied "-" instead of a format, he
+			 * wants the data to be read from stdin.
+			 */
+			if ((datastr != NULL)
+			 && (datastr[0] == '-'))
+				fd_request = 1;
+			else
+				buff_encode_visit(smp_request, request_size,
+						  datastr,
+						  iget, &hook);
+			optind += hook.got;
 			break;
 		default:
 			break;
 		}
 	}
-	if (strcmp(argv[1], "idle") == 0) {
-		if (t == -1)
-			cmd = ATA_IDLE_IMMEDIATE;
-		else
-			cmd = ATA_IDLE_CMD;
-	} else if (strcmp(argv[1], "standby") == 0) {
-		if (t == -1)
-			cmd = ATA_STANDBY_IMMEDIATE;
-		else
-			cmd = ATA_STANDBY_CMD;
-	} else {
-		cmd = ATA_SLEEP;
-		t = -1;
+
+	/*
+	 * If fd_data is set, and we're writing to the device, we need to
+	 * read the data the user wants written from stdin.
+	 */
+	if ((fd_request == 1) && (arglist & CAM_ARG_CMD_OUT)) {
+		ssize_t amt_read;
+		int amt_to_read = request_size;
+		u_int8_t *buf_ptr = smp_request;
+
+		for (amt_read = 0; amt_to_read > 0;
+		     amt_read = read(STDIN_FILENO, buf_ptr, amt_to_read)) {
+			if (amt_read == -1) {
+				warn("error reading data from stdin");
+				error = 1;
+				goto smpcmd_bailout;
+			}
+			amt_to_read -= amt_read;
+			buf_ptr += amt_read;
+		}
 	}
-	if (t < 0)
-		sc = 0;
-	else if (t <= (240 * 5))
-		sc = t / 5;
-	else if (t <= (11 * 30 * 60))
-		sc = t / (30 * 60) + 241;
-	else
-		sc = 253;
-	cam_fill_ataio(&ccb->ataio,
-		      retry_count,
-		      NULL,
-		      /*flags*/CAM_DIR_NONE,
-		      MSG_SIMPLE_Q_TAG,
-		      /*data_ptr*/NULL,
-		      /*dxfer_len*/0,
-		      timeout ? timeout : 30 * 1000);
-	ata_28bit_cmd(&ccb->ataio, cmd, 0, 0, sc);
 
-	/* Disable freezing the device queue */
-	ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
+	if (((arglist & CAM_ARG_CMD_IN) == 0)
+	 || ((arglist & CAM_ARG_CMD_OUT) == 0)) {
+		warnx("%s: need both the request (-r) and response (-R) "
+		      "arguments", __func__);
+		error = 1;
+		goto smpcmd_bailout;
+	}
 
-	if (arglist & CAM_ARG_ERR_RECOVER)
-		ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
+	flags |= CAM_DEV_QFRZDIS;
 
-	if (cam_send_ccb(device, ccb) < 0) {
-		warn("error sending command");
+	cam_fill_smpio(&ccb->smpio,
+		       /*retries*/ retry_count,
+		       /*cbfcnp*/ NULL,
+		       /*flags*/ flags,
+		       /*smp_request*/ smp_request,
+		       /*smp_request_len*/ request_size,
+		       /*smp_response*/ smp_response,
+		       /*smp_response_len*/ response_size,
+		       /*timeout*/ timeout ? timeout : 5000);
 
-		if (arglist & CAM_ARG_VERBOSE)
+	ccb->smpio.flags = SMP_FLAG_NONE;
+
+	if (((retval = cam_send_ccb(device, ccb)) < 0)
+	 || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
+		const char *warnstr = "error sending command";
+
+		if (retval < 0)
+			warn(warnstr);
+		else
+			warnx(warnstr);
+
+		if (arglist & CAM_ARG_VERBOSE) {
 			cam_error_print(device, ccb, CAM_ESF_ALL,
 					CAM_EPF_ALL, stderr);
+		}
+	}
 
-		retval = 1;
+	if (((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP)
+	 && (response_size > 0)) {
+		if (fd_response == 0) {
+			buff_decode_visit(smp_response, response_size,
+					  datastr, arg_put, NULL);
+			fprintf(stdout, "\n");
+		} else {
+			ssize_t amt_written;
+			int amt_to_write = response_size;
+			u_int8_t *buf_ptr = smp_response;
+
+			for (amt_written = 0; (amt_to_write > 0) &&
+			     (amt_written = write(STDOUT_FILENO, buf_ptr,
+						  amt_to_write)) > 0;){
+				amt_to_write -= amt_written;
+				buf_ptr += amt_written;
+			}
+			if (amt_written == -1) {
+				warn("error writing data to stdout");
+				error = 1;
+				goto smpcmd_bailout;
+			} else if ((amt_written == 0)
+				&& (amt_to_write > 0)) {
+				warnx("only wrote %u bytes out of %u",
+				      response_size - amt_to_write, 
+				      response_size);
+			}
+		}
+	}
+smpcmd_bailout:
+	if (ccb != NULL)
+		cam_freeccb(ccb);
+
+	if (smp_request != NULL)
+		free(smp_request);
+
+	if (smp_response != NULL)
+		free(smp_response);
+
+	return (error);
+}
+
+static int
+smpreportgeneral(struct cam_device *device, int argc, char **argv,
+		 char *combinedopt, int retry_count, int timeout)
+{
+	union ccb *ccb;
+	struct smp_report_general_request *request = NULL;
+	struct smp_report_general_response *response = NULL;
+	struct sbuf *sb = NULL;
+	int error = 0;
+	int c, long_response = 0;
+	int retval;
+
+	/*
+	 * Note that at the moment we don't support sending SMP CCBs to
+	 * devices that aren't probed by CAM.
+	 */
+	ccb = cam_getccb(device);
+	if (ccb == NULL) {
+		warnx("%s: error allocating CCB", __func__);
+		return (1);
+	}
+
+	bzero(&(&ccb->ccb_h)[1],
+	      sizeof(union ccb) - sizeof(struct ccb_hdr));
+
+	while ((c = getopt(argc, argv, combinedopt)) != -1) {
+		switch (c) {
+		case 'l':
+			long_response = 1;
+			break;
+		default:
+			break;
+		}
+	}
+	request = malloc(sizeof(*request));
+	if (request == NULL) {
+		warn("%s: unable to allocate %zd bytes", __func__,
+		     sizeof(*request));
+		error = 1;
 		goto bailout;
 	}
 
-	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
-		cam_error_print(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr);
-		retval = 1;
+	response = malloc(sizeof(*response));
+	if (response == NULL) {
+		warn("%s: unable to allocate %zd bytes", __func__,
+		     sizeof(*response));
+		error = 1;
+		goto bailout;
+	}
+
+try_long:
+	smp_report_general(&ccb->smpio,
+			   retry_count,
+			   /*cbfcnp*/ NULL,
+			   request,
+			   /*request_len*/ sizeof(*request),
+			   (uint8_t *)response,
+			   /*response_len*/ sizeof(*response),
+			   /*long_response*/ long_response,
+			   timeout);
+
+	if (((retval = cam_send_ccb(device, ccb)) < 0)
+	 || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
+		const char *warnstr = "error sending command";
+
+		if (retval < 0)
+			warn(warnstr);
+		else
+			warnx(warnstr);
+
+		if (arglist & CAM_ARG_VERBOSE) {
+			cam_error_print(device, ccb, CAM_ESF_ALL,
+					CAM_EPF_ALL, stderr);
+		}
+		error = 1;
+		goto bailout;
+	}
+
+	/*
+	 * If the device supports the long response bit, try again and see
+	 * if we can get all of the data.
+	 */
+	if ((response->long_response & SMP_RG_LONG_RESPONSE)
+	 && (long_response == 0)) {
+		ccb->ccb_h.status = CAM_REQ_INPROG;
+		bzero(&(&ccb->ccb_h)[1],
+		      sizeof(union ccb) - sizeof(struct ccb_hdr));
+		long_response = 1;
+		goto try_long;
+	}
+
+	/*
+	 * XXX KDM detect and decode SMP errors here.
+	 */
+	sb = sbuf_new_auto();
+	if (sb == NULL) {
+		warnx("%s: error allocating sbuf", __func__);
 		goto bailout;
 	}
+
+	smp_report_general_sbuf(response, sizeof(*response), sb);
+
+	sbuf_finish(sb);
+
+	printf("%s", sbuf_data(sb));
+
 bailout:
-	cam_freeccb(ccb);
-	return (retval);
+	if (ccb != NULL)
+		cam_freeccb(ccb);
+
+	if (request != NULL)
+		free(request);
+
+	if (response != NULL)
+		free(response);
+
+	if (sb != NULL)
+		sbuf_delete(sb);
+
+	return (error);
 }
 
-#endif /* MINIMALISTIC */
+struct camcontrol_opts phy_ops[] = {
+	{"nop", SMP_PC_PHY_OP_NOP, CAM_ARG_NONE, NULL},
+	{"linkreset", SMP_PC_PHY_OP_LINK_RESET, CAM_ARG_NONE, NULL},
+	{"hardreset", SMP_PC_PHY_OP_HARD_RESET, CAM_ARG_NONE, NULL},
+	{"disable", SMP_PC_PHY_OP_DISABLE, CAM_ARG_NONE, NULL},
+	{"clearerrlog", SMP_PC_PHY_OP_CLEAR_ERR_LOG, CAM_ARG_NONE, NULL},
+	{"clearaffiliation", SMP_PC_PHY_OP_CLEAR_AFFILIATON, CAM_ARG_NONE,NULL},
+	{"sataportsel", SMP_PC_PHY_OP_TRANS_SATA_PSS, CAM_ARG_NONE, NULL},
+	{"clearitnl", SMP_PC_PHY_OP_CLEAR_STP_ITN_LS, CAM_ARG_NONE, NULL},
+	{"setdevname", SMP_PC_PHY_OP_SET_ATT_DEV_NAME, CAM_ARG_NONE, NULL},
+	{NULL, 0, 0, NULL}
+};
 
-void
-usage(int verbose)
+static int
+smpphycontrol(struct cam_device *device, int argc, char **argv,
+	      char *combinedopt, int retry_count, int timeout)
 {
-	fprintf(verbose ? stdout : stderr,
-"usage:  camcontrol <command>  [device id][generic args][command args]\n"
-"        camcontrol devlist    [-v]\n"
-#ifndef MINIMALISTIC
-"        camcontrol periphlist [dev_id][-n dev_name] [-u unit]\n"
-"        camcontrol tur        [dev_id][generic args]\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"
-"        camcontrol readcap    [dev_id][generic args] [-b] [-h] [-H] [-N]\n"
-"                              [-q] [-s]\n"
-"        camcontrol start      [dev_id][generic args]\n"
-"        camcontrol stop       [dev_id][generic args]\n"
-"        camcontrol load       [dev_id][generic args]\n"
-"        camcontrol eject      [dev_id][generic args]\n"
-#endif /* MINIMALISTIC */
-"        camcontrol rescan     <all | bus[:target:lun]>\n"
-"        camcontrol reset      <all | bus[:target:lun]>\n"
-#ifndef MINIMALISTIC
-"        camcontrol defects    [dev_id][generic args] <-f format> [-P][-G]\n"
-"        camcontrol modepage   [dev_id][generic args] <-m page | -l>\n"
-"                              [-P pagectl][-e | -b][-d]\n"
-"        camcontrol cmd        [dev_id][generic args]\n"
-"                              <-a cmd [args] | -c cmd [args]>\n"
-"                              [-d] [-f] [-i len fmt|-o len fmt [args]] [-r fmt]\n"
-"        camcontrol debug      [-I][-P][-T][-S][-X][-c]\n"
+	union ccb *ccb;
+	struct smp_phy_control_request *request = NULL;
+	struct smp_phy_control_response *response = NULL;
+	int long_response = 0;
+	int retval = 0;
+	int phy = -1;
+	uint32_t phy_operation = SMP_PC_PHY_OP_NOP;
+	int phy_op_set = 0;
+	uint64_t attached_dev_name = 0;
+	int dev_name_set = 0;
+	uint32_t min_plr = 0, max_plr = 0;
+	uint32_t pp_timeout_val = 0;
+	int slumber_partial = 0;
+	int set_pp_timeout_val = 0;
+	int c;
+
+	/*
+	 * Note that at the moment we don't support sending SMP CCBs to
+	 * devices that aren't probed by CAM.
+	 */
+	ccb = cam_getccb(device);
+	if (ccb == NULL) {
+		warnx("%s: error allocating CCB", __func__);
+		return (1);
+	}
+
+	bzero(&(&ccb->ccb_h)[1],
+	      sizeof(union ccb) - sizeof(struct ccb_hdr));
+
+	while ((c = getopt(argc, argv, combinedopt)) != -1) {
+		switch (c) {
+		case 'a':
+		case 'A':
+		case 's':
+		case 'S': {
+			int enable = -1;
+
+			if (strcasecmp(optarg, "enable") == 0)
+				enable = 1;
+			else if (strcasecmp(optarg, "disable") == 0)
+				enable = 2;
+			else {
+				warnx("%s: Invalid argument %s", __func__,
+				      optarg);
+				retval = 1;
+				goto bailout;
+			}
+			switch (c) {
+			case 's':
+				slumber_partial |= enable <<
+						   SMP_PC_SAS_SLUMBER_SHIFT;
+				break;
+			case 'S':
+				slumber_partial |= enable <<
+						   SMP_PC_SAS_PARTIAL_SHIFT;
+				break;
+			case 'a':
+				slumber_partial |= enable <<
+						   SMP_PC_SATA_SLUMBER_SHIFT;
+				break;
+			case 'A':
+				slumber_partial |= enable <<
+						   SMP_PC_SATA_PARTIAL_SHIFT;
+				break;
+			default:
+				warnx("%s: programmer error", __func__);
+				retval = 1;
+				goto bailout;
+				break; /*NOTREACHED*/
+			}
+			break;
+		}
+		case 'd':
+			attached_dev_name = (uintmax_t)strtoumax(optarg,
+								 NULL,0);
+			dev_name_set = 1;
+			break;
+		case 'l':
+			long_response = 1;
+			break;
+		case 'm':
+			/*
+			 * We don't do extensive checking here, so this
+			 * will continue to work when new speeds come out.
+			 */
+			min_plr = strtoul(optarg, NULL, 0);
+			if ((min_plr == 0)
+			 || (min_plr > 0xf)) {
+				warnx("%s: invalid link rate %x",
+				      __func__, min_plr);
+				retval = 1;
+				goto bailout;
+			}
+			break;
+		case 'M':
+			/*
+			 * We don't do extensive checking here, so this
+			 * will continue to work when new speeds come out.
+			 */
+			max_plr = strtoul(optarg, NULL, 0);
+			if ((max_plr == 0)
+			 || (max_plr > 0xf)) {

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


More information about the svn-src-projects mailing list