summaryrefslogtreecommitdiffstats
path: root/sbin/camcontrol/camcontrol.c
diff options
context:
space:
mode:
Diffstat (limited to 'sbin/camcontrol/camcontrol.c')
-rw-r--r--sbin/camcontrol/camcontrol.c692
1 files changed, 487 insertions, 205 deletions
diff --git a/sbin/camcontrol/camcontrol.c b/sbin/camcontrol/camcontrol.c
index cdb379d..c0a1344 100644
--- a/sbin/camcontrol/camcontrol.c
+++ b/sbin/camcontrol/camcontrol.c
@@ -96,7 +96,9 @@ typedef enum {
CAM_CMD_SECURITY = 0x0000001d,
CAM_CMD_HPA = 0x0000001e,
CAM_CMD_SANITIZE = 0x0000001f,
- CAM_CMD_PERSIST = 0x00000020
+ CAM_CMD_PERSIST = 0x00000020,
+ CAM_CMD_APM = 0x00000021,
+ CAM_CMD_AAM = 0x00000022
} cam_cmdmask;
typedef enum {
@@ -167,7 +169,7 @@ struct ata_set_max_pwd
};
static const char scsicmd_opts[] = "a:c:dfi:o:r";
-static const char readdefect_opts[] = "f:GP";
+static const char readdefect_opts[] = "f:GPqsS:X";
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:";
@@ -216,6 +218,8 @@ static struct camcontrol_opts option_table[] = {
{"idle", CAM_CMD_IDLE, CAM_ARG_NONE, "t:"},
{"standby", CAM_CMD_STANDBY, CAM_ARG_NONE, "t:"},
{"sleep", CAM_CMD_SLEEP, CAM_ARG_NONE, ""},
+ {"apm", CAM_CMD_APM, CAM_ARG_NONE, "l:"},
+ {"aam", CAM_CMD_AAM, CAM_ARG_NONE, "l:"},
{"fwdownload", CAM_CMD_DOWNLOAD_FW, CAM_ARG_NONE, "f:ys"},
{"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"},
@@ -1406,7 +1410,7 @@ atacapprint(struct ata_params *parm)
parm->enabled.command2 & ATA_SUPPORT_APM ? "yes" : "no");
if (parm->support.command2 & ATA_SUPPORT_APM) {
printf(" %d/0x%02X\n",
- parm->apm_value, parm->apm_value);
+ parm->apm_value & 0xff, parm->apm_value & 0xff);
} else
printf("\n");
printf("automatic acoustic management %s %s",
@@ -3369,39 +3373,64 @@ scanlun_or_reset_dev(path_id_t bus, target_id_t target, lun_id_t lun, int scan)
}
#ifndef MINIMALISTIC
+
+static struct scsi_nv defect_list_type_map[] = {
+ { "block", SRDD10_BLOCK_FORMAT },
+ { "extbfi", SRDD10_EXT_BFI_FORMAT },
+ { "extphys", SRDD10_EXT_PHYS_FORMAT },
+ { "longblock", SRDD10_LONG_BLOCK_FORMAT },
+ { "bfi", SRDD10_BYTES_FROM_INDEX_FORMAT },
+ { "phys", SRDD10_PHYSICAL_SECTOR_FORMAT }
+};
+
static int
readdefects(struct cam_device *device, int argc, char **argv,
char *combinedopt, int retry_count, int timeout)
{
union ccb *ccb = NULL;
- struct scsi_read_defect_data_10 *rdd_cdb;
+ struct scsi_read_defect_data_hdr_10 *hdr10 = NULL;
+ struct scsi_read_defect_data_hdr_12 *hdr12 = NULL;
+ size_t hdr_size = 0, entry_size = 0;
+ int use_12byte = 0;
+ int hex_format = 0;
u_int8_t *defect_list = NULL;
- u_int32_t max_dlist_length = SRDD10_MAX_LENGTH, dlist_length = 0;
- u_int32_t returned_length = 0;
- u_int32_t num_returned = 0;
- u_int8_t returned_format;
+ u_int8_t list_format = 0;
+ int list_type_set = 0;
+ u_int32_t dlist_length = 0;
+ u_int32_t returned_length = 0, valid_len = 0;
+ u_int32_t num_returned = 0, num_valid = 0;
+ u_int32_t max_possible_size = 0, hdr_max = 0;
+ u_int32_t starting_offset = 0;
+ u_int8_t returned_format, returned_type;
unsigned int i;
+ int summary = 0, quiet = 0;
int c, error = 0;
- int lists_specified;
- int get_length = 1;
+ int lists_specified = 0;
+ int get_length = 1, first_pass = 1;
+ int mads = 0;
while ((c = getopt(argc, argv, combinedopt)) != -1) {
switch(c){
case 'f':
{
- char *tstr;
- tstr = optarg;
- while (isspace(*tstr) && (*tstr != '\0'))
- tstr++;
- if (strcmp(tstr, "block") == 0)
- arglist |= CAM_ARG_FORMAT_BLOCK;
- else if (strcmp(tstr, "bfi") == 0)
- arglist |= CAM_ARG_FORMAT_BFI;
- else if (strcmp(tstr, "phys") == 0)
- arglist |= CAM_ARG_FORMAT_PHYS;
- else {
+ scsi_nv_status status;
+ int entry_num = 0;
+
+ status = scsi_get_nv(defect_list_type_map,
+ sizeof(defect_list_type_map) /
+ sizeof(defect_list_type_map[0]), optarg,
+ &entry_num, SCSI_NV_FLAG_IG_CASE);
+
+ if (status == SCSI_NV_FOUND) {
+ list_format = defect_list_type_map[
+ entry_num].value;
+ list_type_set = 1;
+ } else {
+ warnx("%s: %s %s option %s", __func__,
+ (status == SCSI_NV_AMBIGUOUS) ?
+ "ambiguous" : "invalid", "defect list type",
+ optarg);
error = 1;
- warnx("invalid defect format %s", tstr);
goto defect_bailout;
}
break;
@@ -3412,40 +3441,82 @@ readdefects(struct cam_device *device, int argc, char **argv,
case 'P':
arglist |= CAM_ARG_PLIST;
break;
+ case 'q':
+ quiet = 1;
+ break;
+ case 's':
+ summary = 1;
+ break;
+ case 'S': {
+ char *endptr;
+
+ starting_offset = strtoul(optarg, &endptr, 0);
+ if (*endptr != '\0') {
+ error = 1;
+ warnx("invalid starting offset %s", optarg);
+ goto defect_bailout;
+ }
+ break;
+ }
+ case 'X':
+ hex_format = 1;
+ break;
default:
break;
}
}
- ccb = cam_getccb(device);
-
- /*
- * Eventually we should probably support the 12 byte READ DEFECT
- * DATA command. It supports a longer parameter list, which may be
- * necessary on newer drives with lots of defects. According to
- * the SBC-3 spec, drives are supposed to return an illegal request
- * if they have more defect data than will fit in 64K.
- */
- defect_list = malloc(max_dlist_length);
- if (defect_list == NULL) {
- warnx("can't malloc memory for defect list");
+ if (list_type_set == 0) {
error = 1;
+ warnx("no defect list format specified");
goto defect_bailout;
}
+ if (arglist & CAM_ARG_PLIST) {
+ list_format |= SRDD10_PLIST;
+ lists_specified++;
+ }
+
+ if (arglist & CAM_ARG_GLIST) {
+ list_format |= SRDD10_GLIST;
+ lists_specified++;
+ }
+
+ /*
+ * This implies a summary, and was the previous behavior.
+ */
+ if (lists_specified == 0)
+ summary = 1;
+
+ ccb = cam_getccb(device);
+
+retry_12byte:
+
/*
* We start off asking for just the header to determine how much
* defect data is available. Some Hitachi drives return an error
* if you ask for more data than the drive has. Once we know the
* length, we retry the command with the returned length.
*/
- dlist_length = sizeof(struct scsi_read_defect_data_hdr_10);
-
- rdd_cdb =(struct scsi_read_defect_data_10 *)&ccb->csio.cdb_io.cdb_bytes;
+ if (use_12byte == 0)
+ dlist_length = sizeof(*hdr10);
+ else
+ dlist_length = sizeof(*hdr12);
retry:
+ if (defect_list != NULL) {
+ free(defect_list);
+ defect_list = NULL;
+ }
+ defect_list = malloc(dlist_length);
+ if (defect_list == NULL) {
+ warnx("can't malloc memory for defect list");
+ error = 1;
+ goto defect_bailout;
+ }
- lists_specified = 0;
+next_batch:
+ bzero(defect_list, dlist_length);
/*
* cam_getccb() zeros the CCB header only. So we need to zero the
@@ -3454,41 +3525,17 @@ retry:
bzero(&(&ccb->ccb_h)[1],
sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
- cam_fill_csio(&ccb->csio,
- /*retries*/ retry_count,
- /*cbfcnp*/ NULL,
- /*flags*/ CAM_DIR_IN | ((arglist & CAM_ARG_ERR_RECOVER) ?
- CAM_PASS_ERR_RECOVER : 0),
- /*tag_action*/ MSG_SIMPLE_Q_TAG,
- /*data_ptr*/ defect_list,
- /*dxfer_len*/ dlist_length,
- /*sense_len*/ SSD_FULL_SIZE,
- /*cdb_len*/ sizeof(struct scsi_read_defect_data_10),
- /*timeout*/ timeout ? timeout : 5000);
-
- rdd_cdb->opcode = READ_DEFECT_DATA_10;
- if (arglist & CAM_ARG_FORMAT_BLOCK)
- rdd_cdb->format = SRDD10_BLOCK_FORMAT;
- else if (arglist & CAM_ARG_FORMAT_BFI)
- rdd_cdb->format = SRDD10_BYTES_FROM_INDEX_FORMAT;
- else if (arglist & CAM_ARG_FORMAT_PHYS)
- rdd_cdb->format = SRDD10_PHYSICAL_SECTOR_FORMAT;
- else {
- error = 1;
- warnx("no defect list format specified");
- goto defect_bailout;
- }
- if (arglist & CAM_ARG_PLIST) {
- rdd_cdb->format |= SRDD10_PLIST;
- lists_specified++;
- }
-
- if (arglist & CAM_ARG_GLIST) {
- rdd_cdb->format |= SRDD10_GLIST;
- lists_specified++;
- }
-
- scsi_ulto2b(dlist_length, rdd_cdb->alloc_length);
+ scsi_read_defects(&ccb->csio,
+ /*retries*/ retry_count,
+ /*cbfcnp*/ NULL,
+ /*tag_action*/ MSG_SIMPLE_Q_TAG,
+ /*list_format*/ list_format,
+ /*addr_desc_index*/ starting_offset,
+ /*data_ptr*/ defect_list,
+ /*dxfer_len*/ dlist_length,
+ /*minimum_cmd_size*/ use_12byte ? 12 : 0,
+ /*sense_len*/ SSD_FULL_SIZE,
+ /*timeout*/ timeout ? timeout : 5000);
/* Disable freezing the device queue */
ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
@@ -3505,8 +3552,61 @@ retry:
goto defect_bailout;
}
- returned_length = scsi_2btoul(((struct
- scsi_read_defect_data_hdr_10 *)defect_list)->length);
+ valid_len = ccb->csio.dxfer_len - ccb->csio.resid;
+
+ if (use_12byte == 0) {
+ hdr10 = (struct scsi_read_defect_data_hdr_10 *)defect_list;
+ hdr_size = sizeof(*hdr10);
+ hdr_max = SRDDH10_MAX_LENGTH;
+
+ if (valid_len >= hdr_size) {
+ returned_length = scsi_2btoul(hdr10->length);
+ returned_format = hdr10->format;
+ } else {
+ returned_length = 0;
+ returned_format = 0;
+ }
+ } else {
+ hdr12 = (struct scsi_read_defect_data_hdr_12 *)defect_list;
+ hdr_size = sizeof(*hdr12);
+ hdr_max = SRDDH12_MAX_LENGTH;
+
+ if (valid_len >= hdr_size) {
+ returned_length = scsi_4btoul(hdr12->length);
+ returned_format = hdr12->format;
+ } else {
+ returned_length = 0;
+ returned_format = 0;
+ }
+ }
+
+ returned_type = returned_format & SRDDH10_DLIST_FORMAT_MASK;
+ switch (returned_type) {
+ case SRDD10_BLOCK_FORMAT:
+ entry_size = sizeof(struct scsi_defect_desc_block);
+ break;
+ case SRDD10_LONG_BLOCK_FORMAT:
+ entry_size = sizeof(struct scsi_defect_desc_long_block);
+ break;
+ case SRDD10_EXT_PHYS_FORMAT:
+ case SRDD10_PHYSICAL_SECTOR_FORMAT:
+ entry_size = sizeof(struct scsi_defect_desc_phys_sector);
+ break;
+ case SRDD10_EXT_BFI_FORMAT:
+ case SRDD10_BYTES_FROM_INDEX_FORMAT:
+ entry_size = sizeof(struct scsi_defect_desc_bytes_from_index);
+ break;
+ default:
+ warnx("Unknown defect format 0x%x\n", returned_type);
+ error = 1;
+ goto defect_bailout;
+ break;
+ }
+
+ max_possible_size = (hdr_max / entry_size) * entry_size;
+ num_returned = returned_length / entry_size;
+ num_valid = min(returned_length, valid_len - hdr_size);
+ num_valid /= entry_size;
if (get_length != 0) {
get_length = 0;
@@ -3530,12 +3630,66 @@ retry:
if ((sense_key == SSD_KEY_RECOVERED_ERROR)
&& (asc == 0x1c) && (ascq == 0x00)
&& (returned_length > 0)) {
- dlist_length = returned_length +
- sizeof(struct scsi_read_defect_data_hdr_10);
- dlist_length = min(dlist_length,
- SRDD10_MAX_LENGTH);
- } else
- dlist_length = max_dlist_length;
+ if ((use_12byte == 0)
+ && (returned_length >= max_possible_size)) {
+ get_length = 1;
+ use_12byte = 1;
+ goto retry_12byte;
+ }
+ dlist_length = returned_length + hdr_size;
+ } else if ((sense_key == SSD_KEY_RECOVERED_ERROR)
+ && (asc == 0x1f) && (ascq == 0x00)
+ && (returned_length > 0)) {
+ /* Partial defect list transfer */
+ /*
+ * Hitachi drives return this error
+ * along with a partial defect list if they
+ * have more defects than the 10 byte
+ * command can support. Retry with the 12
+ * byte command.
+ */
+ if (use_12byte == 0) {
+ get_length = 1;
+ use_12byte = 1;
+ goto retry_12byte;
+ }
+ dlist_length = returned_length + hdr_size;
+ } else if ((sense_key == SSD_KEY_ILLEGAL_REQUEST)
+ && (asc == 0x24) && (ascq == 0x00)) {
+ /* Invalid field in CDB */
+ /*
+ * SBC-3 says that if the drive has more
+ * defects than can be reported with the
+ * 10 byte command, it should return this
+ * error and no data. Retry with the 12
+ * byte command.
+ */
+ if (use_12byte == 0) {
+ get_length = 1;
+ use_12byte = 1;
+ goto retry_12byte;
+ }
+ dlist_length = returned_length + hdr_size;
+ } else {
+ /*
+ * If we got a SCSI error and no valid length,
+ * just use the 10 byte maximum. The 12
+ * byte maximum is too large.
+ */
+ if (returned_length == 0)
+ dlist_length = SRDD10_MAX_LENGTH;
+ else {
+ if ((use_12byte == 0)
+ && (returned_length >=
+ max_possible_size)) {
+ get_length = 1;
+ use_12byte = 1;
+ goto retry_12byte;
+ }
+ dlist_length = returned_length +
+ hdr_size;
+ }
+ }
} else if ((ccb->ccb_h.status & CAM_STATUS_MASK) !=
CAM_REQ_CMP){
error = 1;
@@ -3545,16 +3699,40 @@ retry:
CAM_EPF_ALL, stderr);
goto defect_bailout;
} else {
- dlist_length = returned_length +
- sizeof(struct scsi_read_defect_data_hdr_10);
- dlist_length = min(dlist_length, SRDD10_MAX_LENGTH);
+ if ((use_12byte == 0)
+ && (returned_length >= max_possible_size)) {
+ get_length = 1;
+ use_12byte = 1;
+ goto retry_12byte;
+ }
+ dlist_length = returned_length + hdr_size;
}
+ if (summary != 0) {
+ fprintf(stdout, "%u", num_returned);
+ if (quiet == 0) {
+ fprintf(stdout, " defect%s",
+ (num_returned != 1) ? "s" : "");
+ }
+ fprintf(stdout, "\n");
+
+ goto defect_bailout;
+ }
+
+ /*
+ * We always limit the list length to the 10-byte maximum
+ * length (0xffff). The reason is that some controllers
+ * can't handle larger I/Os, and we can transfer the entire
+ * 10 byte list in one shot. For drives that support the 12
+ * byte read defects command, we'll step through the list
+ * by specifying a starting offset. For drives that don't
+ * support the 12 byte command's starting offset, we'll
+ * just display the first 64K.
+ */
+ dlist_length = min(dlist_length, SRDD10_MAX_LENGTH);
goto retry;
}
- returned_format = ((struct scsi_read_defect_data_hdr_10 *)
- defect_list)->format;
if (((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_SCSI_STATUS_ERROR)
&& (ccb->csio.scsi_status == SCSI_STATUS_CHECK_COND)
@@ -3571,32 +3749,32 @@ retry:
* According to the SCSI spec, if the disk doesn't support
* the requested format, it will generally return a sense
* key of RECOVERED ERROR, and an additional sense code
- * of "DEFECT LIST NOT FOUND". So, we check for that, and
- * also check to make sure that the returned length is
- * greater than 0, and then print out whatever format the
- * disk gave us.
+ * of "DEFECT LIST NOT FOUND". HGST drives also return
+ * Primary/Grown defect list not found errors. So just
+ * check for an ASC of 0x1c.
*/
if ((sense_key == SSD_KEY_RECOVERED_ERROR)
- && (asc == 0x1c) && (ascq == 0x00)
- && (returned_length > 0)) {
- warnx("requested defect format not available");
- switch(returned_format & SRDDH10_DLIST_FORMAT_MASK) {
- case SRDD10_BLOCK_FORMAT:
- warnx("Device returned block format");
- break;
- case SRDD10_BYTES_FROM_INDEX_FORMAT:
- warnx("Device returned bytes from index"
- " format");
- break;
- case SRDD10_PHYSICAL_SECTOR_FORMAT:
- warnx("Device returned physical sector format");
- break;
- default:
+ && (asc == 0x1c)) {
+ const char *format_str;
+
+ format_str = scsi_nv_to_str(defect_list_type_map,
+ sizeof(defect_list_type_map) /
+ sizeof(defect_list_type_map[0]),
+ list_format & SRDD10_DLIST_FORMAT_MASK);
+ warnx("requested defect format %s not available",
+ format_str ? format_str : "unknown");
+
+ format_str = scsi_nv_to_str(defect_list_type_map,
+ sizeof(defect_list_type_map) /
+ sizeof(defect_list_type_map[0]), returned_type);
+ if (format_str != NULL) {
+ warnx("Device returned %s format",
+ format_str);
+ } else {
error = 1;
warnx("Device returned unknown defect"
- " data format %#x", returned_format);
+ " data format %#x", returned_type);
goto defect_bailout;
- break; /* NOTREACHED */
}
} else {
error = 1;
@@ -3615,99 +3793,151 @@ retry:
goto defect_bailout;
}
+ if (first_pass != 0) {
+ fprintf(stderr, "Got %d defect", num_returned);
+
+ if ((lists_specified == 0) || (num_returned == 0)) {
+ fprintf(stderr, "s.\n");
+ goto defect_bailout;
+ } else if (num_returned == 1)
+ fprintf(stderr, ":\n");
+ else
+ fprintf(stderr, "s:\n");
+
+ first_pass = 0;
+ }
+
/*
* XXX KDM I should probably clean up the printout format for the
* disk defects.
*/
- switch (returned_format & SRDDH10_DLIST_FORMAT_MASK){
- case SRDDH10_PHYSICAL_SECTOR_FORMAT:
- {
- struct scsi_defect_desc_phys_sector *dlist;
-
- dlist = (struct scsi_defect_desc_phys_sector *)
- (defect_list +
- sizeof(struct scsi_read_defect_data_hdr_10));
-
- num_returned = returned_length /
- sizeof(struct scsi_defect_desc_phys_sector);
-
- fprintf(stderr, "Got %d defect", num_returned);
-
- if ((lists_specified == 0) || (num_returned == 0)) {
- fprintf(stderr, "s.\n");
- break;
- } else if (num_returned == 1)
- fprintf(stderr, ":\n");
+ switch (returned_type) {
+ case SRDD10_PHYSICAL_SECTOR_FORMAT:
+ case SRDD10_EXT_PHYS_FORMAT:
+ {
+ struct scsi_defect_desc_phys_sector *dlist;
+
+ dlist = (struct scsi_defect_desc_phys_sector *)
+ (defect_list + hdr_size);
+
+ for (i = 0; i < num_valid; i++) {
+ uint32_t sector;
+
+ sector = scsi_4btoul(dlist[i].sector);
+ if (returned_type == SRDD10_EXT_PHYS_FORMAT) {
+ mads = (sector & SDD_EXT_PHYS_MADS) ?
+ 0 : 1;
+ sector &= ~SDD_EXT_PHYS_FLAG_MASK;
+ }
+ if (hex_format == 0)
+ fprintf(stdout, "%d:%d:%d%s",
+ scsi_3btoul(dlist[i].cylinder),
+ dlist[i].head,
+ scsi_4btoul(dlist[i].sector),
+ mads ? " - " : "\n");
else
- fprintf(stderr, "s:\n");
-
- for (i = 0; i < num_returned; i++) {
- fprintf(stdout, "%d:%d:%d\n",
+ fprintf(stdout, "0x%x:0x%x:0x%x%s",
scsi_3btoul(dlist[i].cylinder),
dlist[i].head,
- scsi_4btoul(dlist[i].sector));
- }
- break;
+ scsi_4btoul(dlist[i].sector),
+ mads ? " - " : "\n");
+ mads = 0;
}
- case SRDDH10_BYTES_FROM_INDEX_FORMAT:
- {
- struct scsi_defect_desc_bytes_from_index *dlist;
-
- dlist = (struct scsi_defect_desc_bytes_from_index *)
- (defect_list +
- sizeof(struct scsi_read_defect_data_hdr_10));
+ if (num_valid < num_returned) {
+ starting_offset += num_valid;
+ goto next_batch;
+ }
+ break;
+ }
+ case SRDD10_BYTES_FROM_INDEX_FORMAT:
+ case SRDD10_EXT_BFI_FORMAT:
+ {
+ struct scsi_defect_desc_bytes_from_index *dlist;
- num_returned = returned_length /
- sizeof(struct scsi_defect_desc_bytes_from_index);
+ dlist = (struct scsi_defect_desc_bytes_from_index *)
+ (defect_list + hdr_size);
- fprintf(stderr, "Got %d defect", num_returned);
+ for (i = 0; i < num_valid; i++) {
+ uint32_t bfi;
- if ((lists_specified == 0) || (num_returned == 0)) {
- fprintf(stderr, "s.\n");
- break;
- } else if (num_returned == 1)
- fprintf(stderr, ":\n");
+ bfi = scsi_4btoul(dlist[i].bytes_from_index);
+ if (returned_type == SRDD10_EXT_BFI_FORMAT) {
+ mads = (bfi & SDD_EXT_BFI_MADS) ? 1 : 0;
+ bfi &= ~SDD_EXT_BFI_FLAG_MASK;
+ }
+ if (hex_format == 0)
+ fprintf(stdout, "%d:%d:%d%s",
+ scsi_3btoul(dlist[i].cylinder),
+ dlist[i].head,
+ scsi_4btoul(dlist[i].bytes_from_index),
+ mads ? " - " : "\n");
else
- fprintf(stderr, "s:\n");
-
- for (i = 0; i < num_returned; i++) {
- fprintf(stdout, "%d:%d:%d\n",
+ fprintf(stdout, "0x%x:0x%x:0x%x%s",
scsi_3btoul(dlist[i].cylinder),
dlist[i].head,
- scsi_4btoul(dlist[i].bytes_from_index));
- }
- break;
+ scsi_4btoul(dlist[i].bytes_from_index),
+ mads ? " - " : "\n");
+
+ mads = 0;
}
- case SRDDH10_BLOCK_FORMAT:
- {
- struct scsi_defect_desc_block *dlist;
+ if (num_valid < num_returned) {
+ starting_offset += num_valid;
+ goto next_batch;
+ }
+ break;
+ }
+ case SRDDH10_BLOCK_FORMAT:
+ {
+ struct scsi_defect_desc_block *dlist;
- dlist = (struct scsi_defect_desc_block *)(defect_list +
- sizeof(struct scsi_read_defect_data_hdr_10));
+ dlist = (struct scsi_defect_desc_block *)
+ (defect_list + hdr_size);
- num_returned = returned_length /
- sizeof(struct scsi_defect_desc_block);
+ for (i = 0; i < num_valid; i++) {
+ if (hex_format == 0)
+ fprintf(stdout, "%u\n",
+ scsi_4btoul(dlist[i].address));
+ else
+ fprintf(stdout, "0x%x\n",
+ scsi_4btoul(dlist[i].address));
+ }
- fprintf(stderr, "Got %d defect", num_returned);
+ if (num_valid < num_returned) {
+ starting_offset += num_valid;
+ goto next_batch;
+ }
- if ((lists_specified == 0) || (num_returned == 0)) {
- fprintf(stderr, "s.\n");
- break;
- } else if (num_returned == 1)
- fprintf(stderr, ":\n");
+ break;
+ }
+ case SRDD10_LONG_BLOCK_FORMAT:
+ {
+ struct scsi_defect_desc_long_block *dlist;
+
+ dlist = (struct scsi_defect_desc_long_block *)
+ (defect_list + hdr_size);
+
+ for (i = 0; i < num_valid; i++) {
+ if (hex_format == 0)
+ fprintf(stdout, "%ju\n",
+ (uintmax_t)scsi_8btou64(
+ dlist[i].address));
else
- fprintf(stderr, "s:\n");
+ fprintf(stdout, "0x%jx\n",
+ (uintmax_t)scsi_8btou64(
+ dlist[i].address));
+ }
- for (i = 0; i < num_returned; i++)
- fprintf(stdout, "%u\n",
- scsi_4btoul(dlist[i].address));
- break;
+ if (num_valid < num_returned) {
+ starting_offset += num_valid;
+ goto next_batch;
}
- default:
- fprintf(stderr, "Unknown defect format %d\n",
- returned_format & SRDDH10_DLIST_FORMAT_MASK);
- error = 1;
- break;
+ break;
+ }
+ default:
+ fprintf(stderr, "Unknown defect format 0x%x\n",
+ returned_type);
+ error = 1;
+ break;
}
defect_bailout:
@@ -7178,7 +7408,7 @@ getdevid(struct cam_devitem *item)
retry:
ccb->ccb_h.func_code = XPT_DEV_ADVINFO;
ccb->ccb_h.flags = CAM_DIR_IN;
- ccb->cdai.flags = 0;
+ ccb->cdai.flags = CDAI_FLAG_NONE;
ccb->cdai.buftype = CDAI_TYPE_SCSI_DEVID;
ccb->cdai.bufsiz = item->device_id_len;
if (item->device_id_len != 0)
@@ -7738,39 +7968,83 @@ atapm(struct cam_device *device, int argc, char **argv,
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;
+ retval = ata_do_28bit_cmd(device,
+ ccb,
+ /*retries*/retry_count,
+ /*flags*/CAM_DIR_NONE,
+ /*protocol*/AP_PROTO_NON_DATA,
+ /*tag_action*/MSG_SIMPLE_Q_TAG,
+ /*command*/cmd,
+ /*features*/0,
+ /*lba*/0,
+ /*sector_count*/sc,
+ /*data_ptr*/NULL,
+ /*dxfer_len*/0,
+ /*timeout*/timeout ? timeout : 30 * 1000,
+ /*quiet*/1);
- if (arglist & CAM_ARG_ERR_RECOVER)
- ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
+ cam_freeccb(ccb);
+ return (retval);
+}
- if (cam_send_ccb(device, ccb) < 0) {
- warn("error sending command");
+static int
+ataaxm(struct cam_device *device, int argc, char **argv,
+ char *combinedopt, int retry_count, int timeout)
+{
+ union ccb *ccb;
+ int retval = 0;
+ int l = -1;
+ int c;
+ u_char cmd, sc;
- if (arglist & CAM_ARG_VERBOSE)
- cam_error_print(device, ccb, CAM_ESF_ALL,
- CAM_EPF_ALL, stderr);
+ ccb = cam_getccb(device);
- retval = 1;
- goto bailout;
+ if (ccb == NULL) {
+ warnx("%s: error allocating ccb", __func__);
+ return (1);
}
- 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;
- goto bailout;
+ while ((c = getopt(argc, argv, combinedopt)) != -1) {
+ switch (c) {
+ case 'l':
+ l = atoi(optarg);
+ break;
+ default:
+ break;
+ }
}
-bailout:
+ sc = 0;
+ if (strcmp(argv[1], "apm") == 0) {
+ if (l == -1)
+ cmd = 0x85;
+ else {
+ cmd = 0x05;
+ sc = l;
+ }
+ } else /* aam */ {
+ if (l == -1)
+ cmd = 0xC2;
+ else {
+ cmd = 0x42;
+ sc = l;
+ }
+ }
+
+ retval = ata_do_28bit_cmd(device,
+ ccb,
+ /*retries*/retry_count,
+ /*flags*/CAM_DIR_NONE,
+ /*protocol*/AP_PROTO_NON_DATA,
+ /*tag_action*/MSG_SIMPLE_Q_TAG,
+ /*command*/ATA_SETFEATURES,
+ /*features*/cmd,
+ /*lba*/0,
+ /*sector_count*/sc,
+ /*data_ptr*/NULL,
+ /*dxfer_len*/0,
+ /*timeout*/timeout ? timeout : 30 * 1000,
+ /*quiet*/1);
+
cam_freeccb(ccb);
return (retval);
}
@@ -7801,6 +8075,7 @@ usage(int printlong)
" camcontrol reset <all | bus[:target:lun]>\n"
#ifndef MINIMALISTIC
" camcontrol defects [dev_id][generic args] <-f format> [-P][-G]\n"
+" [-q][-s][-S offset][-X]\n"
" camcontrol modepage [dev_id][generic args] <-m page | -l>\n"
" [-P pagectl][-e | -b][-d]\n"
" camcontrol cmd [dev_id][generic args]\n"
@@ -7831,6 +8106,8 @@ usage(int printlong)
" camcontrol idle [dev_id][generic args][-t time]\n"
" camcontrol standby [dev_id][generic args][-t time]\n"
" camcontrol sleep [dev_id][generic args]\n"
+" camcontrol apm [dev_id][generic args][-l level]\n"
+" camcontrol aam [dev_id][generic args][-l level]\n"
" camcontrol fwdownload [dev_id][generic args] <-f fw_image> [-y][-s]\n"
" camcontrol security [dev_id][generic args]\n"
" <-d pwd | -e pwd | -f | -h pwd | -k pwd>\n"
@@ -8351,6 +8628,11 @@ main(int argc, char **argv)
error = atapm(cam_dev, argc, argv,
combinedopt, retry_count, timeout);
break;
+ case CAM_CMD_APM:
+ case CAM_CMD_AAM:
+ error = ataaxm(cam_dev, argc, argv,
+ combinedopt, retry_count, timeout);
+ break;
case CAM_CMD_SECURITY:
error = atasecurity(cam_dev, retry_count, timeout,
argc, argv, combinedopt);
OpenPOWER on IntegriCloud