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