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