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