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