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