diff options
Diffstat (limited to 'sbin/camcontrol/camcontrol.c')
-rw-r--r-- | sbin/camcontrol/camcontrol.c | 211 |
1 files changed, 205 insertions, 6 deletions
diff --git a/sbin/camcontrol/camcontrol.c b/sbin/camcontrol/camcontrol.c index 7afd641..90a6a52 100644 --- a/sbin/camcontrol/camcontrol.c +++ b/sbin/camcontrol/camcontrol.c @@ -101,7 +101,9 @@ typedef enum { CAM_CMD_AAM = 0x00000022, CAM_CMD_ATTRIB = 0x00000023, CAM_CMD_OPCODES = 0x00000024, - CAM_CMD_REPROBE = 0x00000025 + CAM_CMD_REPROBE = 0x00000025, + CAM_CMD_ZONE = 0x00000026, + CAM_CMD_EPC = 0x00000027 } cam_cmdmask; typedef enum { @@ -230,6 +232,8 @@ static struct camcontrol_opts option_table[] = { {"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"}, + {"zone", CAM_CMD_ZONE, CAM_ARG_NONE, "ac:l:No:P:"}, + {"epc", CAM_CMD_EPC, CAM_ARG_NONE, "c:dDeHp:Pr:sS:T:"}, #endif /* MINIMALISTIC */ {"help", CAM_CMD_USAGE, CAM_ARG_NONE, NULL}, {"-?", CAM_CMD_USAGE, CAM_ARG_NONE, NULL}, @@ -5071,13 +5075,16 @@ bailout: return (retval); } -void +int build_ata_cmd(union ccb *ccb, uint32_t retry_count, uint32_t flags, uint8_t tag_action, uint8_t protocol, uint8_t ata_flags, uint16_t features, - uint16_t sector_count, uint64_t lba, uint8_t command, uint8_t *data_ptr, - uint16_t dxfer_len, uint8_t sense_len, uint32_t timeout, + uint16_t sector_count, uint64_t lba, uint8_t command, uint32_t auxiliary, + uint8_t *data_ptr, uint32_t dxfer_len, uint8_t *cdb_storage, + size_t cdb_storage_len, uint8_t sense_len, uint32_t timeout, int is48bit, camcontrol_devtype devtype) { + int retval = 0; + if (devtype == CC_DT_ATA) { cam_fill_ataio(&ccb->ataio, /*retries*/ retry_count, @@ -5093,11 +5100,24 @@ build_ata_cmd(union ccb *ccb, uint32_t retry_count, uint32_t flags, else ata_28bit_cmd(&ccb->ataio, command, features, lba, sector_count); + + if (auxiliary != 0) { + ccb->ataio.ata_flags |= ATA_FLAG_AUX; + ccb->ataio.aux = auxiliary; + } + + if (ata_flags & AP_FLAG_CHK_COND) + ccb->ataio.cmd.flags |= CAM_ATAIO_NEEDRESULT; + + if ((protocol & AP_PROTO_MASK) == AP_PROTO_DMA) + ccb->ataio.cmd.flags |= CAM_ATAIO_DMA; + else if ((protocol & AP_PROTO_MASK) == AP_PROTO_FPDMA) + ccb->ataio.cmd.flags |= CAM_ATAIO_FPDMA; } else { if (is48bit || lba > ATA_MAX_28BIT_LBA) protocol |= AP_EXTEND; - scsi_ata_pass_16(&ccb->csio, + retval = scsi_ata_pass(&ccb->csio, /*retries*/ retry_count, /*cbfcnp*/ NULL, /*flags*/ flags, @@ -5108,14 +5128,158 @@ build_ata_cmd(union ccb *ccb, uint32_t retry_count, uint32_t flags, /*sector_count*/ sector_count, /*lba*/ lba, /*command*/ command, + /*device*/ 0, + /*icc*/ 0, + /*auxiliary*/ auxiliary, /*control*/ 0, /*data_ptr*/ data_ptr, /*dxfer_len*/ dxfer_len, + /*cdb_storage*/ cdb_storage, + /*cdb_storage_len*/ cdb_storage_len, + /*minimum_cmd_size*/ 0, /*sense_len*/ sense_len, /*timeout*/ timeout); } + + return (retval); } +int +get_ata_status(struct cam_device *dev, union ccb *ccb, uint8_t *error, + uint16_t *count, uint64_t *lba, uint8_t *device, uint8_t *status) +{ + int retval = 0; + + switch (ccb->ccb_h.func_code) { + case XPT_SCSI_IO: { + uint8_t opcode; + int error_code = 0, sense_key = 0, asc = 0, ascq = 0; + + /* + * In this case, we have SCSI ATA PASS-THROUGH command, 12 + * or 16 byte, and need to see what + */ + if (ccb->ccb_h.flags & CAM_CDB_POINTER) + opcode = ccb->csio.cdb_io.cdb_ptr[0]; + else + opcode = ccb->csio.cdb_io.cdb_bytes[0]; + if ((opcode != ATA_PASS_12) + && (opcode != ATA_PASS_16)) { + retval = 1; + warnx("%s: unsupported opcode %02x", __func__, opcode); + goto bailout; + } + + retval = scsi_extract_sense_ccb(ccb, &error_code, &sense_key, + &asc, &ascq); + /* Note: the _ccb() variant returns 0 for an error */ + if (retval == 0) { + retval = 1; + goto bailout; + } else + retval = 0; + + switch (error_code) { + case SSD_DESC_CURRENT_ERROR: + case SSD_DESC_DEFERRED_ERROR: { + struct scsi_sense_data_desc *sense; + struct scsi_sense_ata_ret_desc *desc; + uint8_t *desc_ptr; + + sense = (struct scsi_sense_data_desc *) + &ccb->csio.sense_data; + + desc_ptr = scsi_find_desc(sense, ccb->csio.sense_len - + ccb->csio.sense_resid, SSD_DESC_ATA); + if (desc_ptr == NULL) { + cam_error_print(dev, ccb, CAM_ESF_ALL, + CAM_EPF_ALL, stderr); + retval = 1; + goto bailout; + } + desc = (struct scsi_sense_ata_ret_desc *)desc_ptr; + + *error = desc->error; + *count = (desc->count_15_8 << 8) | + desc->count_7_0; + *lba = ((uint64_t)desc->lba_47_40 << 40) | + ((uint64_t)desc->lba_39_32 << 32) | + (desc->lba_31_24 << 24) | + (desc->lba_23_16 << 16) | + (desc->lba_15_8 << 8) | + desc->lba_7_0; + *device = desc->device; + *status = desc->status; + + /* + * If the extend bit isn't set, the result is for a + * 12-byte ATA PASS-THROUGH command or a 16 or 32 byte + * command without the extend bit set. This means + * that the device is supposed to return 28-bit + * status. The count field is only 8 bits, and the + * LBA field is only 8 bits. + */ + if ((desc->flags & SSD_DESC_ATA_FLAG_EXTEND) == 0){ + *count &= 0xff; + *lba &= 0x0fffffff; + } + break; + } + case SSD_CURRENT_ERROR: + case SSD_DEFERRED_ERROR: { +#if 0 + struct scsi_sense_data_fixed *sense; +#endif + /* + * XXX KDM need to support fixed sense data. + */ + warnx("%s: Fixed sense data not supported yet", + __func__); + retval = 1; + goto bailout; + break; /*NOTREACHED*/ + } + default: + retval = 1; + goto bailout; + break; + } + + break; + } + case XPT_ATA_IO: { + struct ata_res *res; + + /* + * In this case, we have an ATA command, and we need to + * fill in the requested values from the result register + * set. + */ + res = &ccb->ataio.res; + *error = res->error; + *status = res->status; + *device = res->device; + *count = res->sector_count; + *lba = (res->lba_high << 16) | + (res->lba_mid << 8) | + (res->lba_low); + if (res->flags & CAM_ATAIO_48BIT) { + *count |= (res->sector_count_exp << 8); + *lba |= (res->lba_low_exp << 24) | + ((uint64_t)res->lba_mid_exp << 32) | + ((uint64_t)res->lba_high_exp << 40); + } else { + *lba |= (res->device & 0xf) << 24; + } + break; + } + default: + retval = 1; + break; + } +bailout: + return (retval); +} static void cpi_print(struct ccb_pathinq *cpi) @@ -8774,6 +8938,11 @@ usage(int printlong) " [-p part][-s start][-T type][-V vol]\n" " camcontrol opcodes [dev_id][generic args][-o opcode][-s SA]\n" " [-N][-T]\n" +" camcontrol zone [dev_id][generic args]<-c cmd> [-a] [-l LBA]\n" +" [-o rep_opts] [-P print_opts]\n" +" camcontrol epc [dev_id][generic_args]<-c cmd> [-d] [-D] [-e]\n" +" [-H] [-p power_cond] [-P] [-r rst_src] [-s]\n" +" [-S power_src] [-T timer]\n" #endif /* MINIMALISTIC */ " camcontrol help\n"); if (!printlong) @@ -8816,6 +8985,8 @@ usage(int printlong) "persist send the SCSI PERSISTENT RESERVE IN or OUT commands\n" "attrib send the SCSI READ or WRITE ATTRIBUTE commands\n" "opcodes send the SCSI REPORT SUPPORTED OPCODES command\n" +"zone manage Zoned Block (Shingled) devices\n" +"epc send ATA Extended Power Conditions commands\n" "help this message\n" "Device Identifiers:\n" "bus:target specify the bus and target, lun defaults to 0\n" @@ -8986,6 +9157,27 @@ usage(int printlong) "-s service_action specify the service action for the opcode\n" "-N do not return SCSI error for unsupported SA\n" "-T request nominal and recommended timeout values\n" +"zone arguments:\n" +"-c cmd required: rz, open, close, finish, or rwp\n" +"-a apply the action to all zones\n" +"-l LBA specify the zone starting LBA\n" +"-o rep_opts report zones options: all, empty, imp_open, exp_open,\n" +" closed, full, ro, offline, reset, nonseq, nonwp\n" +"-P print_opt report zones printing: normal, summary, script\n" +"epc arguments:\n" +"-c cmd required: restore, goto, timer, state, enable, disable,\n" +" source, status, list\n" +"-d disable power mode (timer, state)\n" +"-D delayed entry (goto)\n" +"-e enable power mode (timer, state)\n" +"-H hold power mode (goto)\n" +"-p power_cond Idle_a, Idle_b, Idle_c, Standby_y, Standby_z (timer,\n" +" state, goto)\n" +"-P only display power mode (status)\n" +"-r rst_src restore settings from: default, saved (restore)\n" +"-s save mode (timer, state, restore)\n" +"-S power_src set power source: battery, nonbattery (source)\n" +"-T timer set timer, seconds, .1 sec resolution (timer)\n" ); #endif /* MINIMALISTIC */ } @@ -9341,7 +9533,14 @@ main(int argc, char **argv) case CAM_CMD_REPROBE: error = scsireprobe(cam_dev); break; - + case CAM_CMD_ZONE: + error = zone(cam_dev, argc, argv, combinedopt, + retry_count, timeout, arglist & CAM_ARG_VERBOSE); + break; + case CAM_CMD_EPC: + error = epc(cam_dev, argc, argv, combinedopt, + retry_count, timeout, arglist & CAM_ARG_VERBOSE); + break; #endif /* MINIMALISTIC */ case CAM_CMD_USAGE: usage(1); |