xref: /illumos-gate/usr/src/uts/common/io/fibre-channel/fca/qlc/ql_hba_fru.c (revision 5ee6ac27d4fd4c9412183aa8cc1143f36ae04a8c)
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 2010 QLogic Corporation */
23 
24 /*
25  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
26  */
27 
28 #pragma ident	"Copyright 2010 QLogic Corporation; ql_hba_fru.c"
29 
30 /*
31  * ISP2xxx Solaris Fibre Channel Adapter (FCA) driver source file.
32  *
33  * ***********************************************************************
34  * *									**
35  * *				NOTICE					**
36  * *		COPYRIGHT (C) 1996-2010 QLOGIC CORPORATION		**
37  * *			ALL RIGHTS RESERVED				**
38  * *									**
39  * ***********************************************************************
40  *
41  */
42 
43 /*
44  * Determine HBA FRU card information for T11 FC-HBA
45  */
46 
47 #include <ql_apps.h>
48 #include <ql_api.h>
49 #include <ql_debug.h>
50 #include <ql_ioctl.h>
51 #include <ql_xioctl.h>
52 
53 /*
54  * Temporary define until LV headers are updated
55  */
56 #ifndef	FC_HBA_PORTSPEED_8GBIT
57 #define	FC_HBA_PORTSPEED_8GBIT		16    /* 8 GBit/sec */
58 #endif
59 
60 /* Local prototypes */
61 static uint32_t ql_get_basedev_len(ql_adapter_state_t *, uint32_t *,
62     uint32_t *);
63 static ql_adapter_state_t *ql_search_basedev(ql_adapter_state_t *, uint32_t);
64 
65 /* Local structures */
66 static struct ql_known_models {
67 	uint16_t    ssid;		/* Subsystem ID */
68 	uint16_t    ssvid;		/* Subsystem Vendor ID */
69 	char	    model[256];
70 	char	    model_description[256];
71 
72 } models[] = {
73 	{
74 	    /* QLogic */
75 	    0x2, 0x1077, "QLA2200", "QLogic PCI to 1Gb FC, Single Channel"
76 	}, {
77 	    /* QLogic */
78 	    0x9, 0x1077, "QLA2300", "QLogic PCI to 2Gb FC, Single Channel"
79 	}, {
80 	    /* QLA2200, SUN2200 Amber */
81 	    0x4082, 0x1077, "375-3019-xx", "X6799A"
82 	}, {
83 	    /* QLA2212, SUN2212 Crystal+ */
84 	    0x4083, 0x1077, "375-3030-xx", "X6727A"
85 	}, {
86 	    /* QCP2202, SUNQCP2202 Diamond */
87 	    0x4084, 0x1077, "375-0118-xx", "X6748A"
88 	}, {
89 	    /* QLA2202FS, SUN2202FS Ivory */
90 	    0x4085, 0x1077, "375-3048-xx", "X6757A"
91 	}, {
92 	    /* QLogic */
93 	    0x100, 0x1077, "QLA2340",
94 	    "QLogic 133MHz PCI-X to 2Gb FC, Single Channel"
95 	}, {
96 	    /* QLogic */
97 	    0x101, 0x1077, "QLA2342",
98 	    "QLogic 133MHz PCI-X to 2Gb FC, Dual Channel"
99 	}, {
100 	    /* QLogic */
101 	    0x102, 0x1077, "QLA2344",
102 	    "QLogic 133MHz PCI-X to 2Gb FC, Quad Channel"
103 	}, {
104 	    /* QLogic */
105 	    0x103, 0x1077, "QCP2342", "QLogic cPCI to 2Gb FC, Dual Channel"
106 	}, {
107 	    /* QLogic */
108 	    0x104, 0x1077, "QSB2340", "QLogic SBUS to 2Gb FC, Single Channel"
109 	}, {
110 	    /* QLogic */
111 	    0x105, 0x1077, "QSB2342", "QLogic SBUS to 2Gb FC, Dual Channel"
112 	}, {
113 	    /* QLA2310, SUN-66MHz PCI-X to 2Gb FC, Single Channel, Amber 2 */
114 	    0x0106, 0x1077, "375-3102-xx", "SG-XPCI1FC-QF2 (X6767A)"
115 	}, {
116 	    /* QLogic */
117 	    0x109, 0x1077, "QCP2340", "QLogic cPCI to 2Gb FC, Single Channel"
118 	}, {
119 	    /* QLA2342, SUN-133MHz PCI-X to 2Gb FC, Dualchannel, Crystal 2A */
120 	    0x010A, 0x1077, "375-3108-xx", "SG-XPCI2FC-QF2 (X6768A)"
121 	}, {
122 	    /* QLogic */
123 	    0x115, 0x1077, "QLA2360",
124 	    "QLogic 133MHz PCI-X to 2Gb FC, Single Channel"
125 	}, {
126 	    /* QLogic */
127 	    0x116, 0x1077, "QLA2362",
128 	    "QLogic 133MHz PCI-X to 2Gb FC, Dual Channel"
129 	}, {
130 	    /* QLogic */
131 	    0x117, 0x1077, "QLE2360",
132 	    "QLogic PCI-Express to 2Gb FC, Single Channel"
133 	}, {
134 	    /* QLogic */
135 	    0x118, 0x1077, "QLE2362",
136 	    "QLogic PCI Express to 2Gb FC, Dual Channel"
137 	}, {
138 	    /* QLogic */
139 	    0x119, 0x1077, "QLA200",
140 	    "QLogic 133MHz PCI-X to 2Gb FC, Single Channel"
141 	}, {
142 	    /* QLogic */
143 	    0x11c, 0x1077, "QLA200P",
144 	    "QLogic 133MHz PCI-X to 2Gb FC, Single Channel"
145 	}, {
146 	    /* QLogic */
147 	    0x12f, 0x1077, "QLA210",
148 	    "QLogic 133MHz PCI-X to 2Gb FC, Single Channel"
149 	}, {
150 	    /* QLogic */
151 	    0x130, 0x1077, "EMC250-051-900",
152 	    "QLogic 133MHz PCI-X to 2Gb FC, Single Channel"
153 	}, {
154 	    /* QLA210, SUN-133MHz PCI-X to 2Gb FC, Single Channel, Prism */
155 	    0x132, 0x1077, "375-32X3-01", "SG-PCI1FC-QLC"
156 	}, {
157 	    /* QLogic */
158 	    0x13e, 0x1077, "QLE210",
159 	    "QLogic PCI Express 2Gb FC, Single Channel"
160 	}, {
161 	    /* Sun */
162 	    0x149, 0x1077, "QLA2340",
163 	    "SUN - 133MHz PCI-X to 2Gb FC, Single Channel"
164 	}, {
165 	    /* HP */
166 	    0x100, 0x0e11, "QLA2340-HP", "PCIX to 2Gb FC, Single Channel"
167 	}, {
168 	    /* HP */
169 	    0x101, 0x0e11, "QLA2342-HP", "PCIX to 2Gb FC, Dual Channel"
170 	}, {
171 	    /* HP */
172 	    0x103, 0x0e11, "QLA2312-HP",
173 	    "HP Bladed Server Balcony Card - HP BalcnL"
174 	}, {
175 	    /* HP */
176 	    0x104, 0x0e11, "QLA2312-HP", "HP Bladed Server - HP MezzF"
177 	}, {
178 	    /* HP */
179 	    0x105, 0x0e11, "QLA2312-HP", "HP Bladed Server - HP BalcnL"
180 	}, {
181 	    /* HP */
182 	    0x106, 0x0e11, "QLA2312-HP", "HP Bladed Server - HP BalcnF"
183 	}, {
184 	    /* HP */
185 	    0x107, 0x0e11, "QLA2312-HP", "HP Bladed Server"
186 	}, {
187 	    /* HP */
188 	    0x108, 0x0e11, "QLA2312-HP", "HP Bladed Server"
189 	}, {
190 	    /* IBM FCEC */
191 	    0x27d, 0x1014, "IBM-FCEC",
192 	    "IBM eServer Blade Center FC Expansion Card"
193 	}, {
194 	    /* IBM FCEC */
195 	    0x2fb, 0x1014, "IBM-FCEC",
196 	    "IBM eServer Blade Center FC SFF Expansion Card"
197 	}, {
198 	    /* Intel */
199 	    0x34ba, 0x8086, "Intel SBFCM",
200 	    "Intel Server FC Expansion Card SBFCM"
201 	}, {
202 	    /* Intel */
203 	    0x34a0, 0x8086, "Intel SBEFCM",
204 	    "Intel Server SFF FC Expansion Card SBFCM"
205 	}, {
206 	    /* FCI/O */
207 	    0x1051, 0x1734, "FCI/O-CARD2Gb/s",
208 	    "FSC-Quanta FC I/O-Card 2GBit/s"
209 	}, {
210 	    /* Dell */
211 	    0x18a, 0x1028, "FCI/O-CARD2Gb/s", "Dell Glacier Blade Server"
212 	}, {
213 	    /* end of list */
214 	    0, 0, 0, 0, 0, 0
215 	} };
216 
217 /*
218  * ql_populate_hba_fru_details
219  *	Sets up HBA fru information for UL utilities
220  *	(cfgadm, fcinfo, et. al.)
221  *
222  * Input:
223  *	ha		= adapter state structure
224  *	port_info	= ptr to LV port strcture.
225  *
226  * Returns:
227  *
228  * Context:
229  *	Kernel context.
230  */
231 void
232 ql_populate_hba_fru_details(ql_adapter_state_t *ha,
233     fc_fca_port_info_t *port_info)
234 {
235 	fca_port_attrs_t	*attrs = &port_info->pi_attrs;
236 	uint16_t		chip = ha->device_id;
237 	uint16_t		model = ha->subsys_id;
238 	uint16_t		ssdevid = ha->subven_id;
239 	size_t			vlen;
240 	int32_t			i;
241 
242 	QL_PRINT_3(CE_CONT, "(%d): started\n", ha->instance);
243 
244 	attrs = &port_info->pi_attrs;
245 
246 	/* Constants */
247 	(void) snprintf(attrs->manufacturer, FCHBA_MANUFACTURER_LEN,
248 	    "QLogic Corp.");
249 	(void) snprintf(attrs->driver_name, FCHBA_DRIVER_NAME_LEN,
250 	    "%s", QL_NAME);
251 	(void) snprintf(attrs->driver_version, FCHBA_DRIVER_VERSION_LEN,
252 	    "%s", ha->adapter_stats->revlvl.qlddv);
253 
254 	if ((i = ql_vpd_lookup(ha, (uint8_t *)VPD_TAG_SN, (uint8_t *)
255 	    attrs->serial_number, FCHBA_SERIAL_NUMBER_LEN)) == -1) {
256 		attrs->serial_number[0] = '\0';
257 	}
258 	attrs->hardware_version[0] = '\0';
259 
260 	/* Dynamic data */
261 	(void) snprintf(attrs->firmware_version, FCHBA_FIRMWARE_VERSION_LEN,
262 	    "%02d.%02d.%02d", ha->fw_major_version, ha->fw_minor_version,
263 	    ha->fw_subminor_version);
264 
265 	CACHE_LOCK(ha);
266 
267 	/* Report FCode / BIOS / EFI version(s). */
268 	if (ha->fcache != NULL) {
269 		uint32_t	types = FTYPE_BIOS|FTYPE_FCODE|FTYPE_EFI;
270 		ql_fcache_t	*fptr = ha->fcache;
271 		int8_t		*orv = &*attrs->option_rom_version;
272 
273 		while ((fptr != NULL) && (types != 0)) {
274 			/* Get the next image */
275 			if ((fptr = ql_get_fbuf(ha->fcache, types)) != NULL) {
276 
277 				switch (fptr->type) {
278 				case FTYPE_FCODE:
279 					(void) snprintf(orv,
280 					    FCHBA_OPTION_ROM_VERSION_LEN,
281 					    "%s fcode: %s;", orv, fptr->verstr);
282 					break;
283 				case FTYPE_BIOS:
284 					(void) snprintf(orv,
285 					    FCHBA_OPTION_ROM_VERSION_LEN,
286 					    "%s BIOS: %s;", orv, fptr->verstr);
287 					break;
288 				case FTYPE_EFI:
289 					(void) snprintf(orv,
290 					    FCHBA_OPTION_ROM_VERSION_LEN,
291 					    "%s EFI: %s;", orv, fptr->verstr);
292 					break;
293 				default:
294 					EL(ha, "ignoring ftype: %xh\n",
295 					    fptr->type);
296 					break;
297 				}
298 				types &= ~(fptr->type);
299 			}
300 		}
301 	}
302 
303 	CACHE_UNLOCK(ha);
304 
305 	if (strlen(attrs->option_rom_version) == 0) {
306 		int		rval = -1;
307 		uint32_t	i = 0;
308 		caddr_t		fcode_ver_buf = NULL;
309 
310 		if (CFG_IST(ha, CFG_CTRL_2200)) {
311 			/*LINTED [Solaris DDI_DEV_T_ANY Lint warning]*/
312 			rval = ddi_getlongprop(DDI_DEV_T_ANY, ha->dip,
313 			    DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "version",
314 			    (caddr_t)&fcode_ver_buf, (int32_t *)&i);
315 		}
316 
317 		(void) snprintf(attrs->option_rom_version,
318 		    FCHBA_OPTION_ROM_VERSION_LEN, "%s",
319 		    (rval == DDI_PROP_SUCCESS ? fcode_ver_buf :
320 		    "No boot image detected"));
321 
322 		if (fcode_ver_buf != NULL) {
323 			kmem_free(fcode_ver_buf, (size_t)i);
324 		}
325 
326 	}
327 
328 	attrs->vendor_specific_id = ha->adapter_features;
329 	attrs->max_frame_size = CFG_IST(ha, CFG_CTRL_24258081) ?
330 	    (ha->init_ctrl_blk.cb24.max_frame_length[1] << 8 |
331 	    ha->init_ctrl_blk.cb24.max_frame_length[0]) :
332 	    (ha->init_ctrl_blk.cb.max_frame_length[1] << 8 |
333 	    ha->init_ctrl_blk.cb.max_frame_length[0]);
334 	attrs->supported_cos = 0x10000000; /* Class 3 only */
335 
336 	switch (chip & 0xFF00) {
337 	case 0x2200:
338 		attrs->supported_speed = FC_HBA_PORTSPEED_1GBIT;
339 		break;
340 	case 0x2300:
341 		attrs->supported_speed = FC_HBA_PORTSPEED_2GBIT |
342 		    FC_HBA_PORTSPEED_1GBIT;
343 		break;
344 	case 0x2400:
345 	case 0x8400:
346 		attrs->supported_speed = FC_HBA_PORTSPEED_4GBIT |
347 		    FC_HBA_PORTSPEED_2GBIT | FC_HBA_PORTSPEED_1GBIT;
348 		break;
349 	case 0x8000:
350 		attrs->supported_speed = FC_HBA_PORTSPEED_10GBIT;
351 		break;
352 	case 0x2500:
353 		attrs->supported_speed = FC_HBA_PORTSPEED_8GBIT |
354 		    FC_HBA_PORTSPEED_4GBIT | FC_HBA_PORTSPEED_2GBIT |
355 		    FC_HBA_PORTSPEED_1GBIT;
356 
357 		/*
358 		 * Correct supported speeds based on type of
359 		 * sfp that is present
360 		 */
361 		switch (ha->sfp_stat) {
362 		case 2:
363 		case 4:
364 			/* 4GB sfp */
365 			attrs->supported_speed &= ~FC_HBA_PORTSPEED_8GBIT;
366 			break;
367 		case 3:
368 		case 5:
369 			/* 8GB sfp */
370 			attrs->supported_speed &= ~FC_HBA_PORTSPEED_1GBIT;
371 			break;
372 		default:
373 			EL(ha, "sfp_stat: %xh\n", ha->sfp_stat);
374 			break;
375 
376 		}
377 
378 		break;
379 	case 0x5400:
380 		if (model == 0x13e) {
381 			/* QLE210 */
382 			attrs->supported_speed = FC_HBA_PORTSPEED_2GBIT;
383 		} else {
384 			attrs->supported_speed = FC_HBA_PORTSPEED_4GBIT;
385 		}
386 		break;
387 	case 0x6300:
388 		attrs->supported_speed = FC_HBA_PORTSPEED_2GBIT;
389 		break;
390 	default:
391 		attrs->supported_speed = FC_HBA_PORTSPEED_UNKNOWN;
392 		break;
393 	}
394 
395 	/* Use parent dip as adapter identifier */
396 	attrs->hba_fru_details.low = 0x514C6F6769630000; /* QLogic */
397 
398 	if (ha->fru_hba_index == 0) {
399 		EL(ha, "unable to generate high_fru details from "
400 		    "device path: %s\n", ha->devpath);
401 		attrs->hba_fru_details.low = 0;
402 		attrs->hba_fru_details.high = 0;
403 		attrs->hba_fru_details.port_index = 0;
404 	} else {
405 		attrs->hba_fru_details.high = ha->fru_hba_index;
406 		attrs->hba_fru_details.port_index = ha->fru_port_index;
407 	}
408 
409 	/*
410 	 * Populate the model info. Legacy (22xx, 23xx, 63xx) do not
411 	 * have vpd info, so use the hard coded table. Anything else
412 	 * has VPD (or is suppose to have VPD), so use that. For both
413 	 * cases, if the model isn't found, use defaults.
414 	 */
415 
416 	switch (chip & 0xFF00) {
417 	case 0x2200:
418 	case 0x2300:
419 	case 0x6300:
420 		/* Table based data */
421 		for (i = 0; models[i].ssid; i++) {
422 			if ((model == models[i].ssid) &&
423 			    (ssdevid == models[i].ssvid)) {
424 				break;
425 			}
426 		}
427 
428 		if (models[i].ssid) {
429 			(void) snprintf(attrs->model, FCHBA_MODEL_LEN, "%s",
430 			    models[i].model);
431 			(void) snprintf(attrs->model_description,
432 			    FCHBA_MODEL_DESCRIPTION_LEN, "%s",
433 			    models[i].model_description);
434 		} else {
435 			(void) snprintf(attrs->model, FCHBA_MODEL_LEN,
436 			    "%x", chip);
437 			(void) snprintf(attrs->model_description,
438 			    FCHBA_MODEL_DESCRIPTION_LEN, "%x", chip);
439 		}
440 
441 		/* Special model handling for RoHS version of the HBA */
442 		if (models[i].ssid == 0x10a && ha->adapInfo[10] ==
443 		    (uint8_t)0x36) {
444 			(void) snprintf(attrs->model, FCHBA_MODEL_LEN, "%s",
445 			    "375-3363-xx");
446 			(void) snprintf(attrs->model_description,
447 			    FCHBA_MODEL_DESCRIPTION_LEN, "%s",
448 			    "SG-XPCI2FC-QF2-Z");
449 		}
450 		break;
451 
452 	case 0x2400:
453 	case 0x2500:
454 	case 0x5400:
455 	case 0x8400:
456 	case 0x8000:
457 	default:
458 		if ((i = ql_vpd_lookup(ha, (uint8_t *)VPD_TAG_PN,
459 		    (uint8_t *)attrs->model, FCHBA_MODEL_LEN)) >= 0) {
460 			(void) ql_vpd_lookup(ha, (uint8_t *)VPD_TAG_PRODID,
461 			    (uint8_t *)attrs->model_description,
462 			    FCHBA_MODEL_DESCRIPTION_LEN);
463 		} else {
464 			(void) snprintf(attrs->model, FCHBA_MODEL_LEN,
465 			    "%x", chip);
466 			(void) snprintf(attrs->model_description,
467 			    FCHBA_MODEL_DESCRIPTION_LEN, "%x", chip);
468 		}
469 		break;
470 	}
471 
472 	/*
473 	 * Populate the LV symbolic node and port name strings
474 	 *
475 	 * Symbolic node name format is:
476 	 *	<hostname>
477 	 *
478 	 * Symbolic port name format is:
479 	 *	<driver_name>(<instance>,<vp index>)
480 	 */
481 	vlen = (strlen(utsname.nodename) > FCHBA_SYMB_NAME_LEN ?
482 	    FCHBA_SYMB_NAME_LEN : strlen(utsname.nodename));
483 	(void) snprintf((int8_t *)attrs->sym_node_name, vlen, "%s",
484 	    utsname.nodename);
485 
486 	vlen = (strlen(QL_NAME) + 9 > FCHBA_SYMB_NAME_LEN ?
487 	    FCHBA_SYMB_NAME_LEN : strlen(QL_NAME) + 9);
488 	(void) snprintf((int8_t *)attrs->sym_port_name, vlen,
489 	    "%s(%d,%d)", QL_NAME, ha->instance, ha->vp_index);
490 
491 	QL_PRINT_3(CE_CONT, "(%d): done\n", ha->instance);
492 }
493 
494 /*
495  * ql_setup_fruinfo
496  *	Generates common id's for instances on the same
497  *	physical HBA.
498  *
499  * Input:
500  *	ha =  adapter state structure
501  *
502  * Returns:
503  *
504  * Context:
505  *	Kernel context.
506  */
507 void
508 ql_setup_fruinfo(ql_adapter_state_t *ha)
509 {
510 	uint32_t 		mybasedev_len;
511 	ql_adapter_state_t	*base_ha = NULL;
512 
513 	QL_PRINT_3(CE_CONT, "(%d): started\n", ha->instance);
514 
515 	/*
516 	 * To generate common id for instances residing on the
517 	 * the same HBA, the devpath for each instance is parsed
518 	 * and those instances which have matching base devpaths are
519 	 * given same hba_index, and each port on the same hba are
520 	 * then assigned unique port_indexs based on the devpath.
521 	 */
522 
523 	/*
524 	 * Get this ha's basedev path and its port index
525 	 */
526 	if (ql_get_basedev_len(ha, &mybasedev_len, &ha->fru_port_index) == 0) {
527 
528 		GLOBAL_STATE_LOCK();
529 
530 		/*
531 		 * Search for this basedev against all of the
532 		 * ha in the ql_hba global list. If found one
533 		 * then we are part of other adapter in the
534 		 * ql_hba list and hence use that ha's hba_index.
535 		 * If not create a new one from the global hba index.
536 		 */
537 		base_ha = ql_search_basedev(ha, mybasedev_len);
538 		if (base_ha != NULL && base_ha->fru_hba_index != 0) {
539 			ha->fru_hba_index = base_ha->fru_hba_index;
540 		} else {
541 			ha->fru_hba_index = ql_gfru_hba_index++;
542 		}
543 
544 		if (CFG_IST(ha, CFG_CTRL_8081)) {
545 			/*
546 			 * The FC functions on 81xx hbas are functions 2 and 3
547 			 * while the Nic functions occupy 0 and 1.  Adjust
548 			 * fru port index to be like previous FCAs.
549 			 */
550 			ha->fru_port_index = ha->flags & FUNCTION_1 ? 1 : 0;
551 		}
552 
553 		GLOBAL_STATE_UNLOCK();
554 
555 	} else {
556 		ha->fru_hba_index = 0;
557 		ha->fru_port_index = 0;
558 	}
559 
560 	QL_PRINT_3(CE_CONT, "(%d): done\n", ha->instance);
561 }
562 
563 /*
564  *  ql_get_basedev_len
565  *
566  *	Gets the length of the base device name in the
567  *	devpath of the current instance.
568  *
569  * Input:
570  *	ha		- adapter state pointer.
571  *	basedev_len	- pointer to the integer which
572  *			  holds the calculated length.
573  *	port_index	- pointer to the integer which
574  *			  contains the port index of
575  *			  for this device.
576  * Returns:
577  *	0 if successfully parsed, -1 otherwise.
578  *
579  * Context:
580  *	Kernel context.
581  */
582 static uint32_t
583 ql_get_basedev_len(ql_adapter_state_t *ha, uint32_t *basedev_len,
584     uint32_t *port_index)
585 {
586 	int32_t		dev_off;
587 	int32_t		port_off;
588 	int8_t		*devstr;
589 
590 	QL_PRINT_3(CE_CONT, "(%d): started\n", ha->instance);
591 
592 	if (ha->devpath == NULL) {
593 		return ((uint32_t)-1);
594 	}
595 
596 	dev_off = (int32_t)(strlen(ha->devpath) - 1);
597 	port_off = -1;
598 
599 	/* Until we reach the first char or a '@' char in the path */
600 	while ((dev_off >= 0) && (ha->devpath[dev_off] != '@')) {
601 
602 		if (ha->devpath[dev_off] == ',') {
603 			port_off = dev_off + 1;
604 		}
605 
606 		dev_off--;
607 	}
608 
609 	if (dev_off < 0) {
610 		EL(ha, "Invalid device path '%s'. Cannot get basedev\n",
611 		    ha->devpath);
612 		return ((uint32_t)-1);
613 	}
614 
615 	if (port_off == -1) {
616 		*port_index = 0;
617 		*basedev_len = (uint32_t)strlen(ha->devpath);
618 	} else {
619 		/* Get the port index */
620 		devstr = ha->devpath + port_off;
621 		*port_index = stoi(&devstr);
622 		if (*port_index == 0) {
623 			EL(ha, "Invalid device path '%s'. Cannot get "
624 			    "port_index\n", ha->devpath);
625 			return ((uint32_t)-1);
626 		}
627 
628 		*basedev_len = (uint32_t)(port_off - 1);
629 	}
630 
631 	QL_PRINT_3(CE_CONT, "(%d): done\n", ha->instance);
632 
633 	return (0);
634 }
635 
636 /*
637  * ql_search_basedev
638  *	Searches the list of ha instances to find which
639  *	ha instance has same base device path as input's.
640  *
641  * Input:
642  *	myha 		= current adapter state pointer.
643  *	mybasedev_len	= Length of the base device in the
644  *			  device path name.
645  *
646  * Returns:
647  *	If match	= ptr to matching ha structure.
648  *	If no match	= NULL ptr.
649  *
650  * Context:
651  *	Kernel context.
652  */
653 static ql_adapter_state_t *
654 ql_search_basedev(ql_adapter_state_t *myha, uint32_t mybasedev_len)
655 {
656 	ql_link_t		*link;
657 	ql_adapter_state_t	*ha;
658 	uint32_t		basedev_len, port_index;
659 
660 	QL_PRINT_3(CE_CONT, "(%d): started\n", myha->instance);
661 
662 	for (link = ql_hba.first; link != NULL; link = link->next) {
663 
664 		ha = link->base_address;
665 
666 		if (ha == NULL) {
667 			EL(myha, "null ha link detected!\n");
668 			return (NULL);
669 		}
670 
671 		if (ha == myha) {
672 			continue;
673 		}
674 
675 		if (ql_get_basedev_len(ha, &basedev_len, &port_index) != 0) {
676 			if (ha->devpath == NULL) {
677 				EL(myha, "Device path NULL. Unable to get "
678 				    "the basedev\n");
679 			} else {
680 				EL(myha, "Invalid device path '%s'. Cannot "
681 				    "get the hba index and port index\n",
682 				    ha->devpath);
683 			}
684 			continue;
685 		}
686 
687 		/*
688 		 * If both the basedev len do not match, then it
689 		 * is obvious that both are not pointing to the
690 		 * same base device.
691 		 */
692 		if ((basedev_len == mybasedev_len) && (strncmp(myha->devpath,
693 		    ha->devpath, basedev_len) == 0)) {
694 
695 			/* We found the ha with same basedev */
696 			QL_PRINT_3(CE_CONT, "(%d): found, done\n",
697 			    myha->instance);
698 			return (ha);
699 		}
700 	}
701 
702 	QL_PRINT_3(CE_CONT, "(%d): not found, done\n", myha->instance);
703 
704 	return (NULL);
705 }
706