1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
26 */
27
28 #include <sys/param.h>
29 #include <sys/stat.h>
30 #include <errno.h>
31 #include <string.h>
32 #include <dirent.h>
33 #include "cfga_sata.h"
34
35 /*
36 * This file contains the entry points to the plug-in as defined in the
37 * config_admin(3X) man page.
38 */
39
40 /*
41 * Set the version number for the cfgadm library's use.
42 */
43 int cfga_version = CFGA_HSL_V2;
44
45 enum {
46 HELP_HEADER = 1,
47 HELP_CONFIG,
48 HELP_RESET_PORT,
49 HELP_RESET_DEVICE,
50 HELP_RESET_ALL,
51 HELP_PORT_DEACTIVATE,
52 HELP_PORT_ACTIVATE,
53 HELP_PORT_SELF_TEST,
54 HELP_CNTRL_SELF_TEST,
55 HELP_UNKNOWN
56 };
57
58 /* SATA specific help messages */
59 static char *sata_help[] = {
60 NULL,
61 "SATA specific commands:\n",
62 " cfgadm -c [configure|unconfigure|disconnect|connect] ap_id "
63 "[ap_id...]\n",
64 " cfgadm -x sata_reset_port ap_id [ap_id...]\n",
65 " cfgadm -x sata_reset_device ap_id [ap_id...]\n",
66 " cfgadm -x sata_reset_all ap_id\n",
67 " cfgadm -x sata_port_deactivate ap_id [ap_id...]\n",
68 " cfgadm -x sata_port_activate ap_id [ap_id...]\n",
69 " cfgadm -x sata_port_self_test ap_id [ap_id...]\n",
70 " cfgadm -t ap_id\n",
71 "\tunknown command or option:\n",
72 NULL
73 }; /* End help messages */
74
75
76 /*
77 * Messages.
78 */
79 static msgcvt_t sata_msgs[] = {
80 /* CFGA_SATA_OK */
81 { CVT, CFGA_OK, "" },
82
83 /* CFGA_SATA_NACK */
84 { CVT, CFGA_NACK, "" },
85
86 /* CFGA_SATA_DEVICE_UNCONFIGURED */
87 { CVT, CFGA_OK, "Device unconfigured prior to disconnect" },
88
89 /* CFGA_SATA_UNKNOWN / CFGA_LIB_ERROR -> "Library error" */
90 { CVT, CFGA_LIB_ERROR, "Unknown message; internal error" },
91
92 /* CFGA_SATA_INTERNAL_ERROR / CFGA_LIB_ERROR -> "Library error" */
93 { CVT, CFGA_LIB_ERROR, "Internal error" },
94
95 /* CFGA_SATA_DATA_ERROR / CFGA_DATA_ERROR -> "Data error" */
96 { CVT, CFGA_DATA_ERROR, "cfgadm data error" },
97
98 /* CFGA_SATA_OPTIONS / CFGA_ERROR -> "Hardware specific failure" */
99 { CVT, CFGA_ERROR, "Hardware specific option not supported" },
100
101 /* CFGA_SATA_HWOPNOTSUPP / CFGA_ERROR -> "Hardware specific failure" */
102 { CVT, CFGA_ERROR, "Hardware specific operation not supported" },
103
104 /*
105 * CFGA_SATA_DYNAMIC_AP /
106 * CFGA_LIB_ERROR -> "Configuration operation invalid"
107 */
108 { CVT, CFGA_INVAL, "Cannot identify attached device" },
109
110 /* CFGA_SATA_AP / CFGA_APID_NOEXIST -> "Attachment point not found" */
111 { CVT, CFGA_APID_NOEXIST, "" },
112
113 /* CFGA_SATA_PORT / CFGA_LIB_ERROR -> "Library error" */
114 { CVT, CFGA_LIB_ERROR, "Cannot determine sata port number for " },
115
116 /* CFGA_SATA_DEVCTL / CFGA_LIB_ERROR -> "Library error" */
117 { CVT, CFGA_LIB_ERROR, "Internal error: "
118 "Cannot allocate devctl handle " },
119
120 /*
121 * CFGA_SATA_DEV_CONFIGURE /
122 * CFGA_ERROR -> "Hardware specific failure"
123 */
124 { CVT, CFGA_ERROR, "Failed to config device at " },
125
126 /*
127 * CFGA_SATA_DEV_UNCONFIGURE /
128 * CFGA_ERROR -> "Hardware specific failure"
129 */
130 { CVT, CFGA_ERROR, "Failed to unconfig device at " },
131
132 /*
133 * CFGA_SATA_DISCONNECTED
134 * CFGA_INVAL -> "Configuration operation invalid"
135 */
136 { CVT, CFGA_INVAL, "Port already disconnected " },
137
138 /*
139 * CFGA_SATA_NOT_CONNECTED
140 * CFGA_INVAL -> "Configuration operation invalid"
141 */
142 { CVT, CFGA_INVAL, "No device connected to " },
143
144 /*
145 * CFGA_SATA_NOT_CONFIGURED /
146 * CFGA_INVAL -> "Configuration operation invalid"
147 */
148 { CVT, CFGA_INVAL, "No device configured at " },
149
150 /*
151 * CFGA_SATA_ALREADY_CONNECTED /
152 * CFGA_INVAL -> "Configuration operation invalid"
153 */
154 { CVT, CFGA_INVAL, "Device already connected to " },
155
156 /*
157 * CFGA_SATA_ALREADY_CONFIGURED /
158 * CFGA_INVAL -> "Configuration operation invalid"
159 */
160 { CVT, CFGA_INVAL, "Device already configured at " },
161
162 /*
163 * CFGA_SATA_INVALID_DEVNAME /
164 * CFGA_INVAL -> "Configuration operation invalid"
165 */
166 { CVT, CFGA_INVAL, "Cannot specify device name" },
167
168 /* CFGA_SATA_OPEN / CFGA_LIB_ERROR -> "Library error" */
169 { CVT, CFGA_LIB_ERROR, "Cannot open " },
170
171 /* CFGA_SATA_IOCTL / CFGA_ERROR -> "Hardware specific failure" */
172 { CVT, CFGA_ERROR, "Driver ioctl failed " },
173
174 /*
175 * CFGA_SATA_BUSY /
176 * CFGA_SYSTEM_BUSY -> "System is busy, try again"
177 */
178 { CVT, CFGA_SYSTEM_BUSY, "" },
179
180 /* CFGA_SATA_ALLOC_FAIL / CFGA_LIB_ERROR -> "Library error" */
181 { CVT, CFGA_LIB_ERROR, "Memory allocation failure" },
182
183 /*
184 * CFGA_SATA_OPNOTSUPP /
185 * CFGA_OPNOTSUPP -> "Configuration operation not supported"
186 */
187 { CVT, CFGA_OPNOTSUPP, "Operation not supported" },
188
189 /* CFGA_SATA_DEVLINK / CFGA_LIB_ERROR -> "Library error" */
190 { CVT, CFGA_LIB_ERROR, "Could not find /dev/cfg link for " },
191
192 /* CFGA_SATA_STATE / CFGA_LIB_ERROR -> "Library error" */
193 { CVT, CFGA_LIB_ERROR, "Internal error: Unrecognized ap state" },
194
195 /* CFGA_SATA_PRIV / CFGA_PRIV -> "Insufficient privileges" */
196 { CVT, CFGA_PRIV, "" },
197
198 /* CFGA_SATA_NVLIST / CFGA_ERROR -> "Hardware specific failure" */
199 { CVT, CFGA_ERROR, "Internal error (nvlist)" },
200
201 /* CFGA_SATA_ZEROLEN / CFGA_ERROR -> "Hardware specific failure" */
202 { CVT, CFGA_ERROR, "Internal error (zerolength string)" },
203
204 /* CFGA_SATA_RCM_HANDLE / CFGA_ERROR -> "Hardware specific failure" */
205 { CVT, CFGA_ERROR, "cannot get RCM handle"},
206
207 /*
208 * CFGA_SATA_RCM_ONLINE /
209 * CFGA_SYSTEM_BUSY -> "System is busy, try again"
210 */
211 { CVT, CFGA_SYSTEM_BUSY, "failed to online: "},
212
213 /*
214 * CFGA_SATA_RCM_OFFLINE /
215 * CFGA_SYSTEM_BUSY -> "System is busy, try again"
216 */
217 { CVT, CFGA_SYSTEM_BUSY, "failed to offline: "},
218
219 /* CFGA_SATA_RCM_INFO / CFGA_ERROR -> "Hardware specific failure" */
220 { CVT, CFGA_ERROR, "failed to query: "}
221
222 }; /* End error messages */
223
224 static cfga_sata_ret_t
225 verify_params(const char *ap_id, const char *options, char **errstring);
226
227
228 static cfga_sata_ret_t
229 setup_for_devctl_cmd(const char *ap_id, devctl_hdl_t *devctl_hdl,
230 nvlist_t **user_nvlistp, uint_t oflag);
231
232 static cfga_sata_ret_t
233 port_state(devctl_hdl_t hdl, nvlist_t *list,
234 ap_rstate_t *rstate, ap_ostate_t *ostate);
235
236 static cfga_sata_ret_t
237 do_control_ioctl(const char *ap_id, sata_cfga_apctl_t subcommand, uint_t arg,
238 void **descrp, size_t *sizep);
239
240 static void
241 cleanup_after_devctl_cmd(devctl_hdl_t devctl_hdl, nvlist_t *user_nvlist);
242
243 static char *
244 sata_get_devicepath(const char *ap_id);
245
246 static int
247 sata_confirm(struct cfga_confirm *confp, char *msg);
248
249 static cfga_sata_ret_t
250 get_port_num(const char *ap_id, uint32_t *port);
251
252 /* Utilities */
253
254 static cfga_sata_ret_t
255 physpath_to_devlink(const char *basedir, const char *node_path,
256 char **logpp, int *l_errnop)
257 {
258 char *linkpath;
259 char *buf;
260 char *real_path;
261 DIR *dp;
262 struct dirent *dep, *newdep;
263 int deplen;
264 boolean_t found = B_FALSE;
265 int err = 0;
266 struct stat sb;
267 char *p;
268 cfga_sata_ret_t rv = CFGA_SATA_INTERNAL_ERROR;
269
270 /*
271 * Using libdevinfo for this is overkill and kills performance
272 * when multiple consumers of libcfgadm are executing
273 * concurrently.
274 */
275 if ((dp = opendir(basedir)) == NULL) {
276 *l_errnop = errno;
277 return (CFGA_SATA_INTERNAL_ERROR);
278 }
279
280 linkpath = malloc(PATH_MAX);
281 buf = malloc(PATH_MAX);
282 real_path = malloc(PATH_MAX);
283
284 deplen = pathconf(basedir, _PC_NAME_MAX);
285 deplen = (deplen <= 0 ? MAXNAMELEN : deplen) +
286 sizeof (struct dirent);
287 dep = (struct dirent *)malloc(deplen);
288
289 if (dep == NULL || linkpath == NULL || buf == NULL ||
290 real_path == NULL) {
291 *l_errnop = ENOMEM;
292 rv = CFGA_SATA_ALLOC_FAIL;
293 goto pp_cleanup;
294 }
295
296 *logpp = NULL;
297
298 while (!found && (err = readdir_r(dp, dep, &newdep)) == 0 &&
299 newdep != NULL) {
300
301 assert(newdep == dep);
302
303 if (strcmp(dep->d_name, ".") == 0 ||
304 strcmp(dep->d_name, "..") == 0)
305 continue;
306
307 (void) snprintf(linkpath, MAXPATHLEN,
308 "%s/%s", basedir, dep->d_name);
309
310 if (lstat(linkpath, &sb) < 0)
311 continue;
312
313 if (S_ISDIR(sb.st_mode)) {
314
315 if ((rv = physpath_to_devlink(linkpath, node_path,
316 logpp, l_errnop)) != CFGA_SATA_OK) {
317
318 goto pp_cleanup;
319 }
320
321 if (*logpp != NULL)
322 found = B_TRUE;
323
324 } else if (S_ISLNK(sb.st_mode)) {
325
326 bzero(buf, PATH_MAX);
327 if (readlink(linkpath, buf, PATH_MAX) < 0)
328 continue;
329
330
331 /*
332 * realpath() is too darn slow, so fake
333 * it, by using what we know about /dev
334 * links: they are always of the form:
335 * <"../">+/devices/<path>
336 */
337 p = buf;
338 while (strncmp(p, "../", 3) == 0)
339 p += 3;
340
341 if (p != buf)
342 p--; /* back up to get a slash */
343
344 assert (*p == '/');
345
346 if (strcmp(p, node_path) == 0) {
347 *logpp = strdup(linkpath);
348 if (*logpp == NULL) {
349
350 rv = CFGA_SATA_ALLOC_FAIL;
351 goto pp_cleanup;
352 }
353
354 found = B_TRUE;
355 }
356 }
357 }
358
359 free(linkpath);
360 free(buf);
361 free(real_path);
362 free(dep);
363 (void) closedir(dp);
364
365 if (err != 0) {
366 *l_errnop = err;
367 return (CFGA_SATA_INTERNAL_ERROR);
368 }
369
370 return (CFGA_SATA_OK);
371
372 pp_cleanup:
373
374 if (dp)
375 (void) closedir(dp);
376 if (dep)
377 free(dep);
378 if (linkpath)
379 free(linkpath);
380 if (buf)
381 free(buf);
382 if (real_path)
383 free(real_path);
384 if (*logpp) {
385 free(*logpp);
386 *logpp = NULL;
387 }
388 return (rv);
389 }
390
391
392 /*
393 * Given the index into a table (msgcvt_t) of messages, get the message
394 * string, converting it to the proper locale if necessary.
395 * NOTE: Indexes are defined in cfga_sata.h
396 */
397 static const char *
398 get_msg(uint_t msg_index, msgcvt_t *msg_tbl, uint_t tbl_size)
399 {
400 if (msg_index >= tbl_size) {
401 msg_index = CFGA_SATA_UNKNOWN;
402 }
403
404 return ((msg_tbl[msg_index].intl) ?
405 dgettext(TEXT_DOMAIN, msg_tbl[msg_index].msgstr) :
406 msg_tbl[msg_index].msgstr);
407 }
408
409 /*
410 * Allocates and creates a message string (in *ret_str),
411 * by concatenating all the (char *) args together, in order.
412 * Last arg MUST be NULL.
413 */
414 static void
415 set_msg(char **ret_str, ...)
416 {
417 char *str;
418 size_t total_len;
419 va_list valist;
420
421 va_start(valist, ret_str);
422
423 total_len = (*ret_str == NULL) ? 0 : strlen(*ret_str);
424
425 while ((str = va_arg(valist, char *)) != NULL) {
426 size_t len = strlen(str);
427 char *old_str = *ret_str;
428
429 *ret_str = (char *)realloc(*ret_str, total_len + len + 1);
430 if (*ret_str == NULL) {
431 /* We're screwed */
432 free(old_str);
433 va_end(valist);
434 return;
435 }
436
437 (void) strcpy(*ret_str + total_len, str);
438 total_len += len;
439 }
440
441 va_end(valist);
442 }
443
444 /*
445 * Error message handling.
446 * For the rv passed in, looks up the corresponding error message string(s),
447 * internationalized if necessary, and concatenates it into a new
448 * memory buffer, and points *errstring to it.
449 * Note not all rvs will result in an error message return, as not all
450 * error conditions warrant a SATA-specific error message - for those
451 * conditions the cfgadm generic messages are sufficient.
452 *
453 * Some messages may display ap_id or errno, which is why they are passed
454 * in.
455 */
456
457 cfga_err_t
458 sata_err_msg(
459 char **errstring,
460 cfga_sata_ret_t rv,
461 const char *ap_id,
462 int l_errno)
463 {
464 if (errstring == NULL) {
465 return (sata_msgs[rv].cfga_err);
466 }
467
468 /*
469 * Generate the appropriate SATA-specific error message(s) (if any).
470 */
471 switch (rv) {
472 case CFGA_SATA_OK:
473 case CFGA_NACK:
474 /* Special case - do nothing. */
475 break;
476
477 case CFGA_SATA_UNKNOWN:
478 case CFGA_SATA_DYNAMIC_AP:
479 case CFGA_SATA_INTERNAL_ERROR:
480 case CFGA_SATA_OPTIONS:
481 case CFGA_SATA_ALLOC_FAIL:
482 case CFGA_SATA_STATE:
483 case CFGA_SATA_PRIV:
484 case CFGA_SATA_OPNOTSUPP:
485 case CFGA_SATA_DATA_ERROR:
486 /* These messages require no additional strings passed. */
487 set_msg(errstring, ERR_STR(rv), NULL);
488 break;
489
490 case CFGA_SATA_HWOPNOTSUPP:
491 /* hardware-specific help needed */
492 set_msg(errstring, ERR_STR(rv), NULL);
493 set_msg(errstring, "\n",
494 dgettext(TEXT_DOMAIN, sata_help[HELP_HEADER]), NULL);
495 set_msg(errstring, sata_help[HELP_RESET_PORT], NULL);
496 set_msg(errstring, sata_help[HELP_RESET_DEVICE], NULL);
497 set_msg(errstring, sata_help[HELP_RESET_ALL], NULL);
498 set_msg(errstring, sata_help[HELP_PORT_ACTIVATE], NULL);
499 set_msg(errstring, sata_help[HELP_PORT_DEACTIVATE], NULL);
500 set_msg(errstring, sata_help[HELP_PORT_SELF_TEST], NULL);
501 set_msg(errstring, sata_help[HELP_CNTRL_SELF_TEST], NULL);
502 break;
503
504 case CFGA_SATA_AP:
505 case CFGA_SATA_PORT:
506 case CFGA_SATA_NOT_CONNECTED:
507 case CFGA_SATA_NOT_CONFIGURED:
508 case CFGA_SATA_ALREADY_CONNECTED:
509 case CFGA_SATA_ALREADY_CONFIGURED:
510 case CFGA_SATA_BUSY:
511 case CFGA_SATA_DEVLINK:
512 case CFGA_SATA_RCM_HANDLE:
513 case CFGA_SATA_RCM_ONLINE:
514 case CFGA_SATA_RCM_OFFLINE:
515 case CFGA_SATA_RCM_INFO:
516 case CFGA_SATA_DEV_CONFIGURE:
517 case CFGA_SATA_DEV_UNCONFIGURE:
518 case CFGA_SATA_DISCONNECTED:
519 /* These messages also print ap_id. */
520 set_msg(errstring, ERR_STR(rv), "ap_id: ", ap_id, "", NULL);
521 break;
522
523
524 case CFGA_SATA_IOCTL:
525 case CFGA_SATA_NVLIST:
526 /* These messages also print errno. */
527 {
528 char *errno_str = l_errno ? strerror(l_errno) : "";
529
530 set_msg(errstring, ERR_STR(rv), errno_str,
531 l_errno ? "\n" : "", NULL);
532 break;
533 }
534
535 case CFGA_SATA_OPEN:
536 /* These messages also apid and errno. */
537 {
538 char *errno_str = l_errno ? strerror(l_errno) : "";
539
540 set_msg(errstring, ERR_STR(rv), "ap_id: ", ap_id, "\n",
541 errno_str, l_errno ? "\n" : "", NULL);
542 break;
543 }
544
545 default:
546 set_msg(errstring, ERR_STR(CFGA_SATA_INTERNAL_ERROR), NULL);
547
548 } /* end switch */
549
550
551 /*
552 * Determine the proper error code to send back to the cfgadm library.
553 */
554 return (sata_msgs[rv].cfga_err);
555 }
556
557
558 /*
559 * Entry points
560 */
561 /* cfgadm entry point */
562 /*ARGSUSED*/
563 cfga_err_t
564 cfga_change_state(
565 cfga_cmd_t state_change_cmd,
566 const char *ap_id,
567 const char *options,
568 struct cfga_confirm *confp,
569 struct cfga_msg *msgp,
570 char **errstring,
571 cfga_flags_t flags)
572 {
573 int ret;
574 int len;
575 char *msg;
576 char *devpath;
577 nvlist_t *nvl = NULL;
578 ap_rstate_t rstate;
579 ap_ostate_t ostate;
580 devctl_hdl_t hdl = NULL;
581 cfga_sata_ret_t rv = CFGA_SATA_OK;
582 char *pdyn;
583 char *str_type;
584 size_t size;
585 boolean_t pmult = B_FALSE;
586
587 /*
588 * All sub-commands which can change state of device require
589 * root privileges.
590 */
591 if (geteuid() != 0) {
592 rv = CFGA_SATA_PRIV;
593 goto bailout;
594 }
595
596 if ((rv = verify_params(ap_id, options, errstring)) != CFGA_SATA_OK) {
597 (void) cfga_help(msgp, options, flags);
598 goto bailout;
599 }
600
601 if ((rv = setup_for_devctl_cmd(ap_id, &hdl, &nvl,
602 DC_RDONLY)) != CFGA_SATA_OK) {
603 goto bailout;
604 }
605
606 /*
607 * Checking device type. A port multiplier is not configurable - it is
608 * already configured as soon as it is connected.
609 */
610 if ((rv = do_control_ioctl(ap_id, SATA_CFGA_GET_AP_TYPE, NULL,
611 (void **)&str_type, &size)) != CFGA_SATA_OK) {
612 /* no such deivce */
613 goto bailout;
614 }
615 if (strncmp(str_type, "sata-pmult", sizeof ("sata-pmult")) == 0) {
616 pmult = B_TRUE;
617 }
618
619 switch (state_change_cmd) {
620 case CFGA_CMD_CONFIGURE:
621 if (pmult == B_TRUE) {
622 rv = CFGA_SATA_HWOPNOTSUPP;
623 goto bailout;
624 }
625
626 if ((rv = port_state(hdl, nvl, &rstate, &ostate)) !=
627 CFGA_SATA_OK)
628 goto bailout;
629
630 if (ostate == AP_OSTATE_CONFIGURED) {
631 rv = CFGA_SATA_ALREADY_CONFIGURED;
632 goto bailout;
633 }
634 /* Disallow dynamic AP name component */
635 if (GET_DYN(ap_id) != NULL) {
636 rv = CFGA_SATA_INVALID_DEVNAME;
637 goto bailout;
638 }
639
640 if (rstate == AP_RSTATE_EMPTY) {
641 rv = CFGA_SATA_NOT_CONNECTED;
642 goto bailout;
643 }
644 rv = CFGA_SATA_OK;
645
646 if (devctl_ap_configure(hdl, nvl) != 0) {
647 rv = CFGA_SATA_DEV_CONFIGURE;
648 goto bailout;
649 }
650
651 devpath = sata_get_devicepath(ap_id);
652 if (devpath == NULL) {
653 int i;
654 /*
655 * Try for some time as SATA hotplug thread
656 * takes a while to create the path then
657 * eventually give up.
658 */
659 for (i = 0; i < 12 && (devpath == NULL); i++) {
660 (void) sleep(6);
661 devpath = sata_get_devicepath(ap_id);
662 }
663
664 if (devpath == NULL) {
665 rv = CFGA_SATA_DEV_CONFIGURE;
666 break;
667 }
668 }
669
670 S_FREE(devpath);
671 break;
672
673 case CFGA_CMD_UNCONFIGURE:
674 if (pmult == B_TRUE) {
675 rv = CFGA_SATA_HWOPNOTSUPP;
676 goto bailout;
677 }
678
679 if ((rv = port_state(hdl, nvl, &rstate, &ostate)) !=
680 CFGA_SATA_OK)
681 goto bailout;
682
683 if (rstate != AP_RSTATE_CONNECTED) {
684 rv = CFGA_SATA_NOT_CONNECTED;
685 goto bailout;
686 }
687
688 if (ostate != AP_OSTATE_CONFIGURED) {
689 rv = CFGA_SATA_NOT_CONFIGURED;
690 goto bailout;
691 }
692 /* Strip off AP name dynamic component, if present */
693 if ((pdyn = GET_DYN(ap_id)) != NULL) {
694 *pdyn = '\0';
695 }
696
697 rv = CFGA_SATA_OK;
698
699 len = strlen(SATA_CONFIRM_DEVICE) +
700 strlen(SATA_CONFIRM_DEVICE_SUSPEND) +
701 strlen("Unconfigure") + strlen(ap_id);
702 if ((msg = (char *)calloc(len +3, 1)) != NULL) {
703 (void) snprintf(msg, len + 3, "Unconfigure"
704 " %s%s\n%s",
705 SATA_CONFIRM_DEVICE, ap_id,
706 SATA_CONFIRM_DEVICE_SUSPEND);
707 }
708
709 if (!sata_confirm(confp, msg)) {
710 free(msg);
711 rv = CFGA_SATA_NACK;
712 break;
713 }
714 free(msg);
715
716 devpath = sata_get_devicepath(ap_id);
717 if (devpath == NULL) {
718 (void) printf(
719 "cfga_change_state: get device path failed\n");
720 rv = CFGA_SATA_DEV_UNCONFIGURE;
721 break;
722 }
723
724 if ((rv = sata_rcm_offline(ap_id, errstring, devpath, flags))
725 != CFGA_SATA_OK) {
726 break;
727 }
728
729 ret = devctl_ap_unconfigure(hdl, nvl);
730
731 if (ret != 0) {
732 rv = CFGA_SATA_DEV_UNCONFIGURE;
733 if (errno == EBUSY) {
734 rv = CFGA_SATA_BUSY;
735 }
736 (void) sata_rcm_online(ap_id, errstring, devpath,
737 flags);
738 } else {
739 (void) sata_rcm_remove(ap_id, errstring, devpath,
740 flags);
741
742 }
743 S_FREE(devpath);
744
745 break;
746
747 case CFGA_CMD_DISCONNECT:
748 if ((rv = port_state(hdl, nvl, &rstate, &ostate)) !=
749 CFGA_SATA_OK)
750 goto bailout;
751
752 if (rstate == AP_RSTATE_DISCONNECTED) {
753 rv = CFGA_SATA_DISCONNECTED;
754 goto bailout;
755 }
756
757 /* Strip off AP name dynamic component, if present */
758 if ((pdyn = GET_DYN(ap_id)) != NULL) {
759 *pdyn = '\0';
760 }
761
762
763 rv = CFGA_SATA_OK; /* other statuses don't matter */
764
765 /*
766 * If the port originally with device attached and was
767 * unconfigured already, the devicepath for the sd will be
768 * removed. sata_get_devicepath in this case is not necessary.
769 */
770 /* only call rcm_offline if the state was CONFIGURED */
771 if (ostate == AP_OSTATE_CONFIGURED &&
772 pmult == B_FALSE) {
773 devpath = sata_get_devicepath(ap_id);
774 if (devpath == NULL) {
775 (void) printf(
776 "cfga_change_state: get path failed\n");
777 rv = CFGA_SATA_DEV_UNCONFIGURE;
778 break;
779 }
780
781 len = strlen(SATA_CONFIRM_DEVICE) +
782 strlen(SATA_CONFIRM_DEVICE_SUSPEND) +
783 strlen("Disconnect") + strlen(ap_id);
784 if ((msg = (char *)calloc(len +3, 1)) != NULL) {
785 (void) snprintf(msg, len + 3,
786 "Disconnect"
787 " %s%s\n%s",
788 SATA_CONFIRM_DEVICE, ap_id,
789 SATA_CONFIRM_DEVICE_SUSPEND);
790 }
791 if (!sata_confirm(confp, msg)) {
792 free(msg);
793 rv = CFGA_SATA_NACK;
794 break;
795 }
796 free(msg);
797
798 if ((rv = sata_rcm_offline(ap_id, errstring,
799 devpath, flags)) != CFGA_SATA_OK) {
800 break;
801 }
802
803 ret = devctl_ap_unconfigure(hdl, nvl);
804 if (ret != 0) {
805 (void) printf(
806 "devctl_ap_unconfigure failed\n");
807 rv = CFGA_SATA_DEV_UNCONFIGURE;
808 if (errno == EBUSY)
809 rv = CFGA_SATA_BUSY;
810 (void) sata_rcm_online(ap_id, errstring,
811 devpath, flags);
812 S_FREE(devpath);
813
814 /*
815 * The current policy is that if unconfigure
816 * failed, do not continue with disconnect.
817 * If the port needs to be forced into the
818 * disconnect (shutdown) state,
819 * the -x sata_port_poweroff command should be
820 * used instead of -c disconnect
821 */
822 break;
823 } else {
824 (void) printf("%s\n",
825 ERR_STR(CFGA_SATA_DEVICE_UNCONFIGURED));
826 (void) sata_rcm_remove(ap_id, errstring,
827 devpath, flags);
828 }
829 S_FREE(devpath);
830 } else if (rstate == AP_RSTATE_CONNECTED ||
831 rstate == AP_RSTATE_EMPTY) {
832 len = strlen(SATA_CONFIRM_PORT) +
833 strlen(SATA_CONFIRM_PORT_DISABLE) +
834 strlen("Deactivate Port") + strlen(ap_id);
835 if ((msg = (char *)calloc(len +3, 1)) != NULL) {
836 (void) snprintf(msg, len +3,
837 "Disconnect"
838 " %s%s\n%s",
839 SATA_CONFIRM_PORT, ap_id,
840 SATA_CONFIRM_PORT_DISABLE);
841 }
842 if (!sata_confirm(confp, msg)) {
843 free(msg);
844 rv = CFGA_SATA_NACK;
845 break;
846 }
847 }
848 ret = devctl_ap_disconnect(hdl, nvl);
849 if (ret != 0) {
850 rv = CFGA_SATA_IOCTL;
851 if (errno == EBUSY) {
852 rv = CFGA_SATA_BUSY;
853 }
854 }
855 break;
856
857 case CFGA_CMD_CONNECT:
858 if ((rv = port_state(hdl, nvl, &rstate, &ostate)) !=
859 CFGA_SATA_OK)
860 goto bailout;
861
862 if (rstate == AP_RSTATE_CONNECTED) {
863 rv = CFGA_SATA_ALREADY_CONNECTED;
864 goto bailout;
865 }
866
867 len = strlen(SATA_CONFIRM_PORT) +
868 strlen(SATA_CONFIRM_PORT_ENABLE) +
869 strlen("Activate Port") + strlen(ap_id);
870 if ((msg = (char *)calloc(len +3, 1)) != NULL) {
871 (void) snprintf(msg, len +3, "Activate"
872 " %s%s\n%s",
873 SATA_CONFIRM_PORT, ap_id,
874 SATA_CONFIRM_PORT_ENABLE);
875 }
876 if (!sata_confirm(confp, msg)) {
877 rv = CFGA_SATA_NACK;
878 break;
879 }
880
881 /* Disallow dynamic AP name component */
882 if (GET_DYN(ap_id) != NULL) {
883 rv = CFGA_SATA_INVALID_DEVNAME;
884 goto bailout;
885 }
886
887 ret = devctl_ap_connect(hdl, nvl);
888 if (ret != 0) {
889 rv = CFGA_SATA_IOCTL;
890 } else {
891 rv = CFGA_SATA_OK;
892 }
893
894 break;
895
896 case CFGA_CMD_LOAD:
897 case CFGA_CMD_UNLOAD:
898 (void) cfga_help(msgp, options, flags);
899 rv = CFGA_SATA_OPNOTSUPP;
900 break;
901
902 case CFGA_CMD_NONE:
903 default:
904 (void) cfga_help(msgp, options, flags);
905 rv = CFGA_SATA_INTERNAL_ERROR;
906 }
907
908 bailout:
909 cleanup_after_devctl_cmd(hdl, nvl);
910
911 return (sata_err_msg(errstring, rv, ap_id, errno));
912 }
913
914 /* cfgadm entry point */
915 cfga_err_t
916 cfga_private_func(
917 const char *func,
918 const char *ap_id,
919 const char *options,
920 struct cfga_confirm *confp,
921 struct cfga_msg *msgp,
922 char **errstring,
923 cfga_flags_t flags)
924 {
925 int len;
926 char *msg;
927 nvlist_t *list = NULL;
928 ap_ostate_t ostate;
929 ap_rstate_t rstate;
930 devctl_hdl_t hdl = NULL;
931 cfga_sata_ret_t rv;
932 char *str_p;
933 size_t size;
934
935 if ((rv = verify_params(ap_id, NULL, errstring)) != CFGA_SATA_OK) {
936 (void) cfga_help(msgp, options, flags);
937 return (sata_err_msg(errstring, rv, ap_id, errno));
938 }
939
940 /*
941 * All subcommands which can change state of device require
942 * root privileges.
943 */
944 if (geteuid() != 0) {
945 rv = CFGA_SATA_PRIV;
946 goto bailout;
947 }
948
949 if (func == NULL) {
950 (void) printf("No valid option specified\n");
951 rv = CFGA_SATA_OPTIONS;
952 goto bailout;
953 }
954
955 if ((rv = setup_for_devctl_cmd(ap_id, &hdl, &list, 0)) !=
956 CFGA_SATA_OK) {
957 goto bailout;
958 }
959
960 /* We do not care here about dynamic AP name component */
961 if ((str_p = GET_DYN(ap_id)) != NULL) {
962 *str_p = '\0';
963 }
964
965 rv = CFGA_SATA_OK;
966
967 if (strcmp(func, SATA_RESET_PORT) == 0) {
968 len = strlen(SATA_CONFIRM_PORT) +
969 strlen(SATA_CONFIRM_DEVICE_ABORT) +
970 strlen("Reset Port") + strlen(ap_id);
971
972 if ((msg = (char *)calloc(len +3, 1)) != NULL) {
973 (void) snprintf(msg, len +3, "Reset"
974 " %s%s\n%s",
975 SATA_CONFIRM_PORT, ap_id,
976 SATA_CONFIRM_DEVICE_ABORT);
977 } else {
978 rv = CFGA_SATA_NACK;
979 goto bailout;
980 }
981
982 if (!sata_confirm(confp, msg)) {
983 rv = CFGA_SATA_NACK;
984 goto bailout;
985 }
986
987 rv = do_control_ioctl(ap_id, SATA_CFGA_RESET_PORT, NULL,
988 (void **)&str_p, &size);
989
990 } else if (strcmp(func, SATA_RESET_DEVICE) == 0) {
991 if ((rv = port_state(hdl, list, &rstate, &ostate)) !=
992 CFGA_SATA_OK)
993 goto bailout;
994 /*
995 * Reset device function requires device to be connected
996 */
997 if (rstate != AP_RSTATE_CONNECTED) {
998 rv = CFGA_SATA_NOT_CONNECTED;
999 goto bailout;
1000 }
1001
1002 len = strlen(SATA_CONFIRM_DEVICE) +
1003 strlen(SATA_CONFIRM_DEVICE_ABORT) +
1004 strlen("Reset Device") + strlen(ap_id);
1005
1006 if ((msg = (char *)calloc(len +3, 1)) != NULL) {
1007 (void) snprintf(msg, len +3, "Reset"
1008 " %s%s\n%s",
1009 SATA_CONFIRM_DEVICE, ap_id,
1010 SATA_CONFIRM_DEVICE_ABORT);
1011 } else {
1012 rv = CFGA_SATA_NACK;
1013 goto bailout;
1014 }
1015
1016 if (!sata_confirm(confp, msg)) {
1017 rv = CFGA_SATA_NACK;
1018 goto bailout;
1019 }
1020
1021 rv = do_control_ioctl(ap_id, SATA_CFGA_RESET_DEVICE, NULL,
1022 (void **)&str_p, &size);
1023
1024 } else if (strcmp(func, SATA_RESET_ALL) == 0) {
1025 len = strlen(SATA_CONFIRM_CONTROLLER) +
1026 strlen(SATA_CONFIRM_CONTROLLER_ABORT) +
1027 strlen("Reset All") + strlen(ap_id);
1028
1029 if ((msg = (char *)calloc(len +3, 1)) != NULL) {
1030 (void) snprintf(msg, len +3, "Reset"
1031 " %s%s\n%s",
1032 SATA_CONFIRM_CONTROLLER, ap_id,
1033 SATA_CONFIRM_CONTROLLER_ABORT);
1034 } else {
1035 rv = CFGA_SATA_NACK;
1036 goto bailout;
1037 }
1038
1039 if (!sata_confirm(confp, msg)) {
1040 rv = CFGA_SATA_NACK;
1041 goto bailout;
1042 }
1043 rv = do_control_ioctl(ap_id, SATA_CFGA_RESET_ALL, NULL,
1044 (void **)&str_p, &size);
1045
1046 } else if (strcmp(func, SATA_PORT_DEACTIVATE) == 0) {
1047 len = strlen(SATA_CONFIRM_PORT) +
1048 strlen(SATA_CONFIRM_PORT_DISABLE) +
1049 strlen("Deactivate Port") + strlen(ap_id);
1050
1051 if ((msg = (char *)calloc(len +3, 1)) != NULL) {
1052 (void) snprintf(msg, len +3, "Deactivate"
1053 " %s%s\n%s",
1054 SATA_CONFIRM_PORT, ap_id,
1055 SATA_CONFIRM_PORT_DISABLE);
1056 } else {
1057 rv = CFGA_SATA_NACK;
1058 goto bailout;
1059 }
1060 if (!sata_confirm(confp, msg)) {
1061 rv = CFGA_SATA_NACK;
1062 goto bailout;
1063 }
1064
1065 rv = do_control_ioctl(ap_id, SATA_CFGA_PORT_DEACTIVATE, NULL,
1066 (void **)&str_p, &size);
1067
1068 } else if (strcmp(func, SATA_PORT_ACTIVATE) == 0) {
1069 len = strlen(SATA_CONFIRM_PORT) +
1070 strlen(SATA_CONFIRM_PORT_ENABLE) +
1071 strlen("Activate Port") + strlen(ap_id);
1072
1073 if ((msg = (char *)calloc(len +3, 1)) != NULL) {
1074 (void) snprintf(msg, len +3, "Activate"
1075 " %s%s\n%s",
1076 SATA_CONFIRM_PORT, ap_id,
1077 SATA_CONFIRM_PORT_ENABLE);
1078 } else {
1079 rv = CFGA_SATA_NACK;
1080 goto bailout;
1081 }
1082 if (!sata_confirm(confp, msg)) {
1083 rv = CFGA_SATA_NACK;
1084 goto bailout;
1085 }
1086
1087 rv = do_control_ioctl(ap_id, SATA_CFGA_PORT_ACTIVATE,
1088 NULL, (void **)&str_p, &size);
1089 goto bailout;
1090
1091 } else if (strcmp(func, SATA_PORT_SELF_TEST) == 0) {
1092 len = strlen(SATA_CONFIRM_PORT) +
1093 strlen(SATA_CONFIRM_DEVICE_SUSPEND) +
1094 strlen("Self Test Port") + strlen(ap_id);
1095
1096 if ((msg = (char *)calloc(len +3, 1)) != NULL) {
1097 (void) snprintf(msg, len +3, "Self Test"
1098 " %s%s\n%s",
1099 SATA_CONFIRM_PORT, ap_id,
1100 SATA_CONFIRM_DEVICE_SUSPEND);
1101 } else {
1102 rv = CFGA_SATA_NACK;
1103 goto bailout;
1104 }
1105 if (!sata_confirm(confp, msg)) {
1106 rv = CFGA_SATA_NACK;
1107 goto bailout;
1108 }
1109
1110 rv = do_control_ioctl(ap_id, SATA_CFGA_PORT_SELF_TEST,
1111 NULL, (void **)&str_p, &size);
1112 } else {
1113 /* Unrecognized operation request */
1114 rv = CFGA_SATA_HWOPNOTSUPP;
1115 }
1116
1117 bailout:
1118 cleanup_after_devctl_cmd(hdl, list);
1119
1120 return (sata_err_msg(errstring, rv, ap_id, errno));
1121
1122 }
1123
1124 /* cfgadm entry point */
1125 /*ARGSUSED*/
1126 cfga_err_t
1127 cfga_test(
1128 const char *ap_id,
1129 const char *options,
1130 struct cfga_msg *msgp,
1131 char **errstring,
1132 cfga_flags_t flags)
1133 {
1134 /* Should call ioctl for self test - phase 2 */
1135 return (CFGA_OPNOTSUPP);
1136 }
1137
1138
1139 int
1140 sata_check_target_node(di_node_t node, void *arg)
1141 {
1142 char *minorpath;
1143 char *cp;
1144
1145 minorpath = di_devfs_minor_path(di_minor_next(node, DI_MINOR_NIL));
1146 if (minorpath != NULL) {
1147 if (strstr(minorpath, arg) != NULL) {
1148 cp = strrchr(minorpath, (int)*MINOR_SEP);
1149 if (cp != NULL) {
1150 (void) strcpy(arg, cp);
1151 }
1152 free(minorpath);
1153 return (DI_WALK_TERMINATE);
1154 }
1155 free(minorpath);
1156 }
1157 return (DI_WALK_CONTINUE);
1158 }
1159
1160 struct chk_dev {
1161 int c_isblk;
1162 char *c_minor;
1163 };
1164
1165 /*ARGSUSED*/
1166 static int
1167 chk_dev_fcn(di_node_t node, di_minor_t minor, void *arg)
1168 {
1169 char *mn;
1170 struct chk_dev *chkp = (struct chk_dev *)arg;
1171
1172 mn = di_minor_name(minor);
1173 if (mn == NULL)
1174 return (DI_WALK_CONTINUE);
1175
1176 if (strcmp(mn, chkp->c_minor) != 0)
1177 return (DI_WALK_CONTINUE);
1178
1179 chkp->c_isblk = di_minor_spectype(minor) == S_IFBLK ? 1 : 0;
1180
1181 return (DI_WALK_TERMINATE);
1182 }
1183
1184 /*
1185 * Don't use devfs if stat() in /devices fails. Use libdevinfo instead.
1186 * Retired devices don't show up in devfs.
1187 *
1188 * Returns:
1189 * 1 - minor exists and is of type BLK
1190 * 0 - minor does not exist or is not of type BLK.
1191 */
1192 static int
1193 is_devinfo_blk(char *minor_path)
1194 {
1195 char *minor_portion;
1196 struct chk_dev chk_dev;
1197 di_node_t node;
1198 int rv;
1199
1200 /*
1201 * prune minor path for di_init() - no /devices prefix and no minor name
1202 */
1203 if (strncmp(minor_path, "/devices/", strlen("/devices/")) != 0)
1204 return (0);
1205
1206 minor_portion = strrchr(minor_path, *MINOR_SEP);
1207 if (minor_portion == NULL)
1208 return (0);
1209
1210 *minor_portion = 0;
1211
1212 node = di_init(minor_path + strlen("/devices"), DINFOMINOR);
1213
1214 *minor_portion = *MINOR_SEP;
1215
1216 if (node == DI_NODE_NIL)
1217 return (0);
1218
1219 chk_dev.c_isblk = 0;
1220 chk_dev.c_minor = minor_portion + 1;
1221
1222 rv = di_walk_minor(node, NULL, 0, &chk_dev, chk_dev_fcn);
1223
1224 di_fini(node);
1225
1226 if (rv == 0 && chk_dev.c_isblk)
1227 return (1);
1228 else
1229 return (0);
1230 }
1231
1232 /*
1233 * The dynamic component buffer returned by this function has to be freed!
1234 */
1235 int
1236 sata_make_dyncomp(const char *ap_id, char **dyncomp, const char *type)
1237 {
1238 char *devpath = NULL;
1239 char *cp = NULL;
1240 int l_errno;
1241 char minor_path[MAXPATHLEN];
1242 char name_part[MAXNAMELEN];
1243 char *devlink = NULL;
1244 char *minor_portion = NULL;
1245 int deplen;
1246 int err;
1247 DIR *dp = NULL;
1248 struct stat sb;
1249 struct dirent *dep = NULL;
1250 struct dirent *newdep = NULL;
1251 char *p;
1252
1253 assert(dyncomp != NULL);
1254
1255 /*
1256 * Get target node path
1257 */
1258 devpath = sata_get_devicepath(ap_id);
1259 if (devpath == NULL) {
1260
1261 (void) printf("cfga_list_ext: cannot locate target device\n");
1262 return (CFGA_SATA_DYNAMIC_AP);
1263
1264 } else {
1265
1266 cp = strrchr(devpath, *PATH_SEP);
1267 assert(cp != NULL);
1268 *cp = 0; /* terminate path for opendir() */
1269
1270 (void) strncpy(name_part, cp + 1, MAXNAMELEN);
1271
1272 /*
1273 * Using libdevinfo for this is overkill and kills
1274 * performance when many consumers are using libcfgadm
1275 * concurrently.
1276 */
1277 if ((dp = opendir(devpath)) == NULL) {
1278 goto bailout;
1279 }
1280
1281 /*
1282 * deplen is large enough to fit the largest path-
1283 * struct dirent includes one byte (the terminator)
1284 * so we don't add 1 to the calculation here.
1285 */
1286 deplen = pathconf(devpath, _PC_NAME_MAX);
1287 deplen = ((deplen <= 0) ? MAXNAMELEN : deplen) +
1288 sizeof (struct dirent);
1289 dep = (struct dirent *)malloc(deplen);
1290 if (dep == NULL)
1291 goto bailout;
1292
1293 while ((err = readdir_r(dp, dep, &newdep)) == 0 &&
1294 newdep != NULL) {
1295
1296 assert(newdep == dep);
1297
1298 if (strcmp(dep->d_name, ".") == 0 ||
1299 strcmp(dep->d_name, "..") == 0 ||
1300 (minor_portion = strchr(dep->d_name,
1301 *MINOR_SEP)) == NULL)
1302 continue;
1303
1304 *minor_portion = 0;
1305 if (strcmp(dep->d_name, name_part) != 0)
1306 continue;
1307 *minor_portion = *MINOR_SEP;
1308
1309 (void) snprintf(minor_path, MAXPATHLEN,
1310 "%s/%s", devpath, dep->d_name);
1311
1312 /*
1313 * Break directly for tape device
1314 */
1315 if (strcmp(type, "tape") == 0)
1316 break;
1317
1318 /*
1319 * If stat() fails, the device *may* be retired.
1320 * Check via libdevinfo if the device has a BLK minor.
1321 * We don't use libdevinfo all the time, since taking
1322 * a snapshot is slower than a stat().
1323 */
1324 if (stat(minor_path, &sb) < 0) {
1325 if (is_devinfo_blk(minor_path)) {
1326 break;
1327 } else {
1328 continue;
1329 }
1330 }
1331
1332 if (S_ISBLK(sb.st_mode))
1333 break;
1334
1335 }
1336
1337 (void) closedir(dp);
1338 free(dep);
1339 free(devpath);
1340
1341 dp = NULL;
1342 dep = NULL;
1343 devpath = NULL;
1344
1345 /*
1346 * If there was an error, or we didn't exit the loop
1347 * by finding a block or character device, bail out.
1348 */
1349 if (err != 0 || newdep == NULL)
1350 goto bailout;
1351
1352 /*
1353 * Look for links to the physical path in /dev/dsk
1354 * and /dev/rmt. So far, sata modue supports disk,
1355 * dvd and tape devices, so we will first look for
1356 * BLOCK devices, and then look for tape devices.
1357 */
1358 (void) physpath_to_devlink("/dev/dsk",
1359 minor_path, &devlink, &l_errno);
1360
1361 /* postprocess and copy logical name here */
1362 if (devlink != NULL) {
1363 /*
1364 * For disks, remove partition/slice info
1365 */
1366 if ((cp = strstr(devlink, "dsk/")) != NULL) {
1367 /* cXtYdZ[(s[0..15])|(p[0..X])] */
1368 if ((p = strchr(cp + 4, 'd')) != NULL) {
1369 p++; /* Skip the 'd' */
1370 while (*p != 0 && isdigit(*p))
1371 p++;
1372 *p = 0;
1373 }
1374 *dyncomp = strdup(cp);
1375 }
1376
1377 free(devlink);
1378 } else if (strcmp(type, "tape") == 0) {
1379
1380 /*
1381 * For tape device, logical name looks like
1382 * rmt/X
1383 */
1384 (void) physpath_to_devlink("/dev/rmt",
1385 minor_path, &devlink, &l_errno);
1386
1387 if (devlink != NULL) {
1388 if ((cp = strstr(devlink, "rmt/")) != NULL) {
1389 *dyncomp = strdup(cp);
1390 }
1391
1392 free(devlink);
1393 }
1394 }
1395
1396 return (SATA_CFGA_OK);
1397 }
1398
1399 bailout:
1400 if (dp)
1401 (void) closedir(dp);
1402 if (devpath)
1403 free(devpath);
1404 if (dep)
1405 free(dep);
1406 return (CFGA_SATA_DYNAMIC_AP);
1407 }
1408
1409 /* cfgadm entry point */
1410 /*ARGSUSED*/
1411 cfga_err_t
1412 cfga_list_ext(
1413 const char *ap_id,
1414 cfga_list_data_t **ap_id_list,
1415 int *nlistp,
1416 const char *options,
1417 const char *listopts,
1418 char **errstring,
1419 cfga_flags_t flags)
1420 {
1421 int l_errno;
1422 char *ap_id_log = NULL;
1423 size_t size;
1424 nvlist_t *user_nvlist = NULL;
1425 devctl_hdl_t devctl_hdl = NULL;
1426 cfga_sata_ret_t rv = CFGA_SATA_OK;
1427 devctl_ap_state_t devctl_ap_state;
1428 char *pdyn;
1429 boolean_t pmult = B_FALSE;
1430 uint32_t port;
1431
1432
1433 if ((rv = verify_params(ap_id, options, errstring)) != CFGA_SATA_OK) {
1434 goto bailout;
1435 }
1436 /* We do not care here about dynamic AP name component */
1437 if ((pdyn = GET_DYN(ap_id)) != NULL) {
1438 *pdyn = '\0';
1439 }
1440
1441 if (ap_id_list == NULL || nlistp == NULL) {
1442 rv = CFGA_SATA_DATA_ERROR;
1443 goto bailout;
1444 }
1445
1446 /* Get ap status */
1447 if ((rv = setup_for_devctl_cmd(ap_id, &devctl_hdl, &user_nvlist,
1448 DC_RDONLY)) != CFGA_SATA_OK) {
1449 goto bailout;
1450 }
1451
1452 /* will call dc_cmd to send IOCTL to kernel */
1453 if (devctl_ap_getstate(devctl_hdl, user_nvlist,
1454 &devctl_ap_state) == -1) {
1455 cleanup_after_devctl_cmd(devctl_hdl, user_nvlist);
1456 rv = CFGA_SATA_IOCTL;
1457 goto bailout;
1458 }
1459
1460 cleanup_after_devctl_cmd(devctl_hdl, user_nvlist);
1461
1462 /*
1463 * Create cfga_list_data_t struct.
1464 */
1465 if ((*ap_id_list =
1466 (cfga_list_data_t *)malloc(sizeof (**ap_id_list))) == NULL) {
1467 rv = CFGA_SATA_ALLOC_FAIL;
1468 goto bailout;
1469 }
1470 *nlistp = 1;
1471
1472 /*
1473 * Rest of the code fills in the cfga_list_data_t struct.
1474 */
1475
1476 /* Get /dev/cfg path to corresponding to the physical ap_id */
1477 /* Remember ap_id_log must be freed */
1478 rv = physpath_to_devlink(CFGA_DEV_DIR, (char *)ap_id,
1479 &ap_id_log, &l_errno);
1480
1481 if (rv != 0) {
1482 rv = CFGA_SATA_DEVLINK;
1483 goto bailout;
1484 }
1485
1486 /* Get logical ap_id corresponding to the physical */
1487 if (ap_id_log == NULL || strstr(ap_id_log, CFGA_DEV_DIR) == NULL) {
1488 rv = CFGA_SATA_DEVLINK;
1489 goto bailout;
1490 }
1491
1492 (void) strlcpy((*ap_id_list)->ap_log_id,
1493 /* Strip off /dev/cfg/ */ ap_id_log + strlen(CFGA_DEV_DIR)+ 1,
1494 sizeof ((*ap_id_list)->ap_log_id));
1495
1496 free(ap_id_log);
1497 ap_id_log = NULL;
1498
1499 (void) strlcpy((*ap_id_list)->ap_phys_id, ap_id,
1500 sizeof ((*ap_id_list)->ap_phys_id));
1501
1502 switch (devctl_ap_state.ap_rstate) {
1503 case AP_RSTATE_EMPTY:
1504 (*ap_id_list)->ap_r_state = CFGA_STAT_EMPTY;
1505 break;
1506
1507 case AP_RSTATE_DISCONNECTED:
1508 (*ap_id_list)->ap_r_state = CFGA_STAT_DISCONNECTED;
1509 break;
1510
1511 case AP_RSTATE_CONNECTED:
1512 (*ap_id_list)->ap_r_state = CFGA_STAT_CONNECTED;
1513 break;
1514
1515 default:
1516 rv = CFGA_SATA_STATE;
1517 goto bailout;
1518 }
1519
1520 switch (devctl_ap_state.ap_ostate) {
1521 case AP_OSTATE_CONFIGURED:
1522 (*ap_id_list)->ap_o_state = CFGA_STAT_CONFIGURED;
1523 break;
1524
1525 case AP_OSTATE_UNCONFIGURED:
1526 (*ap_id_list)->ap_o_state = CFGA_STAT_UNCONFIGURED;
1527 break;
1528
1529 default:
1530 rv = CFGA_SATA_STATE;
1531 goto bailout;
1532 }
1533
1534 switch (devctl_ap_state.ap_condition) {
1535 case AP_COND_OK:
1536 (*ap_id_list)->ap_cond = CFGA_COND_OK;
1537 break;
1538
1539 case AP_COND_FAILING:
1540 (*ap_id_list)->ap_cond = CFGA_COND_FAILING;
1541 break;
1542
1543 case AP_COND_FAILED:
1544 (*ap_id_list)->ap_cond = CFGA_COND_FAILED;
1545 break;
1546
1547 case AP_COND_UNUSABLE:
1548 (*ap_id_list)->ap_cond = CFGA_COND_UNUSABLE;
1549 break;
1550
1551 case AP_COND_UNKNOWN:
1552 (*ap_id_list)->ap_cond = CFGA_COND_UNKNOWN;
1553 break;
1554
1555 default:
1556 rv = CFGA_SATA_STATE;
1557 goto bailout;
1558 }
1559
1560 (*ap_id_list)->ap_class[0] = '\0'; /* Filled by libcfgadm */
1561 (*ap_id_list)->ap_busy = devctl_ap_state.ap_in_transition;
1562 (*ap_id_list)->ap_status_time = devctl_ap_state.ap_last_change;
1563 (*ap_id_list)->ap_info[0] = NULL;
1564
1565 if ((*ap_id_list)->ap_r_state == CFGA_STAT_CONNECTED) {
1566 char *str_p;
1567 int skip, i;
1568
1569 /*
1570 * Fill in the 'Information' field for the -v option
1571 * Model (MOD:)
1572 */
1573 if ((rv = do_control_ioctl(ap_id, SATA_CFGA_GET_MODEL_INFO,
1574 NULL, (void **)&str_p, &size)) != CFGA_SATA_OK) {
1575 (void) printf(
1576 "SATA_CFGA_GET_MODULE_INFO ioctl failed\n");
1577 goto bailout;
1578 }
1579 /* drop leading and trailing spaces */
1580 skip = strspn(str_p, " ");
1581 for (i = size - 1; i >= 0; i--) {
1582 if (str_p[i] == '\040')
1583 str_p[i] = '\0';
1584 else if (str_p[i] != '\0')
1585 break;
1586 }
1587
1588 (void) strlcpy((*ap_id_list)->ap_info, "Mod: ",
1589 sizeof ((*ap_id_list)->ap_info));
1590 (void) strlcat((*ap_id_list)->ap_info, str_p + skip,
1591 sizeof ((*ap_id_list)->ap_info));
1592
1593 free(str_p);
1594
1595 /*
1596 * Fill in the 'Information' field for the -v option
1597 * Firmware revision (FREV:)
1598 */
1599 if ((rv = do_control_ioctl(ap_id,
1600 SATA_CFGA_GET_REVFIRMWARE_INFO,
1601 NULL, (void **)&str_p, &size)) != CFGA_SATA_OK) {
1602 (void) printf(
1603 "SATA_CFGA_GET_REVFIRMWARE_INFO ioctl failed\n");
1604 goto bailout;
1605 }
1606 /* drop leading and trailing spaces */
1607 skip = strspn(str_p, " ");
1608 for (i = size - 1; i >= 0; i--) {
1609 if (str_p[i] == '\040')
1610 str_p[i] = '\0';
1611 else if (str_p[i] != '\0')
1612 break;
1613 }
1614 (void) strlcat((*ap_id_list)->ap_info, " FRev: ",
1615 sizeof ((*ap_id_list)->ap_info));
1616 (void) strlcat((*ap_id_list)->ap_info, str_p + skip,
1617 sizeof ((*ap_id_list)->ap_info));
1618
1619 free(str_p);
1620
1621
1622 /*
1623 * Fill in the 'Information' field for the -v option
1624 * Serial Number (SN:)
1625 */
1626 if ((rv = do_control_ioctl(ap_id,
1627 SATA_CFGA_GET_SERIALNUMBER_INFO,
1628 NULL, (void **)&str_p, &size)) != CFGA_SATA_OK) {
1629 (void) printf(
1630 "SATA_CFGA_GET_SERIALNUMBER_INFO ioctl failed\n");
1631 goto bailout;
1632 }
1633 /* drop leading and trailing spaces */
1634 skip = strspn(str_p, " ");
1635 for (i = size - 1; i >= 0; i--) {
1636 if (str_p[i] == '\040')
1637 str_p[i] = '\0';
1638 else if (str_p[i] != '\0')
1639 break;
1640 }
1641 (void) strlcat((*ap_id_list)->ap_info, " SN: ",
1642 sizeof ((*ap_id_list)->ap_info));
1643 (void) strlcat((*ap_id_list)->ap_info, str_p + skip,
1644 sizeof ((*ap_id_list)->ap_info));
1645
1646 free(str_p);
1647
1648
1649
1650 /* Fill in ap_type which is collected from HBA driver */
1651 /* call do_control_ioctl TBD */
1652 if ((rv = do_control_ioctl(ap_id, SATA_CFGA_GET_AP_TYPE, NULL,
1653 (void **)&str_p, &size)) != CFGA_SATA_OK) {
1654 (void) printf(
1655 "SATA_CFGA_GET_AP_TYPE ioctl failed\n");
1656 goto bailout;
1657 }
1658
1659 (void) strlcpy((*ap_id_list)->ap_type, str_p,
1660 sizeof ((*ap_id_list)->ap_type));
1661
1662 free(str_p);
1663
1664 /*
1665 * Checking device type. Port multiplier has no dynamic
1666 * suffix.
1667 */
1668 if (strncmp((*ap_id_list)->ap_type, "sata-pmult",
1669 sizeof ("sata-pmult")) == 0)
1670 pmult = B_TRUE;
1671
1672 if ((*ap_id_list)->ap_o_state == CFGA_STAT_CONFIGURED &&
1673 pmult == B_FALSE) {
1674
1675 char *dyncomp = NULL;
1676
1677 /*
1678 * This is the case where we need to generate
1679 * a dynamic component of the ap_id, i.e. device.
1680 */
1681 rv = sata_make_dyncomp(ap_id, &dyncomp,
1682 (*ap_id_list)->ap_type);
1683 if (rv != CFGA_SATA_OK)
1684 goto bailout;
1685 if (dyncomp != NULL) {
1686 (void) strcat((*ap_id_list)->ap_log_id,
1687 DYN_SEP);
1688 (void) strlcat((*ap_id_list)->ap_log_id,
1689 dyncomp,
1690 sizeof ((*ap_id_list)->ap_log_id));
1691 free(dyncomp);
1692 }
1693 }
1694
1695 } else {
1696 /* This is an empty port */
1697 if (get_port_num(ap_id, &port) != CFGA_SATA_OK) {
1698 goto bailout;
1699 }
1700
1701 if (port & SATA_CFGA_PMPORT_QUAL) {
1702 (void) strlcpy((*ap_id_list)->ap_type, "pmult-port",
1703 sizeof ((*ap_id_list)->ap_type));
1704 } else {
1705 (void) strlcpy((*ap_id_list)->ap_type, "sata-port",
1706 sizeof ((*ap_id_list)->ap_type));
1707 }
1708 }
1709
1710 return (sata_err_msg(errstring, rv, ap_id, errno));
1711
1712 bailout:
1713 if (*ap_id_list != NULL) {
1714 free(*ap_id_list);
1715 }
1716 if (ap_id_log != NULL) {
1717 free(ap_id_log);
1718 }
1719
1720 return (sata_err_msg(errstring, rv, ap_id, errno));
1721 }
1722 /*
1723 * This routine accepts a string adn prints it using
1724 * the message print routine argument.
1725 */
1726 static void
1727 cfga_msg(struct cfga_msg *msgp, const char *str)
1728 {
1729 int len;
1730 char *q;
1731
1732 if (msgp == NULL || msgp->message_routine == NULL) {
1733 (void) printf("cfga_msg: NULL msgp\n");
1734 return;
1735 }
1736
1737 if ((len = strlen(str)) == 0) {
1738 (void) printf("cfga_msg: null str\n");
1739 return;
1740 }
1741
1742 if ((q = (char *)calloc(len + 1, 1)) == NULL) {
1743 perror("cfga_msg");
1744 return;
1745 }
1746
1747 (void) strcpy(q, str);
1748 (*msgp->message_routine)(msgp->appdata_ptr, q);
1749
1750 free(q);
1751 }
1752
1753 /* cfgadm entry point */
1754 /* ARGSUSED */
1755 cfga_err_t
1756 cfga_help(struct cfga_msg *msgp, const char *options, cfga_flags_t flags)
1757 {
1758 if (options != NULL) {
1759 cfga_msg(msgp, dgettext(TEXT_DOMAIN, sata_help[HELP_UNKNOWN]));
1760 cfga_msg(msgp, options);
1761 }
1762 cfga_msg(msgp, dgettext(TEXT_DOMAIN, sata_help[HELP_HEADER]));
1763 cfga_msg(msgp, sata_help[HELP_CONFIG]);
1764 cfga_msg(msgp, sata_help[HELP_RESET_PORT]);
1765 cfga_msg(msgp, sata_help[HELP_RESET_DEVICE]);
1766 cfga_msg(msgp, sata_help[HELP_RESET_ALL]);
1767 cfga_msg(msgp, sata_help[HELP_PORT_ACTIVATE]);
1768 cfga_msg(msgp, sata_help[HELP_PORT_DEACTIVATE]);
1769 cfga_msg(msgp, sata_help[HELP_PORT_SELF_TEST]);
1770 cfga_msg(msgp, sata_help[HELP_CNTRL_SELF_TEST]);
1771
1772 return (CFGA_OK);
1773 }
1774
1775
1776 /*
1777 * Ensure the ap_id passed is in the correct (physical ap_id) form:
1778 * path/device:xx[.xx]
1779 * where xx is a one or two-digit number.
1780 *
1781 * Note the library always calls the plugin with a physical ap_id.
1782 */
1783 static int
1784 verify_valid_apid(const char *ap_id)
1785 {
1786 char *l_ap_id;
1787
1788 if (ap_id == NULL)
1789 return (-1);
1790
1791 l_ap_id = strrchr(ap_id, (int)*MINOR_SEP);
1792 l_ap_id++;
1793
1794 if (strspn(l_ap_id, "0123456789.") != strlen(l_ap_id)) {
1795 /* Bad characters in the ap_id */
1796 return (-1);
1797 }
1798
1799 if (strstr(l_ap_id, "..") != NULL) {
1800 /* ap_id has 1..2 or more than 2 dots */
1801 return (-1);
1802 }
1803
1804 return (0);
1805 }
1806
1807
1808
1809 /*
1810 * Verify the params passed in are valid.
1811 */
1812 static cfga_sata_ret_t
1813 verify_params(
1814 const char *ap_id,
1815 const char *options,
1816 char **errstring)
1817 {
1818 char *pdyn, *lap_id;
1819 int rv;
1820
1821 if (errstring != NULL) {
1822 *errstring = NULL;
1823 }
1824
1825 if (options != NULL) {
1826 return (CFGA_SATA_OPTIONS);
1827 }
1828
1829 /* Strip dynamic AP name component if it is present. */
1830 lap_id = strdup(ap_id);
1831 if (lap_id == NULL) {
1832 return (CFGA_SATA_ALLOC_FAIL);
1833 }
1834 if ((pdyn = GET_DYN(lap_id)) != NULL) {
1835 *pdyn = '\0';
1836 }
1837
1838 if (verify_valid_apid(lap_id) != 0) {
1839 rv = CFGA_SATA_AP;
1840 } else {
1841 rv = CFGA_SATA_OK;
1842 }
1843 free(lap_id);
1844
1845 return (rv);
1846 }
1847
1848 /*
1849 * Takes a validated ap_id and extracts the port number.
1850 * Port multiplier is supported now.
1851 */
1852 static cfga_sata_ret_t
1853 get_port_num(const char *ap_id, uint32_t *port)
1854 {
1855 uint32_t cport, pmport = 0, qual = 0;
1856 char *cport_str, *pmport_str;
1857
1858 /* Get the cport number */
1859 cport_str = strrchr(ap_id, (int)*MINOR_SEP) + strlen(MINOR_SEP);
1860
1861 errno = 0;
1862 cport = strtol(cport_str, NULL, 10);
1863 if ((cport & ~SATA_CFGA_CPORT_MASK) != 0 || errno != 0) {
1864 return (CFGA_SATA_PORT);
1865 }
1866
1867 /* Get pmport number if there is a PORT_SEPARATOR */
1868 errno = 0;
1869 if ((pmport_str = strrchr(ap_id, (int)*PORT_SEPARATOR)) != 0) {
1870 pmport_str += strlen(PORT_SEPARATOR);
1871 pmport = strtol(pmport_str, NULL, 10);
1872 qual = SATA_CFGA_PMPORT_QUAL;
1873 if ((pmport & ~SATA_CFGA_PMPORT_MASK) != 0 || errno != 0) {
1874 return (CFGA_SATA_PORT);
1875 }
1876 }
1877
1878 *port = cport | (pmport << SATA_CFGA_PMPORT_SHIFT) | qual;
1879 return (CFGA_SATA_OK);
1880 }
1881
1882 /*
1883 * Pair of routines to set up for/clean up after a devctl_ap_* lib call.
1884 */
1885 static void
1886 cleanup_after_devctl_cmd(devctl_hdl_t devctl_hdl, nvlist_t *user_nvlist)
1887 {
1888 if (user_nvlist != NULL) {
1889 nvlist_free(user_nvlist);
1890 }
1891 if (devctl_hdl != NULL) {
1892 devctl_release(devctl_hdl);
1893 }
1894 }
1895
1896 static cfga_sata_ret_t
1897 setup_for_devctl_cmd(
1898 const char *ap_id,
1899 devctl_hdl_t *devctl_hdl,
1900 nvlist_t **user_nvlistp,
1901 uint_t oflag)
1902 {
1903
1904 uint_t port;
1905 cfga_sata_ret_t rv = CFGA_SATA_OK;
1906 char *lap_id, *pdyn;
1907
1908 lap_id = strdup(ap_id);
1909 if (lap_id == NULL)
1910 return (CFGA_SATA_ALLOC_FAIL);
1911 if ((pdyn = GET_DYN(lap_id)) != NULL) {
1912 *pdyn = '\0';
1913 }
1914
1915 /* Get a devctl handle to pass to the devctl_ap_XXX functions */
1916 if ((*devctl_hdl = devctl_ap_acquire((char *)lap_id, oflag)) == NULL) {
1917 (void) fprintf(stderr, "[libcfgadm:sata] "
1918 "setup_for_devctl_cmd: devctl_ap_acquire failed: %s\n",
1919 strerror(errno));
1920 rv = CFGA_SATA_DEVCTL;
1921 goto bailout;
1922 }
1923
1924 /* Set up nvlist to pass the port number down to the driver */
1925 if (nvlist_alloc(user_nvlistp, NV_UNIQUE_NAME_TYPE, NULL) != 0) {
1926 *user_nvlistp = NULL;
1927 rv = CFGA_SATA_NVLIST;
1928 (void) printf("nvlist_alloc failed\n");
1929 goto bailout;
1930 }
1931
1932 /*
1933 * Get port id, for Port Multiplier port, things could be a little bit
1934 * complicated because of "port.port" format in ap_id, thus for
1935 * port multiplier port, port number should be coded as 32bit int
1936 * with the sig 16 bit as sata channel number, least 16 bit as
1937 * the port number of sata port multiplier port.
1938 */
1939 if ((rv = get_port_num(lap_id, &port)) != CFGA_SATA_OK) {
1940 (void) printf(
1941 "setup_for_devctl_cmd: get_port_num, errno: %d\n",
1942 errno);
1943 goto bailout;
1944 }
1945
1946 /* Creates an int32_t entry */
1947 if (nvlist_add_int32(*user_nvlistp, PORT, port) == -1) {
1948 (void) printf("nvlist_add_int32 failed\n");
1949 rv = CFGA_SATA_NVLIST;
1950 goto bailout;
1951 }
1952
1953 free(lap_id);
1954 return (rv);
1955
1956 bailout:
1957 free(lap_id);
1958 (void) cleanup_after_devctl_cmd(*devctl_hdl, *user_nvlistp);
1959
1960 return (rv);
1961 }
1962
1963
1964 static cfga_sata_ret_t
1965 port_state(devctl_hdl_t hdl, nvlist_t *list,
1966 ap_rstate_t *rstate, ap_ostate_t *ostate)
1967 {
1968 devctl_ap_state_t devctl_ap_state;
1969
1970 if (devctl_ap_getstate(hdl, list, &devctl_ap_state) == -1) {
1971 (void) printf("devctl_ap_getstate failed, errno: %d\n", errno);
1972 return (CFGA_SATA_IOCTL);
1973 }
1974 *rstate = devctl_ap_state.ap_rstate;
1975 *ostate = devctl_ap_state.ap_ostate;
1976 return (CFGA_SATA_OK);
1977 }
1978
1979
1980 /*
1981 * Given a subcommand to the DEVCTL_AP_CONTROL ioctl, rquest the size of
1982 * the data to be returned, allocate a buffer, then get the data.
1983 * Returns *descrp (which must be freed) and size.
1984 *
1985 * Note SATA_DESCR_TYPE_STRING returns an ASCII NULL-terminated string,
1986 * not a string descr.
1987 */
1988 cfga_sata_ret_t
1989 do_control_ioctl(const char *ap_id, sata_cfga_apctl_t subcommand, uint_t arg,
1990 void **descrp, size_t *sizep)
1991 {
1992 int fd = -1;
1993 uint_t port;
1994 uint32_t local_size;
1995 cfga_sata_ret_t rv = CFGA_SATA_OK;
1996 struct sata_ioctl_data ioctl_data;
1997
1998 assert(descrp != NULL);
1999 *descrp = NULL;
2000 assert(sizep != NULL);
2001
2002 if ((rv = get_port_num(ap_id, &port)) != CFGA_SATA_OK) {
2003 goto bailout;
2004 }
2005
2006 if ((fd = open(ap_id, O_RDONLY)) == -1) {
2007 (void) printf("do_control_ioctl: open failed: errno:%d\n",
2008 errno);
2009 rv = CFGA_SATA_OPEN;
2010 if (errno == EBUSY) {
2011 rv = CFGA_SATA_BUSY;
2012 }
2013 goto bailout;
2014 }
2015
2016 ioctl_data.cmd = subcommand;
2017 ioctl_data.port = port;
2018 ioctl_data.misc_arg = (uint_t)arg;
2019
2020 /*
2021 * Find out how large a buf we need to get the data.
2022 * Note the ioctls only accept/return a 32-bit int for a get_size
2023 * to avoid 32/64 and BE/LE issues.
2024 */
2025 if ((subcommand == SATA_CFGA_GET_AP_TYPE) ||
2026 (subcommand == SATA_CFGA_GET_DEVICE_PATH) ||
2027 (subcommand == SATA_CFGA_GET_MODEL_INFO) ||
2028 (subcommand == SATA_CFGA_GET_REVFIRMWARE_INFO) ||
2029 (subcommand == SATA_CFGA_GET_SERIALNUMBER_INFO)) {
2030 ioctl_data.get_size = B_TRUE;
2031 ioctl_data.buf = (caddr_t)&local_size;
2032 ioctl_data.bufsiz = sizeof (local_size);
2033
2034 if (ioctl(fd, DEVCTL_AP_CONTROL, &ioctl_data) != 0) {
2035 perror("ioctl failed (size)");
2036 rv = CFGA_SATA_IOCTL;
2037 goto bailout;
2038 }
2039 *sizep = local_size;
2040
2041 if (local_size == 0) {
2042 (void) printf("zero length data\n");
2043 rv = CFGA_SATA_ZEROLEN;
2044 goto bailout;
2045 }
2046 if ((*descrp = malloc(*sizep)) == NULL) {
2047 (void) printf("do_control_ioctl: malloc failed\n");
2048 rv = CFGA_SATA_ALLOC_FAIL;
2049 goto bailout;
2050 }
2051 } else {
2052 *sizep = 0;
2053 }
2054 ioctl_data.get_size = B_FALSE;
2055 ioctl_data.buf = *descrp;
2056 ioctl_data.bufsiz = *sizep;
2057
2058 /* Execute IOCTL */
2059
2060 if (ioctl(fd, DEVCTL_AP_CONTROL, &ioctl_data) != 0) {
2061 rv = CFGA_SATA_IOCTL;
2062 goto bailout;
2063 }
2064
2065 (void) close(fd);
2066
2067 return (rv);
2068
2069 bailout:
2070 if (fd != -1) {
2071 (void) close(fd);
2072 }
2073 if (*descrp != NULL) {
2074 free(*descrp);
2075 *descrp = NULL;
2076 }
2077
2078 if (rv == CFGA_SATA_IOCTL && errno == EBUSY) {
2079 rv = CFGA_SATA_BUSY;
2080 }
2081
2082 return (rv);
2083 }
2084
2085
2086 static int
2087 sata_confirm(struct cfga_confirm *confp, char *msg)
2088 {
2089 int rval;
2090
2091 if (confp == NULL || confp->confirm == NULL) {
2092 return (0);
2093 }
2094 rval = (*confp->confirm)(confp->appdata_ptr, msg);
2095
2096 return (rval);
2097 }
2098
2099
2100 static char *
2101 sata_get_devicepath(const char *ap_id)
2102 {
2103 char *devpath = NULL;
2104 size_t size;
2105 cfga_sata_ret_t rv;
2106
2107 rv = do_control_ioctl(ap_id, SATA_CFGA_GET_DEVICE_PATH, NULL,
2108 (void **)&devpath, &size);
2109
2110 if (rv == CFGA_SATA_OK) {
2111 return (devpath);
2112 } else {
2113 return ((char *)NULL);
2114 }
2115
2116 }