1 /*- 2 * Copyright (c) 2016 Spectra Logic Corporation 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions, and the following disclaimer, 10 * without modification. 11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12 * substantially similar to the "NO WARRANTY" disclaimer below 13 * ("Disclaimer") and any redistribution must be conditioned upon 14 * including a substantially similar Disclaimer requirement for further 15 * binary redistribution. 16 * 17 * NO WARRANTY 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 27 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGES. 29 * 30 * Authors: Ken Merry (Spectra Logic Corporation) 31 */ 32 /* 33 * ATA Extended Power Conditions (EPC) support 34 */ 35 36 #include <sys/cdefs.h> 37 __FBSDID("$FreeBSD$"); 38 39 #include <sys/ioctl.h> 40 #include <sys/stdint.h> 41 #include <sys/types.h> 42 #include <sys/endian.h> 43 #include <sys/sbuf.h> 44 #include <sys/queue.h> 45 #include <sys/ata.h> 46 47 #include <stdio.h> 48 #include <stdlib.h> 49 #include <inttypes.h> 50 #include <unistd.h> 51 #include <string.h> 52 #include <strings.h> 53 #include <fcntl.h> 54 #include <ctype.h> 55 #include <limits.h> 56 #include <err.h> 57 #include <locale.h> 58 59 #include <cam/cam.h> 60 #include <cam/cam_debug.h> 61 #include <cam/cam_ccb.h> 62 #include <cam/scsi/scsi_all.h> 63 #include <cam/scsi/scsi_da.h> 64 #include <cam/scsi/scsi_pass.h> 65 #include <cam/scsi/scsi_message.h> 66 #include <camlib.h> 67 #include "camcontrol.h" 68 69 typedef enum { 70 EPC_ACTION_NONE = 0x00, 71 EPC_ACTION_LIST = 0x01, 72 EPC_ACTION_TIMER_SET = 0x02, 73 EPC_ACTION_IMMEDIATE = 0x03, 74 EPC_ACTION_GETMODE = 0x04 75 } epc_action; 76 77 static struct scsi_nv epc_flags[] = { 78 { "Supported", ATA_PCL_COND_SUPPORTED }, 79 { "Saveable", ATA_PCL_COND_SUPPORTED }, 80 { "Changeable", ATA_PCL_COND_CHANGEABLE }, 81 { "Default Timer Enabled", ATA_PCL_DEFAULT_TIMER_EN }, 82 { "Saved Timer Enabled", ATA_PCL_SAVED_TIMER_EN }, 83 { "Current Timer Enabled", ATA_PCL_CURRENT_TIMER_EN }, 84 { "Hold Power Condition Not Supported", ATA_PCL_HOLD_PC_NOT_SUP } 85 }; 86 87 static struct scsi_nv epc_power_cond_map[] = { 88 { "Standby_z", ATA_EPC_STANDBY_Z }, 89 { "z", ATA_EPC_STANDBY_Z }, 90 { "Standby_y", ATA_EPC_STANDBY_Y }, 91 { "y", ATA_EPC_STANDBY_Y }, 92 { "Idle_a", ATA_EPC_IDLE_A }, 93 { "a", ATA_EPC_IDLE_A }, 94 { "Idle_b", ATA_EPC_IDLE_B }, 95 { "b", ATA_EPC_IDLE_B }, 96 { "Idle_c", ATA_EPC_IDLE_C }, 97 { "c", ATA_EPC_IDLE_C } 98 }; 99 100 static struct scsi_nv epc_rst_val[] = { 101 { "default", ATA_SF_EPC_RST_DFLT }, 102 { "saved", 0} 103 }; 104 105 static struct scsi_nv epc_ps_map[] = { 106 { "unknown", ATA_SF_EPC_SRC_UNKNOWN }, 107 { "battery", ATA_SF_EPC_SRC_BAT }, 108 { "notbattery", ATA_SF_EPC_SRC_NOT_BAT } 109 }; 110 111 /* 112 * These aren't subcommands of the EPC SET FEATURES subcommand, but rather 113 * commands that determine the current capabilities and status of the drive. 114 * The EPC subcommands are limited to 4 bits, so we won't collide with any 115 * future values. 116 */ 117 #define CCTL_EPC_GET_STATUS 0x8001 118 #define CCTL_EPC_LIST 0x8002 119 120 static struct scsi_nv epc_cmd_map[] = { 121 { "restore", ATA_SF_EPC_RESTORE }, 122 { "goto", ATA_SF_EPC_GOTO }, 123 { "timer", ATA_SF_EPC_SET_TIMER }, 124 { "state", ATA_SF_EPC_SET_STATE }, 125 { "enable", ATA_SF_EPC_ENABLE }, 126 { "disable", ATA_SF_EPC_DISABLE }, 127 { "source", ATA_SF_EPC_SET_SOURCE }, 128 { "status", CCTL_EPC_GET_STATUS }, 129 { "list", CCTL_EPC_LIST } 130 }; 131 132 static int epc_list(struct cam_device *device, camcontrol_devtype devtype, 133 union ccb *ccb, int retry_count, int timeout); 134 static void epc_print_pcl_desc(struct ata_power_cond_log_desc *desc, 135 const char *prefix); 136 static int epc_getmode(struct cam_device *device, camcontrol_devtype devtype, 137 union ccb *ccb, int retry_count, int timeout, 138 int power_only); 139 static int epc_set_features(struct cam_device *device, 140 camcontrol_devtype devtype, union ccb *ccb, 141 int retry_count, int timeout, int action, 142 int power_cond, int timer, int enable, int save, 143 int delayed_entry, int hold, int power_src, 144 int restore_src); 145 146 static void 147 epc_print_pcl_desc(struct ata_power_cond_log_desc *desc, const char *prefix) 148 { 149 int first; 150 unsigned int i, num_printed, max_chars; 151 152 first = 1; 153 max_chars = 75; 154 155 num_printed = printf("%sFlags: ", prefix); 156 for (i = 0; i < (sizeof(epc_flags) / sizeof(epc_flags[0])); i++) { 157 if ((desc->flags & epc_flags[i].value) == 0) 158 continue; 159 if (first == 0) { 160 num_printed += printf(", "); 161 } 162 if ((num_printed + strlen(epc_flags[i].name)) > max_chars) { 163 printf("\n"); 164 num_printed = printf("%s ", prefix); 165 } 166 num_printed += printf("%s", epc_flags[i].name); 167 first = 0; 168 } 169 if (first != 0) 170 printf("None"); 171 printf("\n"); 172 173 printf("%sDefault timer setting: %.1f sec\n", prefix, 174 (double)(le32dec(desc->default_timer) / 10)); 175 printf("%sSaved timer setting: %.1f sec\n", prefix, 176 (double)(le32dec(desc->saved_timer) / 10)); 177 printf("%sCurrent timer setting: %.1f sec\n", prefix, 178 (double)(le32dec(desc->current_timer) / 10)); 179 printf("%sNominal time to active: %.1f sec\n", prefix, 180 (double)(le32dec(desc->nom_time_to_active) / 10)); 181 printf("%sMinimum timer: %.1f sec\n", prefix, 182 (double)(le32dec(desc->min_timer) / 10)); 183 printf("%sMaximum timer: %.1f sec\n", prefix, 184 (double)(le32dec(desc->max_timer) / 10)); 185 printf("%sNumber of transitions to power condition: %u\n", prefix, 186 le32dec(desc->num_transitions_to_pc)); 187 printf("%sHours in power condition: %u\n", prefix, 188 le32dec(desc->hours_in_pc)); 189 } 190 191 static int 192 epc_list(struct cam_device *device, camcontrol_devtype devtype, union ccb *ccb, 193 int retry_count, int timeout) 194 { 195 struct ata_power_cond_log_idle *idle_log; 196 struct ata_power_cond_log_standby *standby_log; 197 uint8_t log_buf[sizeof(*idle_log) + sizeof(*standby_log)]; 198 uint16_t log_addr = ATA_POWER_COND_LOG; 199 uint16_t page_number = ATA_PCL_IDLE; 200 uint64_t lba; 201 int error = 0; 202 203 lba = (((uint64_t)page_number & 0xff00) << 32) | 204 ((page_number & 0x00ff) << 8) | 205 (log_addr & 0xff); 206 207 error = build_ata_cmd(ccb, 208 /*retry_count*/ retry_count, 209 /*flags*/ CAM_DIR_IN | CAM_DEV_QFRZDIS, 210 /*tag_action*/ MSG_SIMPLE_Q_TAG, 211 /*protocol*/ AP_PROTO_DMA | AP_EXTEND, 212 /*ata_flags*/ AP_FLAG_BYT_BLOK_BLOCKS | 213 AP_FLAG_TLEN_SECT_CNT | 214 AP_FLAG_TDIR_FROM_DEV, 215 /*features*/ 0, 216 /*sector_count*/ 2, 217 /*lba*/ lba, 218 /*command*/ ATA_READ_LOG_DMA_EXT, 219 /*auxiliary*/ 0, 220 /*data_ptr*/ log_buf, 221 /*dxfer_len*/ sizeof(log_buf), 222 /*cdb_storage*/ NULL, 223 /*cdb_storage_len*/ 0, 224 /*sense_len*/ SSD_FULL_SIZE, 225 /*timeout*/ timeout ? timeout : 60000, 226 /*is48bit*/ 1, 227 /*devtype*/ devtype); 228 229 if (error != 0) { 230 warnx("%s: build_ata_cmd() failed, likely programmer error", 231 __func__); 232 goto bailout; 233 } 234 235 if (retry_count > 0) 236 ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 237 238 error = cam_send_ccb(device, ccb); 239 if (error != 0) { 240 warn("error sending ATA READ LOG EXT CCB"); 241 error = 1; 242 goto bailout; 243 } 244 245 if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 246 cam_error_print(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL,stderr); 247 error = 1; 248 goto bailout; 249 } 250 251 idle_log = (struct ata_power_cond_log_idle *)log_buf; 252 standby_log = 253 (struct ata_power_cond_log_standby *)&log_buf[sizeof(*idle_log)]; 254 255 printf("ATA Power Conditions Log:\n"); 256 printf(" Idle power conditions page:\n"); 257 printf(" Idle A condition:\n"); 258 epc_print_pcl_desc(&idle_log->idle_a_desc, " "); 259 printf(" Idle B condition:\n"); 260 epc_print_pcl_desc(&idle_log->idle_b_desc, " "); 261 printf(" Idle C condition:\n"); 262 epc_print_pcl_desc(&idle_log->idle_c_desc, " "); 263 printf(" Standby power conditions page:\n"); 264 printf(" Standby Y condition:\n"); 265 epc_print_pcl_desc(&standby_log->standby_y_desc, " "); 266 printf(" Standby Z condition:\n"); 267 epc_print_pcl_desc(&standby_log->standby_z_desc, " "); 268 bailout: 269 return (error); 270 } 271 272 static int 273 epc_getmode(struct cam_device *device, camcontrol_devtype devtype, 274 union ccb *ccb, int retry_count, int timeout, int power_only) 275 { 276 struct ata_params *ident = NULL; 277 struct ata_identify_log_sup_cap sup_cap; 278 const char *mode_name = NULL; 279 uint8_t error = 0, ata_device = 0, status = 0; 280 uint16_t count = 0; 281 uint64_t lba = 0; 282 uint32_t page_number, log_address; 283 uint64_t caps = 0; 284 int avail_bytes = 0; 285 int res_available = 0; 286 int retval; 287 288 retval = 0; 289 290 if (power_only != 0) 291 goto check_power_mode; 292 293 /* 294 * Get standard ATA Identify data. 295 */ 296 retval = ata_do_identify(device, retry_count, timeout, ccb, &ident); 297 if (retval != 0) { 298 warnx("Couldn't get identify data"); 299 goto bailout; 300 } 301 302 /* 303 * Get the ATA Identify Data Log (0x30), 304 * Supported Capabilities Page (0x03). 305 */ 306 log_address = ATA_IDENTIFY_DATA_LOG; 307 page_number = ATA_IDL_SUP_CAP; 308 lba = (((uint64_t)page_number & 0xff00) << 32) | 309 ((page_number & 0x00ff) << 8) | 310 (log_address & 0xff); 311 312 bzero(&sup_cap, sizeof(sup_cap)); 313 /* 314 * XXX KDM check the supported protocol. 315 */ 316 retval = build_ata_cmd(ccb, 317 /*retry_count*/ retry_count, 318 /*flags*/ CAM_DIR_IN | CAM_DEV_QFRZDIS, 319 /*tag_action*/ MSG_SIMPLE_Q_TAG, 320 /*protocol*/ AP_PROTO_DMA | 321 AP_EXTEND, 322 /*ata_flags*/ AP_FLAG_BYT_BLOK_BLOCKS | 323 AP_FLAG_TLEN_SECT_CNT | 324 AP_FLAG_TDIR_FROM_DEV, 325 /*features*/ 0, 326 /*sector_count*/ 1, 327 /*lba*/ lba, 328 /*command*/ ATA_READ_LOG_DMA_EXT, 329 /*auxiliary*/ 0, 330 /*data_ptr*/ (uint8_t *)&sup_cap, 331 /*dxfer_len*/ sizeof(sup_cap), 332 /*cdb_storage*/ NULL, 333 /*cdb_storage_len*/ 0, 334 /*sense_len*/ SSD_FULL_SIZE, 335 /*timeout*/ timeout ? timeout : 60000, 336 /*is48bit*/ 1, 337 /*devtype*/ devtype); 338 339 if (retval != 0) { 340 warnx("%s: build_ata_cmd() failed, likely a programmer error", 341 __func__); 342 goto bailout; 343 } 344 345 if (retry_count > 0) 346 ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 347 348 retval = cam_send_ccb(device, ccb); 349 if (retval != 0) { 350 warn("error sending ATA READ LOG CCB"); 351 retval = 1; 352 goto bailout; 353 } 354 355 if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 356 cam_error_print(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL,stderr); 357 retval = 1; 358 goto bailout; 359 } 360 361 if (ccb->ccb_h.func_code == XPT_SCSI_IO) { 362 avail_bytes = ccb->csio.dxfer_len - ccb->csio.resid; 363 } else { 364 avail_bytes = ccb->ataio.dxfer_len - ccb->ataio.resid; 365 } 366 if (avail_bytes < (int)sizeof(sup_cap)) { 367 warnx("Couldn't get enough of the ATA Supported " 368 "Capabilities log, %d bytes returned", avail_bytes); 369 retval = 1; 370 goto bailout; 371 } 372 caps = le64dec(sup_cap.sup_cap); 373 if ((caps & ATA_SUP_CAP_VALID) == 0) { 374 warnx("Supported capabilities bits are not valid"); 375 retval = 1; 376 goto bailout; 377 } 378 379 printf("APM: %sSupported, %sEnabled\n", 380 (ident->support.command2 & ATA_SUPPORT_APM) ? "" : "NOT ", 381 (ident->enabled.command2 & ATA_SUPPORT_APM) ? "" : "NOT "); 382 printf("EPC: %sSupported, %sEnabled\n", 383 (ident->support2 & ATA_SUPPORT_EPC) ? "" : "NOT ", 384 (ident->enabled2 & ATA_ENABLED_EPC) ? "" : "NOT "); 385 printf("Low Power Standby %sSupported\n", 386 (caps & ATA_SC_LP_STANDBY_SUP) ? "" : "NOT "); 387 printf("Set EPC Power Source %sSupported\n", 388 (caps & ATA_SC_SET_EPC_PS_SUP) ? "" : "NOT "); 389 390 391 check_power_mode: 392 393 retval = build_ata_cmd(ccb, 394 /*retry_count*/ retry_count, 395 /*flags*/ CAM_DIR_NONE | CAM_DEV_QFRZDIS, 396 /*tag_action*/ MSG_SIMPLE_Q_TAG, 397 /*protocol*/ AP_PROTO_NON_DATA | 398 AP_EXTEND, 399 /*ata_flags*/ AP_FLAG_BYT_BLOK_BLOCKS | 400 AP_FLAG_TLEN_NO_DATA | 401 AP_FLAG_CHK_COND, 402 /*features*/ ATA_SF_EPC, 403 /*sector_count*/ 0, 404 /*lba*/ 0, 405 /*command*/ ATA_CHECK_POWER_MODE, 406 /*auxiliary*/ 0, 407 /*data_ptr*/ NULL, 408 /*dxfer_len*/ 0, 409 /*cdb_storage*/ NULL, 410 /*cdb_storage_len*/ 0, 411 /*sense_len*/ SSD_FULL_SIZE, 412 /*timeout*/ timeout ? timeout : 60000, 413 /*is48bit*/ 0, 414 /*devtype*/ devtype); 415 416 if (retval != 0) { 417 warnx("%s: build_ata_cmd() failed, likely a programmer error", 418 __func__); 419 goto bailout; 420 } 421 422 if (retry_count > 0) 423 ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 424 425 retval = cam_send_ccb(device, ccb); 426 if (retval != 0) { 427 warn("error sending ATA CHECK POWER MODE CCB"); 428 retval = 1; 429 goto bailout; 430 } 431 432 /* 433 * Check to see whether we got the requested ATA result if this 434 * is an SCSI ATA PASS-THROUGH command. 435 */ 436 if (((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_SCSI_STATUS_ERROR) 437 && (ccb->csio.scsi_status == SCSI_STATUS_CHECK_COND)) { 438 int error_code, sense_key, asc, ascq; 439 440 retval = scsi_extract_sense_ccb(ccb, &error_code, 441 &sense_key, &asc, &ascq); 442 if (retval == 0) { 443 cam_error_print(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL, 444 stderr); 445 retval = 1; 446 goto bailout; 447 } 448 if ((sense_key == SSD_KEY_RECOVERED_ERROR) 449 && (asc == 0x00) 450 && (ascq == 0x1d)) { 451 res_available = 1; 452 } 453 454 } 455 if (((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) 456 && (res_available == 0)) { 457 cam_error_print(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL,stderr); 458 retval = 1; 459 goto bailout; 460 } 461 462 retval = get_ata_status(device, ccb, &error, &count, &lba, &ata_device, 463 &status); 464 if (retval != 0) { 465 warnx("Unable to get ATA CHECK POWER MODE result"); 466 retval = 1; 467 goto bailout; 468 } 469 470 mode_name = scsi_nv_to_str(epc_power_cond_map, 471 sizeof(epc_power_cond_map) / sizeof(epc_power_cond_map[0]), count); 472 printf("Current power state: "); 473 /* Note: ident can be null in power_only mode */ 474 if ((ident == NULL) 475 || (ident->enabled2 & ATA_ENABLED_EPC)) { 476 if (mode_name != NULL) 477 printf("%s", mode_name); 478 else if (count == 0xff) { 479 printf("PM0:Active or PM1:Idle"); 480 } 481 } else { 482 switch (count) { 483 case 0x00: 484 printf("PM2:Standby"); 485 break; 486 case 0x80: 487 printf("PM1:Idle"); 488 break; 489 case 0xff: 490 printf("PM0:Active or PM1:Idle"); 491 break; 492 } 493 } 494 printf("(0x%02x)\n", count); 495 496 if (power_only != 0) 497 goto bailout; 498 499 if (caps & ATA_SC_LP_STANDBY_SUP) { 500 uint32_t wait_mode; 501 502 wait_mode = (lba >> 20) & 0xff; 503 if (wait_mode == 0xff) { 504 printf("Device not waiting to enter lower power " 505 "condition"); 506 } else { 507 mode_name = scsi_nv_to_str(epc_power_cond_map, 508 sizeof(epc_power_cond_map) / 509 sizeof(epc_power_cond_map[0]), wait_mode); 510 printf("Device waiting to enter mode %s (0x%02x)\n", 511 (mode_name != NULL) ? mode_name : "Unknown", 512 wait_mode); 513 } 514 printf("Device is %sheld in the current power condition\n", 515 (lba & 0x80000) ? "" : "NOT "); 516 } 517 bailout: 518 return (retval); 519 520 } 521 522 static int 523 epc_set_features(struct cam_device *device, camcontrol_devtype devtype, 524 union ccb *ccb, int retry_count, int timeout, int action, 525 int power_cond, int timer, int enable, int save, 526 int delayed_entry, int hold, int power_src, int restore_src) 527 { 528 uint64_t lba; 529 uint16_t count = 0; 530 int error; 531 532 error = 0; 533 534 lba = action; 535 536 switch (action) { 537 case ATA_SF_EPC_SET_TIMER: 538 lba |= ((timer << ATA_SF_EPC_TIMER_SHIFT) & 539 ATA_SF_EPC_TIMER_MASK); 540 /* FALLTHROUGH */ 541 case ATA_SF_EPC_SET_STATE: 542 lba |= (enable ? ATA_SF_EPC_TIMER_EN : 0) | 543 (save ? ATA_SF_EPC_TIMER_SAVE : 0); 544 count = power_cond; 545 break; 546 case ATA_SF_EPC_GOTO: 547 count = power_cond; 548 lba |= (delayed_entry ? ATA_SF_EPC_GOTO_DELAY : 0) | 549 (hold ? ATA_SF_EPC_GOTO_HOLD : 0); 550 break; 551 case ATA_SF_EPC_RESTORE: 552 lba |= restore_src | 553 (save ? ATA_SF_EPC_RST_SAVE : 0); 554 break; 555 case ATA_SF_EPC_ENABLE: 556 case ATA_SF_EPC_DISABLE: 557 break; 558 case ATA_SF_EPC_SET_SOURCE: 559 count = power_src; 560 break; 561 } 562 563 error = build_ata_cmd(ccb, 564 /*retry_count*/ retry_count, 565 /*flags*/ CAM_DIR_NONE | CAM_DEV_QFRZDIS, 566 /*tag_action*/ MSG_SIMPLE_Q_TAG, 567 /*protocol*/ AP_PROTO_NON_DATA | AP_EXTEND, 568 /*ata_flags*/ AP_FLAG_BYT_BLOK_BLOCKS | 569 AP_FLAG_TLEN_NO_DATA | 570 AP_FLAG_TDIR_FROM_DEV, 571 /*features*/ ATA_SF_EPC, 572 /*sector_count*/ count, 573 /*lba*/ lba, 574 /*command*/ ATA_SETFEATURES, 575 /*auxiliary*/ 0, 576 /*data_ptr*/ NULL, 577 /*dxfer_len*/ 0, 578 /*cdb_storage*/ NULL, 579 /*cdb_storage_len*/ 0, 580 /*sense_len*/ SSD_FULL_SIZE, 581 /*timeout*/ timeout ? timeout : 60000, 582 /*is48bit*/ 1, 583 /*devtype*/ devtype); 584 585 if (error != 0) { 586 warnx("%s: build_ata_cmd() failed, likely a programmer error", 587 __func__); 588 goto bailout; 589 } 590 591 if (retry_count > 0) 592 ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 593 594 error = cam_send_ccb(device, ccb); 595 if (error != 0) { 596 warn("error sending ATA SET FEATURES CCB"); 597 error = 1; 598 goto bailout; 599 } 600 601 if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 602 cam_error_print(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL,stderr); 603 error = 1; 604 goto bailout; 605 } 606 607 bailout: 608 return (error); 609 } 610 611 int 612 epc(struct cam_device *device, int argc, char **argv, char *combinedopt, 613 int retry_count, int timeout, int verbosemode __unused) 614 { 615 union ccb *ccb = NULL; 616 int error = 0; 617 int c; 618 int action = -1; 619 camcontrol_devtype devtype; 620 double timer_val = -1; 621 int timer_tenths = 0, power_cond = -1; 622 int delayed_entry = 0, hold = 0; 623 int enable = -1, save = 0; 624 int restore_src = -1; 625 int power_src = -1; 626 int power_only = 0; 627 628 629 ccb = cam_getccb(device); 630 if (ccb == NULL) { 631 warnx("%s: error allocating CCB", __func__); 632 error = 1; 633 goto bailout; 634 } 635 636 while ((c = getopt(argc, argv, combinedopt)) != -1) { 637 switch (c) { 638 case 'c': { 639 scsi_nv_status status; 640 int entry_num; 641 642 status = scsi_get_nv(epc_cmd_map, 643 (sizeof(epc_cmd_map) / sizeof(epc_cmd_map[0])), 644 optarg, &entry_num, SCSI_NV_FLAG_IG_CASE); 645 if (status == SCSI_NV_FOUND) 646 action = epc_cmd_map[entry_num].value; 647 else { 648 warnx("%s: %s: %s option %s", __func__, 649 (status == SCSI_NV_AMBIGUOUS) ? 650 "ambiguous" : "invalid", "epc command", 651 optarg); 652 error = 1; 653 goto bailout; 654 } 655 break; 656 } 657 case 'd': 658 enable = 0; 659 break; 660 case 'D': 661 delayed_entry = 1; 662 break; 663 case 'e': 664 enable = 1; 665 break; 666 case 'H': 667 hold = 1; 668 break; 669 case 'p': { 670 scsi_nv_status status; 671 int entry_num; 672 673 status = scsi_get_nv(epc_power_cond_map, 674 (sizeof(epc_power_cond_map) / 675 sizeof(epc_power_cond_map[0])), optarg, 676 &entry_num, SCSI_NV_FLAG_IG_CASE); 677 if (status == SCSI_NV_FOUND) 678 power_cond =epc_power_cond_map[entry_num].value; 679 else { 680 warnx("%s: %s: %s option %s", __func__, 681 (status == SCSI_NV_AMBIGUOUS) ? 682 "ambiguous" : "invalid", "power condition", 683 optarg); 684 error = 1; 685 goto bailout; 686 } 687 break; 688 } 689 case 'P': 690 power_only = 1; 691 break; 692 case 'r': { 693 scsi_nv_status status; 694 int entry_num; 695 696 status = scsi_get_nv(epc_rst_val, 697 (sizeof(epc_rst_val) / 698 sizeof(epc_rst_val[0])), optarg, 699 &entry_num, SCSI_NV_FLAG_IG_CASE); 700 if (status == SCSI_NV_FOUND) 701 restore_src = epc_rst_val[entry_num].value; 702 else { 703 warnx("%s: %s: %s option %s", __func__, 704 (status == SCSI_NV_AMBIGUOUS) ? 705 "ambiguous" : "invalid", 706 "restore value source", optarg); 707 error = 1; 708 goto bailout; 709 } 710 break; 711 } 712 case 's': 713 save = 1; 714 break; 715 case 'S': { 716 scsi_nv_status status; 717 int entry_num; 718 719 status = scsi_get_nv(epc_ps_map, 720 (sizeof(epc_ps_map) / sizeof(epc_ps_map[0])), 721 optarg, &entry_num, SCSI_NV_FLAG_IG_CASE); 722 if (status == SCSI_NV_FOUND) 723 power_src = epc_ps_map[entry_num].value; 724 else { 725 warnx("%s: %s: %s option %s", __func__, 726 (status == SCSI_NV_AMBIGUOUS) ? 727 "ambiguous" : "invalid", "power source", 728 optarg); 729 error = 1; 730 goto bailout; 731 } 732 break; 733 } 734 case 'T': { 735 char *endptr; 736 737 timer_val = strtod(optarg, &endptr); 738 if (timer_val < 0) { 739 warnx("Invalid timer value %f", timer_val); 740 error = 1; 741 goto bailout; 742 } else if (*endptr != '\0') { 743 warnx("Invalid timer value %s", optarg); 744 error = 1; 745 goto bailout; 746 } 747 timer_tenths = timer_val * 10; 748 break; 749 } 750 default: 751 break; 752 } 753 } 754 755 if (action == -1) { 756 warnx("Must specify an action"); 757 error = 1; 758 goto bailout; 759 } 760 761 error = get_device_type(device, retry_count, timeout, 762 /*printerrors*/ 1, &devtype); 763 if (error != 0) 764 errx(1, "Unable to determine device type"); 765 766 switch (devtype) { 767 case CC_DT_ATA: 768 case CC_DT_SATL: 769 break; 770 default: 771 warnx("The epc subcommand only works with ATA protocol " 772 "devices"); 773 error = 1; 774 goto bailout; 775 break; /*NOTREACHED*/ 776 } 777 778 switch (action) { 779 case ATA_SF_EPC_SET_TIMER: 780 if (timer_val == -1) { 781 warnx("Must specify a timer value (-T time)"); 782 error = 1; 783 } 784 /* FALLTHROUGH */ 785 case ATA_SF_EPC_SET_STATE: 786 if (enable == -1) { 787 warnx("Must specify enable (-e) or disable (-d)"); 788 error = 1; 789 } 790 /* FALLTHROUGH */ 791 case ATA_SF_EPC_GOTO: 792 if (power_cond == -1) { 793 warnx("Must specify a power condition with -p"); 794 error = 1; 795 } 796 if (error != 0) 797 goto bailout; 798 break; 799 case ATA_SF_EPC_SET_SOURCE: 800 if (power_src == -1) { 801 warnx("Must specify a power source (-S battery or " 802 "-S notbattery) value"); 803 error = 1; 804 goto bailout; 805 } 806 break; 807 case ATA_SF_EPC_RESTORE: 808 if (restore_src == -1) { 809 warnx("Must specify a source for restored value, " 810 "-r default or -r saved"); 811 error = 1; 812 goto bailout; 813 } 814 break; 815 case ATA_SF_EPC_ENABLE: 816 case ATA_SF_EPC_DISABLE: 817 case CCTL_EPC_GET_STATUS: 818 case CCTL_EPC_LIST: 819 default: 820 break; 821 } 822 823 switch (action) { 824 case CCTL_EPC_GET_STATUS: 825 error = epc_getmode(device, devtype, ccb, retry_count, timeout, 826 power_only); 827 break; 828 case CCTL_EPC_LIST: 829 error = epc_list(device, devtype, ccb, retry_count, timeout); 830 break; 831 case ATA_SF_EPC_RESTORE: 832 case ATA_SF_EPC_GOTO: 833 case ATA_SF_EPC_SET_TIMER: 834 case ATA_SF_EPC_SET_STATE: 835 case ATA_SF_EPC_ENABLE: 836 case ATA_SF_EPC_DISABLE: 837 case ATA_SF_EPC_SET_SOURCE: 838 error = epc_set_features(device, devtype, ccb, retry_count, 839 timeout, action, power_cond, timer_tenths, enable, save, 840 delayed_entry, hold, power_src, restore_src); 841 break; 842 default: 843 warnx("Not implemented yet"); 844 error = 1; 845 goto bailout; 846 break; 847 } 848 849 850 bailout: 851 if (ccb != NULL) 852 cam_freeccb(ccb); 853 854 return (error); 855 } 856