From owner-svn-src-all@freebsd.org Thu Aug 8 02:24:58 2019 Return-Path: Delivered-To: svn-src-all@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id E8DC6C0B93; Thu, 8 Aug 2019 02:24:58 +0000 (UTC) (envelope-from mav@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 463sf26bkKz3Crg; Thu, 8 Aug 2019 02:24:58 +0000 (UTC) (envelope-from mav@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id C00CD1E392; Thu, 8 Aug 2019 02:24:58 +0000 (UTC) (envelope-from mav@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id x782OwtE038086; Thu, 8 Aug 2019 02:24:58 GMT (envelope-from mav@FreeBSD.org) Received: (from mav@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id x782Ovv6038082; Thu, 8 Aug 2019 02:24:57 GMT (envelope-from mav@FreeBSD.org) Message-Id: <201908080224.x782Ovv6038082@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: mav set sender to mav@FreeBSD.org using -f From: Alexander Motin Date: Thu, 8 Aug 2019 02:24:57 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org Subject: svn commit: r350730 - in stable/12: sbin/camcontrol sys/cam/ata sys/sys X-SVN-Group: stable-12 X-SVN-Commit-Author: mav X-SVN-Commit-Paths: in stable/12: sbin/camcontrol sys/cam/ata sys/sys X-SVN-Commit-Revision: 350730 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.29 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: Thu, 08 Aug 2019 02:24:59 -0000 Author: mav Date: Thu Aug 8 02:24:57 2019 New Revision: 350730 URL: https://svnweb.freebsd.org/changeset/base/350730 Log: MFC r350149: Add Accessible Max Address Configuration support to camcontrol. AMA replaced HPA in ACS-3 specification. It allows to limit size of the disk alike to HPA, but declares inaccessible data as indeterminate. One of its practical use cases is to under-provision SATA SSDs for better reliability and performance. While there, fix HPA Security detection/reporting. Modified: stable/12/sbin/camcontrol/camcontrol.8 stable/12/sbin/camcontrol/camcontrol.c stable/12/sys/cam/ata/ata_all.c stable/12/sys/sys/ata.h Directory Properties: stable/12/ (props changed) Modified: stable/12/sbin/camcontrol/camcontrol.8 ============================================================================== --- stable/12/sbin/camcontrol/camcontrol.8 Thu Aug 8 02:21:30 2019 (r350729) +++ stable/12/sbin/camcontrol/camcontrol.8 Thu Aug 8 02:24:57 2019 (r350730) @@ -27,7 +27,7 @@ .\" .\" $FreeBSD$ .\" -.Dd March 12, 2019 +.Dd July 19, 2019 .Dt CAMCONTROL 8 .Os .Sh NAME @@ -292,6 +292,13 @@ .Op Fl U Ar pwd .Op Fl y .Nm +.Ic ama +.Op device id +.Op generic args +.Op Fl f +.Op Fl q +.Op Fl s Ar max_sectors +.Nm .Ic persist .Op device id .Op generic args @@ -1599,6 +1606,40 @@ without prompting for confirmation .Pp The password for all HPA commands is limited to 32 characters, longer passwords will fail. +.It Ic ama +Update or report Accessible Max Address Configuration. +By default +.Nm +will print out the Accessible Max Address Configuration support and associated +settings of the device. +The +.Ic ama +command takes several optional arguments: +.Bl -tag -width 0n +.It Fl f +.Pp +Freeze the Accessible Max Address Configuration of the specified device. +.Pp +After command completion any other commands that update the configuration +shall be command aborted. +Frozen mode is disabled by power-off. +.It Fl q +.Pp +Be quiet, do not print any status messages. +.It Fl s Ar max_sectors +.Pp +Configures the maximum user accessible sectors of the device. +This will change the number of sectors the device reports. +.Pp +.Em WARNING! WARNING! WARNING! +.Pp +Changing the max sectors of a device using this option will make the data on +the device beyond the specified value indeterminate. +.Pp +Only one successful +.Fl s Ar max_sectors +call can be made without a power-on reset of the device. +.El .It Ic fwdownload Program firmware of the named .Tn SCSI Modified: stable/12/sbin/camcontrol/camcontrol.c ============================================================================== --- stable/12/sbin/camcontrol/camcontrol.c Thu Aug 8 02:21:30 2019 (r350729) +++ stable/12/sbin/camcontrol/camcontrol.c Thu Aug 8 02:24:57 2019 (r350730) @@ -112,6 +112,7 @@ typedef enum { CAM_CMD_MMCSD_CMD = 0x00000029, CAM_CMD_POWER_MODE = 0x0000002a, CAM_CMD_DEVTYPE = 0x0000002b, + CAM_CMD_AMA = 0x0000002c, } cam_cmdmask; typedef enum { @@ -245,6 +246,7 @@ static struct camcontrol_opts option_table[] = { {"fwdownload", CAM_CMD_DOWNLOAD_FW, CAM_ARG_NONE, "f:qsy"}, {"security", CAM_CMD_SECURITY, CAM_ARG_NONE, "d:e:fh:k:l:qs:T:U:y"}, {"hpa", CAM_CMD_HPA, CAM_ARG_NONE, "Pflp:qs:U:y"}, + {"ama", CAM_CMD_AMA, CAM_ARG_NONE, "fqs:"}, {"persist", CAM_CMD_PERSIST, CAM_ARG_NONE, "ai:I:k:K:o:ps:ST:U"}, {"attrib", CAM_CMD_ATTRIB, CAM_ARG_NONE, "a:ce:F:p:r:s:T:w:V:"}, {"opcodes", CAM_CMD_OPCODES, CAM_ARG_NONE, "No:s:T"}, @@ -374,6 +376,8 @@ static int atasecurity(struct cam_device *device, int int argc, char **argv, char *combinedopt); static int atahpa(struct cam_device *device, int retry_count, int timeout, int argc, char **argv, char *combinedopt); +static int ataama(struct cam_device *device, int retry_count, int timeout, + int argc, char **argv, char *combinedopt); static int scsiprintoneopcode(struct cam_device *device, int req_opcode, int sa_set, int req_sa, uint8_t *buf, uint32_t valid_len); @@ -1442,8 +1446,9 @@ atahpa_print(struct ata_params *parm, u_int64_t hpasiz lba, hpasize); printf("HPA - Security "); - if (parm->support.command1 & ATA_SUPPORT_MAXSECURITY) - printf("yes\n"); + if (parm->support.command2 & ATA_SUPPORT_MAXSECURITY) + printf("yes %s\n", (parm->enabled.command2 & + ATA_SUPPORT_MAXSECURITY) ? "yes" : "no "); else printf("no\n"); } else { @@ -1451,6 +1456,32 @@ atahpa_print(struct ata_params *parm, u_int64_t hpasiz } } +static void +ataama_print(struct ata_params *parm, u_int64_t nativesize, int header) +{ + u_int32_t lbasize = (u_int32_t)parm->lba_size_1 | + ((u_int32_t)parm->lba_size_2 << 16); + + u_int64_t lbasize48 = ((u_int64_t)parm->lba_size48_1) | + ((u_int64_t)parm->lba_size48_2 << 16) | + ((u_int64_t)parm->lba_size48_3 << 32) | + ((u_int64_t)parm->lba_size48_4 << 48); + + if (header) { + printf("\nFeature " + "Support Enabled Value\n"); + } + + printf("Accessible Max Address Config "); + if (parm->support2 & ATA_SUPPORT_AMAX_ADDR) { + u_int64_t lba = lbasize48 ? lbasize48 : lbasize; + printf("yes %s %ju/%ju\n", + (nativesize > lba) ? "yes" : "no ", lba, nativesize); + } else { + printf("no\n"); + } +} + static int atasata(struct ata_params *parm) { @@ -2277,7 +2308,95 @@ atahpa_freeze_lock(struct cam_device *device, int retr return atahpa_proc_resp(device, ccb, is48bit, NULL); } +static int +ata_get_native_max(struct cam_device *device, int retry_count, + u_int32_t timeout, union ccb *ccb, + u_int64_t *nativesize) +{ + int error; + error = ata_do_cmd(device, + ccb, + retry_count, + /*flags*/CAM_DIR_NONE, + /*protocol*/AP_PROTO_NON_DATA | AP_EXTEND, + /*ata_flags*/AP_FLAG_CHK_COND, + /*tag_action*/MSG_SIMPLE_Q_TAG, + /*command*/ATA_AMAX_ADDR, + /*features*/ATA_AMAX_ADDR_GET, + /*lba*/0, + /*sector_count*/0, + /*data_ptr*/NULL, + /*dxfer_len*/0, + timeout ? timeout : 30 * 1000, + /*force48bit*/1); + + if (error) + return (error); + + return atahpa_proc_resp(device, ccb, /*is48bit*/1, nativesize); +} + +static int +ataama_set(struct cam_device *device, int retry_count, + u_int32_t timeout, union ccb *ccb, u_int64_t maxsize) +{ + int error; + + /* lba's are zero indexed so the max lba is requested max - 1 */ + if (maxsize) + maxsize--; + + error = ata_do_cmd(device, + ccb, + retry_count, + /*flags*/CAM_DIR_NONE, + /*protocol*/AP_PROTO_NON_DATA | AP_EXTEND, + /*ata_flags*/AP_FLAG_CHK_COND, + /*tag_action*/MSG_SIMPLE_Q_TAG, + /*command*/ATA_AMAX_ADDR, + /*features*/ATA_AMAX_ADDR_SET, + /*lba*/maxsize, + /*sector_count*/0, + /*data_ptr*/NULL, + /*dxfer_len*/0, + timeout ? timeout : 30 * 1000, + /*force48bit*/1); + + if (error) + return (error); + + return atahpa_proc_resp(device, ccb, /*is48bit*/1, NULL); +} + +static int +ataama_freeze(struct cam_device *device, int retry_count, + u_int32_t timeout, union ccb *ccb) +{ + int error; + + error = ata_do_cmd(device, + ccb, + retry_count, + /*flags*/CAM_DIR_NONE, + /*protocol*/AP_PROTO_NON_DATA | AP_EXTEND, + /*ata_flags*/AP_FLAG_CHK_COND, + /*tag_action*/MSG_SIMPLE_Q_TAG, + /*command*/ATA_AMAX_ADDR, + /*features*/ATA_AMAX_ADDR_FREEZE, + /*lba*/0, + /*sector_count*/0, + /*data_ptr*/NULL, + /*dxfer_len*/0, + timeout ? timeout : 30 * 1000, + /*force48bit*/1); + + if (error) + return (error); + + return atahpa_proc_resp(device, ccb, /*is48bit*/1, NULL); +} + int ata_do_identify(struct cam_device *device, int retry_count, int timeout, union ccb *ccb, struct ata_params** ident_bufp) @@ -2390,7 +2509,7 @@ ataidentify(struct cam_device *device, int retry_count { union ccb *ccb; struct ata_params *ident_buf; - u_int64_t hpasize; + u_int64_t hpasize, nativesize; if ((ccb = cam_getccb(device)) == NULL) { warnx("couldn't allocate CCB"); @@ -2411,12 +2530,22 @@ ataidentify(struct cam_device *device, int retry_count } else { hpasize = 0; } + if (ident_buf->support2 & ATA_SUPPORT_AMAX_ADDR) { + if (ata_get_native_max(device, retry_count, timeout, ccb, + &nativesize) != 0) { + cam_freeccb(ccb); + return (1); + } + } else { + nativesize = 0; + } printf("%s%d: ", device->device_name, device->dev_unit_num); ata_print_ident(ident_buf); camxferrate(device); atacapprint(ident_buf); atahpa_print(ident_buf, hpasize, 0); + ataama_print(ident_buf, nativesize, 0); free(ident_buf); cam_freeccb(ccb); @@ -2938,7 +3067,7 @@ atahpa(struct cam_device *device, int retry_count, int return (1); } - if (security && !(ident_buf->support.command1 & ATA_SUPPORT_MAXSECURITY)) { + if (security && !(ident_buf->support.command2 & ATA_SUPPORT_MAXSECURITY)) { warnx("HPA Security is not supported by this device"); cam_freeccb(ccb); free(ident_buf); @@ -2967,7 +3096,7 @@ atahpa(struct cam_device *device, int retry_count, int if (error == 0) { error = atahpa_set_max(device, retry_count, timeout, ccb, is48bit, maxsize, persist); - if (error == 0) { + if (error == 0 && quiet == 0) { /* redo identify to get new lba values */ error = ata_do_identify(device, retry_count, timeout, ccb, @@ -2980,28 +3109,28 @@ atahpa(struct cam_device *device, int retry_count, int case ATA_HPA_ACTION_SET_PWD: error = atahpa_password(device, retry_count, timeout, ccb, is48bit, &pwd); - if (error == 0) + if (error == 0 && quiet == 0) printf("HPA password has been set\n"); break; case ATA_HPA_ACTION_LOCK: error = atahpa_lock(device, retry_count, timeout, ccb, is48bit); - if (error == 0) + if (error == 0 && quiet == 0) printf("HPA has been locked\n"); break; case ATA_HPA_ACTION_UNLOCK: error = atahpa_unlock(device, retry_count, timeout, ccb, is48bit, &pwd); - if (error == 0) + if (error == 0 && quiet == 0) printf("HPA has been unlocked\n"); break; case ATA_HPA_ACTION_FREEZE_LOCK: error = atahpa_freeze_lock(device, retry_count, timeout, ccb, is48bit); - if (error == 0) + if (error == 0 && quiet == 0) printf("HPA has been frozen\n"); break; @@ -3015,7 +3144,128 @@ atahpa(struct cam_device *device, int retry_count, int return (error); } +enum { + ATA_AMA_ACTION_PRINT, + ATA_AMA_ACTION_SET_MAX, + ATA_AMA_ACTION_FREEZE_LOCK +}; + static int +ataama(struct cam_device *device, int retry_count, int timeout, + int argc, char **argv, char *combinedopt) +{ + union ccb *ccb; + struct ata_params *ident_buf; + struct ccb_getdev cgd; + int error, quiet, c, action, actions; + u_int64_t nativesize, maxsize; + + actions = 0; + quiet = 0; + maxsize = 0; + + /* default action is to print AMA information */ + action = ATA_AMA_ACTION_PRINT; + + while ((c = getopt(argc, argv, combinedopt)) != -1) { + switch(c){ + case 's': + action = ATA_AMA_ACTION_SET_MAX; + maxsize = strtoumax(optarg, NULL, 0); + actions++; + break; + + case 'f': + action = ATA_AMA_ACTION_FREEZE_LOCK; + actions++; + break; + + case 'q': + quiet++; + break; + } + } + + if (actions > 1) { + warnx("too many AMA actions specified"); + return (1); + } + + if (get_cgd(device, &cgd) != 0) { + warnx("couldn't get CGD"); + return (1); + } + + ccb = cam_getccb(device); + if (ccb == NULL) { + warnx("couldn't allocate CCB"); + return (1); + } + + error = ata_do_identify(device, retry_count, timeout, ccb, &ident_buf); + if (error != 0) { + cam_freeccb(ccb); + return (1); + } + + if (quiet == 0) { + printf("%s%d: ", device->device_name, device->dev_unit_num); + ata_print_ident(ident_buf); + camxferrate(device); + } + + if (action == ATA_AMA_ACTION_PRINT) { + error = ata_get_native_max(device, retry_count, timeout, ccb, + &nativesize); + if (error == 0) + ataama_print(ident_buf, nativesize, 1); + + cam_freeccb(ccb); + free(ident_buf); + return (error); + } + + if (!(ident_buf->support2 & ATA_SUPPORT_AMAX_ADDR)) { + warnx("Accessible Max Address is not supported by this device"); + cam_freeccb(ccb); + free(ident_buf); + return (1); + } + + switch(action) { + case ATA_AMA_ACTION_SET_MAX: + error = ata_get_native_max(device, retry_count, timeout, ccb, + &nativesize); + if (error == 0) { + error = ataama_set(device, retry_count, timeout, + ccb, maxsize); + if (error == 0 && quiet == 0) { + /* redo identify to get new lba values */ + error = ata_do_identify(device, retry_count, + timeout, ccb, &ident_buf); + ataama_print(ident_buf, nativesize, 1); + } + } + break; + + case ATA_AMA_ACTION_FREEZE_LOCK: + error = ataama_freeze(device, retry_count, timeout, + ccb); + if (error == 0 && quiet == 0) + printf("Accessible Max Address has been frozen\n"); + break; + + default: + errx(1, "Option currently not supported"); + } + + cam_freeccb(ccb); + free(ident_buf); + + return (error); +} + +static int atasecurity(struct cam_device *device, int retry_count, int timeout, int argc, char **argv, char *combinedopt) { @@ -9677,6 +9927,7 @@ usage(int printlong) " [-U ] [-y]\n" " camcontrol hpa [dev_id][generic args] [-f] [-l] [-P] [-p pwd]\n" " [-q] [-s max_sectors] [-U pwd] [-y]\n" +" camcontrol ama [dev_id][generic args] [-f] [-q] [-s max_sectors]\n" " camcontrol persist [dev_id][generic args] <-i action|-o action>\n" " [-a][-I tid][-k key][-K sa_key][-p][-R rtp]\n" " [-s scope][-S][-T type][-U]\n" @@ -9877,6 +10128,11 @@ usage(int printlong) " device\n" "-U pwd unlock the HPA configuration of the device\n" "-y don't ask any questions\n" +"ama arguments:\n" +"-f freeze the AMA configuration of the device\n" +"-q be quiet, do not print any status messages\n" +"-s sectors configures the maximum user accessible sectors of the\n" +" device\n" "persist arguments:\n" "-i action specify read_keys, read_reservation, report_cap, or\n" " read_full_status\n" @@ -10207,6 +10463,10 @@ main(int argc, char **argv) break; case CAM_CMD_HPA: error = atahpa(cam_dev, retry_count, timeout, + argc, argv, combinedopt); + break; + case CAM_CMD_AMA: + error = ataama(cam_dev, retry_count, timeout, argc, argv, combinedopt); break; #endif /* MINIMALISTIC */ Modified: stable/12/sys/cam/ata/ata_all.c ============================================================================== --- stable/12/sys/cam/ata/ata_all.c Thu Aug 8 02:21:30 2019 (r350729) +++ stable/12/sys/cam/ata/ata_all.c Thu Aug 8 02:24:57 2019 (r350730) @@ -184,7 +184,13 @@ ata_op_string(struct ata_cmd *cmd) return ("SEP_ATTN"); case 0x70: return ("SEEK"); case 0x77: return ("SET_DATE_TIME_EXT"); - case 0x78: return ("ACCESSIBLE_MAX_ADDRESS_CONFIGURATION"); + case 0x78: + switch (cmd->features) { + case 0x00: return ("GET_NATIVE_MAX_ADDRESS_EXT"); + case 0x01: return ("SET_ACCESSIBLE_MAX_ADDRESS_EXT"); + case 0x02: return ("FREEZE_ACCESSIBLE_MAX_ADDRESS_EXT"); + } + return ("ACCESSIBLE_MAX_ADDRESS_CONFIGURATION"); case 0x7C: return ("REMOVE_ELEMENT_AND_TRUNCATE"); case 0x87: return ("CFA_TRANSLATE_SECTOR"); case 0x90: return ("EXECUTE_DEVICE_DIAGNOSTIC"); Modified: stable/12/sys/sys/ata.h ============================================================================== --- stable/12/sys/sys/ata.h Thu Aug 8 02:21:30 2019 (r350729) +++ stable/12/sys/sys/ata.h Thu Aug 8 02:24:57 2019 (r350730) @@ -236,12 +236,15 @@ struct ata_params { #define ATA_SUPPORT_FREEFALL 0x0020 #define ATA_SUPPORT_SENSE_REPORT 0x0040 #define ATA_SUPPORT_EPC 0x0080 +#define ATA_SUPPORT_AMAX_ADDR 0x0100 +#define ATA_SUPPORT_DSN 0x0200 /*120*/ u_int16_t enabled2; #define ATA_ENABLED_WRITEREADVERIFY 0x0002 #define ATA_ENABLED_WRITEUNCORREXT 0x0004 #define ATA_ENABLED_FREEFALL 0x0020 #define ATA_ENABLED_SENSE_REPORT 0x0040 #define ATA_ENABLED_EPC 0x0080 +#define ATA_ENABLED_DSN 0x0200 u_int16_t reserved121[6]; /*127*/ u_int16_t removable_status; /*128*/ u_int16_t security_status; @@ -418,6 +421,10 @@ struct ata_params { #define ATA_RFPDMA_ZAC_MGMT_IN 0x02 /* NCQ ZAC mgmt in w/data */ #define ATA_SEP_ATTN 0x67 /* SEP request */ #define ATA_SEEK 0x70 /* seek */ +#define ATA_AMAX_ADDR 0x78 /* Accessible Max Address */ +#define ATA_AMAX_ADDR_GET 0x00 /* GET NATIVE MAX ADDRESS EXT */ +#define ATA_AMAX_ADDR_SET 0x01 /* SET ACCESSIBLE MAX ADDRESS EXT */ +#define ATA_AMAX_ADDR_FREEZE 0x02 /* FREEZE ACCESSIBLE MAX ADDRESS EXT */ #define ATA_ZAC_MANAGEMENT_OUT 0x9f /* ZAC management out */ #define ATA_ZM_CLOSE_ZONE 0x01 /* close zone */ #define ATA_ZM_FINISH_ZONE 0x02 /* finish zone */