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