xref: /freebsd/sbin/camcontrol/epc.c (revision 61e21613)
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