From owner-svn-src-all@FreeBSD.ORG Sun Sep 6 14:05:01 2009 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 96AD6106566B; Sun, 6 Sep 2009 14:05:01 +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 83BF18FC1C; Sun, 6 Sep 2009 14:05:01 +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 n86E51aP085828; Sun, 6 Sep 2009 14:05:01 GMT (envelope-from mav@svn.freebsd.org) Received: (from mav@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id n86E51PV085825; Sun, 6 Sep 2009 14:05:01 GMT (envelope-from mav@svn.freebsd.org) Message-Id: <200909061405.n86E51PV085825@svn.freebsd.org> From: Alexander Motin Date: Sun, 6 Sep 2009 14:05:01 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org X-SVN-Group: stable-8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r196892 - stable/8/sbin/camcontrol X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 06 Sep 2009 14:05:01 -0000 Author: mav Date: Sun Sep 6 14:05:01 2009 New Revision: 196892 URL: http://svn.freebsd.org/changeset/base/196892 Log: MFC r196831: Add to `camcontrol cmd` support for sending arbitrary ATA commands. It could be used for broad range of tasks, such as configuring drive power management, caching, security and any other features and tasks, not supported by existing drivers. Approved by: re (ATA-CAM blanket) Modified: stable/8/sbin/camcontrol/ (props changed) stable/8/sbin/camcontrol/camcontrol.8 stable/8/sbin/camcontrol/camcontrol.c Modified: stable/8/sbin/camcontrol/camcontrol.8 ============================================================================== --- stable/8/sbin/camcontrol/camcontrol.8 Sun Sep 6 13:31:05 2009 (r196891) +++ stable/8/sbin/camcontrol/camcontrol.8 Sun Sep 6 14:05:01 2009 (r196892) @@ -27,7 +27,7 @@ .\" .\" $FreeBSD$ .\" -.Dd June 29, 2009 +.Dd September 4, 2009 .Dt CAMCONTROL 8 .Os .Sh NAME @@ -120,10 +120,12 @@ .Ic cmd .Op device id .Op generic args +.Aq Fl a Ar cmd Op args .Aq Fl c Ar cmd Op args .Op Fl i Ar len Ar fmt .Bk -words .Op Fl o Ar len Ar fmt Op args +.Op Fl r Ar fmt .Ek .Nm .Ic debug @@ -486,12 +488,14 @@ Saved values .El .El .It Ic cmd -Allows the user to send an arbitrary SCSI CDB to any device. +Allows the user to send an arbitrary ATA or SCSI CDB to any device. The .Ic cmd function requires the .Fl c -argument to specify the CDB. +argument to specify SCSI CDB or the +.Fl a +argument to specify ATA Command Block registers values. Other arguments are optional, depending on the command type. The command and data specification syntax is documented @@ -503,9 +507,13 @@ SCSI device in question, you MUST specif or .Fl o . .Bl -tag -width 17n +.It Fl a Ar cmd Op args +This specifies the content of 12 ATA Command Block registers (command, +features, lba_low, lba_mid, lba_high, device, lba_low_exp, lba_mid_exp. +lba_high_exp, features_exp, sector_count, sector_count_exp). .It Fl c Ar cmd Op args This specifies the SCSI CDB. -CDBs may be 6, 10, 12 or 16 bytes. +SCSI CDBs may be 6, 10, 12 or 16 bytes. .It Fl i Ar len Ar fmt This specifies the amount of data to read, and how it should be displayed. If the format is @@ -519,6 +527,13 @@ If the format is .Sq - , .Ar len bytes of data will be read from standard input and written to the device. +.It Fl r Ar fmt +This specifies that 11 result ATA Command Block registers should be displayed +(status, error, lba_low, lba_mid, lba_high, device, lba_low_exp, lba_mid_exp, +lba_high_exp, sector_count, sector_count_exp), and how. +If the format is +.Sq - , +11 result registers will be written to standard output in hex. .El .It Ic debug Turn on CAM debugging printfs in the kernel. Modified: stable/8/sbin/camcontrol/camcontrol.c ============================================================================== --- stable/8/sbin/camcontrol/camcontrol.c Sun Sep 6 13:31:05 2009 (r196891) +++ stable/8/sbin/camcontrol/camcontrol.c Sun Sep 6 14:05:01 2009 (r196892) @@ -120,7 +120,7 @@ struct camcontrol_opts { }; #ifndef MINIMALISTIC -static const char scsicmd_opts[] = "c:i:o:"; +static const char scsicmd_opts[] = "a:c:i:o:r"; static const char readdefect_opts[] = "f:GP"; static const char negotiate_opts[] = "acD:O:qR:T:UW:"; #endif @@ -2078,12 +2078,15 @@ scsicmd(struct cam_device *device, int a u_int32_t flags = CAM_DIR_NONE; u_int8_t *data_ptr = NULL; u_int8_t cdb[20]; + u_int8_t atacmd[12]; struct get_hook hook; int c, data_bytes = 0; int cdb_len = 0; - char *datastr = NULL, *tstr; + int atacmd_len = 0; + int need_res = 0; + char *datastr = NULL, *tstr, *resstr = NULL; int error = 0; - int fd_data = 0; + int fd_data = 0, fd_res = 0; int retval; ccb = cam_getccb(device); @@ -2094,10 +2097,32 @@ scsicmd(struct cam_device *device, int a } bzero(&(&ccb->ccb_h)[1], - sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr)); + sizeof(union ccb) - sizeof(struct ccb_hdr)); while ((c = getopt(argc, argv, combinedopt)) != -1) { switch(c) { + case 'a': + tstr = optarg; + while (isspace(*tstr) && (*tstr != '\0')) + tstr++; + hook.argc = argc - optind; + hook.argv = argv + optind; + hook.got = 0; + atacmd_len = buff_encode_visit(atacmd, sizeof(atacmd), tstr, + iget, &hook); + /* + * Increment optind by the number of arguments the + * encoding routine processed. After each call to + * getopt(3), optind points to the argument that + * getopt should process _next_. In this case, + * that means it points to the first command string + * argument, if there is one. Once we increment + * this, it should point to either the next command + * line argument, or it should be past the end of + * the list. + */ + optind += hook.got; + break; case 'c': tstr = optarg; while (isspace(*tstr) && (*tstr != '\0')) @@ -2194,6 +2219,16 @@ scsicmd(struct cam_device *device, int a iget, &hook); optind += hook.got; break; + case 'r': + need_res = 1; + hook.argc = argc - optind; + hook.argv = argv + optind; + hook.got = 0; + resstr = cget(&hook, NULL); + if ((resstr != NULL) && (resstr[0] == '-')) + fd_res = 1; + optind += hook.got; + break; default: break; } @@ -2226,50 +2261,51 @@ scsicmd(struct cam_device *device, int a /* Disable freezing the device queue */ flags |= CAM_DEV_QFRZDIS; - /* - * This is taken from the SCSI-3 draft spec. - * (T10/1157D revision 0.3) - * The top 3 bits of an opcode are the group code. The next 5 bits - * are the command code. - * Group 0: six byte commands - * Group 1: ten byte commands - * Group 2: ten byte commands - * Group 3: reserved - * Group 4: sixteen byte commands - * Group 5: twelve byte commands - * Group 6: vendor specific - * Group 7: vendor specific - */ - switch((cdb[0] >> 5) & 0x7) { - case 0: - cdb_len = 6; - break; - case 1: - case 2: - cdb_len = 10; - break; - case 3: - case 6: - case 7: - /* computed by buff_encode_visit */ - break; - case 4: - cdb_len = 16; - break; - case 5: - cdb_len = 12; - break; - } + if (cdb_len) { + /* + * This is taken from the SCSI-3 draft spec. + * (T10/1157D revision 0.3) + * The top 3 bits of an opcode are the group code. + * The next 5 bits are the command code. + * Group 0: six byte commands + * Group 1: ten byte commands + * Group 2: ten byte commands + * Group 3: reserved + * Group 4: sixteen byte commands + * Group 5: twelve byte commands + * Group 6: vendor specific + * Group 7: vendor specific + */ + switch((cdb[0] >> 5) & 0x7) { + case 0: + cdb_len = 6; + break; + case 1: + case 2: + cdb_len = 10; + break; + case 3: + case 6: + case 7: + /* computed by buff_encode_visit */ + break; + case 4: + cdb_len = 16; + break; + case 5: + cdb_len = 12; + break; + } - /* - * We should probably use csio_build_visit or something like that - * here, but it's easier to encode arguments as you go. The - * alternative would be skipping the CDB argument and then encoding - * it here, since we've got the data buffer argument by now. - */ - bcopy(cdb, &ccb->csio.cdb_io.cdb_bytes, cdb_len); + /* + * We should probably use csio_build_visit or something like that + * here, but it's easier to encode arguments as you go. The + * alternative would be skipping the CDB argument and then encoding + * it here, since we've got the data buffer argument by now. + */ + bcopy(cdb, &ccb->csio.cdb_io.cdb_bytes, cdb_len); - cam_fill_csio(&ccb->csio, + cam_fill_csio(&ccb->csio, /*retries*/ retry_count, /*cbfcnp*/ NULL, /*flags*/ flags, @@ -2279,6 +2315,21 @@ scsicmd(struct cam_device *device, int a /*sense_len*/ SSD_FULL_SIZE, /*cdb_len*/ cdb_len, /*timeout*/ timeout ? timeout : 5000); + } else { + atacmd_len = 12; + bcopy(atacmd, &ccb->ataio.cmd.command, atacmd_len); + if (need_res) + ccb->ataio.cmd.flags |= CAM_ATAIO_NEEDRESULT; + + cam_fill_ataio(&ccb->ataio, + /*retries*/ retry_count, + /*cbfcnp*/ NULL, + /*flags*/ flags, + /*tag_action*/ 0, + /*data_ptr*/ data_ptr, + /*dxfer_len*/ data_bytes, + /*timeout*/ timeout ? timeout : 5000); + } if (((retval = cam_send_ccb(device, ccb)) < 0) || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) { @@ -2296,6 +2347,28 @@ scsicmd(struct cam_device *device, int a goto scsicmd_bailout; } + if (atacmd_len && need_res) { + if (fd_res == 0) { + buff_decode_visit(&ccb->ataio.res.status, 11, resstr, + arg_put, NULL); + fprintf(stdout, "\n"); + } else { + fprintf(stdout, + "%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", + ccb->ataio.res.status, + ccb->ataio.res.error, + ccb->ataio.res.lba_low, + ccb->ataio.res.lba_mid, + ccb->ataio.res.lba_high, + ccb->ataio.res.device, + ccb->ataio.res.lba_low_exp, + ccb->ataio.res.lba_mid_exp, + ccb->ataio.res.lba_high_exp, + ccb->ataio.res.sector_count, + ccb->ataio.res.sector_count_exp); + fflush(stdout); + } + } if (((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) && (arglist & CAM_ARG_CMD_IN) @@ -4029,8 +4102,9 @@ usage(int verbose) " 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] <-c cmd [args]>\n" -" [-i len fmt|-o len fmt [args]]\n" +" camcontrol cmd [dev_id][generic args]\n" +" <-a cmd [args] | -c cmd [args]>\n" +" [-i len fmt|-o len fmt [args]] [-r fmt]\n" " camcontrol debug [-I][-P][-T][-S][-X][-c]\n" " \n" " camcontrol tags [dev_id][generic args] [-N tags] [-q] [-v]\n"