svn commit: r350149 - in head: sbin/camcontrol sys/cam/ata sys/sys
Alexander Motin
mav at FreeBSD.org
Fri Jul 19 19:15:10 UTC 2019
Author: mav
Date: Fri Jul 19 19:15:08 2019
New Revision: 350149
URL: https://svnweb.freebsd.org/changeset/base/350149
Log:
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.
MFC after: 2 weeks
Relnotes: yes
Sponsored by: iXsystems, Inc.
Modified:
head/sbin/camcontrol/camcontrol.8
head/sbin/camcontrol/camcontrol.c
head/sys/cam/ata/ata_all.c
head/sys/sys/ata.h
Modified: head/sbin/camcontrol/camcontrol.8
==============================================================================
--- head/sbin/camcontrol/camcontrol.8 Fri Jul 19 18:47:13 2019 (r350148)
+++ head/sbin/camcontrol/camcontrol.8 Fri Jul 19 19:15:08 2019 (r350149)
@@ -27,7 +27,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd April 22, 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: head/sbin/camcontrol/camcontrol.c
==============================================================================
--- head/sbin/camcontrol/camcontrol.c Fri Jul 19 18:47:13 2019 (r350148)
+++ head/sbin/camcontrol/camcontrol.c Fri Jul 19 19:15:08 2019 (r350149)
@@ -110,6 +110,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 {
@@ -236,6 +237,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"},
@@ -359,6 +361,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);
@@ -1423,8 +1427,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 {
@@ -1432,6 +1437,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)
{
@@ -2258,7 +2289,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)
@@ -2371,7 +2490,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");
@@ -2392,12 +2511,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);
@@ -2917,7 +3046,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);
@@ -2946,7 +3075,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,
@@ -2959,28 +3088,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;
@@ -2994,7 +3123,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)
{
@@ -9649,6 +9899,7 @@ usage(int printlong)
" [-U <user|master>] [-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"
@@ -9847,6 +10098,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"
@@ -10169,6 +10425,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;
case CAM_CMD_DEVTREE:
Modified: head/sys/cam/ata/ata_all.c
==============================================================================
--- head/sys/cam/ata/ata_all.c Fri Jul 19 18:47:13 2019 (r350148)
+++ head/sys/cam/ata/ata_all.c Fri Jul 19 19:15:08 2019 (r350149)
@@ -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: head/sys/sys/ata.h
==============================================================================
--- head/sys/sys/ata.h Fri Jul 19 18:47:13 2019 (r350148)
+++ head/sys/sys/ata.h Fri Jul 19 19:15:08 2019 (r350149)
@@ -242,12 +242,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;
@@ -436,6 +439,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 */
More information about the svn-src-head
mailing list