From owner-svn-src-projects@FreeBSD.ORG Thu Jan 27 16:47:33 2011 Return-Path: Delivered-To: svn-src-projects@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 5FC72106566C; Thu, 27 Jan 2011 16:47:33 +0000 (UTC) (envelope-from mav@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 4B88D8FC1C; Thu, 27 Jan 2011 16:47:33 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id p0RGlXIh023862; Thu, 27 Jan 2011 16:47:33 GMT (envelope-from mav@svn.freebsd.org) Received: (from mav@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id p0RGlXNK023857; Thu, 27 Jan 2011 16:47:33 GMT (envelope-from mav@svn.freebsd.org) Message-Id: <201101271647.p0RGlXNK023857@svn.freebsd.org> From: Alexander Motin Date: Thu, 27 Jan 2011 16:47:33 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org X-SVN-Group: projects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: 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 X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 27 Jan 2011 16:47:33 -0000 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 #include #include +#include #include #include #include #include +#include +#include #include #include #include @@ -50,6 +53,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #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 [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 \n" -" camcontrol reset \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 ***