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 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 27 #include "cfga_fp.h" 28 #include <sys/fibre-channel/impl/fc_error.h> 29 30 /* Structure for walking the tree */ 31 typedef struct { 32 apid_t *apidp; 33 char *xport_logp; 34 ldata_list_t *listp; 35 fpcfga_cmd_t cmd; 36 cfga_stat_t chld_config; 37 cfga_type_t xport_type; 38 cfga_stat_t xport_rstate; 39 fpcfga_ret_t ret; 40 int l_errno; 41 } fpcfga_list_t; 42 43 typedef struct { 44 uint_t itype; 45 const char *ntype; 46 const char *name; 47 } fpcfga_devtype_t; 48 49 #define ERR_INQ_DTYPE 0xff 50 51 /* The TYPE field is parseable and should not contain spaces */ 52 #define FP_FC_PORT_TYPE "fc" 53 #define FP_FC_PORT_ERROR "fc-error" 54 #define FP_FC_FABRIC_PORT_TYPE "fc-fabric" 55 #define FP_FC_PUBLIC_PORT_TYPE "fc-public" 56 #define FP_FC_PRIVATE_PORT_TYPE "fc-private" 57 #define FP_FC_PT_TO_PT_PORT_TYPE "fc-pt_to_pt" 58 59 /* Indicates no plag passing */ 60 #define NO_FLAG 0 61 62 /* defines for retry algorithm */ 63 #define OPEN_RETRY_COUNT 5 64 #define OPEN_RETRY_INTERVAL 10000 /* 1/100 of a sec. */ 65 #define IOCTL_RETRY_COUNT 5 66 #define IOCTL_RETRY_INTERVAL 5000000 /* 5 sec */ 67 68 /* define for fcp scsi passthru wait */ 69 #define FCP_SCSI_CMD_TIMEOUT 10 70 71 /* define for fcp pseudo node */ 72 #define FCP_PATH "/devices/pseudo/fcp@0:fcp" 73 74 /* Function prototypes */ 75 static fpcfga_ret_t postprocess_list_data(const ldata_list_t *listp, 76 fpcfga_cmd_t cmd, cfga_stat_t chld_config, int *np, uint_t flags); 77 static int stat_fc_dev(di_node_t node, void *arg); 78 static int stat_FCP_dev(di_node_t node, void *arg); 79 static fpcfga_ret_t do_stat_fca_xport(fpcfga_list_t *lap, int limited_stat, 80 HBA_PORTATTRIBUTES portAttrs); 81 static int get_xport_state(di_node_t node, void *arg); 82 83 static fpcfga_ret_t do_stat_fc_dev(const di_node_t node, const char *nodepath, 84 fpcfga_list_t *lap, int limited_stat); 85 static fpcfga_ret_t do_stat_FCP_dev(const di_node_t node, const char *nodepath, 86 fpcfga_list_t *lap, int limited_stat); 87 static cfga_stat_t xport_devinfo_to_recep_state(uint_t xport_di_state); 88 static cfga_stat_t dev_devinfo_to_occupant_state(uint_t dev_di_state); 89 static void get_hw_info(di_node_t node, cfga_list_data_t *clp); 90 static const char *get_device_type(di_node_t); 91 static fpcfga_ret_t init_ldata_for_accessible_dev(const char *dyncomp, 92 uchar_t inq_type, fpcfga_list_t *lap); 93 static fpcfga_ret_t init_ldata_for_accessible_FCP_dev(const char *port_wwn, 94 int num_luns, struct report_lun_resp *resp_buf, 95 fpcfga_list_t *larg, int *l_errnop); 96 static fpcfga_ret_t is_dyn_ap_on_ldata_list(const char *port_wwn, 97 const ldata_list_t *listp, ldata_list_t **matchldpp, int *l_errno); 98 static fpcfga_ret_t is_FCP_dev_ap_on_ldata_list(const char *port_wwn, 99 const int lun_num, ldata_list_t *ldatap, ldata_list_t **matchldpp); 100 101 static fpcfga_ret_t init_ldata_for_mpath_dev(di_path_t path, char *port_wwn, 102 int *l_errnop, fpcfga_list_t *lap); 103 static fpcfga_ret_t insert_ldata_to_ldatalist(const char *port_wwn, 104 int *lun_nump, ldata_list_t *listp, ldata_list_t **ldatapp); 105 static fpcfga_ret_t insert_fc_dev_ldata(const char *port_wwn, 106 ldata_list_t *listp, ldata_list_t **ldatapp); 107 static fpcfga_ret_t insert_FCP_dev_ldata(const char *port_wwn, int lun_num, 108 ldata_list_t *listp, ldata_list_t **ldatapp); 109 static int stat_path_info_fc_dev(di_node_t root, fpcfga_list_t *lap, 110 int *l_errnop); 111 static int stat_path_info_FCP_dev(di_node_t root, fpcfga_list_t *lap, 112 int *l_errnop); 113 static fpcfga_ret_t get_accessible_FCP_dev_ldata(const char *dyncomp, 114 fpcfga_list_t *lap, int *l_errnop); 115 static fpcfga_ret_t get_standard_inq_data(const char *xport_phys, 116 const char *dyncomp, uchar_t *lun_num, struct scsi_inquiry **inq_buf, 117 int *l_errnop); 118 static void init_fcp_scsi_cmd(struct fcp_scsi_cmd *fscsi, uchar_t *lun_num, 119 la_wwn_t *pwwn, void *scmdbuf, size_t scmdbuf_len, void *respbuf, 120 size_t respbuf_len, void *sensebuf, size_t sensebuf_len); 121 static fpcfga_ret_t issue_fcp_scsi_cmd(const char *xport_phys, 122 struct fcp_scsi_cmd *fscsi, int *l_errnop); 123 static uchar_t get_inq_dtype(char *xport_phys, char *dyncomp, HBA_HANDLE handle, 124 HBA_PORTATTRIBUTES *portAttrs, HBA_PORTATTRIBUTES *discPortAttrs); 125 126 static fpcfga_devtype_t device_list[] = { 127 { DTYPE_DIRECT, DDI_NT_BLOCK_CHAN, "disk"}, 128 { DTYPE_DIRECT, DDI_NT_BLOCK, "disk"}, 129 { DTYPE_DIRECT, DDI_NT_BLOCK_WWN, "disk"}, 130 { DTYPE_DIRECT, DDI_NT_BLOCK_FABRIC, "disk"}, 131 { DTYPE_SEQUENTIAL, DDI_NT_TAPE, "tape"}, 132 { DTYPE_PRINTER, NULL, "printer"}, 133 { DTYPE_PROCESSOR, NULL, "processor"}, 134 { DTYPE_WORM, NULL, "WORM"}, 135 { DTYPE_RODIRECT, DDI_NT_CD_CHAN, "CD-ROM"}, 136 { DTYPE_RODIRECT, DDI_NT_CD, "CD-ROM"}, 137 { DTYPE_SCANNER, NULL, "scanner"}, 138 { DTYPE_OPTICAL, NULL, "optical"}, 139 { DTYPE_CHANGER, NULL, "med-changer"}, 140 { DTYPE_COMM, NULL, "comm-device"}, 141 { DTYPE_ARRAY_CTRL, NULL, "array-ctrl"}, 142 { DTYPE_ESI, NULL, "ESI"}, 143 /* 144 * This has to be the LAST entry for DTYPE_UNKNOWN_INDEX. 145 * Add entries before this. 146 */ 147 { DTYPE_UNKNOWN, NULL, "unknown"} 148 }; 149 150 #define N_DEVICE_TYPES (sizeof (device_list) / sizeof (device_list[0])) 151 152 #define DTYPE_UNKNOWN_INDEX (N_DEVICE_TYPES - 1) 153 154 /* 155 * Main routine for list operation. 156 * It calls various routines to consturct ldata list and 157 * postprocess the list data. 158 * 159 * Overall algorithm: 160 * Get the device list on input hba port and construct ldata list for 161 * accesible devices. 162 * Stat hba port and devices through walking the device tree. 163 * Verify the validity of the list data. 164 */ 165 fpcfga_ret_t 166 do_list( 167 apid_t *apidp, 168 fpcfga_cmd_t cmd, 169 ldata_list_t **llpp, 170 int *nelemp, 171 char **errstring) 172 { 173 int n = -1, l_errno = 0, limited_stat; 174 walkarg_t walkarg; 175 fpcfga_list_t larg = {NULL}; 176 fpcfga_ret_t ret; 177 la_wwn_t pwwn; 178 char *dyncomp = NULL; 179 HBA_HANDLE handle; 180 HBA_PORTATTRIBUTES portAttrs; 181 HBA_PORTATTRIBUTES discPortAttrs; 182 HBA_STATUS status; 183 int portIndex, discIndex; 184 int retry; 185 uchar_t inq_dtype; 186 187 if (*llpp != NULL || *nelemp != 0) { 188 return (FPCFGA_ERR); 189 } 190 191 /* Create the hba logid (also base component of logical ap_id) */ 192 ret = make_xport_logid(apidp->xport_phys, &larg.xport_logp, &l_errno); 193 if (ret != FPCFGA_OK) { 194 cfga_err(errstring, l_errno, ERR_LIST, 0); 195 return (FPCFGA_ERR); 196 } 197 198 assert(larg.xport_logp != NULL); 199 200 larg.cmd = cmd; 201 larg.apidp = apidp; 202 larg.xport_rstate = CFGA_STAT_NONE; 203 204 if ((ret = findMatchingAdapterPort(larg.apidp->xport_phys, &handle, 205 &portIndex, &portAttrs, errstring)) != FPCFGA_OK) { 206 S_FREE(larg.xport_logp); 207 return (ret); 208 } 209 210 /* 211 * If stating a specific device, we will do limited stat on fca port. 212 * otherwise full stat on fca part is required. 213 * If stating a specific device we don't know if it exists or is 214 * configured yet. larg.ret is set to apid noexist for do_stat_dev. 215 * otherwise larg.ret is set to ok initially. 216 */ 217 if (larg.cmd == FPCFGA_STAT_FC_DEV) { 218 limited_stat = 1; /* for do_stat_fca_xport */ 219 larg.ret = FPCFGA_APID_NOEXIST; /* for stat_fc_dev */ 220 } else { 221 limited_stat = 0; /* for do_stat_fca_xport */ 222 larg.ret = FPCFGA_OK; /* for stat_fc_dev */ 223 } 224 225 /* For all list commands, the fca port needs to be stat'ed */ 226 if ((ret = do_stat_fca_xport(&larg, limited_stat, 227 portAttrs)) != FPCFGA_OK) { 228 cfga_err(errstring, larg.l_errno, ERR_LIST, 0); 229 list_free(&larg.listp); 230 S_FREE(larg.xport_logp); 231 HBA_CloseAdapter(handle); 232 HBA_FreeLibrary(); 233 return (ret); 234 } 235 236 #ifdef DEBUG 237 if (limited_stat) { 238 assert(larg.listp == NULL); 239 } else { 240 assert(larg.listp != NULL); 241 } 242 #endif 243 /* 244 * If stat'ing a FCA port or ALL, we have the bus stat data at 245 * this point. 246 * Assume that the bus has no configured children. 247 */ 248 larg.chld_config = CFGA_STAT_UNCONFIGURED; 249 250 switch (larg.cmd) { 251 case FPCFGA_STAT_FC_DEV: 252 /* la_wwn_t has uchar_t raw_wwn[8] thus no need to free. */ 253 if (cvt_dyncomp_to_lawwn(apidp->dyncomp, &pwwn) != 0) { 254 cfga_err(errstring, 0, ERR_LIST, 0); 255 list_free(&larg.listp); 256 S_FREE(larg.xport_logp); 257 HBA_CloseAdapter(handle); 258 HBA_FreeLibrary(); 259 return (FPCFGA_LIB_ERR); 260 } 261 /* 262 * if the dyncomp exists on disco ports construct list_data 263 * otherwise return FPCFGA_APID_NOEXIST. 264 */ 265 retry = 0; 266 do { 267 status = getPortAttrsByWWN(handle, 268 *((HBA_WWN *)(&pwwn)), &discPortAttrs); 269 if (status == HBA_STATUS_ERROR_STALE_DATA) { 270 /* get Port Attributes again after refresh. */ 271 HBA_RefreshInformation(handle); 272 } else { 273 break; /* either okay or some other error */ 274 } 275 } while (retry++ < HBA_MAX_RETRIES); 276 277 if (status == HBA_STATUS_OK) { 278 /* 279 * if dyncomp found in disco ports 280 * construct ldata_list and return. 281 * otherwise continue to stat on dev tree with 282 * larg.ret set to access_ok which informs stat_fc_dev 283 * the existence of device on disco ports. 284 * 285 * if path is null that guatantees the node is not 286 * configured. if node is detached the path 287 * is incomplete and not usable for further 288 * operations like uscsi_inq so take care of it here. 289 */ 290 inq_dtype = get_inq_dtype(apidp->xport_phys, 291 apidp->dyncomp, handle, &portAttrs, &discPortAttrs); 292 293 if (init_ldata_for_accessible_dev(apidp->dyncomp, 294 inq_dtype, &larg) != FPCFGA_OK) { 295 cfga_err(errstring, larg.l_errno, 296 ERR_LIST, 0); 297 list_free(&larg.listp); 298 S_FREE(larg.xport_logp); 299 HBA_CloseAdapter(handle); 300 HBA_FreeLibrary(); 301 return (FPCFGA_LIB_ERR); 302 } 303 if (apidp->lunlist == NULL) { 304 n = 0; 305 if (postprocess_list_data( 306 larg.listp, cmd, 307 larg.chld_config, &n, NO_FLAG) != 308 FPCFGA_OK) { 309 cfga_err(errstring, 310 larg.l_errno, ERR_LIST, 0); 311 list_free(&larg.listp); 312 S_FREE(larg.xport_logp); 313 HBA_CloseAdapter(handle); 314 HBA_FreeLibrary(); 315 return (FPCFGA_LIB_ERR); 316 } 317 *nelemp = n; 318 *llpp = larg.listp; 319 S_FREE(larg.xport_logp); 320 HBA_CloseAdapter(handle); 321 HBA_FreeLibrary(); 322 return (FPCFGA_OK); 323 } 324 larg.ret = FPCFGA_ACCESS_OK; 325 } else if (status == HBA_STATUS_ERROR_ILLEGAL_WWN) { 326 /* 327 * path indicates if the node exists in dev tree. 328 * if not found in dev tree return apid no exist. 329 * otherwise continue to stat with larg.ret set to 330 * apid_noexist. 331 */ 332 if (apidp->lunlist == NULL) { 333 list_free(&larg.listp); 334 S_FREE(larg.xport_logp); 335 HBA_CloseAdapter(handle); 336 HBA_FreeLibrary(); 337 return (FPCFGA_APID_NOEXIST); 338 } 339 } else { /* any error */ 340 /* 341 * path indicates if the node exists in dev tree. 342 * if not found in dev tree return lib error. 343 * otherwise continue to stat with larg.ret set to 344 * apid_noexist. 345 */ 346 if (apidp->lunlist == NULL) { 347 cfga_err(errstring, 0, ERR_FC_GET_DEVLIST, 0); 348 list_free(&larg.listp); 349 S_FREE(larg.xport_logp); 350 HBA_CloseAdapter(handle); 351 HBA_FreeLibrary(); 352 return (FPCFGA_LIB_ERR); 353 } 354 } 355 break; 356 case FPCFGA_STAT_ALL: 357 /* 358 * for each dev in disco ports, create a ldata_list element. 359 * if if no disco ports found, continue to stat on devinfo tree 360 * to see if any node exist on the fca port. 361 */ 362 for (discIndex = 0; 363 discIndex < portAttrs.NumberofDiscoveredPorts; 364 discIndex++) { 365 if (getDiscPortAttrs(handle, portIndex, 366 discIndex, &discPortAttrs)) { 367 /* Move on to the next target */ 368 continue; 369 } 370 memcpy(&pwwn, &discPortAttrs.PortWWN, sizeof (la_wwn_t)); 371 cvt_lawwn_to_dyncomp(&pwwn, &dyncomp, &l_errno); 372 if (dyncomp == NULL) { 373 cfga_err(errstring, l_errno, ERR_LIST, 0); 374 list_free(&larg.listp); 375 S_FREE(larg.xport_logp); 376 HBA_CloseAdapter(handle); 377 HBA_FreeLibrary(); 378 return (FPCFGA_LIB_ERR); 379 } 380 inq_dtype = get_inq_dtype(apidp->xport_phys, dyncomp, 381 handle, &portAttrs, &discPortAttrs); 382 383 if ((ret = init_ldata_for_accessible_dev( 384 dyncomp, inq_dtype, &larg)) != FPCFGA_OK) { 385 S_FREE(dyncomp); 386 cfga_err(errstring, larg.l_errno, ERR_LIST, 0); 387 list_free(&larg.listp); 388 S_FREE(larg.xport_logp); 389 HBA_CloseAdapter(handle); 390 HBA_FreeLibrary(); 391 return (FPCFGA_LIB_ERR); 392 } 393 S_FREE(dyncomp); 394 } 395 break; 396 default: 397 break; 398 } 399 400 /* we need to stat at least 1 device for all commands */ 401 if (apidp->flags == FLAG_DEVINFO_FORCE) { 402 walkarg.flags = FLAG_DEVINFO_FORCE; 403 } else { 404 walkarg.flags = 0; 405 } 406 407 walkarg.flags |= FLAG_PATH_INFO_WALK; 408 walkarg.walkmode.node_args.flags = DI_WALK_CLDFIRST; 409 walkarg.walkmode.node_args.fcn = stat_fc_dev; 410 411 /* 412 * Subtree is ALWAYS rooted at the HBA (not at the device) as 413 * otherwise deadlock may occur if bus is disconnected. 414 * 415 * DINFOPROP was sufficient on apidp->xport_phys prior to the support 416 * on scsi_vhci child node. In order to get the link between 417 * scsi_vhci node and path info node the snap shot of the 418 * the whole device tree is required with DINFOCPYALL | DINFOPATH flag. 419 */ 420 ret = walk_tree(apidp->xport_phys, &larg, DINFOCPYALL | DINFOPATH, 421 &walkarg, FPCFGA_WALK_NODE, &larg.l_errno); 422 423 /* 424 * ret from walk_tree is either FPCFGA_OK or FPCFGA_ERR. 425 * larg.ret is used to detect other errors. Make sure larg.ret 426 * is set to a correct error. 427 */ 428 if (ret != FPCFGA_OK || (ret = larg.ret) != FPCFGA_OK) { 429 if (ret != FPCFGA_APID_NOEXIST) { 430 cfga_err(errstring, larg.l_errno, ERR_LIST, 0); 431 } 432 /* if larg.ret = FPCFGA_APID_NOEXIST; */ 433 goto out; 434 } 435 436 assert(larg.listp != NULL); 437 438 n = 0; 439 ret = postprocess_list_data(larg.listp, cmd, larg.chld_config, &n, 440 NO_FLAG); 441 if (ret != FPCFGA_OK) { 442 cfga_err(errstring, 0, ERR_LIST, 0); 443 ret = FPCFGA_LIB_ERR; 444 goto out; 445 } 446 447 *nelemp = n; 448 *llpp = larg.listp; 449 ret = FPCFGA_OK; 450 /* FALLTHROUGH */ 451 out: 452 if (ret != FPCFGA_OK) list_free(&larg.listp); 453 S_FREE(larg.xport_logp); 454 HBA_CloseAdapter(handle); 455 HBA_FreeLibrary(); 456 return (ret); 457 } 458 459 /* 460 * Main routine for list operation when show_FCP_dev option is given. 461 * It calls various routines to consturct ldata list and 462 * postprocess the list data. 463 * 464 * The difference between do_list() and do_list_FCP_dev() is to 465 * process FCP SCSI LUN data list via uscsi report lun operation and 466 * stat lun level instead of port WWN based target level. 467 * The rest of logic is same. 468 * 469 * Overall algorithm: 470 * Get the device list on input hba port and construct ldata list for 471 * accesible devices. 472 * For each configured device, USCSI report lun is issued and ldata list 473 * with FCP device level(LUN) information is created. 474 * Stat hba port and LUN devices through walking the device tree. 475 * Verify the validity of the list data. 476 */ 477 fpcfga_ret_t 478 do_list_FCP_dev( 479 const char *ap_id, 480 uint_t flags, 481 fpcfga_cmd_t cmd, 482 ldata_list_t **llpp, 483 int *nelemp, 484 char **errstring) 485 { 486 int n = -1, l_errno = 0, limited_stat, len; 487 walkarg_t walkarg; 488 fpcfga_list_t larg = {NULL}; 489 fpcfga_ret_t ret; 490 la_wwn_t pwwn; 491 char *xport_phys = NULL, *dyn = NULL, *dyncomp = NULL, 492 *lun_dyn = NULL; 493 apid_t apid_con = {NULL}; 494 HBA_HANDLE handle; 495 HBA_PORTATTRIBUTES portAttrs; 496 HBA_PORTATTRIBUTES discPortAttrs; 497 HBA_STATUS status; 498 int portIndex, discIndex; 499 int retry; 500 uint64_t lun = 0; 501 struct scsi_inquiry inq; 502 struct scsi_extended_sense sense; 503 HBA_UINT8 scsiStatus; 504 uint32_t inquirySize = sizeof (inq), 505 senseSize = sizeof (sense); 506 507 if (*llpp != NULL || *nelemp != 0) { 508 return (FPCFGA_ERR); 509 } 510 511 if ((xport_phys = pathdup(ap_id, &l_errno)) == NULL) { 512 cfga_err(errstring, l_errno, ERR_OP_FAILED, 0); 513 return (FPCFGA_LIB_ERR); 514 } 515 516 /* Extract the base(hba) and dynamic(device) component if any */ 517 if ((dyn = GET_DYN(xport_phys)) != NULL) { 518 len = strlen(DYN_TO_DYNCOMP(dyn)) + 1; 519 dyncomp = calloc(1, len); 520 if (dyncomp == NULL) { 521 cfga_err(errstring, errno, ERR_OP_FAILED, 0); 522 S_FREE(xport_phys); 523 return (FPCFGA_LIB_ERR); 524 } 525 526 (void) strcpy(dyncomp, DYN_TO_DYNCOMP(dyn)); 527 /* Remove the dynamic component from the base. */ 528 *dyn = '\0'; 529 /* if lun dyncomp exists delete it */ 530 if ((lun_dyn = GET_LUN_DYN(dyncomp)) != NULL) { 531 *lun_dyn = '\0'; 532 } 533 } 534 535 apid_con.xport_phys = xport_phys; 536 apid_con.dyncomp = dyncomp; 537 apid_con.flags = flags; 538 539 larg.apidp = &apid_con; 540 541 /* Create the hba logid (also base component of logical ap_id) */ 542 ret = make_xport_logid(larg.apidp->xport_phys, &larg.xport_logp, 543 &l_errno); 544 if (ret != FPCFGA_OK) { 545 cfga_err(errstring, l_errno, ERR_LIST, 0); 546 S_FREE(larg.apidp->xport_phys); 547 S_FREE(larg.apidp->dyncomp); 548 return (FPCFGA_ERR); 549 } 550 551 assert(larg.xport_logp != NULL); 552 553 larg.cmd = cmd; 554 larg.xport_rstate = CFGA_STAT_NONE; 555 556 if ((ret = findMatchingAdapterPort(larg.apidp->xport_phys, &handle, 557 &portIndex, &portAttrs, errstring)) != FPCFGA_OK) { 558 S_FREE(larg.xport_logp); 559 S_FREE(larg.apidp->dyncomp); 560 return (ret); 561 } 562 563 /* 564 * If stating a specific device, we will do limited stat on fca port. 565 * otherwise full stat on fca part is required. 566 * If stating a specific device we don't know if it exists or is 567 * configured yet. larg.ret is set to apid noexist for do_stat_dev. 568 * otherwise larg.ret is set to ok initially. 569 */ 570 if (larg.cmd == FPCFGA_STAT_FC_DEV) { 571 limited_stat = 1; /* for do_stat_fca_xport */ 572 larg.ret = FPCFGA_APID_NOEXIST; /* for stat_fc_dev */ 573 } else { 574 limited_stat = 0; /* for do_stat_fca_xport */ 575 larg.ret = FPCFGA_OK; /* for stat_fc_dev */ 576 } 577 578 /* For all list commands, the fca port needs to be stat'ed */ 579 if ((ret = do_stat_fca_xport(&larg, limited_stat, 580 portAttrs)) != FPCFGA_OK) { 581 cfga_err(errstring, larg.l_errno, ERR_LIST, 0); 582 list_free(&larg.listp); 583 S_FREE(larg.xport_logp); 584 S_FREE(larg.apidp->xport_phys); 585 S_FREE(larg.apidp->dyncomp); 586 HBA_CloseAdapter(handle); 587 HBA_FreeLibrary(); 588 return (ret); 589 } 590 591 /* 592 * If stat'ing a FCA port or ALL, we have the bus stat data at 593 * this point. 594 * Assume that the bus has no configured children. 595 */ 596 larg.chld_config = CFGA_STAT_UNCONFIGURED; 597 598 switch (larg.cmd) { 599 case FPCFGA_STAT_FC_DEV: 600 /* la_wwn_t has uchar_t raw_wwn[8] thus no need to free. */ 601 if (cvt_dyncomp_to_lawwn(larg.apidp->dyncomp, &pwwn) != 0) { 602 cfga_err(errstring, 0, ERR_LIST, 0); 603 list_free(&larg.listp); 604 S_FREE(larg.xport_logp); 605 S_FREE(larg.apidp->xport_phys); 606 S_FREE(larg.apidp->dyncomp); 607 HBA_CloseAdapter(handle); 608 HBA_FreeLibrary(); 609 return (FPCFGA_LIB_ERR); 610 } 611 /* 612 * if the dyncomp exists on disco ports construct list_data 613 * otherwise return FPCFGA_APID_NOEXIST. 614 */ 615 retry = 0; 616 do { 617 status = getPortAttrsByWWN(handle, 618 *((HBA_WWN *)(&pwwn)), &discPortAttrs); 619 if (status == HBA_STATUS_ERROR_STALE_DATA) { 620 /* get Port Attributes again after refresh. */ 621 HBA_RefreshInformation(handle); 622 } else { 623 break; /* either okay or some other error */ 624 } 625 } while (retry++ < HBA_MAX_RETRIES); 626 627 if (status == HBA_STATUS_OK) { 628 /* 629 * if dyncomp exists only in dev list 630 * construct ldata_list and return. 631 * otherwise continue to stat on dev tree with 632 * larg.ret set to access_ok which informs stat_fc_dev 633 * the existence of device on dev_list. 634 * 635 * if path is null that guatantees the node is not 636 * configured. if node is detached the path 637 * is incomplete and not usable for further 638 * operations like uscsi_inq so take care of it here. 639 */ 640 status = HBA_ScsiInquiryV2(handle, portAttrs.PortWWN, 641 discPortAttrs.PortWWN, lun, 0, 0, 642 &inq, &inquirySize, &scsiStatus, 643 &sense, &senseSize); 644 if (status == HBA_STATUS_OK) { 645 inq.inq_dtype = inq.inq_dtype & DTYPE_MASK; 646 } else if (status == HBA_STATUS_ERROR_NOT_A_TARGET) { 647 inq.inq_dtype = DTYPE_UNKNOWN; 648 } else { 649 inq.inq_dtype = ERR_INQ_DTYPE; 650 } 651 652 if (init_ldata_for_accessible_dev(larg.apidp->dyncomp, 653 inq.inq_dtype, &larg) != FPCFGA_OK) { 654 cfga_err(errstring, larg.l_errno, 655 ERR_LIST, 0); 656 list_free(&larg.listp); 657 S_FREE(larg.xport_logp); 658 S_FREE(larg.apidp->xport_phys); 659 S_FREE(larg.apidp->dyncomp); 660 HBA_CloseAdapter(handle); 661 HBA_FreeLibrary(); 662 return (FPCFGA_LIB_ERR); 663 } 664 if ((ret = get_accessible_FCP_dev_ldata( 665 larg.apidp->dyncomp, &larg, &l_errno)) 666 != FPCFGA_OK) { 667 cfga_err(errstring, larg.l_errno, ERR_LIST, 0); 668 list_free(&larg.listp); 669 S_FREE(larg.xport_logp); 670 S_FREE(larg.apidp->xport_phys); 671 S_FREE(larg.apidp->dyncomp); 672 HBA_CloseAdapter(handle); 673 HBA_FreeLibrary(); 674 return (FPCFGA_LIB_ERR); 675 } else { 676 /* continue to stat dev with access okay. */ 677 larg.ret = FPCFGA_ACCESS_OK; 678 } 679 } else if (status == HBA_STATUS_ERROR_ILLEGAL_WWN) { 680 /* 681 * path indicates if the node exists in dev tree. 682 * if not found in dev tree return apid no exist. 683 * otherwise continue to stat with larg.ret set to 684 * apid_noexist. 685 */ 686 if (larg.apidp->lunlist == NULL) { 687 list_free(&larg.listp); 688 S_FREE(larg.xport_logp); 689 HBA_CloseAdapter(handle); 690 HBA_FreeLibrary(); 691 return (FPCFGA_APID_NOEXIST); 692 } 693 } else { /* not found or any error */ 694 /* 695 * continue to stat dev with larg.ret set to 696 * apid_noexist. 697 */ 698 larg.ret = FPCFGA_APID_NOEXIST; 699 } 700 break; 701 case FPCFGA_STAT_ALL: 702 /* 703 * for each dev in disco ports, create a ldata_list element. 704 * if if no disco ports found, continue to stat on devinfo tree 705 * to see if any node exist on the fca port. 706 */ 707 for (discIndex = 0; 708 discIndex < portAttrs.NumberofDiscoveredPorts; 709 discIndex++) { 710 if (getDiscPortAttrs(handle, portIndex, 711 discIndex, &discPortAttrs)) { 712 /* Move on to the next target */ 713 continue; 714 } 715 memcpy(&pwwn, &discPortAttrs.PortWWN, sizeof (la_wwn_t)); 716 cvt_lawwn_to_dyncomp(&pwwn, &dyncomp, &l_errno); 717 if (dyncomp == NULL) { 718 cfga_err(errstring, l_errno, ERR_LIST, 0); 719 list_free(&larg.listp); 720 S_FREE(larg.xport_logp); 721 S_FREE(larg.apidp->xport_phys); 722 S_FREE(larg.apidp->dyncomp); 723 HBA_CloseAdapter(handle); 724 HBA_FreeLibrary(); 725 return (FPCFGA_LIB_ERR); 726 } 727 status = HBA_ScsiInquiryV2(handle, portAttrs.PortWWN, 728 discPortAttrs.PortWWN, lun, 0, 0, 729 &inq, &inquirySize, &scsiStatus, 730 &sense, &senseSize); 731 if (status == HBA_STATUS_OK) { 732 inq.inq_dtype = inq.inq_dtype & DTYPE_MASK; 733 } else if (status == HBA_STATUS_ERROR_NOT_A_TARGET) { 734 inq.inq_dtype = DTYPE_UNKNOWN; 735 } else { 736 inq.inq_dtype = ERR_INQ_DTYPE; 737 } 738 if ((ret = init_ldata_for_accessible_dev( 739 dyncomp, inq.inq_dtype, &larg)) != FPCFGA_OK) { 740 S_FREE(dyncomp); 741 cfga_err(errstring, larg.l_errno, ERR_LIST, 0); 742 list_free(&larg.listp); 743 S_FREE(larg.xport_logp); 744 S_FREE(larg.apidp->xport_phys); 745 S_FREE(larg.apidp->dyncomp); 746 HBA_CloseAdapter(handle); 747 HBA_FreeLibrary(); 748 return (FPCFGA_LIB_ERR); 749 } 750 if ((ret = get_accessible_FCP_dev_ldata( 751 dyncomp, &larg, &l_errno)) != FPCFGA_OK) { 752 S_FREE(dyncomp); 753 cfga_err(errstring, larg.l_errno, ERR_LIST, 0); 754 list_free(&larg.listp); 755 S_FREE(larg.xport_logp); 756 S_FREE(larg.apidp->xport_phys); 757 S_FREE(larg.apidp->dyncomp); 758 HBA_CloseAdapter(handle); 759 HBA_FreeLibrary(); 760 return (ret); 761 } 762 S_FREE(dyncomp); 763 } 764 break; 765 /* default: continue */ 766 } 767 768 /* we need to stat at least 1 device for all commands */ 769 if ((larg.apidp->flags & FLAG_DEVINFO_FORCE) == FLAG_DEVINFO_FORCE) { 770 walkarg.flags = FLAG_DEVINFO_FORCE; 771 } else { 772 walkarg.flags = 0; 773 } 774 775 walkarg.flags |= FLAG_PATH_INFO_WALK; 776 walkarg.walkmode.node_args.flags = DI_WALK_CLDFIRST; 777 walkarg.walkmode.node_args.fcn = stat_FCP_dev; 778 779 /* 780 * Subtree is ALWAYS rooted at the HBA (not at the device) as 781 * otherwise deadlock may occur if bus is disconnected. 782 * 783 * DINFOPROP was sufficient on apidp->xport_phys prior to the support 784 * on scsi_vhci child node. In order to get the link between 785 * scsi_vhci node and path info node the snap shot of the 786 * the whole device tree is required with DINFOCPYALL | DINFOPATH flag. 787 */ 788 ret = walk_tree(larg.apidp->xport_phys, &larg, DINFOCPYALL | DINFOPATH, 789 &walkarg, FPCFGA_WALK_NODE, &larg.l_errno); 790 791 /* 792 * ret from walk_tree is either FPCFGA_OK or FPCFGA_ERR. 793 * larg.ret is used to detect other errors. Make sure larg.ret 794 * is set to a correct error. 795 */ 796 if (ret != FPCFGA_OK || (ret = larg.ret) != FPCFGA_OK) { 797 if (ret != FPCFGA_APID_NOEXIST) { 798 cfga_err(errstring, larg.l_errno, ERR_LIST, 0); 799 } 800 /* if larg.ret = FPCFGA_APID_NOEXIST return. */ 801 list_free(&larg.listp); 802 S_FREE(larg.xport_logp); 803 S_FREE(larg.apidp->xport_phys); 804 S_FREE(larg.apidp->dyncomp); 805 HBA_CloseAdapter(handle); 806 HBA_FreeLibrary(); 807 return (ret); 808 } 809 810 assert(larg.listp != NULL); 811 812 n = 0; 813 ret = postprocess_list_data(larg.listp, cmd, larg.chld_config, &n, 814 flags); 815 if (ret != FPCFGA_OK) { 816 cfga_err(errstring, 0, ERR_LIST, 0); 817 list_free(&larg.listp); 818 S_FREE(larg.xport_logp); 819 S_FREE(larg.apidp->xport_phys); 820 S_FREE(larg.apidp->dyncomp); 821 HBA_CloseAdapter(handle); 822 HBA_FreeLibrary(); 823 return (FPCFGA_LIB_ERR); 824 } 825 826 *nelemp = n; 827 *llpp = larg.listp; 828 ret = FPCFGA_OK; 829 S_FREE(larg.xport_logp); 830 S_FREE(larg.apidp->xport_phys); 831 S_FREE(larg.apidp->dyncomp); 832 HBA_CloseAdapter(handle); 833 HBA_FreeLibrary(); 834 return (FPCFGA_OK); 835 } 836 837 /* 838 * This routine returns initialize struct fcp_ioctl. 839 */ 840 static void 841 init_fcp_scsi_cmd( 842 struct fcp_scsi_cmd *fscsi, 843 uchar_t *lun_num, 844 la_wwn_t *pwwn, 845 void *scmdbuf, 846 size_t scmdbuf_len, 847 void *respbuf, 848 size_t respbuf_len, 849 void *sensebuf, 850 size_t sensebuf_len) 851 { 852 memset(fscsi, 0, sizeof (struct fcp_scsi_cmd)); 853 memset(scmdbuf, 0, scmdbuf_len); 854 memcpy(fscsi->scsi_fc_pwwn.raw_wwn, pwwn, sizeof (u_longlong_t)); 855 fscsi->scsi_fc_rspcode = 0; 856 fscsi->scsi_flags = FCP_SCSI_READ; 857 fscsi->scsi_timeout = FCP_SCSI_CMD_TIMEOUT; /* second */ 858 fscsi->scsi_cdbbufaddr = (caddr_t)scmdbuf; 859 fscsi->scsi_cdblen = scmdbuf_len; 860 fscsi->scsi_bufaddr = (caddr_t)respbuf; 861 fscsi->scsi_buflen = respbuf_len; 862 fscsi->scsi_bufresid = 0; 863 fscsi->scsi_bufstatus = 0; 864 fscsi->scsi_rqbufaddr = (caddr_t)sensebuf; 865 fscsi->scsi_rqlen = sensebuf_len; 866 fscsi->scsi_rqresid = 0; 867 memcpy(&fscsi->scsi_lun, lun_num, sizeof (fscsi->scsi_lun)); 868 } 869 870 /* 871 * This routine returns issues FCP_TGT_SEND_SCSI 872 */ 873 static fpcfga_ret_t 874 issue_fcp_scsi_cmd( 875 const char *xport_phys, 876 struct fcp_scsi_cmd *fscsi, 877 int *l_errnop) 878 { 879 struct stat stbuf; 880 int fcp_fd, retry, rv; 881 882 if (stat(xport_phys, &stbuf) < 0) { 883 *l_errnop = errno; 884 return (FPCFGA_LIB_ERR); 885 } 886 887 fscsi->scsi_fc_port_num = (uint32_t)minor(stbuf.st_rdev); 888 fcp_fd = open(FCP_PATH, O_RDONLY | O_NDELAY); 889 retry = 0; 890 while (fcp_fd < 0 && retry++ < OPEN_RETRY_COUNT && ( 891 errno == EBUSY || errno == EAGAIN)) { 892 (void) usleep(OPEN_RETRY_INTERVAL); 893 fcp_fd = open(FCP_PATH, O_RDONLY|O_NDELAY); 894 } 895 if (fcp_fd < 0) { 896 *l_errnop = errno; 897 return (FPCFGA_LIB_ERR); 898 } 899 900 rv = ioctl(fcp_fd, FCP_TGT_SEND_SCSI, fscsi); 901 retry = 0; 902 while ((rv != 0 && retry++ < IOCTL_RETRY_COUNT && 903 (errno == EBUSY || errno == EAGAIN)) || 904 (retry++ < IOCTL_RETRY_COUNT && 905 ((uchar_t)fscsi->scsi_bufstatus & STATUS_MASK) 906 == STATUS_BUSY)) { 907 (void) usleep(IOCTL_RETRY_INTERVAL); 908 rv = ioctl(fcp_fd, FCP_TGT_SEND_SCSI, fscsi); 909 } 910 close(fcp_fd); 911 912 if (fscsi->scsi_fc_status == FC_DEVICE_NOT_TGT) { 913 return (FPCFGA_FCP_SEND_SCSI_DEV_NOT_TGT); 914 } else if (rv != 0 || fscsi->scsi_bufstatus != 0) { 915 *l_errnop = errno; 916 return (FPCFGA_FCP_TGT_SEND_SCSI_FAILED); 917 } 918 return (FPCFGA_OK); 919 } 920 921 /* 922 * This routine returns standard inq data for 923 * a target represented by dyncomp. 924 * 925 * Calls FCP passthru ioctl FCP_TGT_SEND_SCSI to get inquiry data. 926 * 927 * Caller should free the *inq_buf. 928 */ 929 static fpcfga_ret_t 930 get_standard_inq_data( 931 const char *xport_phys, 932 const char *dyncomp, 933 uchar_t *lun_num, 934 struct scsi_inquiry **inq_buf, 935 int *l_errnop) 936 { 937 struct fcp_scsi_cmd fscsi; 938 struct scsi_extended_sense sensebuf; 939 union scsi_cdb scsi_inq_req; 940 la_wwn_t pwwn; 941 int alloc_len; 942 fpcfga_ret_t ret; 943 944 945 alloc_len = sizeof (struct scsi_inquiry); 946 if ((*inq_buf = (struct scsi_inquiry *)calloc(1, alloc_len)) == NULL) { 947 *l_errnop = errno; 948 return (FPCFGA_LIB_ERR); 949 } 950 951 if (cvt_dyncomp_to_lawwn(dyncomp, &pwwn) != 0) { 952 return (FPCFGA_LIB_ERR); 953 } 954 955 init_fcp_scsi_cmd(&fscsi, lun_num, &pwwn, &scsi_inq_req, 956 sizeof (scsi_inq_req), *inq_buf, alloc_len, &sensebuf, 957 sizeof (struct scsi_extended_sense)); 958 scsi_inq_req.scc_cmd = SCMD_INQUIRY; 959 scsi_inq_req.g0_count0 = sizeof (struct scsi_inquiry); 960 961 if ((ret = issue_fcp_scsi_cmd(xport_phys, &fscsi, l_errnop)) 962 != FPCFGA_OK) { 963 S_FREE(*inq_buf); 964 return (ret); 965 } 966 967 return (FPCFGA_OK); 968 } 969 970 /* 971 * This routine returns report lun data and number of luns found 972 * on a target represented by dyncomp. 973 * 974 * Calls FCP passthru ioctl FCP_TGT_SEND_SCSI to get report lun data. 975 * 976 * Caller should free the *resp_buf when FPCFGA_OK is returned. 977 */ 978 fpcfga_ret_t 979 get_report_lun_data( 980 const char *xport_phys, 981 const char *dyncomp, 982 int *num_luns, 983 report_lun_resp_t **resp_buf, 984 struct scsi_extended_sense *sensebuf, 985 int *l_errnop) 986 { 987 struct fcp_scsi_cmd fscsi; 988 union scsi_cdb scsi_rl_req; 989 la_wwn_t pwwn; 990 int alloc_len; 991 fpcfga_ret_t ret; 992 uchar_t lun_data[SAM_LUN_SIZE]; 993 994 alloc_len = sizeof (struct report_lun_resp); 995 if ((*resp_buf = (report_lun_resp_t *)calloc(1, alloc_len)) == NULL) { 996 *l_errnop = errno; 997 return (FPCFGA_LIB_ERR); 998 } 999 1000 if (cvt_dyncomp_to_lawwn(dyncomp, &pwwn) != 0) { 1001 S_FREE(*resp_buf); 1002 return (FPCFGA_LIB_ERR); 1003 } 1004 1005 /* sending to LUN 0 so initializing lun_data buffer to be 0 */ 1006 memset(lun_data, 0, sizeof (lun_data)); 1007 init_fcp_scsi_cmd(&fscsi, lun_data, &pwwn, &scsi_rl_req, 1008 sizeof (scsi_rl_req), *resp_buf, alloc_len, sensebuf, 1009 sizeof (struct scsi_extended_sense)); 1010 scsi_rl_req.scc_cmd = FP_SCMD_REPORT_LUN; 1011 FORMG5COUNT(&scsi_rl_req, alloc_len); 1012 1013 if ((ret = issue_fcp_scsi_cmd(xport_phys, &fscsi, l_errnop)) 1014 != FPCFGA_OK) { 1015 S_FREE(*resp_buf); 1016 return (ret); 1017 } 1018 1019 if (ntohl((*resp_buf)->num_lun) > 1020 (sizeof (struct report_lun_resp) - REPORT_LUN_HDR_SIZE)) { 1021 alloc_len = (*resp_buf)->num_lun + REPORT_LUN_HDR_SIZE; 1022 S_FREE(*resp_buf); 1023 if ((*resp_buf = (report_lun_resp_t *)calloc(1, alloc_len)) 1024 == NULL) { 1025 *l_errnop = errno; 1026 return (FPCFGA_LIB_ERR); 1027 } 1028 (void) memset((char *)*resp_buf, 0, alloc_len); 1029 FORMG5COUNT(&scsi_rl_req, alloc_len); 1030 1031 fscsi.scsi_bufaddr = (caddr_t)*resp_buf; 1032 fscsi.scsi_buflen = alloc_len; 1033 1034 if ((ret = issue_fcp_scsi_cmd(xport_phys, &fscsi, l_errnop)) 1035 != FPCFGA_OK) { 1036 S_FREE(*resp_buf); 1037 return (ret); 1038 } 1039 } 1040 1041 /* num_lun represent number of luns * 8. */ 1042 *num_luns = ntohl((*resp_buf)->num_lun) >> 3; 1043 1044 return (FPCFGA_OK); 1045 } 1046 1047 /* 1048 * Routine for consturct ldata list for each FCP SCSI LUN device 1049 * for a discovered target device. 1050 * It calls get_report_lun_data to get report lun data and 1051 * construct ldata list per each lun. 1052 * 1053 * It is called only when show_FCP_dev option is given. 1054 * 1055 * Overall algorithm: 1056 * Get the report lun data thru FCP passthru ioctl. 1057 * Call init_ldata_for_accessible_FCP_dev to process the report LUN data. 1058 * For each LUN found standard inquiry is issued to get device type. 1059 */ 1060 static fpcfga_ret_t 1061 get_accessible_FCP_dev_ldata( 1062 const char *dyncomp, 1063 fpcfga_list_t *lap, 1064 int *l_errnop) 1065 { 1066 report_lun_resp_t *resp_buf; 1067 struct scsi_extended_sense sense; 1068 int num_luns; 1069 fpcfga_ret_t ret; 1070 1071 memset(&sense, 0, sizeof (sense)); 1072 if ((ret = get_report_lun_data(lap->apidp->xport_phys, dyncomp, 1073 &num_luns, &resp_buf, &sense, l_errnop)) != FPCFGA_OK) { 1074 /* 1075 * when report lun data fails then return FPCFGA_OK thus 1076 * keep the ldata for the target which is acquired previously. 1077 * For remote hba node this will be normal. 1078 * For a target error may already be detected through 1079 * FCP_TGT_INQ. 1080 */ 1081 if ((ret == FPCFGA_FCP_TGT_SEND_SCSI_FAILED) || 1082 (ret == FPCFGA_FCP_SEND_SCSI_DEV_NOT_TGT)) { 1083 ret = FPCFGA_OK; 1084 } 1085 return (ret); 1086 } 1087 1088 if (num_luns > 0) { 1089 ret = init_ldata_for_accessible_FCP_dev( 1090 dyncomp, num_luns, resp_buf, lap, l_errnop); 1091 } else { 1092 /* 1093 * proceed with to stat if no lun found. 1094 * This will make the target apid will be kept. 1095 */ 1096 ret = FPCFGA_OK; 1097 } 1098 1099 S_FREE(resp_buf); 1100 return (ret); 1101 } 1102 1103 /* 1104 * Routine for checking validity of ldata list based on input argumemnt. 1105 * Set the occupant state of hba port if the list is valid. 1106 */ 1107 static fpcfga_ret_t 1108 postprocess_list_data( 1109 const ldata_list_t *listp, 1110 fpcfga_cmd_t cmd, 1111 cfga_stat_t chld_config, 1112 int *np, 1113 uint_t flags) 1114 { 1115 ldata_list_t *tmplp = NULL; 1116 cfga_list_data_t *xport_ldatap = NULL; 1117 int i; 1118 1119 1120 *np = 0; 1121 1122 if (listp == NULL) { 1123 return (FPCFGA_ERR); 1124 } 1125 1126 tmplp = (ldata_list_t *)listp; 1127 for (i = 0; tmplp != NULL; tmplp = tmplp->next) { 1128 i++; 1129 if (GET_DYN(tmplp->ldata.ap_phys_id) == NULL) { 1130 /* A bus stat data */ 1131 assert(GET_DYN(tmplp->ldata.ap_log_id) == NULL); 1132 xport_ldatap = &tmplp->ldata; 1133 #ifdef DEBUG 1134 } else { 1135 assert(GET_DYN(tmplp->ldata.ap_log_id) != NULL); 1136 #endif 1137 } 1138 } 1139 1140 switch (cmd) { 1141 case FPCFGA_STAT_FC_DEV: 1142 if ((flags & FLAG_FCP_DEV) == FLAG_FCP_DEV) { 1143 if (i < 1 || xport_ldatap != NULL) { 1144 return (FPCFGA_LIB_ERR); 1145 } 1146 } else { 1147 if (i != 1 || xport_ldatap != NULL) { 1148 return (FPCFGA_LIB_ERR); 1149 } 1150 } 1151 break; 1152 case FPCFGA_STAT_FCA_PORT: 1153 if (i != 1 || xport_ldatap == NULL) { 1154 return (FPCFGA_LIB_ERR); 1155 } 1156 break; 1157 case FPCFGA_STAT_ALL: 1158 if (i < 1 || xport_ldatap == NULL) { 1159 return (FPCFGA_LIB_ERR); 1160 } 1161 break; 1162 default: 1163 return (FPCFGA_LIB_ERR); 1164 } 1165 1166 *np = i; 1167 1168 /* Fill in the occupant (child) state. */ 1169 if (xport_ldatap != NULL) { 1170 xport_ldatap->ap_o_state = chld_config; 1171 } 1172 return (FPCFGA_OK); 1173 } 1174 1175 /* 1176 * Routine for checking each target device found in device tree. 1177 * When the matching port WWN dev is found from the accessble ldata list 1178 * the target device is updated with configured ostate. 1179 * 1180 * Overall algorithm: 1181 * Parse the device tree to find configured devices which matches with 1182 * list argument. If cmd is stat on a specific target device it 1183 * matches port WWN and continues to further processing. If cmd is 1184 * stat on hba port all the device target under the hba are processed. 1185 */ 1186 static int 1187 stat_fc_dev(di_node_t node, void *arg) 1188 { 1189 fpcfga_list_t *lap = NULL; 1190 char *devfsp = NULL, *nodepath = NULL; 1191 size_t len = 0; 1192 int limited_stat = 0, match_minor, rv; 1193 fpcfga_ret_t ret; 1194 di_prop_t prop = DI_PROP_NIL; 1195 uchar_t *port_wwn_data; 1196 char port_wwn[WWN_SIZE*2+1]; 1197 int count; 1198 1199 lap = (fpcfga_list_t *)arg; 1200 1201 /* 1202 * Skip partial nodes 1203 * 1204 * This checking is from the scsi plug-in and will be deleted for 1205 * fp plug-in. The node will be processed for fp even if it is 1206 * in driver detached state. From fp perspective the node is configured 1207 * as long as the node is not in offline or down state. 1208 * scsi plug-in considers the known state when it is offlined 1209 * regradless of driver detached state or when it is not in driver 1210 * detached state like normal state. 1211 * If the node is only in driver detached state it is considered as 1212 * unknown state. 1213 * 1214 * if (!known_state(node) && (lap->cmd != FPCFGA_STAT_FC_DEV)) { 1215 * return (DI_WALK_CONTINUE); 1216 * 1217 */ 1218 1219 devfsp = di_devfs_path(node); 1220 if (devfsp == NULL) { 1221 rv = DI_WALK_CONTINUE; 1222 goto out; 1223 } 1224 1225 len = strlen(DEVICES_DIR) + strlen(devfsp) + 1; 1226 1227 nodepath = calloc(1, len); 1228 if (nodepath == NULL) { 1229 lap->l_errno = errno; 1230 lap->ret = FPCFGA_LIB_ERR; 1231 rv = DI_WALK_TERMINATE; 1232 goto out; 1233 } 1234 1235 (void) snprintf(nodepath, len, "%s%s", DEVICES_DIR, devfsp); 1236 1237 /* Skip node if it is HBA */ 1238 match_minor = 0; 1239 if (!dev_cmp(lap->apidp->xport_phys, nodepath, match_minor)) { 1240 rv = DI_WALK_CONTINUE; 1241 goto out; 1242 } 1243 1244 /* If stat'ing a specific device, is this node that device */ 1245 if (lap->cmd == FPCFGA_STAT_FC_DEV) { 1246 /* checks port wwn property to find a match */ 1247 while ((prop = di_prop_next(node, prop)) 1248 != DI_PROP_NIL) { 1249 if ((strcmp(PORT_WWN_PROP, 1250 di_prop_name(prop)) == 0) && 1251 (di_prop_type(prop) == 1252 DI_PROP_TYPE_BYTE)) { 1253 break; 1254 } 1255 } 1256 1257 if (prop != DI_PROP_NIL) { 1258 count = di_prop_bytes(prop, &port_wwn_data); 1259 if (count != WWN_SIZE) { 1260 lap->ret = FPCFGA_LIB_ERR; 1261 rv = DI_WALK_TERMINATE; 1262 goto out; 1263 } 1264 (void) sprintf(port_wwn, "%016llx", 1265 (wwnConversion(port_wwn_data))); 1266 /* 1267 * port wwn doesn't match contine to walk 1268 * if match call do_stat_fc_dev. 1269 */ 1270 if (strncmp(port_wwn, lap->apidp->dyncomp, 1271 WWN_SIZE*2)) { 1272 rv = DI_WALK_CONTINUE; 1273 goto out; 1274 } 1275 } else { 1276 rv = DI_WALK_CONTINUE; 1277 goto out; 1278 } 1279 } 1280 1281 /* 1282 * If stat'ing a xport only, we look at device nodes only to get 1283 * xport configuration status. So a limited stat will suffice. 1284 */ 1285 if (lap->cmd == FPCFGA_STAT_FCA_PORT) { 1286 limited_stat = 1; 1287 } else { 1288 limited_stat = 0; 1289 } 1290 1291 /* 1292 * Ignore errors if stat'ing a bus or listing all 1293 */ 1294 ret = do_stat_fc_dev(node, nodepath, lap, limited_stat); 1295 if (ret != FPCFGA_OK) { 1296 if (lap->cmd == FPCFGA_STAT_FC_DEV) { 1297 lap->ret = ret; 1298 rv = DI_WALK_TERMINATE; 1299 } else { 1300 rv = DI_WALK_CONTINUE; 1301 } 1302 goto out; 1303 } 1304 1305 /* Are we done ? */ 1306 rv = DI_WALK_CONTINUE; 1307 if (lap->cmd == FPCFGA_STAT_FCA_PORT && 1308 lap->chld_config == CFGA_STAT_CONFIGURED) { 1309 rv = DI_WALK_TERMINATE; 1310 } else if (lap->cmd == FPCFGA_STAT_FC_DEV) { 1311 /* 1312 * If stat'ing a specific device, we are done at this point. 1313 */ 1314 rv = DI_WALK_TERMINATE; 1315 } 1316 1317 /*FALLTHRU*/ 1318 out: 1319 S_FREE(nodepath); 1320 if (devfsp != NULL) di_devfs_path_free(devfsp); 1321 return (rv); 1322 } 1323 1324 /* 1325 * Routine for checking each FCP SCSI LUN device found in device tree. 1326 * When the matching port WWN and LUN are found from the accessble ldata list 1327 * the FCP SCSI LUN is updated with configured ostate. 1328 * 1329 * Overall algorithm: 1330 * Parse the device tree to find configured devices which matches with 1331 * list argument. If cmd is stat on a specific target device it 1332 * matches port WWN and continues to further processing. If cmd is 1333 * stat on hba port all the FCP SCSI LUN under the hba are processed. 1334 */ 1335 static int 1336 stat_FCP_dev(di_node_t node, void *arg) 1337 { 1338 fpcfga_list_t *lap = NULL; 1339 char *devfsp = NULL, *nodepath = NULL; 1340 size_t len = 0; 1341 int limited_stat = 0, match_minor, rv, di_ret; 1342 fpcfga_ret_t ret; 1343 uchar_t *port_wwn_data; 1344 char port_wwn[WWN_SIZE*2+1]; 1345 1346 lap = (fpcfga_list_t *)arg; 1347 1348 devfsp = di_devfs_path(node); 1349 if (devfsp == NULL) { 1350 rv = DI_WALK_CONTINUE; 1351 goto out; 1352 } 1353 1354 len = strlen(DEVICES_DIR) + strlen(devfsp) + 1; 1355 1356 nodepath = calloc(1, len); 1357 if (nodepath == NULL) { 1358 lap->l_errno = errno; 1359 lap->ret = FPCFGA_LIB_ERR; 1360 rv = DI_WALK_TERMINATE; 1361 goto out; 1362 } 1363 1364 (void) snprintf(nodepath, len, "%s%s", DEVICES_DIR, devfsp); 1365 1366 /* Skip node if it is HBA */ 1367 match_minor = 0; 1368 if (!dev_cmp(lap->apidp->xport_phys, nodepath, match_minor)) { 1369 rv = DI_WALK_CONTINUE; 1370 goto out; 1371 } 1372 1373 /* If stat'ing a specific device, is this node that device */ 1374 if (lap->cmd == FPCFGA_STAT_FC_DEV) { 1375 /* checks port wwn property to find a match */ 1376 di_ret = di_prop_lookup_bytes(DDI_DEV_T_ANY, node, 1377 PORT_WWN_PROP, &port_wwn_data); 1378 if (di_ret == -1) { 1379 rv = DI_WALK_CONTINUE; 1380 goto out; 1381 } else { 1382 (void) sprintf(port_wwn, "%016llx", 1383 (wwnConversion(port_wwn_data))); 1384 /* 1385 * port wwn doesn't match contine to walk 1386 * if match call do_stat_FCP_dev. 1387 */ 1388 if (strncmp(port_wwn, lap->apidp->dyncomp, 1389 WWN_SIZE*2)) { 1390 rv = DI_WALK_CONTINUE; 1391 goto out; 1392 } 1393 } 1394 } 1395 1396 /* 1397 * If stat'ing a xport only, we look at device nodes only to get 1398 * xport configuration status. So a limited stat will suffice. 1399 */ 1400 if (lap->cmd == FPCFGA_STAT_FCA_PORT) { 1401 limited_stat = 1; 1402 } else { 1403 limited_stat = 0; 1404 } 1405 1406 /* 1407 * Ignore errors if stat'ing a bus or listing all 1408 */ 1409 ret = do_stat_FCP_dev(node, nodepath, lap, limited_stat); 1410 if (ret != FPCFGA_OK) { 1411 rv = DI_WALK_CONTINUE; 1412 goto out; 1413 } 1414 1415 /* Are we done ? */ 1416 rv = DI_WALK_CONTINUE; 1417 if (lap->cmd == FPCFGA_STAT_FCA_PORT && 1418 lap->chld_config == CFGA_STAT_CONFIGURED) { 1419 rv = DI_WALK_TERMINATE; 1420 } 1421 1422 /*FALLTHRU*/ 1423 out: 1424 S_FREE(nodepath); 1425 if (devfsp != NULL) di_devfs_path_free(devfsp); 1426 return (rv); 1427 } 1428 1429 static fpcfga_ret_t 1430 do_stat_fca_xport(fpcfga_list_t *lap, int limited_stat, 1431 HBA_PORTATTRIBUTES portAttrs) 1432 { 1433 cfga_list_data_t *clp = NULL; 1434 ldata_list_t *listp = NULL; 1435 int l_errno = 0; 1436 uint_t devinfo_state = 0; 1437 walkarg_t walkarg; 1438 fpcfga_ret_t ret; 1439 cfga_cond_t cond = CFGA_COND_UNKNOWN; 1440 1441 assert(lap->xport_logp != NULL); 1442 1443 /* Get xport state */ 1444 if (lap->apidp->flags == FLAG_DEVINFO_FORCE) { 1445 walkarg.flags = FLAG_DEVINFO_FORCE; 1446 } else { 1447 walkarg.flags = 0; 1448 } 1449 walkarg.walkmode.node_args.flags = 0; 1450 walkarg.walkmode.node_args.fcn = get_xport_state; 1451 1452 ret = walk_tree(lap->apidp->xport_phys, &devinfo_state, 1453 DINFOCPYALL | DINFOPATH, &walkarg, FPCFGA_WALK_NODE, &l_errno); 1454 if (ret == FPCFGA_OK) { 1455 lap->xport_rstate = xport_devinfo_to_recep_state(devinfo_state); 1456 } else { 1457 lap->xport_rstate = CFGA_STAT_NONE; 1458 } 1459 1460 /* 1461 * Get topology works okay even if the fp port is connected 1462 * to a switch and no devices connected to the switch. 1463 * In this case the list will only shows fp port info without 1464 * any device listed. 1465 */ 1466 switch (portAttrs.PortType) { 1467 case HBA_PORTTYPE_NLPORT: 1468 (void) snprintf(lap->xport_type, 1469 sizeof (lap->xport_type), "%s", 1470 FP_FC_PUBLIC_PORT_TYPE); 1471 break; 1472 case HBA_PORTTYPE_NPORT: 1473 (void) snprintf(lap->xport_type, 1474 sizeof (lap->xport_type), "%s", 1475 FP_FC_FABRIC_PORT_TYPE); 1476 break; 1477 case HBA_PORTTYPE_LPORT: 1478 (void) snprintf(lap->xport_type, 1479 sizeof (lap->xport_type), "%s", 1480 FP_FC_PRIVATE_PORT_TYPE); 1481 break; 1482 case HBA_PORTTYPE_PTP: 1483 (void) snprintf(lap->xport_type, 1484 sizeof (lap->xport_type), "%s", 1485 FP_FC_PT_TO_PT_PORT_TYPE); 1486 break; 1487 /* 1488 * HBA_PORTTYPE_UNKNOWN means nothing is connected 1489 */ 1490 case HBA_PORTTYPE_UNKNOWN: 1491 (void) snprintf(lap->xport_type, 1492 sizeof (lap->xport_type), "%s", 1493 FP_FC_PORT_TYPE); 1494 break; 1495 /* NOT_PRESENT, OTHER, FPORT, FLPORT */ 1496 default: 1497 (void) snprintf(lap->xport_type, 1498 sizeof (lap->xport_type), "%s", 1499 FP_FC_PORT_TYPE); 1500 cond = CFGA_COND_FAILED; 1501 break; 1502 } 1503 1504 if (limited_stat) { 1505 /* We only want to know bus(receptacle) connect status */ 1506 return (FPCFGA_OK); 1507 } 1508 1509 listp = calloc(1, sizeof (ldata_list_t)); 1510 if (listp == NULL) { 1511 lap->l_errno = errno; 1512 return (FPCFGA_LIB_ERR); 1513 } 1514 1515 clp = &listp->ldata; 1516 1517 (void) snprintf(clp->ap_log_id, sizeof (clp->ap_log_id), "%s", 1518 lap->xport_logp); 1519 (void) snprintf(clp->ap_phys_id, sizeof (clp->ap_phys_id), "%s", 1520 lap->apidp->xport_phys); 1521 1522 clp->ap_class[0] = '\0'; /* Filled by libcfgadm */ 1523 clp->ap_r_state = lap->xport_rstate; 1524 clp->ap_o_state = lap->chld_config; 1525 clp->ap_cond = cond; 1526 clp->ap_busy = 0; 1527 clp->ap_status_time = (time_t)-1; 1528 clp->ap_info[0] = '\0'; 1529 (void) strncpy(clp->ap_type, lap->xport_type, sizeof (clp->ap_type)); 1530 1531 /* Link it in. lap->listp is NULL originally. */ 1532 listp->next = lap->listp; 1533 /* lap->listp now gets cfga_list_data for the fca port. */ 1534 lap->listp = listp; 1535 1536 return (FPCFGA_OK); 1537 } 1538 1539 1540 static int 1541 get_xport_state(di_node_t node, void *arg) 1542 { 1543 uint_t *di_statep = (uint_t *)arg; 1544 1545 *di_statep = di_state(node); 1546 1547 return (DI_WALK_TERMINATE); 1548 } 1549 1550 /* 1551 * Routine for updating ldata list based on the state of device node. 1552 * When no matching accessible ldata is found a new ldata is created 1553 * with proper state information. 1554 * 1555 * Overall algorithm: 1556 * If the device node is online and the matching ldata is found 1557 * the target device is updated with configued and unknown condition. 1558 * If the device node is offline or down and the matching ldata is found 1559 * the target device is updated with configued and unusable condition. 1560 * If the device node is online but the matching ldata is not found 1561 * the target device is created with configued and failing condition. 1562 * If the device node is offline or down and the matching ldata is not found 1563 * the target device is created with configued and unusable condition. 1564 */ 1565 static fpcfga_ret_t 1566 do_stat_fc_dev( 1567 const di_node_t node, 1568 const char *nodepath, 1569 fpcfga_list_t *lap, 1570 int limited_stat) 1571 { 1572 uint_t dctl_state = 0, devinfo_state = 0; 1573 char *dyncomp = NULL; 1574 cfga_list_data_t *clp = NULL; 1575 cfga_busy_t busy; 1576 ldata_list_t *listp = NULL; 1577 ldata_list_t *matchldp = NULL; 1578 int l_errno = 0; 1579 cfga_stat_t ostate; 1580 cfga_cond_t cond; 1581 fpcfga_ret_t ret; 1582 1583 assert(lap->apidp->xport_phys != NULL); 1584 assert(lap->xport_logp != NULL); 1585 1586 cond = CFGA_COND_UNKNOWN; 1587 1588 devinfo_state = di_state(node); 1589 ostate = dev_devinfo_to_occupant_state(devinfo_state); 1590 1591 /* 1592 * NOTE: The framework cannot currently detect layered driver 1593 * opens, so the busy indicator is not very reliable. Also, 1594 * non-root users will not be able to determine busy 1595 * status (libdevice needs root permissions). 1596 * This should probably be fixed by adding a DI_BUSY to the di_state() 1597 * routine in libdevinfo. 1598 */ 1599 if (devctl_cmd(nodepath, FPCFGA_DEV_GETSTATE, &dctl_state, 1600 &l_errno) == FPCFGA_OK) { 1601 busy = ((dctl_state & DEVICE_BUSY) == DEVICE_BUSY) ? 1 : 0; 1602 } else { 1603 busy = 0; 1604 } 1605 1606 /* We only want to know device config state */ 1607 if (limited_stat) { 1608 if (((strcmp(lap->xport_type, FP_FC_FABRIC_PORT_TYPE) == 0) || 1609 strcmp(lap->xport_type, FP_FC_PUBLIC_PORT_TYPE) == 0)) { 1610 lap->chld_config = CFGA_STAT_CONFIGURED; 1611 } else { 1612 if (ostate != CFGA_STAT_UNCONFIGURED) { 1613 lap->chld_config = CFGA_STAT_CONFIGURED; 1614 } 1615 } 1616 return (FPCFGA_OK); 1617 } 1618 1619 /* 1620 * If child device is configured, see if it is accessible also 1621 * for FPCFGA_STAT_FC_DEV cmd. 1622 */ 1623 if (lap->cmd == FPCFGA_STAT_FC_DEV) { 1624 switch (ostate) { 1625 case CFGA_STAT_CONFIGURED: 1626 /* 1627 * if configured and not accessble, the device is 1628 * till be displayed with failing condition. 1629 * return code should be FPCFGA_OK to display it. 1630 */ 1631 case CFGA_STAT_NONE: 1632 /* 1633 * If not unconfigured and not attached 1634 * the state is set to CFGA_STAT_NONE currently. 1635 * This is okay for the detached node due to 1636 * the driver being unloaded. 1637 * May need to define another state to 1638 * isolate the detached only state. 1639 * 1640 * handle the same way as configured. 1641 */ 1642 if (lap->ret != FPCFGA_ACCESS_OK) { 1643 cond = CFGA_COND_FAILING; 1644 } 1645 lap->chld_config = CFGA_STAT_CONFIGURED; 1646 break; 1647 case CFGA_STAT_UNCONFIGURED: 1648 /* 1649 * if unconfigured - offline or down, 1650 * set to cond to unusable regardless of accessibility. 1651 * This behavior needs to be examined further. 1652 * When the device is not accessible the node 1653 * may get offline or down. In that case failing 1654 * cond may make more sense. 1655 * In anycase the ostate will be set to configured 1656 * configured. 1657 */ 1658 cond = CFGA_COND_UNUSABLE; 1659 /* 1660 * For fabric port the fca port is considered as 1661 * configured since user configured previously 1662 * for any existing node. Otherwise when the 1663 * device was accessible, the hba is considered as 1664 * configured. 1665 */ 1666 if (((strcmp(lap->xport_type, 1667 FP_FC_PUBLIC_PORT_TYPE) == 0) || 1668 (strcmp(lap->xport_type, 1669 FP_FC_FABRIC_PORT_TYPE) == 0)) || 1670 (lap->ret == FPCFGA_ACCESS_OK)) { 1671 lap->chld_config = CFGA_STAT_CONFIGURED; 1672 } else { 1673 lap->ret = FPCFGA_APID_NOEXIST; 1674 return (FPCFGA_OK); 1675 } 1676 break; 1677 default: 1678 break; 1679 } 1680 1681 /* if device found in disco ports, ldata already created. */ 1682 if (lap->ret == FPCFGA_ACCESS_OK) { 1683 /* 1684 * if cond is not changed then don't update 1685 * condition to keep the previous condition. 1686 */ 1687 if (cond != CFGA_COND_UNKNOWN) { 1688 lap->listp->ldata.ap_cond = cond; 1689 } 1690 lap->listp->ldata.ap_o_state = CFGA_STAT_CONFIGURED; 1691 lap->listp->ldata.ap_busy = busy; 1692 lap->ret = FPCFGA_OK; 1693 return (FPCFGA_OK); 1694 } 1695 } 1696 1697 /* 1698 * if cmd is stat all check ldata list 1699 * to see if the node exist on the dev list. Otherwise create 1700 * the list element. 1701 */ 1702 if (lap->cmd == FPCFGA_STAT_ALL) { 1703 if (lap->listp != NULL) { 1704 if ((ret = make_dyncomp_from_dinode(node, 1705 &dyncomp, &l_errno)) != FPCFGA_OK) { 1706 return (ret); 1707 } 1708 ret = is_dyn_ap_on_ldata_list(dyncomp, lap->listp, 1709 &matchldp, &l_errno); 1710 switch (ret) { 1711 case FPCFGA_ACCESS_OK: 1712 /* node exists so set ostate to configured. */ 1713 lap->chld_config = CFGA_STAT_CONFIGURED; 1714 matchldp->ldata.ap_o_state = 1715 CFGA_STAT_CONFIGURED; 1716 matchldp->ldata.ap_busy = busy; 1717 clp = &matchldp->ldata; 1718 switch (ostate) { 1719 case CFGA_STAT_CONFIGURED: 1720 /* 1721 * If not unconfigured and not attached 1722 * the state is set to CFGA_STAT_NONE currently. 1723 * This is okay for the detached node due to 1724 * the driver being unloaded. 1725 * May need to define another state to 1726 * isolate the detached only state. 1727 */ 1728 case CFGA_STAT_NONE: 1729 /* update ap_type and ap_info */ 1730 get_hw_info(node, clp); 1731 break; 1732 /* 1733 * node is offline or down. 1734 * set cond to unusable. 1735 */ 1736 case CFGA_STAT_UNCONFIGURED: 1737 /* 1738 * if cond is not unknown 1739 * we already set the cond from 1740 * a different node with the same 1741 * port WWN or initial probing 1742 * was failed so don't update again. 1743 */ 1744 if (matchldp->ldata.ap_cond == 1745 CFGA_COND_UNKNOWN) { 1746 matchldp->ldata.ap_cond = 1747 CFGA_COND_UNUSABLE; 1748 } 1749 break; 1750 default: 1751 break; 1752 } 1753 /* node found in ldata list so just return. */ 1754 lap->ret = FPCFGA_OK; 1755 S_FREE(dyncomp); 1756 return (FPCFGA_OK); 1757 case FPCFGA_LIB_ERR: 1758 lap->l_errno = l_errno; 1759 S_FREE(dyncomp); 1760 return (ret); 1761 case FPCFGA_APID_NOACCESS: 1762 switch (ostate) { 1763 /* node is attached but not in dev list */ 1764 case CFGA_STAT_CONFIGURED: 1765 case CFGA_STAT_NONE: 1766 lap->chld_config = CFGA_STAT_CONFIGURED; 1767 cond = CFGA_COND_FAILING; 1768 break; 1769 /* 1770 * node is offline or down. 1771 * set cond to unusable. 1772 */ 1773 case CFGA_STAT_UNCONFIGURED: 1774 /* 1775 * For fabric port the fca port is 1776 * considered as configured since user 1777 * configured previously for any 1778 * existing node. 1779 */ 1780 cond = CFGA_COND_UNUSABLE; 1781 if ((strcmp(lap->xport_type, 1782 FP_FC_PUBLIC_PORT_TYPE) == 0) || 1783 (strcmp(lap->xport_type, 1784 FP_FC_FABRIC_PORT_TYPE) == 0)) { 1785 lap->chld_config = 1786 CFGA_STAT_CONFIGURED; 1787 } else { 1788 lap->ret = FPCFGA_OK; 1789 S_FREE(dyncomp); 1790 return (FPCFGA_OK); 1791 } 1792 break; 1793 default: 1794 /* 1795 * continue to create ldata_list struct for 1796 * this node 1797 */ 1798 break; 1799 } 1800 default: 1801 break; 1802 } 1803 } else { 1804 /* 1805 * dev_list is null so there is no accessible dev. 1806 * set the cond and continue to create ldata. 1807 */ 1808 switch (ostate) { 1809 case CFGA_STAT_CONFIGURED: 1810 case CFGA_STAT_NONE: 1811 cond = CFGA_COND_FAILING; 1812 lap->chld_config = CFGA_STAT_CONFIGURED; 1813 break; 1814 /* 1815 * node is offline or down. 1816 * set cond to unusable. 1817 */ 1818 case CFGA_STAT_UNCONFIGURED: 1819 cond = CFGA_COND_UNUSABLE; 1820 /* 1821 * For fabric port the fca port is 1822 * considered as configured since user 1823 * configured previously for any 1824 * existing node. 1825 */ 1826 if ((strcmp(lap->xport_type, 1827 FP_FC_PUBLIC_PORT_TYPE) == 0) || 1828 (strcmp(lap->xport_type, 1829 FP_FC_FABRIC_PORT_TYPE) == 0)) { 1830 lap->chld_config = 1831 CFGA_STAT_CONFIGURED; 1832 } else { 1833 lap->ret = FPCFGA_OK; 1834 S_FREE(dyncomp); 1835 return (FPCFGA_OK); 1836 } 1837 break; 1838 default: 1839 break; 1840 } 1841 } 1842 } 1843 1844 listp = calloc(1, sizeof (ldata_list_t)); 1845 if (listp == NULL) { 1846 lap->l_errno = errno; 1847 S_FREE(dyncomp); 1848 return (FPCFGA_LIB_ERR); 1849 } 1850 1851 clp = &listp->ldata; 1852 1853 /* Create the dynamic component. */ 1854 if (dyncomp == NULL) { 1855 ret = make_dyncomp_from_dinode(node, &dyncomp, &l_errno); 1856 if (ret != FPCFGA_OK) { 1857 S_FREE(listp); 1858 return (ret); 1859 } 1860 } 1861 1862 /* Create logical and physical ap_id */ 1863 (void) snprintf(clp->ap_log_id, sizeof (clp->ap_log_id), "%s%s%s", 1864 lap->xport_logp, DYN_SEP, dyncomp); 1865 1866 (void) snprintf(clp->ap_phys_id, sizeof (clp->ap_phys_id), "%s%s%s", 1867 lap->apidp->xport_phys, DYN_SEP, dyncomp); 1868 1869 S_FREE(dyncomp); 1870 1871 clp->ap_class[0] = '\0'; /* Filled in by libcfgadm */ 1872 clp->ap_r_state = lap->xport_rstate; 1873 /* set to ostate to configured and set cond with info. */ 1874 clp->ap_o_state = CFGA_STAT_CONFIGURED; 1875 clp->ap_cond = cond; 1876 clp->ap_busy = busy; 1877 clp->ap_status_time = (time_t)-1; 1878 1879 /* get ap_type and ap_info. */ 1880 get_hw_info(node, clp); 1881 1882 /* Link it in */ 1883 listp->next = lap->listp; 1884 lap->listp = listp; 1885 1886 lap->ret = FPCFGA_OK; 1887 return (FPCFGA_OK); 1888 } 1889 1890 /* 1891 * Wrapper routine for handling path info. 1892 * 1893 * When show_FCP_dev option is given stat_path_info_FCP_dev() is called. 1894 * Otherwise stat_path_info_fc_dev() is called. 1895 */ 1896 int 1897 stat_path_info_node( 1898 di_node_t root, 1899 void *arg, 1900 int *l_errnop) 1901 { 1902 fpcfga_list_t *lap = NULL; 1903 1904 lap = (fpcfga_list_t *)arg; 1905 if ((lap->apidp->flags & (FLAG_FCP_DEV)) == FLAG_FCP_DEV) { 1906 return (stat_path_info_FCP_dev(root, lap, l_errnop)); 1907 } else { 1908 return (stat_path_info_fc_dev(root, lap, l_errnop)); 1909 } 1910 } 1911 1912 /* 1913 * Routine for updating ldata list based on the state of path info node. 1914 * When no matching accessible ldata is found a new ldata is created 1915 * with proper state information. 1916 * 1917 * Overall algorithm: 1918 * If the path info node is not offline and the matching ldata is found 1919 * the target device is updated with configued and unknown condition. 1920 * If the path info node is offline or failed and the matching ldata is found 1921 * the target device is updated with configued and unusable condition. 1922 * If the path info node is online but the matching ldata is not found 1923 * the target device is created with configued and failing condition. 1924 * If the path info is offline or failed and the matching ldata is not found 1925 * the target device is created with configued and unusable condition. 1926 */ 1927 static int 1928 stat_path_info_fc_dev( 1929 di_node_t root, 1930 fpcfga_list_t *lap, 1931 int *l_errnop) 1932 { 1933 ldata_list_t *matchldp = NULL; 1934 di_path_t path = DI_PATH_NIL; 1935 uchar_t *port_wwn_data; 1936 char port_wwn[WWN_SIZE*2+1]; 1937 int count; 1938 fpcfga_ret_t ret; 1939 di_path_state_t pstate; 1940 1941 if (root == DI_NODE_NIL) { 1942 return (FPCFGA_LIB_ERR); 1943 } 1944 1945 /* 1946 * if stat on a specific dev and walk_node found it okay 1947 * then just return ok. 1948 */ 1949 if ((lap->cmd == FPCFGA_STAT_FC_DEV) && (lap->ret == FPCFGA_OK)) { 1950 return (FPCFGA_OK); 1951 } 1952 1953 /* 1954 * if stat on a fca xport and chld_config is set 1955 * then just return ok. 1956 */ 1957 if ((lap->cmd == FPCFGA_STAT_FCA_PORT) && 1958 (lap->chld_config == CFGA_STAT_CONFIGURED)) { 1959 return (FPCFGA_OK); 1960 } 1961 1962 /* 1963 * when there is no path_info node return FPCFGA_OK. 1964 * That way the result from walk_node shall be maintained. 1965 */ 1966 if ((path = di_path_next_client(root, path)) == DI_PATH_NIL) { 1967 /* 1968 * if the dev was in dev list but not found 1969 * return OK to indicate is not configured. 1970 */ 1971 if (lap->ret == FPCFGA_ACCESS_OK) { 1972 lap->ret = FPCFGA_OK; 1973 } 1974 return (FPCFGA_OK); 1975 } 1976 1977 /* if stat on fca port return. */ 1978 if (lap->cmd == FPCFGA_STAT_FCA_PORT) { 1979 if (((strcmp(lap->xport_type, FP_FC_FABRIC_PORT_TYPE) == 0) || 1980 strcmp(lap->xport_type, FP_FC_PUBLIC_PORT_TYPE) == 0)) { 1981 lap->chld_config = CFGA_STAT_CONFIGURED; 1982 return (FPCFGA_OK); 1983 } else { 1984 if ((pstate = di_path_state(path)) != 1985 DI_PATH_STATE_OFFLINE) { 1986 lap->chld_config = CFGA_STAT_CONFIGURED; 1987 return (FPCFGA_OK); 1988 } 1989 } 1990 } 1991 /* 1992 * now parse the path info node. 1993 */ 1994 do { 1995 count = di_path_prop_lookup_bytes(path, PORT_WWN_PROP, 1996 &port_wwn_data); 1997 if (count != WWN_SIZE) { 1998 ret = FPCFGA_LIB_ERR; 1999 break; 2000 } 2001 2002 (void) sprintf(port_wwn, "%016llx", 2003 (wwnConversion(port_wwn_data))); 2004 switch (lap->cmd) { 2005 case FPCFGA_STAT_FC_DEV: 2006 /* if no match contine to the next path info node. */ 2007 if (strncmp(port_wwn, lap->apidp->dyncomp, 2008 WWN_SIZE*2)) { 2009 break; 2010 } 2011 /* if device in dev_list, ldata already created. */ 2012 if (lap->ret == FPCFGA_ACCESS_OK) { 2013 lap->listp->ldata.ap_o_state = 2014 CFGA_STAT_CONFIGURED; 2015 if (((pstate = di_path_state(path)) == 2016 DI_PATH_STATE_OFFLINE) || 2017 (pstate == DI_PATH_STATE_FAULT)) { 2018 lap->listp->ldata.ap_cond = 2019 CFGA_COND_UNUSABLE; 2020 } 2021 lap->ret = FPCFGA_OK; 2022 return (FPCFGA_OK); 2023 } else { 2024 if ((strcmp(lap->xport_type, 2025 FP_FC_PUBLIC_PORT_TYPE) == 0) || 2026 (strcmp(lap->xport_type, 2027 FP_FC_FABRIC_PORT_TYPE) == 0)) { 2028 lap->chld_config = CFGA_STAT_CONFIGURED; 2029 return (init_ldata_for_mpath_dev( 2030 path, port_wwn, l_errnop, lap)); 2031 } else { 2032 if ((di_path_state(path)) != 2033 DI_PATH_STATE_OFFLINE) { 2034 return (init_ldata_for_mpath_dev( 2035 path, port_wwn, l_errnop, lap)); 2036 } else { 2037 lap->ret = FPCFGA_APID_NOEXIST; 2038 return (FPCFGA_OK); 2039 } 2040 } 2041 } 2042 case FPCFGA_STAT_ALL: 2043 /* check if there is list data. */ 2044 if (lap->listp != NULL) { 2045 ret = is_dyn_ap_on_ldata_list(port_wwn, 2046 lap->listp, &matchldp, l_errnop); 2047 if (ret == FPCFGA_ACCESS_OK) { 2048 lap->chld_config = CFGA_STAT_CONFIGURED; 2049 matchldp->ldata.ap_o_state = 2050 CFGA_STAT_CONFIGURED; 2051 /* 2052 * Update the condition as unusable 2053 * if the pathinfo state is failed 2054 * or offline. 2055 */ 2056 if (((pstate = di_path_state(path)) == 2057 DI_PATH_STATE_OFFLINE) || 2058 (pstate == 2059 DI_PATH_STATE_FAULT)) { 2060 matchldp->ldata.ap_cond = 2061 CFGA_COND_UNUSABLE; 2062 } 2063 break; 2064 } else if (ret == FPCFGA_LIB_ERR) { 2065 lap->l_errno = *l_errnop; 2066 return (ret); 2067 } 2068 } 2069 /* 2070 * now create ldata for this particular path info node. 2071 * if port top is private loop and pathinfo is in 2072 * in offline state don't include to ldata list. 2073 */ 2074 if (((strcmp(lap->xport_type, 2075 FP_FC_PUBLIC_PORT_TYPE) == 0) || 2076 (strcmp(lap->xport_type, 2077 FP_FC_FABRIC_PORT_TYPE) == 0)) || 2078 (di_path_state(path) != 2079 DI_PATH_STATE_OFFLINE)) { 2080 lap->chld_config = CFGA_STAT_CONFIGURED; 2081 ret = init_ldata_for_mpath_dev( 2082 path, port_wwn, l_errnop, lap); 2083 if (ret != FPCFGA_OK) { 2084 return (ret); 2085 } 2086 } 2087 break; 2088 case FPCFGA_STAT_FCA_PORT: 2089 if (di_path_state(path) != DI_PATH_STATE_OFFLINE) { 2090 lap->chld_config = CFGA_STAT_CONFIGURED; 2091 return (FPCFGA_OK); 2092 } 2093 } 2094 path = di_path_next_client(root, path); 2095 } while (path != DI_PATH_NIL); 2096 2097 return (FPCFGA_OK); 2098 2099 } 2100 2101 /* 2102 * Routine for updating ldata list based on the state of path info node. 2103 * When no matching accessible ldata is found a new ldata is created 2104 * with proper state information. 2105 * 2106 * The difference from stat_path_info_fc_dev() is 2107 * to handle FCP SCSI LUN information. Otherwise overall algorithm is 2108 * same. 2109 * 2110 * Overall algorithm: 2111 * If the path info node is not offline and the matching ldata is found 2112 * the target device is updated with configued and unknown condition. 2113 * If the path info node is offline or failed and the matching ldata is found 2114 * the target device is updated with configued and unusable condition. 2115 * If the path info node is online but the matching ldata is not found 2116 * the target device is created with configued and failing condition. 2117 * If the path info is offline or failed and the matching ldata is not found 2118 * the target device is created with configued and unusable condition. 2119 */ 2120 static int 2121 stat_path_info_FCP_dev( 2122 di_node_t root, 2123 fpcfga_list_t *lap, 2124 int *l_errnop) 2125 { 2126 ldata_list_t *matchldp = NULL, *listp = NULL; 2127 cfga_list_data_t *clp; 2128 di_path_t path = DI_PATH_NIL; 2129 di_node_t client_node = DI_NODE_NIL; 2130 char *port_wwn = NULL, *nodepath = NULL; 2131 int *lun_nump; 2132 fpcfga_ret_t ldata_ret; 2133 di_path_state_t pstate; 2134 cfga_busy_t busy; 2135 uint_t dctl_state = 0; 2136 2137 if (root == DI_NODE_NIL) { 2138 return (FPCFGA_LIB_ERR); 2139 } 2140 2141 /* 2142 * if stat on a fca xport and chld_config is set 2143 * then just return ok. 2144 */ 2145 if ((lap->cmd == FPCFGA_STAT_FCA_PORT) && 2146 (lap->chld_config == CFGA_STAT_CONFIGURED)) { 2147 return (FPCFGA_OK); 2148 } 2149 /* 2150 * when there is no path_info node return FPCFGA_OK. 2151 * That way the result from walk_node shall be maintained. 2152 */ 2153 if ((path = di_path_next_client(root, path)) == DI_PATH_NIL) { 2154 /* 2155 * if the dev was in dev list but not found 2156 * return ok. 2157 */ 2158 if (lap->ret == FPCFGA_ACCESS_OK) { 2159 lap->ret = FPCFGA_OK; 2160 } 2161 return (FPCFGA_OK); 2162 } 2163 /* 2164 * If stat on fca port and port topology is fabric return here. 2165 * If not fabric return only when path state is not offfline. 2166 * The other cases are handbled below. 2167 */ 2168 if (lap->cmd == FPCFGA_STAT_FCA_PORT) { 2169 if (((strcmp(lap->xport_type, FP_FC_FABRIC_PORT_TYPE) == 0) || 2170 strcmp(lap->xport_type, FP_FC_PUBLIC_PORT_TYPE) == 0)) { 2171 lap->chld_config = CFGA_STAT_CONFIGURED; 2172 return (FPCFGA_OK); 2173 } else { 2174 if ((pstate = di_path_state(path)) != 2175 DI_PATH_STATE_OFFLINE) { 2176 lap->chld_config = CFGA_STAT_CONFIGURED; 2177 return (FPCFGA_OK); 2178 } 2179 } 2180 } 2181 /* 2182 * now parse the path info node. 2183 */ 2184 do { 2185 switch (lap->cmd) { 2186 case FPCFGA_STAT_FC_DEV: 2187 if ((make_portwwn_luncomp_from_pinode(path, &port_wwn, 2188 &lun_nump, l_errnop)) != FPCFGA_OK) { 2189 return (FPCFGA_LIB_ERR); 2190 } 2191 2192 if ((ldata_ret = is_FCP_dev_ap_on_ldata_list(port_wwn, 2193 *lun_nump, lap->listp, &matchldp)) 2194 == FPCFGA_LIB_ERR) { 2195 S_FREE(port_wwn); 2196 return (ldata_ret); 2197 } 2198 2199 if (ldata_ret == FPCFGA_ACCESS_OK) { 2200 lap->chld_config = CFGA_STAT_CONFIGURED; 2201 matchldp->ldata.ap_o_state = 2202 CFGA_STAT_CONFIGURED; 2203 /* 2204 * Update the condition as unusable 2205 * if the pathinfo state is failed 2206 * or offline. 2207 */ 2208 if (((pstate = di_path_state(path)) == 2209 DI_PATH_STATE_OFFLINE) || 2210 (pstate == DI_PATH_STATE_FAULT)) { 2211 matchldp->ldata.ap_cond = 2212 CFGA_COND_UNUSABLE; 2213 } 2214 lap->ret = FPCFGA_OK; 2215 break; 2216 } 2217 2218 if (strncmp(port_wwn, lap->apidp->dyncomp, WWN_SIZE*2) 2219 != 0) { 2220 break; 2221 } 2222 /* 2223 * now create ldata for this particular path info node. 2224 * if port top is private loop and pathinfo is in 2225 * in offline state don't include to ldata list. 2226 */ 2227 if (((strcmp(lap->xport_type, 2228 FP_FC_PUBLIC_PORT_TYPE) == 0) || 2229 (strcmp(lap->xport_type, 2230 FP_FC_FABRIC_PORT_TYPE) == 0)) || 2231 (di_path_state(path) != 2232 DI_PATH_STATE_OFFLINE)) { 2233 lap->chld_config = CFGA_STAT_CONFIGURED; 2234 /* create ldata for this pi node. */ 2235 client_node = di_path_client_node(path); 2236 if (client_node == DI_NODE_NIL) { 2237 *l_errnop = errno; 2238 S_FREE(port_wwn); 2239 return (FPCFGA_LIB_ERR); 2240 } 2241 if ((construct_nodepath_from_dinode( 2242 client_node, &nodepath, l_errnop)) 2243 != FPCFGA_OK) { 2244 S_FREE(port_wwn); 2245 return (FPCFGA_LIB_ERR); 2246 } 2247 2248 listp = calloc(1, sizeof (ldata_list_t)); 2249 if (listp == NULL) { 2250 S_FREE(port_wwn); 2251 S_FREE(nodepath); 2252 lap->l_errno = errno; 2253 return (FPCFGA_LIB_ERR); 2254 } 2255 2256 clp = &listp->ldata; 2257 2258 /* Create logical and physical ap_id */ 2259 (void) snprintf(clp->ap_log_id, 2260 sizeof (clp->ap_log_id), "%s%s%s%s%d", 2261 lap->xport_logp, DYN_SEP, port_wwn, 2262 LUN_COMP_SEP, *lun_nump); 2263 (void) snprintf(clp->ap_phys_id, 2264 sizeof (clp->ap_phys_id), "%s%s%s%s%d", 2265 lap->apidp->xport_phys, DYN_SEP, port_wwn, 2266 LUN_COMP_SEP, *lun_nump); 2267 /* 2268 * We reached here since FCP dev is not found 2269 * in ldata list but path info node exists. 2270 * 2271 * Update the condition as failing 2272 * if the pathinfo state was normal. 2273 * Update the condition as unusable 2274 * if the pathinfo state is failed 2275 * or offline. 2276 */ 2277 clp->ap_class[0] = '\0'; /* Filled by libcfgadm */ 2278 clp->ap_o_state = CFGA_STAT_CONFIGURED; 2279 if (((pstate = di_path_state(path)) 2280 == DI_PATH_STATE_OFFLINE) || 2281 (pstate == DI_PATH_STATE_FAULT)) { 2282 clp->ap_cond = CFGA_COND_UNUSABLE; 2283 } else { 2284 clp->ap_cond = CFGA_COND_FAILING; 2285 } 2286 clp->ap_r_state = lap->xport_rstate; 2287 clp->ap_info[0] = '\0'; 2288 /* update ap_type and ap_info */ 2289 get_hw_info(client_node, clp); 2290 if (devctl_cmd(nodepath, FPCFGA_DEV_GETSTATE, 2291 &dctl_state, l_errnop) == FPCFGA_OK) { 2292 busy = ((dctl_state & DEVICE_BUSY) 2293 == DEVICE_BUSY) ? 1 : 0; 2294 } else { 2295 busy = 0; 2296 } 2297 clp->ap_busy = busy; 2298 clp->ap_status_time = (time_t)-1; 2299 2300 (void) insert_ldata_to_ldatalist(port_wwn, 2301 lun_nump, listp, &(lap->listp)); 2302 } 2303 break; 2304 case FPCFGA_STAT_ALL: 2305 if ((make_portwwn_luncomp_from_pinode(path, &port_wwn, 2306 &lun_nump, l_errnop)) != FPCFGA_OK) { 2307 return (FPCFGA_LIB_ERR); 2308 } 2309 2310 if ((ldata_ret = is_FCP_dev_ap_on_ldata_list(port_wwn, 2311 *lun_nump, lap->listp, &matchldp)) 2312 == FPCFGA_LIB_ERR) { 2313 S_FREE(port_wwn); 2314 return (ldata_ret); 2315 } 2316 2317 if (ldata_ret == FPCFGA_ACCESS_OK) { 2318 lap->chld_config = CFGA_STAT_CONFIGURED; 2319 matchldp->ldata.ap_o_state = 2320 CFGA_STAT_CONFIGURED; 2321 /* 2322 * Update the condition as unusable 2323 * if the pathinfo state is failed 2324 * or offline. 2325 */ 2326 if (((pstate = di_path_state(path)) == 2327 DI_PATH_STATE_OFFLINE) || 2328 (pstate == DI_PATH_STATE_FAULT)) { 2329 matchldp->ldata.ap_cond = 2330 CFGA_COND_UNUSABLE; 2331 } 2332 break; 2333 } 2334 /* 2335 * now create ldata for this particular path info node. 2336 * if port top is private loop and pathinfo is in 2337 * in offline state don't include to ldata list. 2338 */ 2339 if (((strcmp(lap->xport_type, 2340 FP_FC_PUBLIC_PORT_TYPE) == 0) || 2341 (strcmp(lap->xport_type, 2342 FP_FC_FABRIC_PORT_TYPE) == 0)) || 2343 (di_path_state(path) != 2344 DI_PATH_STATE_OFFLINE)) { 2345 lap->chld_config = CFGA_STAT_CONFIGURED; 2346 /* create ldata for this pi node. */ 2347 client_node = di_path_client_node(path); 2348 if (client_node == DI_NODE_NIL) { 2349 *l_errnop = errno; 2350 S_FREE(port_wwn); 2351 return (FPCFGA_LIB_ERR); 2352 } 2353 if ((construct_nodepath_from_dinode( 2354 client_node, &nodepath, l_errnop)) 2355 != FPCFGA_OK) { 2356 S_FREE(port_wwn); 2357 return (FPCFGA_LIB_ERR); 2358 } 2359 2360 listp = calloc(1, sizeof (ldata_list_t)); 2361 if (listp == NULL) { 2362 S_FREE(port_wwn); 2363 S_FREE(nodepath); 2364 lap->l_errno = errno; 2365 return (FPCFGA_LIB_ERR); 2366 } 2367 2368 clp = &listp->ldata; 2369 2370 /* Create logical and physical ap_id */ 2371 (void) snprintf(clp->ap_log_id, 2372 sizeof (clp->ap_log_id), "%s%s%s%s%d", 2373 lap->xport_logp, DYN_SEP, port_wwn, 2374 LUN_COMP_SEP, *lun_nump); 2375 (void) snprintf(clp->ap_phys_id, 2376 sizeof (clp->ap_phys_id), "%s%s%s%s%d", 2377 lap->apidp->xport_phys, DYN_SEP, port_wwn, 2378 LUN_COMP_SEP, *lun_nump); 2379 /* 2380 * We reached here since FCP dev is not found 2381 * in ldata list but path info node exists. 2382 * 2383 * Update the condition as failing 2384 * if the pathinfo state was normal. 2385 * Update the condition as unusable 2386 * if the pathinfo state is failed 2387 * or offline. 2388 */ 2389 clp->ap_class[0] = '\0'; /* Filled by libcfgadm */ 2390 clp->ap_o_state = CFGA_STAT_CONFIGURED; 2391 if (((pstate = di_path_state(path)) 2392 == DI_PATH_STATE_OFFLINE) || 2393 (pstate == DI_PATH_STATE_FAULT)) { 2394 clp->ap_cond = CFGA_COND_UNUSABLE; 2395 } else { 2396 clp->ap_cond = CFGA_COND_FAILING; 2397 } 2398 clp->ap_r_state = lap->xport_rstate; 2399 clp->ap_info[0] = '\0'; 2400 /* update ap_type and ap_info */ 2401 get_hw_info(client_node, clp); 2402 if (devctl_cmd(nodepath, FPCFGA_DEV_GETSTATE, 2403 &dctl_state, l_errnop) == FPCFGA_OK) { 2404 busy = ((dctl_state & DEVICE_BUSY) 2405 == DEVICE_BUSY) ? 1 : 0; 2406 } else { 2407 busy = 0; 2408 } 2409 clp->ap_busy = busy; 2410 clp->ap_status_time = (time_t)-1; 2411 2412 (void) insert_ldata_to_ldatalist(port_wwn, 2413 lun_nump, listp, &(lap->listp)); 2414 } 2415 break; 2416 case FPCFGA_STAT_FCA_PORT: 2417 if (di_path_state(path) != DI_PATH_STATE_OFFLINE) { 2418 lap->chld_config = CFGA_STAT_CONFIGURED; 2419 lap->ret = FPCFGA_OK; 2420 return (FPCFGA_OK); 2421 } 2422 } 2423 path = di_path_next_client(root, path); 2424 } while (path != DI_PATH_NIL); 2425 2426 lap->ret = FPCFGA_OK; 2427 S_FREE(port_wwn); 2428 S_FREE(nodepath); 2429 return (FPCFGA_OK); 2430 2431 } 2432 2433 /* 2434 * Routine for updating ldata list based on the state of device node. 2435 * When no matching accessible ldata is found a new ldata is created 2436 * with proper state information. 2437 * 2438 * The difference from do_stat_fc_dev() is 2439 * to handle FCP SCSI LUN information. Otherwise overall algorithm is 2440 * same. 2441 * 2442 * Overall algorithm: 2443 * If the device node is online and the matching ldata is found 2444 * the target device is updated with configued and unknown condition. 2445 * If the device node is offline or down and the matching ldata is found 2446 * the target device is updated with configued and unusable condition. 2447 * If the device node is online but the matching ldata is not found 2448 * the target device is created with configued and failing condition. 2449 * If the device node is offline or down and the matching ldata is not found 2450 * the target device is created with configued and unusable condition. 2451 */ 2452 static fpcfga_ret_t 2453 do_stat_FCP_dev( 2454 const di_node_t node, 2455 const char *nodepath, 2456 fpcfga_list_t *lap, 2457 int limited_stat) 2458 { 2459 uint_t dctl_state = 0, devinfo_state = 0; 2460 char *port_wwn = NULL; 2461 cfga_list_data_t *clp = NULL; 2462 cfga_busy_t busy; 2463 ldata_list_t *listp = NULL; 2464 ldata_list_t *matchldp = NULL; 2465 int l_errno = 0, *lun_nump; 2466 cfga_stat_t ostate; 2467 cfga_cond_t cond; 2468 fpcfga_ret_t ldata_ret; 2469 2470 assert(lap->apidp->xport_phys != NULL); 2471 assert(lap->xport_logp != NULL); 2472 2473 cond = CFGA_COND_UNKNOWN; 2474 2475 devinfo_state = di_state(node); 2476 ostate = dev_devinfo_to_occupant_state(devinfo_state); 2477 2478 /* 2479 * NOTE: The devctl framework cannot currently detect layered driver 2480 * opens, so the busy indicator is not very reliable. Also, 2481 * non-root users will not be able to determine busy 2482 * status (libdevice needs root permissions). 2483 * This should probably be fixed by adding a DI_BUSY to the di_state() 2484 * routine in libdevinfo. 2485 */ 2486 if (devctl_cmd(nodepath, FPCFGA_DEV_GETSTATE, &dctl_state, 2487 &l_errno) == FPCFGA_OK) { 2488 busy = ((dctl_state & DEVICE_BUSY) == DEVICE_BUSY) ? 1 : 0; 2489 } else { 2490 busy = 0; 2491 } 2492 2493 /* We only want to know device config state */ 2494 if (limited_stat) { 2495 if (((strcmp(lap->xport_type, FP_FC_FABRIC_PORT_TYPE) == 0) || 2496 strcmp(lap->xport_type, FP_FC_PUBLIC_PORT_TYPE) == 0)) { 2497 lap->chld_config = CFGA_STAT_CONFIGURED; 2498 } else { 2499 if (ostate != CFGA_STAT_UNCONFIGURED) { 2500 lap->chld_config = CFGA_STAT_CONFIGURED; 2501 } 2502 } 2503 return (FPCFGA_OK); 2504 } 2505 2506 /* 2507 * If child device is configured, see if it is accessible also 2508 * for FPCFGA_STAT_FC_DEV cmd. 2509 */ 2510 if ((make_portwwn_luncomp_from_dinode(node, &port_wwn, &lun_nump, 2511 &l_errno)) != FPCFGA_OK) { 2512 lap->l_errno = l_errno; 2513 return (FPCFGA_LIB_ERR); 2514 } 2515 2516 if ((ldata_ret = is_FCP_dev_ap_on_ldata_list(port_wwn, *lun_nump, 2517 lap->listp, &matchldp)) == FPCFGA_LIB_ERR) { 2518 lap->l_errno = l_errno; 2519 S_FREE(port_wwn); 2520 return (ldata_ret); 2521 } 2522 2523 if (lap->cmd == FPCFGA_STAT_FC_DEV) { 2524 switch (ostate) { 2525 case CFGA_STAT_CONFIGURED: 2526 /* 2527 * if configured and not accessble, the device is 2528 * till be displayed with failing condition. 2529 * return code should be FPCFGA_OK to display it. 2530 */ 2531 case CFGA_STAT_NONE: 2532 /* 2533 * If not unconfigured and not attached 2534 * the state is set to CFGA_STAT_NONE currently. 2535 * This is okay for the detached node due to 2536 * the driver being unloaded. 2537 * May need to define another state to 2538 * isolate the detached only state. 2539 * 2540 * handle the same way as configured. 2541 */ 2542 if (ldata_ret != FPCFGA_ACCESS_OK) { 2543 cond = CFGA_COND_FAILING; 2544 } 2545 lap->chld_config = CFGA_STAT_CONFIGURED; 2546 break; 2547 case CFGA_STAT_UNCONFIGURED: 2548 /* 2549 * if unconfigured - offline or down, 2550 * set to cond to unusable regardless of accessibility. 2551 * This behavior needs to be examined further. 2552 * When the device is not accessible the node 2553 * may get offline or down. In that case failing 2554 * cond may make more sense. 2555 * In anycase the ostate will be set to configured 2556 * configured. 2557 */ 2558 cond = CFGA_COND_UNUSABLE; 2559 /* 2560 * For fabric port the fca port is considered as 2561 * configured since user configured previously 2562 * for any existing node. Otherwise when the 2563 * device was accessible, the hba is considered as 2564 * configured. 2565 */ 2566 if (((strcmp(lap->xport_type, 2567 FP_FC_PUBLIC_PORT_TYPE) == 0) || 2568 (strcmp(lap->xport_type, 2569 FP_FC_FABRIC_PORT_TYPE) == 0)) || 2570 (lap->ret == FPCFGA_ACCESS_OK)) { 2571 lap->chld_config = CFGA_STAT_CONFIGURED; 2572 } else { 2573 /* 2574 * if lap->ret is okay there is at least 2575 * one matching ldata exist. Need to keep 2576 * okay ret to display the matching ones. 2577 */ 2578 if (lap->ret != FPCFGA_OK) { 2579 lap->ret = FPCFGA_APID_NOEXIST; 2580 } 2581 S_FREE(port_wwn); 2582 return (FPCFGA_OK); 2583 } 2584 break; 2585 default: 2586 break; 2587 } 2588 2589 /* if device found in dev_list, ldata already created. */ 2590 if (ldata_ret == FPCFGA_ACCESS_OK) { 2591 /* 2592 * if cond is not changed then don't update 2593 * condition to keep any condtion 2594 * from initial discovery. If the initial 2595 * cond was failed the same condition will be kept. 2596 */ 2597 if (cond != CFGA_COND_UNKNOWN) { 2598 matchldp->ldata.ap_cond = cond; 2599 } 2600 matchldp->ldata.ap_o_state = CFGA_STAT_CONFIGURED; 2601 matchldp->ldata.ap_busy = busy; 2602 /* update ap_info via inquiry */ 2603 clp = &matchldp->ldata; 2604 /* update ap_type and ap_info */ 2605 get_hw_info(node, clp); 2606 lap->ret = FPCFGA_OK; 2607 S_FREE(port_wwn); 2608 return (FPCFGA_OK); 2609 } 2610 } 2611 2612 /* 2613 * if cmd is stat all check ldata list 2614 * to see if the node exist on the dev list. Otherwise create 2615 * the list element. 2616 */ 2617 if (lap->cmd == FPCFGA_STAT_ALL) { 2618 switch (ldata_ret) { 2619 case FPCFGA_ACCESS_OK: 2620 /* node exists so set ostate to configured. */ 2621 lap->chld_config = CFGA_STAT_CONFIGURED; 2622 matchldp->ldata.ap_o_state = 2623 CFGA_STAT_CONFIGURED; 2624 matchldp->ldata.ap_busy = busy; 2625 clp = &matchldp->ldata; 2626 switch (ostate) { 2627 case CFGA_STAT_CONFIGURED: 2628 /* 2629 * If not unconfigured and not attached 2630 * the state is set to CFGA_STAT_NONE currently. 2631 * This is okay for the detached node due to 2632 * the driver being unloaded. 2633 * May need to define another state to 2634 * isolate the detached only state. 2635 */ 2636 case CFGA_STAT_NONE: 2637 /* update ap_type and ap_info */ 2638 get_hw_info(node, clp); 2639 break; 2640 /* 2641 * node is offline or down. 2642 * set cond to unusable. 2643 */ 2644 case CFGA_STAT_UNCONFIGURED: 2645 /* 2646 * if cond is not unknown 2647 * initial probing was failed 2648 * so don't update again. 2649 */ 2650 if (matchldp->ldata.ap_cond == 2651 CFGA_COND_UNKNOWN) { 2652 matchldp->ldata.ap_cond = 2653 CFGA_COND_UNUSABLE; 2654 } 2655 break; 2656 default: 2657 break; 2658 } 2659 /* node found in ldata list so just return. */ 2660 lap->ret = FPCFGA_OK; 2661 S_FREE(port_wwn); 2662 return (FPCFGA_OK); 2663 case FPCFGA_APID_NOACCESS: 2664 switch (ostate) { 2665 /* node is attached but not in dev list */ 2666 case CFGA_STAT_CONFIGURED: 2667 case CFGA_STAT_NONE: 2668 lap->chld_config = CFGA_STAT_CONFIGURED; 2669 cond = CFGA_COND_FAILING; 2670 break; 2671 /* 2672 * node is offline or down. 2673 * set cond to unusable. 2674 */ 2675 case CFGA_STAT_UNCONFIGURED: 2676 /* 2677 * For fabric port the fca port is 2678 * considered as configured since user 2679 * configured previously for any 2680 * existing node. 2681 */ 2682 cond = CFGA_COND_UNUSABLE; 2683 if ((strcmp(lap->xport_type, 2684 FP_FC_PUBLIC_PORT_TYPE) == 0) || 2685 (strcmp(lap->xport_type, 2686 FP_FC_FABRIC_PORT_TYPE) == 0)) { 2687 lap->chld_config = 2688 CFGA_STAT_CONFIGURED; 2689 } else { 2690 lap->ret = FPCFGA_OK; 2691 S_FREE(port_wwn); 2692 return (FPCFGA_OK); 2693 } 2694 break; 2695 default: 2696 /* 2697 * continue to create ldata_list struct for 2698 * this node 2699 */ 2700 break; 2701 } 2702 default: 2703 break; 2704 } 2705 } 2706 2707 listp = calloc(1, sizeof (ldata_list_t)); 2708 if (listp == NULL) { 2709 lap->l_errno = errno; 2710 S_FREE(port_wwn); 2711 return (FPCFGA_LIB_ERR); 2712 } 2713 2714 clp = &listp->ldata; 2715 2716 /* Create logical and physical ap_id */ 2717 (void) snprintf(clp->ap_log_id, sizeof (clp->ap_log_id), 2718 "%s%s%s%s%d", lap->xport_logp, DYN_SEP, port_wwn, 2719 LUN_COMP_SEP, *lun_nump); 2720 (void) snprintf(clp->ap_phys_id, sizeof (clp->ap_phys_id), 2721 "%s%s%s%s%d", lap->apidp->xport_phys, DYN_SEP, port_wwn, 2722 LUN_COMP_SEP, *lun_nump); 2723 clp->ap_class[0] = '\0'; /* Filled in by libcfgadm */ 2724 clp->ap_r_state = lap->xport_rstate; 2725 clp->ap_o_state = CFGA_STAT_CONFIGURED; 2726 clp->ap_cond = cond; 2727 clp->ap_busy = busy; 2728 clp->ap_status_time = (time_t)-1; 2729 clp->ap_info[0] = '\0'; 2730 2731 get_hw_info(node, clp); 2732 2733 (void) insert_ldata_to_ldatalist(port_wwn, lun_nump, listp, 2734 &(lap->listp)); 2735 2736 lap->ret = FPCFGA_OK; 2737 S_FREE(port_wwn); 2738 return (FPCFGA_OK); 2739 } 2740 2741 /* 2742 * Searches the ldata_list to find if the the input port_wwn exist. 2743 * 2744 * Input: port_wwn, ldata_list. 2745 * Return value: FPCFGA_APID_NOACCESS if not found on ldata_list. 2746 * FPCFGA_ACCESS_OK if found on ldata_list. 2747 */ 2748 static fpcfga_ret_t 2749 is_dyn_ap_on_ldata_list(const char *port_wwn, const ldata_list_t *listp, 2750 ldata_list_t **matchldpp, int *l_errnop) 2751 { 2752 char *dyn = NULL, *dyncomp = NULL; 2753 int len; 2754 ldata_list_t *tmplp; 2755 fpcfga_ret_t ret; 2756 2757 2758 ret = FPCFGA_APID_NOACCESS; 2759 2760 tmplp = (ldata_list_t *)listp; 2761 while (tmplp != NULL) { 2762 if ((dyn = GET_DYN(tmplp->ldata.ap_phys_id)) != NULL) { 2763 len = strlen(DYN_TO_DYNCOMP(dyn)) + 1; 2764 dyncomp = calloc(1, len); 2765 if (dyncomp == NULL) { 2766 *l_errnop = errno; 2767 ret = FPCFGA_LIB_ERR; 2768 break; 2769 } 2770 (void) strcpy(dyncomp, DYN_TO_DYNCOMP(dyn)); 2771 if (!(strncmp(port_wwn, dyncomp, WWN_SIZE*2))) { 2772 *matchldpp = tmplp; 2773 S_FREE(dyncomp); 2774 ret = FPCFGA_ACCESS_OK; 2775 break; 2776 } 2777 S_FREE(dyncomp); 2778 } 2779 tmplp = tmplp->next; 2780 } 2781 2782 return (ret); 2783 } 2784 2785 /* 2786 * Searches the ldata_list to find if the the input port_wwn and lun exist. 2787 * 2788 * Input: port_wwn, ldata_list. 2789 * Return value: FPCFGA_APID_NOACCESS if not found on ldata_list. 2790 * FPCFGA_ACCESS_OK if found on ldata_list. 2791 */ 2792 static fpcfga_ret_t 2793 is_FCP_dev_ap_on_ldata_list(const char *port_wwn, const int lun_num, 2794 ldata_list_t *ldatap, 2795 ldata_list_t **matchldpp) 2796 { 2797 ldata_list_t *curlp = NULL; 2798 char *dyn = NULL, *dyncomp = NULL; 2799 char *lun_dyn = NULL, *lunp = NULL; 2800 int ldata_lun; 2801 fpcfga_ret_t ret; 2802 2803 /* 2804 * if there is no list data just return the FCP dev list. 2805 * Normally this should not occur since list data should 2806 * be created through discoveredPort list. 2807 */ 2808 ret = FPCFGA_APID_NOACCESS; 2809 if (ldatap == NULL) { 2810 return (ret); 2811 } 2812 2813 dyn = GET_DYN(ldatap->ldata.ap_phys_id); 2814 if (dyn != NULL) dyncomp = DYN_TO_DYNCOMP(dyn); 2815 if ((dyncomp != NULL) && 2816 (strncmp(dyncomp, port_wwn, WWN_SIZE*2) == 0)) { 2817 lun_dyn = GET_LUN_DYN(dyncomp); 2818 if (lun_dyn != NULL) { 2819 lunp = LUN_DYN_TO_LUNCOMP(lun_dyn); 2820 if ((ldata_lun = atoi(lunp)) == lun_num) { 2821 *matchldpp = ldatap; 2822 return (FPCFGA_ACCESS_OK); 2823 } else if (ldata_lun > lun_num) { 2824 return (ret); 2825 } 2826 /* else continue */ 2827 } else { 2828 /* we have match without lun comp. */ 2829 *matchldpp = ldatap; 2830 return (FPCFGA_ACCESS_OK); 2831 } 2832 } 2833 2834 curlp = ldatap->next; 2835 2836 dyn = dyncomp = NULL; 2837 lun_dyn = lunp = NULL; 2838 while (curlp != NULL) { 2839 dyn = GET_DYN(curlp->ldata.ap_phys_id); 2840 if (dyn != NULL) dyncomp = DYN_TO_DYNCOMP(dyn); 2841 if ((dyncomp != NULL) && 2842 (strncmp(dyncomp, port_wwn, WWN_SIZE*2) == 0)) { 2843 lun_dyn = GET_LUN_DYN(dyncomp); 2844 if (lun_dyn != NULL) { 2845 lunp = LUN_DYN_TO_LUNCOMP(lun_dyn); 2846 if ((ldata_lun = atoi(lunp)) == lun_num) { 2847 *matchldpp = curlp; 2848 return (FPCFGA_ACCESS_OK); 2849 } else if (ldata_lun > lun_num) { 2850 return (ret); 2851 } 2852 /* else continue */ 2853 } else { 2854 /* we have match without lun comp. */ 2855 *matchldpp = curlp; 2856 return (FPCFGA_ACCESS_OK); 2857 } 2858 } 2859 dyn = dyncomp = NULL; 2860 lun_dyn = lunp = NULL; 2861 curlp = curlp->next; 2862 } 2863 2864 return (ret); 2865 2866 } 2867 2868 /* 2869 * This routine is called when a pathinfo without matching pwwn in dev_list 2870 * is found. 2871 */ 2872 static fpcfga_ret_t 2873 init_ldata_for_mpath_dev(di_path_t path, char *pwwn, int *l_errnop, 2874 fpcfga_list_t *lap) 2875 { 2876 ldata_list_t *listp = NULL; 2877 cfga_list_data_t *clp = NULL; 2878 size_t devlen; 2879 char *devpath; 2880 di_node_t client_node = DI_NODE_NIL; 2881 uint_t dctl_state = 0; 2882 cfga_busy_t busy; 2883 char *client_path; 2884 di_path_state_t pstate; 2885 2886 /* get the client node path */ 2887 if (path == DI_PATH_NIL) { 2888 return (FPCFGA_LIB_ERR); 2889 } 2890 client_node = di_path_client_node(path); 2891 if (client_node == DI_NODE_NIL) { 2892 return (FPCFGA_LIB_ERR); 2893 } 2894 if ((client_path = di_devfs_path(client_node)) == NULL) { 2895 return (FPCFGA_LIB_ERR); 2896 } 2897 devlen = strlen(DEVICES_DIR) + strlen(client_path) + 1; 2898 devpath = calloc(1, devlen); 2899 if (devpath == NULL) { 2900 di_devfs_path_free(client_path); 2901 *l_errnop = errno; 2902 return (FPCFGA_LIB_ERR); 2903 } 2904 (void) snprintf(devpath, devlen, "%s%s", DEVICES_DIR, client_path); 2905 2906 /* now need to create ldata for this dev */ 2907 listp = calloc(1, sizeof (ldata_list_t)); 2908 if (listp == NULL) { 2909 di_devfs_path_free(client_path); 2910 S_FREE(devpath); 2911 *l_errnop = errno; 2912 return (FPCFGA_LIB_ERR); 2913 } 2914 2915 clp = &listp->ldata; 2916 2917 /* Create logical and physical ap_id */ 2918 (void) snprintf(clp->ap_log_id, sizeof (clp->ap_log_id), "%s%s%s", 2919 lap->xport_logp, DYN_SEP, pwwn); 2920 (void) snprintf(clp->ap_phys_id, sizeof (clp->ap_phys_id), "%s%s%s", 2921 lap->apidp->xport_phys, DYN_SEP, pwwn); 2922 2923 /* Filled in by libcfgadm */ 2924 clp->ap_class[0] = '\0'; /* Filled by libcfgadm */ 2925 clp->ap_r_state = lap->xport_rstate; 2926 /* set to ostate to configured. */ 2927 clp->ap_o_state = CFGA_STAT_CONFIGURED; 2928 /* 2929 * This routine is called when a port WWN is not found in dev list 2930 * but path info node exists. 2931 * 2932 * Update the condition as failing if the pathinfo state was normal. 2933 * Update the condition as unusable if the pathinfo state is failed 2934 * or offline. 2935 */ 2936 if (((pstate = di_path_state(path)) == DI_PATH_STATE_OFFLINE) || 2937 (pstate == DI_PATH_STATE_FAULT)) { 2938 clp->ap_cond = CFGA_COND_UNUSABLE; 2939 } else { 2940 clp->ap_cond = CFGA_COND_FAILING; 2941 } 2942 clp->ap_status_time = (time_t)-1; 2943 /* update ap_type and ap_info */ 2944 get_hw_info(client_node, clp); 2945 2946 if (devctl_cmd(devpath, FPCFGA_DEV_GETSTATE, 2947 &dctl_state, l_errnop) == FPCFGA_OK) { 2948 busy = ((dctl_state & DEVICE_BUSY) == DEVICE_BUSY) ? 1 : 0; 2949 } else { 2950 busy = 0; 2951 } 2952 clp->ap_busy = busy; 2953 /* Link it in */ 2954 listp->next = lap->listp; 2955 lap->listp = listp; 2956 2957 di_devfs_path_free(client_path); 2958 S_FREE(devpath); 2959 2960 /* now return with ok status with ldata. */ 2961 lap->ret = FPCFGA_OK; 2962 return (FPCFGA_OK); 2963 } 2964 2965 /* 2966 * Initialize the cfga_list_data struct for an accessible device 2967 * from g_get_dev_list(). 2968 * 2969 * Input: fca port ldata. 2970 * Output: device cfga_list_data. 2971 * 2972 */ 2973 static fpcfga_ret_t 2974 init_ldata_for_accessible_dev(const char *dyncomp, uchar_t inq_type, 2975 fpcfga_list_t *lap) 2976 { 2977 ldata_list_t *listp = NULL; 2978 cfga_list_data_t *clp = NULL; 2979 int i; 2980 2981 listp = calloc(1, sizeof (ldata_list_t)); 2982 if (listp == NULL) { 2983 lap->l_errno = errno; 2984 return (FPCFGA_LIB_ERR); 2985 } 2986 2987 clp = &listp->ldata; 2988 2989 assert(dyncomp != NULL); 2990 2991 /* Create logical and physical ap_id */ 2992 (void) snprintf(clp->ap_log_id, sizeof (clp->ap_log_id), "%s%s%s", 2993 lap->xport_logp, DYN_SEP, dyncomp); 2994 2995 (void) snprintf(clp->ap_phys_id, sizeof (clp->ap_phys_id), "%s%s%s", 2996 lap->apidp->xport_phys, DYN_SEP, dyncomp); 2997 2998 clp->ap_class[0] = '\0'; /* Filled in by libcfgadm */ 2999 clp->ap_r_state = lap->xport_rstate; 3000 clp->ap_o_state = CFGA_STAT_UNCONFIGURED; 3001 clp->ap_cond = CFGA_COND_UNKNOWN; 3002 clp->ap_busy = 0; 3003 clp->ap_status_time = (time_t)-1; 3004 clp->ap_info[0] = '\0'; 3005 for (i = 0; i < N_DEVICE_TYPES; i++) { 3006 if (inq_type == device_list[i].itype) { 3007 (void) snprintf(clp->ap_type, sizeof (clp->ap_type), 3008 "%s", (char *)device_list[i].name); 3009 break; 3010 } 3011 } 3012 if (i == N_DEVICE_TYPES) { 3013 if (inq_type == ERR_INQ_DTYPE) { 3014 clp->ap_cond = CFGA_COND_FAILED; 3015 snprintf(clp->ap_type, sizeof (clp->ap_type), "%s", 3016 (char *)GET_MSG_STR(ERR_UNAVAILABLE)); 3017 } else { 3018 (void) snprintf(clp->ap_type, sizeof (clp->ap_type), 3019 "%s", "unknown"); 3020 } 3021 } 3022 3023 /* Link it in */ 3024 (void) insert_ldata_to_ldatalist(dyncomp, NULL, listp, &(lap->listp)); 3025 3026 return (FPCFGA_OK); 3027 } 3028 3029 /* 3030 * Initialize the cfga_list_data struct for an accessible FCP SCSI LUN device 3031 * from the report lun data. 3032 * 3033 * Input: fca port ldata. report lun info 3034 * Output: device cfga_list_data. 3035 * 3036 */ 3037 static fpcfga_ret_t 3038 init_ldata_for_accessible_FCP_dev( 3039 const char *port_wwn, 3040 int num_luns, 3041 struct report_lun_resp *resp_buf, 3042 fpcfga_list_t *lap, 3043 int *l_errnop) 3044 { 3045 ldata_list_t *listp = NULL, *listp_start = NULL, *listp_end = NULL, 3046 *prevlp = NULL, *curlp = NULL, *matchp_start = NULL, 3047 *matchp_end = NULL; 3048 cfga_list_data_t *clp = NULL; 3049 char *dyn = NULL, *dyncomp = NULL; 3050 uchar_t *lun_string; 3051 uint16_t lun_num; 3052 int i, j, str_ret; 3053 fpcfga_ret_t ret; 3054 char dtype[CFGA_TYPE_LEN]; 3055 struct scsi_inquiry *inq_buf; 3056 uchar_t peri_qual; 3057 cfga_cond_t cond = CFGA_COND_UNKNOWN; 3058 uchar_t lun_num_raw[SAM_LUN_SIZE]; 3059 3060 /* when number of lun is 0 it is not an error. so just return ok. */ 3061 if (num_luns == 0) { 3062 return (FPCFGA_OK); 3063 } 3064 3065 for (i = 0; i < num_luns; i++) { 3066 lun_string = (uchar_t *)&(resp_buf->lun_string[i]); 3067 memcpy(lun_num_raw, lun_string, sizeof (lun_num_raw)); 3068 if ((ret = get_standard_inq_data(lap->apidp->xport_phys, port_wwn, 3069 lun_num_raw, &inq_buf, l_errnop)) 3070 != FPCFGA_OK) { 3071 if (ret == FPCFGA_FCP_TGT_SEND_SCSI_FAILED) { 3072 (void) strlcpy(dtype, 3073 (char *)GET_MSG_STR(ERR_UNAVAILABLE), CFGA_TYPE_LEN); 3074 cond = CFGA_COND_FAILED; 3075 } else { 3076 S_FREE(inq_buf); 3077 return (FPCFGA_LIB_ERR); 3078 } 3079 } else { 3080 peri_qual = inq_buf->inq_dtype & FP_PERI_QUAL_MASK; 3081 /* 3082 * peripheral qualifier is not 0 so the device node should not 3083 * included in the ldata list. There should not be a device 3084 * node for the lun either. 3085 */ 3086 if (peri_qual != DPQ_POSSIBLE) { 3087 S_FREE(inq_buf); 3088 continue; 3089 } 3090 *dtype = NULL; 3091 for (j = 0; j < N_DEVICE_TYPES; j++) { 3092 if ((inq_buf->inq_dtype & DTYPE_MASK) 3093 == device_list[j].itype) { 3094 (void) strlcpy(dtype, (char *)device_list[j].name, 3095 CFGA_TYPE_LEN); 3096 break; 3097 } 3098 } 3099 if (*dtype == NULL) { 3100 (void) strlcpy(dtype, 3101 (char *)device_list[DTYPE_UNKNOWN_INDEX].name, 3102 CFGA_TYPE_LEN); 3103 } 3104 } 3105 /* 3106 * Followed FCP driver for getting lun number from report 3107 * lun data. 3108 * According to SAM-2 there are multiple address method for 3109 * FCP SCIS LUN. Logincal unit addressing, peripheral device 3110 * addressing, flat space addressing, and extended logical 3111 * unit addressing. 3112 * 3113 * as of 11/2001 FCP supports logical unit addressing and 3114 * peripheral device addressing even thoough 3 defined. 3115 * SSFCP_LUN_ADDRESSING 0x80 3116 * SSFCP_PD_ADDRESSING 0x00 3117 * SSFCP_VOLUME_ADDRESSING 0x40 3118 * 3119 * the menthod below is used by FCP when (lun_string[0] & 0xC0) 3120 * is either SSFCP_LUN_ADDRESSING or SSFCP_PD_ADDRESSING mode. 3121 */ 3122 lun_num = ((lun_string[0] & 0x3F) << 8) | lun_string[1]; 3123 listp = calloc(1, sizeof (ldata_list_t)); 3124 if (listp == NULL) { 3125 *l_errnop = errno; 3126 list_free(&listp_start); 3127 return (FPCFGA_LIB_ERR); 3128 } 3129 3130 clp = &listp->ldata; 3131 /* Create logical and physical ap_id */ 3132 (void) snprintf(clp->ap_log_id, sizeof (clp->ap_log_id), 3133 "%s%s%s%s%d", lap->xport_logp, DYN_SEP, port_wwn, 3134 LUN_COMP_SEP, lun_num); 3135 (void) snprintf(clp->ap_phys_id, sizeof (clp->ap_phys_id), 3136 "%s%s%s%s%d", lap->apidp->xport_phys, DYN_SEP, port_wwn, 3137 LUN_COMP_SEP, lun_num); 3138 (void) strncpy(clp->ap_type, dtype, strlen(dtype)); 3139 clp->ap_class[0] = '\0'; /* Filled in by libcfgadm */ 3140 clp->ap_r_state = lap->xport_rstate; 3141 clp->ap_o_state = CFGA_STAT_UNCONFIGURED; 3142 clp->ap_cond = cond; 3143 clp->ap_busy = 0; 3144 clp->ap_status_time = (time_t)-1; 3145 clp->ap_info[0] = '\0'; 3146 if (listp_start == NULL) { 3147 listp_start = listp; 3148 } else { 3149 if ((ret = insert_FCP_dev_ldata( 3150 port_wwn, lun_num, listp, 3151 &listp_start)) != FPCFGA_OK) { 3152 list_free(&listp_start); 3153 return (ret); 3154 } 3155 } 3156 listp = NULL; 3157 S_FREE(inq_buf); 3158 } 3159 3160 /* 3161 * list data can be null when device peripheral qualifier is not 0 3162 * for any luns. Return ok to continue. 3163 */ 3164 if (listp_start == NULL) { 3165 return (FPCFGA_OK); 3166 } 3167 /* 3168 * get the end of list for later uses. 3169 */ 3170 curlp = listp_start->next; 3171 prevlp = listp_start; 3172 while (curlp) { 3173 prevlp = curlp; 3174 curlp = curlp->next; 3175 } 3176 listp_end = prevlp; 3177 3178 /* 3179 * if there is no list data just return the FCP dev list. 3180 * Normally this should not occur since list data should 3181 * be created through g_get_dev_list(). 3182 */ 3183 if (lap->listp == NULL) { 3184 lap->listp = listp_start; 3185 for (listp = listp_start; listp != NULL; listp = listp->next) { 3186 listp->ldata.ap_cond = CFGA_COND_FAILING; 3187 } 3188 return (FPCFGA_OK); 3189 } 3190 3191 dyn = GET_DYN(lap->listp->ldata.ap_phys_id); 3192 if ((dyn != NULL) && ((dyncomp = DYN_TO_DYNCOMP(dyn)) != NULL)) { 3193 if ((str_ret = strncmp(dyncomp, port_wwn, WWN_SIZE*2)) == 0) { 3194 matchp_start = matchp_end = lap->listp; 3195 while (matchp_end->next != NULL) { 3196 dyn = GET_DYN( 3197 matchp_end->next->ldata.ap_phys_id); 3198 if ((dyn != NULL) && 3199 ((dyncomp = DYN_TO_DYNCOMP(dyn)) != NULL)) { 3200 if ((str_ret = strncmp(dyncomp, 3201 port_wwn, WWN_SIZE*2)) == 0) { 3202 matchp_end = matchp_end->next; 3203 } else { 3204 break; 3205 } 3206 } else { 3207 break; 3208 } 3209 } 3210 /* fillup inqdtype */ 3211 for (listp = listp_start; listp != NULL; 3212 listp = listp->next) { 3213 listp->ldata.ap_cond = 3214 lap->listp->ldata.ap_cond; 3215 } 3216 /* link the new elem of lap->listp. */ 3217 listp_end->next = matchp_end->next; 3218 /* free the one matching wwn. */ 3219 matchp_end->next = NULL; 3220 list_free(&matchp_start); 3221 /* link lap->listp to listp_start. */ 3222 lap->listp = listp_start; 3223 return (FPCFGA_OK); 3224 } else if (str_ret > 0) { 3225 for (listp = listp_start; listp != NULL; 3226 listp = listp->next) { 3227 listp->ldata.ap_cond = CFGA_COND_FAILING; 3228 } 3229 listp_end->next = lap->listp->next; 3230 lap->listp = listp_start; 3231 return (FPCFGA_OK); 3232 } 3233 } 3234 3235 prevlp = lap->listp; 3236 curlp = lap->listp->next; 3237 3238 dyn = dyncomp = NULL; 3239 while (curlp != NULL) { 3240 dyn = GET_DYN(curlp->ldata.ap_phys_id); 3241 if ((dyn != NULL) && 3242 ((dyncomp = DYN_TO_DYNCOMP(dyn)) != NULL)) { 3243 if ((str_ret = strncmp(dyncomp, port_wwn, 3244 WWN_SIZE*2)) == 0) { 3245 matchp_start = matchp_end = curlp; 3246 while (matchp_end->next != NULL) { 3247 dyn = GET_DYN( 3248 matchp_end->next->ldata.ap_phys_id); 3249 if ((dyn != NULL) && 3250 ((dyncomp = DYN_TO_DYNCOMP(dyn)) 3251 != NULL)) { 3252 if ((str_ret = strncmp(dyncomp, 3253 port_wwn, WWN_SIZE*2)) 3254 == 0) { 3255 matchp_end = 3256 matchp_end->next; 3257 } else { 3258 break; 3259 } 3260 } else { 3261 break; 3262 } 3263 } 3264 for (listp = listp_start; listp != NULL; 3265 listp = listp->next) { 3266 listp->ldata.ap_cond = curlp->ldata.ap_cond; 3267 } 3268 /* link the next elem to listp_end. */ 3269 listp_end->next = matchp_end->next; 3270 /* link prevlp to listp_start to drop curlp. */ 3271 prevlp->next = listp_start; 3272 /* free matching pwwn elem. */ 3273 matchp_end->next = NULL; 3274 list_free(&matchp_start); 3275 return (FPCFGA_OK); 3276 } else if (str_ret > 0) { 3277 for (listp = listp_start; listp != NULL; 3278 listp = listp->next) { 3279 /* 3280 * Dev not found from accessible 3281 * fc dev list but the node should 3282 * exist. Set to failing cond now 3283 * and check the node state later. 3284 */ 3285 listp->ldata.ap_cond = CFGA_COND_FAILING; 3286 } 3287 /* keep the cur elem by linking to list_end. */ 3288 listp_end->next = curlp; 3289 prevlp->next = listp_start; 3290 return (FPCFGA_OK); 3291 } 3292 } 3293 dyn = dyncomp = NULL; 3294 prevlp = curlp; 3295 curlp = curlp->next; 3296 } 3297 3298 prevlp->next = listp_start; 3299 for (listp = listp_start; listp != NULL; listp = listp->next) { 3300 listp->ldata.ap_cond = CFGA_COND_FAILING; 3301 } 3302 3303 return (FPCFGA_OK); 3304 3305 } 3306 3307 /* fill in device type, vid, pid from properties */ 3308 static void 3309 get_hw_info(di_node_t node, cfga_list_data_t *clp) 3310 { 3311 char *cp = NULL; 3312 char *inq_vid, *inq_pid; 3313 int i; 3314 3315 /* 3316 * if the type is not previously assigned with valid SCSI device type 3317 * check devinfo to find the type. 3318 * once device is configured it should have a valid device type. 3319 * device node is configured but no valid device type is found 3320 * the type will be set to unavailable. 3321 */ 3322 if (clp->ap_type != NULL) { 3323 /* 3324 * if the type is not one of defined SCSI device type 3325 * check devinfo to find the type. 3326 * 3327 * Note: unknown type is not a valid device type. 3328 * It is added in to the device list table to provide 3329 * constant string of "unknown". 3330 */ 3331 for (i = 0; i < (N_DEVICE_TYPES -1); i++) { 3332 if (strncmp((char *)clp->ap_type, (char *)device_list[i].name, 3333 sizeof (clp->ap_type)) == 0) { 3334 break; 3335 } 3336 } 3337 if (i == (N_DEVICE_TYPES - 1)) { 3338 cp = (char *)get_device_type(node); 3339 if (cp == NULL) { 3340 cp = (char *)GET_MSG_STR(ERR_UNAVAILABLE); 3341 } 3342 (void) snprintf(clp->ap_type, sizeof (clp->ap_type), "%s", 3343 S_STR(cp)); 3344 } 3345 } else { 3346 cp = (char *)get_device_type(node); 3347 if (cp == NULL) { 3348 cp = (char *)GET_MSG_STR(ERR_UNAVAILABLE); 3349 } 3350 (void) snprintf(clp->ap_type, sizeof (clp->ap_type), "%s", 3351 S_STR(cp)); 3352 } 3353 3354 /* 3355 * Fill in vendor and product ID. 3356 */ 3357 if ((di_prop_lookup_strings(DDI_DEV_T_ANY, node, 3358 "inquiry-product-id", &inq_pid) == 1) && 3359 (di_prop_lookup_strings(DDI_DEV_T_ANY, node, 3360 "inquiry-vendor-id", &inq_vid) == 1)) { 3361 (void) snprintf(clp->ap_info, sizeof (clp->ap_info), 3362 "%s %s", inq_vid, inq_pid); 3363 } 3364 } 3365 3366 /* 3367 * Get dtype from "inquiry-device-type" property. If not present, 3368 * derive it from minor node type 3369 */ 3370 static const char * 3371 get_device_type(di_node_t node) 3372 { 3373 char *name = NULL; 3374 int *inq_dtype; 3375 int i; 3376 3377 if (node == DI_NODE_NIL) { 3378 return (NULL); 3379 } 3380 3381 /* first, derive type based on inquiry property */ 3382 if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "inquiry-device-type", 3383 &inq_dtype) != -1) { 3384 int itype = (*inq_dtype) & DTYPE_MASK; 3385 3386 for (i = 0; i < N_DEVICE_TYPES; i++) { 3387 if (itype == device_list[i].itype) { 3388 name = (char *)device_list[i].name; 3389 break; 3390 } 3391 } 3392 /* 3393 * when found to be unknown type, set name to null to check 3394 * device minor node type. 3395 */ 3396 if (i == (N_DEVICE_TYPES - 1)) { 3397 name = NULL; 3398 } 3399 } 3400 3401 /* if property fails, use minor nodetype */ 3402 if (name == NULL) { 3403 char *nodetype; 3404 di_minor_t minor = di_minor_next(node, DI_MINOR_NIL); 3405 3406 if ((minor != DI_MINOR_NIL) && 3407 ((nodetype = di_minor_nodetype(minor)) != NULL)) { 3408 for (i = 0; i < N_DEVICE_TYPES; i++) { 3409 if (device_list[i].ntype && 3410 (strcmp(nodetype, device_list[i].ntype) 3411 == 0)) { 3412 name = (char *)device_list[i].name; 3413 break; 3414 } 3415 } 3416 } 3417 } 3418 3419 return (name); 3420 } 3421 3422 /* Transform list data to stat data */ 3423 fpcfga_ret_t 3424 list_ext_postprocess( 3425 ldata_list_t **llpp, 3426 int nelem, 3427 cfga_list_data_t **ap_id_list, 3428 int *nlistp, 3429 char **errstring) 3430 { 3431 cfga_list_data_t *ldatap = NULL; 3432 ldata_list_t *tmplp = NULL; 3433 int i = -1; 3434 3435 *ap_id_list = NULL; 3436 *nlistp = 0; 3437 3438 if (*llpp == NULL || nelem < 0) { 3439 return (FPCFGA_LIB_ERR); 3440 } 3441 3442 if (nelem == 0) { 3443 return (FPCFGA_APID_NOEXIST); 3444 } 3445 3446 ldatap = calloc(nelem, sizeof (cfga_list_data_t)); 3447 if (ldatap == NULL) { 3448 cfga_err(errstring, errno, ERR_LIST, 0); 3449 return (FPCFGA_LIB_ERR); 3450 } 3451 3452 /* Extract the list_data structures from the linked list */ 3453 tmplp = *llpp; 3454 for (i = 0; i < nelem && tmplp != NULL; i++) { 3455 ldatap[i] = tmplp->ldata; 3456 tmplp = tmplp->next; 3457 } 3458 3459 if (i < nelem || tmplp != NULL) { 3460 S_FREE(ldatap); 3461 return (FPCFGA_LIB_ERR); 3462 } 3463 3464 *nlistp = nelem; 3465 *ap_id_list = ldatap; 3466 3467 return (FPCFGA_OK); 3468 } 3469 3470 /* 3471 * Convert bus state to receptacle state 3472 */ 3473 static cfga_stat_t 3474 xport_devinfo_to_recep_state(uint_t xport_di_state) 3475 { 3476 cfga_stat_t rs; 3477 3478 switch (xport_di_state) { 3479 case DI_BUS_QUIESCED: 3480 case DI_BUS_DOWN: 3481 rs = CFGA_STAT_DISCONNECTED; 3482 break; 3483 /* 3484 * NOTE: An explicit flag for active should probably be added to 3485 * libdevinfo. 3486 */ 3487 default: 3488 rs = CFGA_STAT_CONNECTED; 3489 break; 3490 } 3491 3492 return (rs); 3493 } 3494 3495 /* 3496 * Convert device state to occupant state 3497 * if driver is attached the node is configured. 3498 * if offline or down the node is unconfigured. 3499 * if only driver detached it is none state which is treated the same 3500 * way as configured state. 3501 */ 3502 static cfga_stat_t 3503 dev_devinfo_to_occupant_state(uint_t dev_di_state) 3504 { 3505 /* Driver attached ? */ 3506 if ((dev_di_state & DI_DRIVER_DETACHED) != DI_DRIVER_DETACHED) { 3507 return (CFGA_STAT_CONFIGURED); 3508 } 3509 3510 if ((dev_di_state & DI_DEVICE_OFFLINE) == DI_DEVICE_OFFLINE || 3511 (dev_di_state & DI_DEVICE_DOWN) == DI_DEVICE_DOWN) { 3512 return (CFGA_STAT_UNCONFIGURED); 3513 } else { 3514 return (CFGA_STAT_NONE); 3515 } 3516 } 3517 3518 /* 3519 * Wrapper routine for inserting ldata to make an sorted ldata list. 3520 * 3521 * When show_FCP_dev option is given insert_FCP_dev_ldata() is called. 3522 * Otherwise insert_fc_dev_ldata() is called. 3523 */ 3524 static fpcfga_ret_t 3525 insert_ldata_to_ldatalist( 3526 const char *port_wwn, 3527 int *lun_nump, 3528 ldata_list_t *listp, 3529 ldata_list_t **ldatapp) 3530 { 3531 3532 if (lun_nump == NULL) { 3533 return (insert_fc_dev_ldata(port_wwn, listp, ldatapp)); 3534 } else { 3535 return 3536 (insert_FCP_dev_ldata(port_wwn, *lun_nump, listp, ldatapp)); 3537 } 3538 } 3539 3540 /* 3541 * Insert an input ldata to ldata list to make sorted ldata list. 3542 */ 3543 static fpcfga_ret_t 3544 insert_fc_dev_ldata( 3545 const char *port_wwn, 3546 ldata_list_t *listp, 3547 ldata_list_t **ldatapp) 3548 { 3549 ldata_list_t *prevlp = NULL, *curlp = NULL; 3550 char *dyn = NULL, *dyncomp = NULL; 3551 3552 if (*ldatapp == NULL) { 3553 *ldatapp = listp; 3554 return (FPCFGA_OK); 3555 } 3556 3557 dyn = GET_DYN((*ldatapp)->ldata.ap_phys_id); 3558 if (dyn != NULL) dyncomp = DYN_TO_DYNCOMP(dyn); 3559 if ((dyncomp != NULL) && 3560 (strncmp(dyncomp, port_wwn, WWN_SIZE*2) >= 0)) { 3561 listp->next = *ldatapp; 3562 *ldatapp = listp; 3563 return (FPCFGA_OK); 3564 } 3565 /* else continue */ 3566 3567 prevlp = *ldatapp; 3568 curlp = (*ldatapp)->next; 3569 3570 dyn = dyncomp = NULL; 3571 while (curlp != NULL) { 3572 dyn = GET_DYN(curlp->ldata.ap_phys_id); 3573 if (dyn != NULL) dyncomp = DYN_TO_DYNCOMP(dyn); 3574 if ((dyncomp != NULL) && 3575 (strncmp(dyncomp, port_wwn, WWN_SIZE*2) >= 0)) { 3576 listp->next = prevlp->next; 3577 prevlp->next = listp; 3578 return (FPCFGA_OK); 3579 } 3580 dyn = dyncomp = NULL; 3581 prevlp = curlp; 3582 curlp = curlp->next; 3583 } 3584 3585 /* add the ldata to the end of the list. */ 3586 prevlp->next = listp; 3587 return (FPCFGA_OK); 3588 } 3589 3590 /* 3591 * Insert an input ldata to ldata list to make sorted ldata list. 3592 */ 3593 static fpcfga_ret_t 3594 insert_FCP_dev_ldata( 3595 const char *port_wwn, 3596 int lun_num, 3597 ldata_list_t *listp, 3598 ldata_list_t **ldatapp) 3599 { 3600 ldata_list_t *prevlp = NULL, *curlp = NULL; 3601 char *dyn = NULL, *dyncomp = NULL; 3602 char *lun_dyn = NULL, *lunp = NULL; 3603 3604 if (*ldatapp == NULL) { 3605 *ldatapp = listp; 3606 return (FPCFGA_OK); 3607 } 3608 3609 dyn = GET_DYN((*ldatapp)->ldata.ap_phys_id); 3610 if (dyn != NULL) dyncomp = DYN_TO_DYNCOMP(dyn); 3611 if ((dyncomp != NULL) && 3612 (strncmp(dyncomp, port_wwn, WWN_SIZE*2) == 0)) { 3613 lun_dyn = GET_LUN_DYN(dyncomp); 3614 if (lun_dyn != NULL) { 3615 lunp = LUN_DYN_TO_LUNCOMP(lun_dyn); 3616 if ((atoi(lunp)) >= lun_num) { 3617 listp->next = *ldatapp; 3618 *ldatapp = listp; 3619 return (FPCFGA_OK); 3620 } 3621 } 3622 } else if ((dyncomp != NULL) && 3623 (strncmp(dyncomp, port_wwn, WWN_SIZE*2) > 0)) { 3624 listp->next = *ldatapp; 3625 *ldatapp = listp; 3626 return (FPCFGA_OK); 3627 } 3628 3629 prevlp = *ldatapp; 3630 curlp = (*ldatapp)->next; 3631 3632 dyn = dyncomp = NULL; 3633 lun_dyn = lunp = NULL; 3634 while (curlp != NULL) { 3635 dyn = GET_DYN(curlp->ldata.ap_phys_id); 3636 if (dyn != NULL) dyncomp = DYN_TO_DYNCOMP(dyn); 3637 3638 if ((dyncomp != NULL) && 3639 (strncmp(dyncomp, port_wwn, WWN_SIZE*2) == 0)) { 3640 lun_dyn = GET_LUN_DYN(dyncomp); 3641 if (lun_dyn != NULL) { 3642 lunp = LUN_DYN_TO_LUNCOMP(lun_dyn); 3643 if ((atoi(lunp)) >= lun_num) { 3644 listp->next = prevlp->next; 3645 prevlp->next = listp; 3646 return (FPCFGA_OK); 3647 } 3648 } 3649 /* else continue */ 3650 } else if ((dyncomp != NULL) && 3651 (strncmp(dyncomp, port_wwn, WWN_SIZE*2) > 0)) { 3652 listp->next = prevlp->next; 3653 prevlp->next = listp; 3654 return (FPCFGA_OK); 3655 } 3656 /* else continue */ 3657 3658 dyn = dyncomp = NULL; 3659 lun_dyn = lunp = NULL; 3660 prevlp = curlp; 3661 curlp = curlp->next; 3662 } 3663 3664 /* add the ldata to the end of the list. */ 3665 prevlp->next = listp; 3666 return (FPCFGA_OK); 3667 } 3668 3669 /* 3670 * This function will return the dtype for the given device 3671 * It will first issue a report lun to lun 0 and then it will issue a SCSI 3672 * Inquiry to the first lun returned by report luns. 3673 * 3674 * If everything is successful, the dtype will be returned with the peri 3675 * qualifier masked out. 3676 * 3677 * If either the report lun or the scsi inquiry fails, we will first check 3678 * the return status. If the return status is SCSI_DEVICE_NOT_TGT, then 3679 * we will assume this is a remote HBA and return an UNKNOWN DTYPE 3680 * for all other failures, we will return a dtype of ERR_INQ_DTYPE 3681 */ 3682 static uchar_t 3683 get_inq_dtype(char *xport_phys, char *dyncomp, HBA_HANDLE handle, 3684 HBA_PORTATTRIBUTES *portAttrs, HBA_PORTATTRIBUTES *discPortAttrs) { 3685 HBA_STATUS status; 3686 report_lun_resp_t *resp_buf; 3687 int num_luns = 0, ret, l_errno; 3688 uchar_t *lun_string; 3689 uint64_t lun = 0; 3690 struct scsi_inquiry inq; 3691 struct scsi_extended_sense sense; 3692 HBA_UINT8 scsiStatus; 3693 uint32_t inquirySize = sizeof (inq); 3694 uint32_t senseSize = sizeof (sense); 3695 3696 memset(&inq, 0, sizeof (inq)); 3697 memset(&sense, 0, sizeof (sense)); 3698 if ((ret = get_report_lun_data(xport_phys, dyncomp, 3699 &num_luns, &resp_buf, &sense, &l_errno)) 3700 != FPCFGA_OK) { 3701 /* 3702 * Checking the sense key data as well as the additional 3703 * sense key. The SES Node is not required to repond 3704 * to Report LUN. In the case of Minnow, the SES node 3705 * returns with KEY_ILLEGAL_REQUEST and the additional 3706 * sense key of 0x20. In this case we will blindly 3707 * send the SCSI Inquiry call to lun 0 3708 * 3709 * if we get any other error we will set the inq_type 3710 * appropriately 3711 */ 3712 if ((sense.es_key == KEY_ILLEGAL_REQUEST) && 3713 (sense.es_add_code == 0x20)) { 3714 lun = 0; 3715 } else { 3716 if (ret == FPCFGA_FCP_SEND_SCSI_DEV_NOT_TGT) { 3717 inq.inq_dtype = DTYPE_UNKNOWN; 3718 } else { 3719 inq.inq_dtype = ERR_INQ_DTYPE; 3720 } 3721 return (inq.inq_dtype); 3722 } 3723 } else { 3724 /* send the inquiry to the first lun */ 3725 lun_string = (uchar_t *)&(resp_buf->lun_string[0]); 3726 memcpy(&lun, lun_string, sizeof (lun)); 3727 S_FREE(resp_buf); 3728 } 3729 3730 memset(&sense, 0, sizeof (sense)); 3731 status = HBA_ScsiInquiryV2(handle, 3732 portAttrs->PortWWN, discPortAttrs->PortWWN, lun, 0, 0, 3733 &inq, &inquirySize, &scsiStatus, &sense, &senseSize); 3734 if (status == HBA_STATUS_OK) { 3735 inq.inq_dtype = inq.inq_dtype & DTYPE_MASK; 3736 } else if (status == HBA_STATUS_ERROR_NOT_A_TARGET) { 3737 inq.inq_dtype = DTYPE_UNKNOWN; 3738 } else { 3739 inq.inq_dtype = ERR_INQ_DTYPE; 3740 } 3741 return (inq.inq_dtype); 3742 } 3743