xref: /titanic_41/usr/src/uts/common/io/fibre-channel/impl/fp.c (revision 26fd77009b17f8c8fb32eb362584cfd635e87ad9)
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 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  *
25  * NOT a DDI compliant Sun Fibre Channel port driver(fp)
26  *
27  */
28 
29 #include <sys/types.h>
30 #include <sys/varargs.h>
31 #include <sys/param.h>
32 #include <sys/errno.h>
33 #include <sys/uio.h>
34 #include <sys/buf.h>
35 #include <sys/modctl.h>
36 #include <sys/open.h>
37 #include <sys/file.h>
38 #include <sys/kmem.h>
39 #include <sys/poll.h>
40 #include <sys/conf.h>
41 #include <sys/thread.h>
42 #include <sys/var.h>
43 #include <sys/cmn_err.h>
44 #include <sys/stat.h>
45 #include <sys/ddi.h>
46 #include <sys/sunddi.h>
47 #include <sys/promif.h>
48 #include <sys/nvpair.h>
49 #include <sys/byteorder.h>
50 #include <sys/scsi/scsi.h>
51 #include <sys/fibre-channel/fc.h>
52 #include <sys/fibre-channel/impl/fc_ulpif.h>
53 #include <sys/fibre-channel/impl/fc_fcaif.h>
54 #include <sys/fibre-channel/impl/fctl_private.h>
55 #include <sys/fibre-channel/impl/fc_portif.h>
56 #include <sys/fibre-channel/impl/fp.h>
57 
58 /* These are defined in fctl.c! */
59 extern int did_table_size;
60 extern int pwwn_table_size;
61 
62 static struct cb_ops fp_cb_ops = {
63 	fp_open,			/* open */
64 	fp_close,			/* close */
65 	nodev,				/* strategy */
66 	nodev,				/* print */
67 	nodev,				/* dump */
68 	nodev,				/* read */
69 	nodev,				/* write */
70 	fp_ioctl,			/* ioctl */
71 	nodev,				/* devmap */
72 	nodev,				/* mmap */
73 	nodev,				/* segmap */
74 	nochpoll,			/* chpoll */
75 	ddi_prop_op,			/* cb_prop_op */
76 	0,				/* streamtab */
77 	D_NEW | D_MP | D_HOTPLUG,	/* cb_flag */
78 	CB_REV,				/* rev */
79 	nodev,				/* aread */
80 	nodev				/* awrite */
81 };
82 
83 static struct dev_ops fp_ops = {
84 	DEVO_REV,			/* build revision */
85 	0,				/* reference count */
86 	fp_getinfo,			/* getinfo */
87 	nulldev,			/* identify - Obsoleted */
88 	nulldev,			/* probe */
89 	fp_attach,			/* attach */
90 	fp_detach,			/* detach */
91 	nodev,				/* reset */
92 	&fp_cb_ops,			/* cb_ops */
93 	NULL,				/* bus_ops */
94 	fp_power,			/* power */
95 	ddi_quiesce_not_needed 		/* quiesce */
96 };
97 
98 #define	FP_VERSION		"20090729-1.100"
99 #define	FP_NAME_VERSION		"SunFC Port v" FP_VERSION
100 
101 char *fp_version = FP_NAME_VERSION;
102 
103 static struct modldrv modldrv = {
104 	&mod_driverops,			/* Type of Module */
105 	FP_NAME_VERSION,		/* Name/Version of fp */
106 	&fp_ops				/* driver ops */
107 };
108 
109 static struct modlinkage modlinkage = {
110 	MODREV_1,	/* Rev of the loadable modules system */
111 	&modldrv,	/* NULL terminated list of */
112 	NULL		/* Linkage structures */
113 };
114 
115 
116 
117 static uint16_t ns_reg_cmds[] = {
118 	NS_RPN_ID,
119 	NS_RNN_ID,
120 	NS_RCS_ID,
121 	NS_RFT_ID,
122 	NS_RPT_ID,
123 	NS_RSPN_ID,
124 	NS_RSNN_NN
125 };
126 
127 struct fp_xlat {
128 	uchar_t	xlat_state;
129 	int	xlat_rval;
130 } fp_xlat [] = {
131 	{ FC_PKT_SUCCESS,	FC_SUCCESS },
132 	{ FC_PKT_REMOTE_STOP,	FC_FAILURE },
133 	{ FC_PKT_LOCAL_RJT,	FC_FAILURE },
134 	{ FC_PKT_NPORT_RJT,	FC_ELS_PREJECT },
135 	{ FC_PKT_FABRIC_RJT,	FC_ELS_FREJECT },
136 	{ FC_PKT_LOCAL_BSY,	FC_TRAN_BUSY },
137 	{ FC_PKT_TRAN_BSY,	FC_TRAN_BUSY },
138 	{ FC_PKT_NPORT_BSY,	FC_PBUSY },
139 	{ FC_PKT_FABRIC_BSY,	FC_FBUSY },
140 	{ FC_PKT_LS_RJT,	FC_FAILURE },
141 	{ FC_PKT_BA_RJT,	FC_FAILURE },
142 	{ FC_PKT_TIMEOUT,	FC_FAILURE },
143 	{ FC_PKT_TRAN_ERROR,	FC_TRANSPORT_ERROR },
144 	{ FC_PKT_FAILURE,	FC_FAILURE },
145 	{ FC_PKT_PORT_OFFLINE,	FC_OFFLINE }
146 };
147 
148 static uchar_t fp_valid_alpas[] = {
149 	0x01, 0x02, 0x04, 0x08, 0x0F, 0x10, 0x17, 0x18, 0x1B,
150 	0x1D, 0x1E, 0x1F, 0x23, 0x25, 0x26, 0x27, 0x29, 0x2A,
151 	0x2B, 0x2C, 0x2D, 0x2E, 0x31, 0x32, 0x33, 0x34, 0x35,
152 	0x36, 0x39, 0x3A, 0x3C, 0x43, 0x45, 0x46, 0x47, 0x49,
153 	0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x51, 0x52, 0x53, 0x54,
154 	0x55, 0x56, 0x59, 0x5A, 0x5C, 0x63, 0x65, 0x66, 0x67,
155 	0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x71, 0x72, 0x73,
156 	0x74, 0x75, 0x76, 0x79, 0x7A, 0x7C, 0x80, 0x81, 0x82,
157 	0x84, 0x88, 0x8F, 0x90, 0x97, 0x98, 0x9B, 0x9D, 0x9E,
158 	0x9F, 0xA3, 0xA5, 0xA6, 0xA7, 0xA9, 0xAA, 0xAB, 0xAC,
159 	0xAD, 0xAE, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB9,
160 	0xBA, 0xBC, 0xC3, 0xC5, 0xC6, 0xC7, 0xC9, 0xCA, 0xCB,
161 	0xCC, 0xCD, 0xCE, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
162 	0xD9, 0xDA, 0xDC, 0xE0, 0xE1, 0xE2, 0xE4, 0xE8, 0xEF
163 };
164 
165 static struct fp_perms {
166 	uint16_t	fp_ioctl_cmd;
167 	uchar_t		fp_open_flag;
168 } fp_perm_list [] = {
169 	{ FCIO_GET_NUM_DEVS,		FP_OPEN },
170 	{ FCIO_GET_DEV_LIST,		FP_OPEN },
171 	{ FCIO_GET_SYM_PNAME,		FP_OPEN },
172 	{ FCIO_GET_SYM_NNAME,		FP_OPEN },
173 	{ FCIO_SET_SYM_PNAME,		FP_EXCL },
174 	{ FCIO_SET_SYM_NNAME,		FP_EXCL },
175 	{ FCIO_GET_LOGI_PARAMS,		FP_OPEN },
176 	{ FCIO_DEV_LOGIN,		FP_EXCL },
177 	{ FCIO_DEV_LOGOUT,		FP_EXCL },
178 	{ FCIO_GET_STATE,		FP_OPEN },
179 	{ FCIO_DEV_REMOVE,		FP_EXCL },
180 	{ FCIO_GET_FCODE_REV,		FP_OPEN },
181 	{ FCIO_GET_FW_REV,		FP_OPEN },
182 	{ FCIO_GET_DUMP_SIZE,		FP_OPEN },
183 	{ FCIO_FORCE_DUMP,		FP_EXCL },
184 	{ FCIO_GET_DUMP,		FP_OPEN },
185 	{ FCIO_GET_TOPOLOGY,		FP_OPEN },
186 	{ FCIO_RESET_LINK,		FP_EXCL },
187 	{ FCIO_RESET_HARD,		FP_EXCL },
188 	{ FCIO_RESET_HARD_CORE,		FP_EXCL },
189 	{ FCIO_DIAG,			FP_OPEN },
190 	{ FCIO_NS,			FP_EXCL },
191 	{ FCIO_DOWNLOAD_FW,		FP_EXCL },
192 	{ FCIO_DOWNLOAD_FCODE,		FP_EXCL },
193 	{ FCIO_LINK_STATUS,		FP_OPEN },
194 	{ FCIO_GET_HOST_PARAMS,		FP_OPEN },
195 	{ FCIO_GET_NODE_ID,		FP_OPEN },
196 	{ FCIO_SET_NODE_ID,		FP_EXCL },
197 	{ FCIO_SEND_NODE_ID,		FP_OPEN },
198 	{ FCIO_GET_ADAPTER_ATTRIBUTES,	FP_OPEN },
199 	{ FCIO_GET_OTHER_ADAPTER_PORTS,	FP_OPEN },
200 	{ FCIO_GET_ADAPTER_PORT_ATTRIBUTES,	FP_OPEN },
201 	{ FCIO_GET_DISCOVERED_PORT_ATTRIBUTES,	FP_OPEN },
202 	{ FCIO_GET_PORT_ATTRIBUTES,	FP_OPEN },
203 	{ FCIO_GET_ADAPTER_PORT_STATS,	FP_OPEN },
204 	{ FCIO_GET_ADAPTER_PORT_NPIV_ATTRIBUTES, FP_OPEN },
205 	{ FCIO_GET_NPIV_PORT_LIST, FP_OPEN },
206 	{ FCIO_DELETE_NPIV_PORT, FP_OPEN },
207 	{ FCIO_GET_NPIV_ATTRIBUTES, FP_OPEN },
208 	{ FCIO_CREATE_NPIV_PORT, FP_OPEN },
209 	{ FCIO_NPIV_GET_ADAPTER_ATTRIBUTES, FP_OPEN }
210 };
211 
212 static char *fp_pm_comps[] = {
213 	"NAME=FC Port",
214 	"0=Port Down",
215 	"1=Port Up"
216 };
217 
218 
219 #ifdef	_LITTLE_ENDIAN
220 #define	MAKE_BE_32(x)	{						\
221 		uint32_t	*ptr1, i;				\
222 		ptr1 = (uint32_t *)(x);					\
223 		for (i = 0; i < sizeof (*(x)) / sizeof (uint32_t); i++) { \
224 			*ptr1 = BE_32(*ptr1);				\
225 			ptr1++;						\
226 		}							\
227 	}
228 #else
229 #define	MAKE_BE_32(x)
230 #endif
231 
232 static uchar_t fp_verbosity = (FP_WARNING_MESSAGES | FP_FATAL_MESSAGES);
233 static uint32_t fp_options = 0;
234 
235 static int fp_cmd_wait_cnt = FP_CMDWAIT_DELAY;
236 static int fp_retry_delay = FP_RETRY_DELAY;	/* retry after this delay */
237 static int fp_retry_count = FP_RETRY_COUNT;	/* number of retries */
238 unsigned int fp_offline_ticker;			/* seconds */
239 
240 /*
241  * Driver global variable to anchor the list of soft state structs for
242  * all fp driver instances.  Used with the Solaris DDI soft state functions.
243  */
244 static void *fp_driver_softstate;
245 
246 static clock_t	fp_retry_ticks;
247 static clock_t	fp_offline_ticks;
248 
249 static int fp_retry_ticker;
250 static uint32_t fp_unsol_buf_count = FP_UNSOL_BUF_COUNT;
251 static uint32_t fp_unsol_buf_size = FP_UNSOL_BUF_SIZE;
252 
253 static int		fp_log_size = FP_LOG_SIZE;
254 static int		fp_trace = FP_TRACE_DEFAULT;
255 static fc_trace_logq_t	*fp_logq = NULL;
256 
257 int fp_get_adapter_paths(char *pathList, int count);
258 static void fp_log_port_event(fc_local_port_t *port, char *subclass);
259 static void fp_log_target_event(fc_local_port_t *port, char *subclass,
260     la_wwn_t tgt_pwwn, uint32_t port_id);
261 static uint32_t fp_map_remote_port_state(uint32_t rm_state);
262 static void fp_init_symbolic_names(fc_local_port_t *port);
263 
264 
265 /*
266  * Perform global initialization
267  */
268 int
269 _init(void)
270 {
271 	int ret;
272 
273 	if ((ret = ddi_soft_state_init(&fp_driver_softstate,
274 	    sizeof (struct fc_local_port), 8)) != 0) {
275 		return (ret);
276 	}
277 
278 	if ((ret = scsi_hba_init(&modlinkage)) != 0) {
279 		ddi_soft_state_fini(&fp_driver_softstate);
280 		return (ret);
281 	}
282 
283 	fp_logq = fc_trace_alloc_logq(fp_log_size);
284 
285 	if ((ret = mod_install(&modlinkage)) != 0) {
286 		fc_trace_free_logq(fp_logq);
287 		ddi_soft_state_fini(&fp_driver_softstate);
288 		scsi_hba_fini(&modlinkage);
289 	}
290 
291 	return (ret);
292 }
293 
294 
295 /*
296  * Prepare for driver unload
297  */
298 int
299 _fini(void)
300 {
301 	int ret;
302 
303 	if ((ret = mod_remove(&modlinkage)) == 0) {
304 		fc_trace_free_logq(fp_logq);
305 		ddi_soft_state_fini(&fp_driver_softstate);
306 		scsi_hba_fini(&modlinkage);
307 	}
308 
309 	return (ret);
310 }
311 
312 
313 /*
314  * Request mod_info() to handle all cases
315  */
316 int
317 _info(struct modinfo *modinfo)
318 {
319 	return (mod_info(&modlinkage, modinfo));
320 }
321 
322 
323 /*
324  * fp_attach:
325  *
326  * The respective cmd handlers take care of performing
327  * ULP related invocations
328  */
329 static int
330 fp_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
331 {
332 	int rval;
333 
334 	/*
335 	 * We check the value of fp_offline_ticker at this
336 	 * point. The variable is global for the driver and
337 	 * not specific to an instance.
338 	 *
339 	 * If there is no user-defined value found in /etc/system
340 	 * or fp.conf, then we use 90 seconds (FP_OFFLINE_TICKER).
341 	 * The minimum setting for this offline timeout according
342 	 * to the FC-FS2 standard (Fibre Channel Framing and
343 	 * Signalling-2, see www.t11.org) is R_T_TOV == 100msec.
344 	 *
345 	 * We do not recommend setting the value to less than 10
346 	 * seconds (RA_TOV) or more than 90 seconds. If this
347 	 * variable is greater than 90 seconds then drivers above
348 	 * fp (fcp, sd, scsi_vhci, vxdmp et al) might complain.
349 	 */
350 
351 	fp_offline_ticker = ddi_prop_get_int(DDI_DEV_T_ANY,
352 	    dip, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "fp_offline_ticker",
353 	    FP_OFFLINE_TICKER);
354 
355 	if ((fp_offline_ticker < 10) ||
356 	    (fp_offline_ticker > 90)) {
357 		cmn_err(CE_WARN, "Setting fp_offline_ticker to "
358 		    "%d second(s). This is outside the "
359 		    "recommended range of 10..90 seconds",
360 		    fp_offline_ticker);
361 	}
362 
363 	/*
364 	 * Tick every second when there are commands to retry.
365 	 * It should tick at the least granular value of pkt_timeout
366 	 * (which is one second)
367 	 */
368 	fp_retry_ticker = 1;
369 
370 	fp_retry_ticks = drv_usectohz(fp_retry_ticker * 1000 * 1000);
371 	fp_offline_ticks = drv_usectohz(fp_offline_ticker * 1000 * 1000);
372 
373 	switch (cmd) {
374 	case DDI_ATTACH:
375 		rval = fp_attach_handler(dip);
376 		break;
377 
378 	case DDI_RESUME:
379 		rval = fp_resume_handler(dip);
380 		break;
381 
382 	default:
383 		rval = DDI_FAILURE;
384 		break;
385 	}
386 	return (rval);
387 }
388 
389 
390 /*
391  * fp_detach:
392  *
393  * If a ULP fails to handle cmd request converse of
394  * cmd is invoked for ULPs that previously succeeded
395  * cmd request.
396  */
397 static int
398 fp_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
399 {
400 	int			rval = DDI_FAILURE;
401 	fc_local_port_t		*port;
402 	fc_attach_cmd_t		converse;
403 	uint8_t			cnt;
404 
405 	if ((port = ddi_get_soft_state(fp_driver_softstate,
406 	    ddi_get_instance(dip))) == NULL) {
407 		return (DDI_FAILURE);
408 	}
409 
410 	mutex_enter(&port->fp_mutex);
411 
412 	if (port->fp_ulp_attach) {
413 		mutex_exit(&port->fp_mutex);
414 		return (DDI_FAILURE);
415 	}
416 
417 	switch (cmd) {
418 	case DDI_DETACH:
419 		if (port->fp_task != FP_TASK_IDLE) {
420 			mutex_exit(&port->fp_mutex);
421 			return (DDI_FAILURE);
422 		}
423 
424 		/* Let's attempt to quit the job handler gracefully */
425 		port->fp_soft_state |= FP_DETACH_INPROGRESS;
426 
427 		mutex_exit(&port->fp_mutex);
428 		converse = FC_CMD_ATTACH;
429 		if (fctl_detach_ulps(port, FC_CMD_DETACH,
430 		    &modlinkage) != FC_SUCCESS) {
431 			mutex_enter(&port->fp_mutex);
432 			port->fp_soft_state &= ~FP_DETACH_INPROGRESS;
433 			mutex_exit(&port->fp_mutex);
434 			rval = DDI_FAILURE;
435 			break;
436 		}
437 
438 		mutex_enter(&port->fp_mutex);
439 		for (cnt = 0; (port->fp_job_head) && (cnt < fp_cmd_wait_cnt);
440 		    cnt++) {
441 			mutex_exit(&port->fp_mutex);
442 			delay(drv_usectohz(1000000));
443 			mutex_enter(&port->fp_mutex);
444 		}
445 
446 		if (port->fp_job_head) {
447 			mutex_exit(&port->fp_mutex);
448 			rval = DDI_FAILURE;
449 			break;
450 		}
451 		mutex_exit(&port->fp_mutex);
452 
453 		rval = fp_detach_handler(port);
454 		break;
455 
456 	case DDI_SUSPEND:
457 		mutex_exit(&port->fp_mutex);
458 		converse = FC_CMD_RESUME;
459 		if (fctl_detach_ulps(port, FC_CMD_SUSPEND,
460 		    &modlinkage) != FC_SUCCESS) {
461 			rval = DDI_FAILURE;
462 			break;
463 		}
464 		if ((rval = fp_suspend_handler(port)) != DDI_SUCCESS) {
465 			(void) callb_generic_cpr(&port->fp_cpr_info,
466 			    CB_CODE_CPR_RESUME);
467 		}
468 		break;
469 
470 	default:
471 		mutex_exit(&port->fp_mutex);
472 		break;
473 	}
474 
475 	/*
476 	 * Use softint to perform reattach.  Mark fp_ulp_attach so we
477 	 * don't attempt to do this repeatedly on behalf of some persistent
478 	 * caller.
479 	 */
480 	if (rval != DDI_SUCCESS) {
481 		mutex_enter(&port->fp_mutex);
482 		port->fp_ulp_attach = 1;
483 
484 		/*
485 		 * If the port is in the low power mode then there is
486 		 * possibility that fca too could be in low power mode.
487 		 * Try to raise the power before calling attach ulps.
488 		 */
489 
490 		if ((port->fp_soft_state & FP_SOFT_POWER_DOWN) &&
491 		    (!(port->fp_soft_state & FP_SOFT_NO_PMCOMP))) {
492 			mutex_exit(&port->fp_mutex);
493 			(void) pm_raise_power(port->fp_port_dip,
494 			    FP_PM_COMPONENT, FP_PM_PORT_UP);
495 		} else {
496 			mutex_exit(&port->fp_mutex);
497 		}
498 
499 
500 		fp_attach_ulps(port, converse);
501 
502 		mutex_enter(&port->fp_mutex);
503 		while (port->fp_ulp_attach) {
504 			cv_wait(&port->fp_attach_cv, &port->fp_mutex);
505 		}
506 
507 		port->fp_soft_state &= ~FP_DETACH_INPROGRESS;
508 
509 		/*
510 		 * Mark state as detach failed so asynchronous ULP attach
511 		 * events (downstream, not the ones we're initiating with
512 		 * the call to fp_attach_ulps) are not honored.	 We're
513 		 * really still in pending detach.
514 		 */
515 		port->fp_soft_state |= FP_DETACH_FAILED;
516 
517 		mutex_exit(&port->fp_mutex);
518 	}
519 
520 	return (rval);
521 }
522 
523 
524 /*
525  * fp_getinfo:
526  *   Given the device number, return either the
527  *   dev_info_t pointer or the instance number.
528  */
529 
530 /* ARGSUSED */
531 static int
532 fp_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
533 {
534 	int		rval;
535 	minor_t		instance;
536 	fc_local_port_t *port;
537 
538 	rval = DDI_SUCCESS;
539 	instance = getminor((dev_t)arg);
540 
541 	switch (cmd) {
542 	case DDI_INFO_DEVT2DEVINFO:
543 		if ((port = ddi_get_soft_state(fp_driver_softstate,
544 		    instance)) == NULL) {
545 			rval = DDI_FAILURE;
546 			break;
547 		}
548 		*result = (void *)port->fp_port_dip;
549 		break;
550 
551 	case DDI_INFO_DEVT2INSTANCE:
552 		*result = (void *)(uintptr_t)instance;
553 		break;
554 
555 	default:
556 		rval = DDI_FAILURE;
557 		break;
558 	}
559 
560 	return (rval);
561 }
562 
563 
564 /*
565  * Entry point for power up and power down request from kernel
566  */
567 static int
568 fp_power(dev_info_t *dip, int comp, int level)
569 {
570 	int		rval = DDI_FAILURE;
571 	fc_local_port_t	*port;
572 
573 	port = ddi_get_soft_state(fp_driver_softstate, ddi_get_instance(dip));
574 	if (port == NULL || comp != FP_PM_COMPONENT) {
575 		return (rval);
576 	}
577 
578 	switch (level) {
579 	case FP_PM_PORT_UP:
580 		rval = DDI_SUCCESS;
581 
582 		/*
583 		 * If the port is DDI_SUSPENDed, let the DDI_RESUME
584 		 * code complete the rediscovery.
585 		 */
586 		mutex_enter(&port->fp_mutex);
587 		if (port->fp_soft_state & FP_SOFT_SUSPEND) {
588 			port->fp_soft_state &= ~FP_SOFT_POWER_DOWN;
589 			port->fp_pm_level = FP_PM_PORT_UP;
590 			mutex_exit(&port->fp_mutex);
591 			fctl_attach_ulps(port, FC_CMD_POWER_UP, &modlinkage);
592 			break;
593 		}
594 
595 		if (port->fp_soft_state & FP_SOFT_POWER_DOWN) {
596 			ASSERT(port->fp_pm_level == FP_PM_PORT_DOWN);
597 
598 			port->fp_pm_level = FP_PM_PORT_UP;
599 			rval = fp_power_up(port);
600 			if (rval != DDI_SUCCESS) {
601 				port->fp_pm_level = FP_PM_PORT_DOWN;
602 			}
603 		} else {
604 			port->fp_pm_level = FP_PM_PORT_UP;
605 		}
606 		mutex_exit(&port->fp_mutex);
607 		break;
608 
609 	case FP_PM_PORT_DOWN:
610 		mutex_enter(&port->fp_mutex);
611 
612 		ASSERT(!(port->fp_soft_state & FP_SOFT_NO_PMCOMP));
613 		if (port->fp_soft_state & FP_SOFT_NO_PMCOMP) {
614 			/*
615 			 * PM framework goofed up. We have don't
616 			 * have any PM components. Let's never go down.
617 			 */
618 			mutex_exit(&port->fp_mutex);
619 			break;
620 
621 		}
622 
623 		if (port->fp_ulp_attach) {
624 			/* We shouldn't let the power go down */
625 			mutex_exit(&port->fp_mutex);
626 			break;
627 		}
628 
629 		/*
630 		 * Not a whole lot to do if we are detaching
631 		 */
632 		if (port->fp_soft_state & FP_SOFT_IN_DETACH) {
633 			port->fp_pm_level = FP_PM_PORT_DOWN;
634 			mutex_exit(&port->fp_mutex);
635 			rval = DDI_SUCCESS;
636 			break;
637 		}
638 
639 		if (!port->fp_pm_busy && !port->fp_pm_busy_nocomp) {
640 			port->fp_pm_level = FP_PM_PORT_DOWN;
641 
642 			rval = fp_power_down(port);
643 			if (rval != DDI_SUCCESS) {
644 				port->fp_pm_level = FP_PM_PORT_UP;
645 				ASSERT(!(port->fp_soft_state &
646 				    FP_SOFT_POWER_DOWN));
647 			} else {
648 				ASSERT(port->fp_soft_state &
649 				    FP_SOFT_POWER_DOWN);
650 			}
651 		}
652 		mutex_exit(&port->fp_mutex);
653 		break;
654 
655 	default:
656 		break;
657 	}
658 
659 	return (rval);
660 }
661 
662 
663 /*
664  * Open FC port devctl node
665  */
666 static int
667 fp_open(dev_t *devp, int flag, int otype, cred_t *credp)
668 {
669 	int		instance;
670 	fc_local_port_t *port;
671 
672 	if (otype != OTYP_CHR) {
673 		return (EINVAL);
674 	}
675 
676 	/*
677 	 * This is not a toy to play with. Allow only powerful
678 	 * users (hopefully knowledgeable) to access the port
679 	 * (A hacker potentially could download a sick binary
680 	 * file into FCA)
681 	 */
682 	if (drv_priv(credp)) {
683 		return (EPERM);
684 	}
685 
686 	instance = (int)getminor(*devp);
687 
688 	port = ddi_get_soft_state(fp_driver_softstate, instance);
689 	if (port == NULL) {
690 		return (ENXIO);
691 	}
692 
693 	mutex_enter(&port->fp_mutex);
694 	if (port->fp_flag & FP_EXCL) {
695 		/*
696 		 * It is already open for exclusive access.
697 		 * So shut the door on this caller.
698 		 */
699 		mutex_exit(&port->fp_mutex);
700 		return (EBUSY);
701 	}
702 
703 	if (flag & FEXCL) {
704 		if (port->fp_flag & FP_OPEN) {
705 			/*
706 			 * Exclusive operation not possible
707 			 * as it is already opened
708 			 */
709 			mutex_exit(&port->fp_mutex);
710 			return (EBUSY);
711 		}
712 		port->fp_flag |= FP_EXCL;
713 	}
714 	port->fp_flag |= FP_OPEN;
715 	mutex_exit(&port->fp_mutex);
716 
717 	return (0);
718 }
719 
720 
721 /*
722  * The driver close entry point is called on the last close()
723  * of a device. So it is perfectly alright to just clobber the
724  * open flag and reset it to idle (instead of having to reset
725  * each flag bits). For any confusion, check out close(9E).
726  */
727 
728 /* ARGSUSED */
729 static int
730 fp_close(dev_t dev, int flag, int otype, cred_t *credp)
731 {
732 	int		instance;
733 	fc_local_port_t *port;
734 
735 	if (otype != OTYP_CHR) {
736 		return (EINVAL);
737 	}
738 
739 	instance = (int)getminor(dev);
740 
741 	port = ddi_get_soft_state(fp_driver_softstate, instance);
742 	if (port == NULL) {
743 		return (ENXIO);
744 	}
745 
746 	mutex_enter(&port->fp_mutex);
747 	if ((port->fp_flag & FP_OPEN) == 0) {
748 		mutex_exit(&port->fp_mutex);
749 		return (ENODEV);
750 	}
751 	port->fp_flag = FP_IDLE;
752 	mutex_exit(&port->fp_mutex);
753 
754 	return (0);
755 }
756 
757 /*
758  * Handle IOCTL requests
759  */
760 
761 /* ARGSUSED */
762 static int
763 fp_ioctl(dev_t dev, int cmd, intptr_t data, int mode, cred_t *credp, int *rval)
764 {
765 	int		instance;
766 	int		ret = 0;
767 	fcio_t		fcio;
768 	fc_local_port_t *port;
769 
770 	instance = (int)getminor(dev);
771 
772 	port = ddi_get_soft_state(fp_driver_softstate, instance);
773 	if (port == NULL) {
774 		return (ENXIO);
775 	}
776 
777 	mutex_enter(&port->fp_mutex);
778 	if ((port->fp_flag & FP_OPEN) == 0) {
779 		mutex_exit(&port->fp_mutex);
780 		return (ENXIO);
781 	}
782 
783 	if (port->fp_soft_state & FP_SOFT_SUSPEND) {
784 		mutex_exit(&port->fp_mutex);
785 		return (ENXIO);
786 	}
787 
788 	mutex_exit(&port->fp_mutex);
789 
790 	/* this will raise power if necessary */
791 	ret = fctl_busy_port(port);
792 	if (ret != 0) {
793 		return (ret);
794 	}
795 
796 	ASSERT(port->fp_pm_level == FP_PM_PORT_UP);
797 
798 
799 	switch (cmd) {
800 	case FCIO_CMD: {
801 #ifdef	_MULTI_DATAMODEL
802 		switch (ddi_model_convert_from(mode & FMODELS)) {
803 		case DDI_MODEL_ILP32: {
804 			struct fcio32 fcio32;
805 
806 			if (ddi_copyin((void *)data, (void *)&fcio32,
807 			    sizeof (struct fcio32), mode)) {
808 				ret = EFAULT;
809 				break;
810 			}
811 			fcio.fcio_xfer = fcio32.fcio_xfer;
812 			fcio.fcio_cmd = fcio32.fcio_cmd;
813 			fcio.fcio_flags = fcio32.fcio_flags;
814 			fcio.fcio_cmd_flags = fcio32.fcio_cmd_flags;
815 			fcio.fcio_ilen = (size_t)fcio32.fcio_ilen;
816 			fcio.fcio_ibuf =
817 			    (caddr_t)(uintptr_t)fcio32.fcio_ibuf;
818 			fcio.fcio_olen = (size_t)fcio32.fcio_olen;
819 			fcio.fcio_obuf =
820 			    (caddr_t)(uintptr_t)fcio32.fcio_obuf;
821 			fcio.fcio_alen = (size_t)fcio32.fcio_alen;
822 			fcio.fcio_abuf =
823 			    (caddr_t)(uintptr_t)fcio32.fcio_abuf;
824 			fcio.fcio_errno = fcio32.fcio_errno;
825 			break;
826 		}
827 
828 		case DDI_MODEL_NONE:
829 			if (ddi_copyin((void *)data, (void *)&fcio,
830 			    sizeof (fcio_t), mode)) {
831 				ret = EFAULT;
832 			}
833 			break;
834 		}
835 #else	/* _MULTI_DATAMODEL */
836 		if (ddi_copyin((void *)data, (void *)&fcio,
837 		    sizeof (fcio_t), mode)) {
838 			ret = EFAULT;
839 			break;
840 		}
841 #endif	/* _MULTI_DATAMODEL */
842 		if (!ret) {
843 			ret = fp_fciocmd(port, data, mode, &fcio);
844 		}
845 		break;
846 	}
847 
848 	default:
849 		ret = fctl_ulp_port_ioctl(port, dev, cmd, data,
850 		    mode, credp, rval);
851 	}
852 
853 	fctl_idle_port(port);
854 
855 	return (ret);
856 }
857 
858 
859 /*
860  * Init Symbolic Port Name and Node Name
861  * LV will try to get symbolic names from FCA driver
862  * and register these to name server,
863  * if LV fails to get these,
864  * LV will register its default symbolic names to name server.
865  * The Default symbolic node name format is :
866  *	<hostname>:<hba driver name>(instance)
867  * The Default symbolic port name format is :
868  *	<fp path name>
869  */
870 static void
871 fp_init_symbolic_names(fc_local_port_t *port)
872 {
873 	const char *vendorname = ddi_driver_name(port->fp_fca_dip);
874 	char *sym_name;
875 	char fcaname[50] = {0};
876 	int hostnlen, fcanlen;
877 
878 	if (port->fp_sym_node_namelen == 0) {
879 		hostnlen = strlen(utsname.nodename);
880 		(void) snprintf(fcaname, sizeof (fcaname),
881 		    "%s%d", vendorname, ddi_get_instance(port->fp_fca_dip));
882 		fcanlen = strlen(fcaname);
883 
884 		sym_name = kmem_zalloc(hostnlen + fcanlen + 2, KM_SLEEP);
885 		(void) sprintf(sym_name, "%s:%s", utsname.nodename, fcaname);
886 		port->fp_sym_node_namelen = strlen(sym_name);
887 		if (port->fp_sym_node_namelen >= FCHBA_SYMB_NAME_LEN) {
888 			port->fp_sym_node_namelen = FCHBA_SYMB_NAME_LEN;
889 		}
890 		(void) strncpy(port->fp_sym_node_name, sym_name,
891 		    port->fp_sym_node_namelen);
892 		kmem_free(sym_name, hostnlen + fcanlen + 2);
893 	}
894 
895 	if (port->fp_sym_port_namelen == 0) {
896 		char *pathname = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
897 
898 		(void) ddi_pathname(port->fp_port_dip, pathname);
899 		port->fp_sym_port_namelen = strlen(pathname);
900 		if (port->fp_sym_port_namelen >= FCHBA_SYMB_NAME_LEN) {
901 			port->fp_sym_port_namelen = FCHBA_SYMB_NAME_LEN;
902 		}
903 		(void) strncpy(port->fp_sym_port_name, pathname,
904 		    port->fp_sym_port_namelen);
905 		kmem_free(pathname, MAXPATHLEN);
906 	}
907 }
908 
909 
910 /*
911  * Perform port attach
912  */
913 static int
914 fp_attach_handler(dev_info_t *dip)
915 {
916 	int			rval;
917 	int			instance;
918 	int			port_num;
919 	int			port_len;
920 	char			name[30];
921 	char			i_pwwn[17];
922 	fp_cmd_t		*pkt;
923 	uint32_t		ub_count;
924 	fc_local_port_t		*port;
925 	job_request_t		*job;
926 	fc_local_port_t *phyport = NULL;
927 	int portpro1;
928 	char pwwn[17], nwwn[17];
929 
930 	instance = ddi_get_instance(dip);
931 	port_len = sizeof (port_num);
932 	rval = ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF,
933 	    DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "port",
934 	    (caddr_t)&port_num, &port_len);
935 	if (rval != DDI_SUCCESS) {
936 		cmn_err(CE_WARN, "fp(%d): No port property in devinfo",
937 		    instance);
938 		return (DDI_FAILURE);
939 	}
940 
941 	if (ddi_create_minor_node(dip, "devctl", S_IFCHR, instance,
942 	    DDI_NT_NEXUS, 0) != DDI_SUCCESS) {
943 		cmn_err(CE_WARN, "fp(%d): failed to create devctl minor node",
944 		    instance);
945 		return (DDI_FAILURE);
946 	}
947 
948 	if (ddi_create_minor_node(dip, "fc", S_IFCHR, instance,
949 	    DDI_NT_FC_ATTACHMENT_POINT, 0) != DDI_SUCCESS) {
950 		cmn_err(CE_WARN, "fp(%d): failed to create fc attachment"
951 		    " point minor node", instance);
952 		ddi_remove_minor_node(dip, NULL);
953 		return (DDI_FAILURE);
954 	}
955 
956 	if (ddi_soft_state_zalloc(fp_driver_softstate, instance)
957 	    != DDI_SUCCESS) {
958 		cmn_err(CE_WARN, "fp(%d): failed to alloc soft state",
959 		    instance);
960 		ddi_remove_minor_node(dip, NULL);
961 		return (DDI_FAILURE);
962 	}
963 	port = ddi_get_soft_state(fp_driver_softstate, instance);
964 
965 	(void) sprintf(port->fp_ibuf, "fp(%d)", instance);
966 
967 	port->fp_instance = instance;
968 	port->fp_ulp_attach = 1;
969 	port->fp_port_num = port_num;
970 	port->fp_verbose = fp_verbosity;
971 	port->fp_options = fp_options;
972 
973 	port->fp_fca_dip = ddi_get_parent(dip);
974 	port->fp_port_dip = dip;
975 	port->fp_fca_tran = (fc_fca_tran_t *)
976 	    ddi_get_driver_private(port->fp_fca_dip);
977 
978 	port->fp_task = port->fp_last_task = FP_TASK_IDLE;
979 
980 	/*
981 	 * Init the starting value of fp_rscn_count. Note that if
982 	 * FC_INVALID_RSCN_COUNT is 0 (which is what it currently is), the
983 	 * actual # of RSCNs will be (fp_rscn_count - 1)
984 	 */
985 	port->fp_rscn_count = FC_INVALID_RSCN_COUNT + 1;
986 
987 	mutex_init(&port->fp_mutex, NULL, MUTEX_DRIVER, NULL);
988 	cv_init(&port->fp_cv, NULL, CV_DRIVER, NULL);
989 	cv_init(&port->fp_attach_cv, NULL, CV_DRIVER, NULL);
990 
991 	(void) sprintf(name, "fp%d_cache", instance);
992 
993 	if ((portpro1 = ddi_prop_get_int(DDI_DEV_T_ANY,
994 	    dip, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
995 	    "phyport-instance", -1)) != -1) {
996 		phyport = ddi_get_soft_state(fp_driver_softstate, portpro1);
997 		fc_wwn_to_str(&phyport->fp_service_params.nport_ww_name, pwwn);
998 		fc_wwn_to_str(&phyport->fp_service_params.node_ww_name, nwwn);
999 		port->fp_npiv_type = FC_NPIV_PORT;
1000 	}
1001 
1002 	/*
1003 	 * Allocate the pool of fc_packet_t structs to be used with
1004 	 * this fp instance.
1005 	 */
1006 	port->fp_pkt_cache = kmem_cache_create(name,
1007 	    (port->fp_fca_tran->fca_pkt_size) + sizeof (fp_cmd_t), 8,
1008 	    fp_cache_constructor, fp_cache_destructor, NULL, (void *)port,
1009 	    NULL, 0);
1010 	port->fp_out_fpcmds = 0;
1011 	if (port->fp_pkt_cache == NULL) {
1012 		goto cache_alloc_failed;
1013 	}
1014 
1015 
1016 	/*
1017 	 * Allocate the d_id and pwwn hash tables for all remote ports
1018 	 * connected to this local port.
1019 	 */
1020 	port->fp_did_table = kmem_zalloc(did_table_size *
1021 	    sizeof (struct d_id_hash), KM_SLEEP);
1022 
1023 	port->fp_pwwn_table = kmem_zalloc(pwwn_table_size *
1024 	    sizeof (struct pwwn_hash), KM_SLEEP);
1025 
1026 	port->fp_taskq = taskq_create("fp_ulp_callback", 1,
1027 	    MINCLSYSPRI, 1, 16, 0);
1028 
1029 	/* Indicate that don't have the pm components yet */
1030 	port->fp_soft_state |=	FP_SOFT_NO_PMCOMP;
1031 
1032 	/*
1033 	 * Bind the callbacks with the FCA driver. This will open the gate
1034 	 * for asynchronous callbacks, so after this call the fp_mutex
1035 	 * must be held when updating the fc_local_port_t struct.
1036 	 *
1037 	 * This is done _before_ setting up the job thread so we can avoid
1038 	 * cleaning up after the thread_create() in the error path. This
1039 	 * also means fp will be operating with fp_els_resp_pkt set to NULL.
1040 	 */
1041 	if (fp_bind_callbacks(port) != DDI_SUCCESS) {
1042 		goto bind_callbacks_failed;
1043 	}
1044 
1045 	if (phyport) {
1046 		mutex_enter(&phyport->fp_mutex);
1047 		if (phyport->fp_port_next) {
1048 			phyport->fp_port_next->fp_port_prev = port;
1049 			port->fp_port_next =  phyport->fp_port_next;
1050 			phyport->fp_port_next = port;
1051 			port->fp_port_prev = phyport;
1052 		} else {
1053 			phyport->fp_port_next = port;
1054 			phyport->fp_port_prev = port;
1055 			port->fp_port_next =  phyport;
1056 			port->fp_port_prev = phyport;
1057 		}
1058 		mutex_exit(&phyport->fp_mutex);
1059 	}
1060 
1061 	/*
1062 	 * Init Symbolic Names
1063 	 */
1064 	fp_init_symbolic_names(port);
1065 
1066 	pkt = fp_alloc_pkt(port, sizeof (la_els_logi_t), sizeof (la_els_logi_t),
1067 	    KM_SLEEP, NULL);
1068 
1069 	if (pkt == NULL) {
1070 		cmn_err(CE_WARN, "fp(%d): failed to allocate ELS packet",
1071 		    instance);
1072 		goto alloc_els_packet_failed;
1073 	}
1074 
1075 	(void) thread_create(NULL, 0, fp_job_handler, port, 0, &p0, TS_RUN,
1076 	    v.v_maxsyspri - 2);
1077 
1078 	fc_wwn_to_str(&port->fp_service_params.nport_ww_name, i_pwwn);
1079 	if (ddi_prop_update_string(DDI_DEV_T_NONE, dip, "initiator-port",
1080 	    i_pwwn) != DDI_PROP_SUCCESS) {
1081 		fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
1082 		    "fp(%d): Updating 'initiator-port' property"
1083 		    " on fp dev_info node failed", instance);
1084 	}
1085 
1086 	fc_wwn_to_str(&port->fp_service_params.node_ww_name, i_pwwn);
1087 	if (ddi_prop_update_string(DDI_DEV_T_NONE, dip, "initiator-node",
1088 	    i_pwwn) != DDI_PROP_SUCCESS) {
1089 		fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
1090 		    "fp(%d): Updating 'initiator-node' property"
1091 		    " on fp dev_info node failed", instance);
1092 	}
1093 
1094 	mutex_enter(&port->fp_mutex);
1095 	port->fp_els_resp_pkt = pkt;
1096 	mutex_exit(&port->fp_mutex);
1097 
1098 	/*
1099 	 * Determine the count of unsolicited buffers this FCA can support
1100 	 */
1101 	fp_retrieve_caps(port);
1102 
1103 	/*
1104 	 * Allocate unsolicited buffer tokens
1105 	 */
1106 	if (port->fp_ub_count) {
1107 		ub_count = port->fp_ub_count;
1108 		port->fp_ub_tokens = kmem_zalloc(ub_count *
1109 		    sizeof (*port->fp_ub_tokens), KM_SLEEP);
1110 		/*
1111 		 * Do not fail the attach if unsolicited buffer allocation
1112 		 * fails; Just try to get along with whatever the FCA can do.
1113 		 */
1114 		if (fc_ulp_uballoc(port, &ub_count, fp_unsol_buf_size,
1115 		    FC_TYPE_EXTENDED_LS, port->fp_ub_tokens) !=
1116 		    FC_SUCCESS || ub_count != port->fp_ub_count) {
1117 			cmn_err(CE_WARN, "fp(%d): failed to allocate "
1118 			    " Unsolicited buffers. proceeding with attach...",
1119 			    instance);
1120 			kmem_free(port->fp_ub_tokens,
1121 			    sizeof (*port->fp_ub_tokens) * port->fp_ub_count);
1122 			port->fp_ub_tokens = NULL;
1123 		}
1124 	}
1125 
1126 	fp_load_ulp_modules(dip, port);
1127 
1128 	/*
1129 	 * Enable DDI_SUSPEND and DDI_RESUME for this instance.
1130 	 */
1131 	(void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
1132 	    "pm-hardware-state", "needs-suspend-resume",
1133 	    strlen("needs-suspend-resume") + 1);
1134 
1135 	/*
1136 	 * fctl maintains a list of all port handles, so
1137 	 * help fctl add this one to its list now.
1138 	 */
1139 	mutex_enter(&port->fp_mutex);
1140 	fctl_add_port(port);
1141 
1142 	/*
1143 	 * If a state change is already in progress, set the bind state t
1144 	 * OFFLINE as well, so further state change callbacks into ULPs
1145 	 * will pass the appropriate states
1146 	 */
1147 	if (FC_PORT_STATE_MASK(port->fp_bind_state) == FC_STATE_OFFLINE ||
1148 	    port->fp_statec_busy) {
1149 		port->fp_bind_state = FC_STATE_OFFLINE;
1150 		mutex_exit(&port->fp_mutex);
1151 
1152 		fp_startup_done((opaque_t)port, FC_PKT_SUCCESS);
1153 	} else {
1154 		/*
1155 		 * Without dropping the mutex, ensure that the port
1156 		 * startup happens ahead of state change callback
1157 		 * processing
1158 		 */
1159 		ASSERT(port->fp_job_tail == NULL && port->fp_job_head == NULL);
1160 
1161 		port->fp_last_task = port->fp_task;
1162 		port->fp_task = FP_TASK_PORT_STARTUP;
1163 
1164 		job = fctl_alloc_job(JOB_PORT_STARTUP, JOB_TYPE_FCTL_ASYNC,
1165 		    fp_startup_done, (opaque_t)port, KM_SLEEP);
1166 
1167 		port->fp_job_head = port->fp_job_tail = job;
1168 
1169 		cv_signal(&port->fp_cv);
1170 
1171 		mutex_exit(&port->fp_mutex);
1172 	}
1173 
1174 	mutex_enter(&port->fp_mutex);
1175 	while (port->fp_ulp_attach) {
1176 		cv_wait(&port->fp_attach_cv, &port->fp_mutex);
1177 	}
1178 	mutex_exit(&port->fp_mutex);
1179 
1180 	if (ddi_prop_update_string_array(DDI_DEV_T_NONE, dip,
1181 	    "pm-components", fp_pm_comps,
1182 	    sizeof (fp_pm_comps) / sizeof (fp_pm_comps[0])) !=
1183 	    DDI_PROP_SUCCESS) {
1184 		FP_TRACE(FP_NHEAD2(9, 0), "Failed to create PM"
1185 		    " components property, PM disabled on this port.");
1186 		mutex_enter(&port->fp_mutex);
1187 		port->fp_pm_level = FP_PM_PORT_UP;
1188 		mutex_exit(&port->fp_mutex);
1189 	} else {
1190 		if (pm_raise_power(dip, FP_PM_COMPONENT,
1191 		    FP_PM_PORT_UP) != DDI_SUCCESS) {
1192 			FP_TRACE(FP_NHEAD2(9, 0), "Failed to raise"
1193 			    " power level");
1194 			mutex_enter(&port->fp_mutex);
1195 			port->fp_pm_level = FP_PM_PORT_UP;
1196 			mutex_exit(&port->fp_mutex);
1197 		}
1198 
1199 		/*
1200 		 * Don't unset the FP_SOFT_NO_PMCOMP flag until after
1201 		 * the call to pm_raise_power.	The PM framework can't
1202 		 * handle multiple threads calling into it during attach.
1203 		 */
1204 
1205 		mutex_enter(&port->fp_mutex);
1206 		port->fp_soft_state &=	~FP_SOFT_NO_PMCOMP;
1207 		mutex_exit(&port->fp_mutex);
1208 	}
1209 
1210 	ddi_report_dev(dip);
1211 
1212 	fp_log_port_event(port, ESC_SUNFC_PORT_ATTACH);
1213 
1214 	return (DDI_SUCCESS);
1215 
1216 	/*
1217 	 * Unwind any/all preceeding allocations in the event of an error.
1218 	 */
1219 
1220 alloc_els_packet_failed:
1221 
1222 	if (port->fp_fca_handle != NULL) {
1223 		port->fp_fca_tran->fca_unbind_port(port->fp_fca_handle);
1224 		port->fp_fca_handle = NULL;
1225 	}
1226 
1227 	if (port->fp_ub_tokens != NULL) {
1228 		(void) fc_ulp_ubfree(port, port->fp_ub_count,
1229 		    port->fp_ub_tokens);
1230 		kmem_free(port->fp_ub_tokens,
1231 		    port->fp_ub_count * sizeof (*port->fp_ub_tokens));
1232 		port->fp_ub_tokens = NULL;
1233 	}
1234 
1235 	if (port->fp_els_resp_pkt != NULL) {
1236 		fp_free_pkt(port->fp_els_resp_pkt);
1237 		port->fp_els_resp_pkt = NULL;
1238 	}
1239 
1240 bind_callbacks_failed:
1241 
1242 	if (port->fp_taskq != NULL) {
1243 		taskq_destroy(port->fp_taskq);
1244 	}
1245 
1246 	if (port->fp_pwwn_table != NULL) {
1247 		kmem_free(port->fp_pwwn_table,
1248 		    pwwn_table_size * sizeof (struct pwwn_hash));
1249 		port->fp_pwwn_table = NULL;
1250 	}
1251 
1252 	if (port->fp_did_table != NULL) {
1253 		kmem_free(port->fp_did_table,
1254 		    did_table_size * sizeof (struct d_id_hash));
1255 		port->fp_did_table = NULL;
1256 	}
1257 
1258 	if (port->fp_pkt_cache != NULL) {
1259 		kmem_cache_destroy(port->fp_pkt_cache);
1260 		port->fp_pkt_cache = NULL;
1261 	}
1262 
1263 cache_alloc_failed:
1264 
1265 	cv_destroy(&port->fp_attach_cv);
1266 	cv_destroy(&port->fp_cv);
1267 	mutex_destroy(&port->fp_mutex);
1268 	ddi_remove_minor_node(port->fp_port_dip, NULL);
1269 	ddi_soft_state_free(fp_driver_softstate, instance);
1270 	ddi_prop_remove_all(dip);
1271 
1272 	return (DDI_FAILURE);
1273 }
1274 
1275 
1276 /*
1277  * Handle DDI_RESUME request
1278  */
1279 static int
1280 fp_resume_handler(dev_info_t *dip)
1281 {
1282 	int		rval;
1283 	fc_local_port_t *port;
1284 
1285 	port = ddi_get_soft_state(fp_driver_softstate, ddi_get_instance(dip));
1286 
1287 	ASSERT(port != NULL);
1288 
1289 #ifdef	DEBUG
1290 	mutex_enter(&port->fp_mutex);
1291 	ASSERT(port->fp_soft_state & FP_SOFT_SUSPEND);
1292 	mutex_exit(&port->fp_mutex);
1293 #endif
1294 
1295 	/*
1296 	 * If the port was power suspended, raise the power level
1297 	 */
1298 	mutex_enter(&port->fp_mutex);
1299 	if ((port->fp_soft_state & FP_SOFT_POWER_DOWN) &&
1300 	    (!(port->fp_soft_state & FP_SOFT_NO_PMCOMP))) {
1301 		ASSERT(port->fp_pm_level == FP_PM_PORT_DOWN);
1302 
1303 		mutex_exit(&port->fp_mutex);
1304 		if (pm_raise_power(dip, FP_PM_COMPONENT,
1305 		    FP_PM_PORT_UP) != DDI_SUCCESS) {
1306 			FP_TRACE(FP_NHEAD2(9, 0),
1307 			    "Failed to raise the power level");
1308 			return (DDI_FAILURE);
1309 		}
1310 		mutex_enter(&port->fp_mutex);
1311 	}
1312 	port->fp_soft_state &= ~FP_SOFT_SUSPEND;
1313 	mutex_exit(&port->fp_mutex);
1314 
1315 	/*
1316 	 * All the discovery is initiated and handled by per-port thread.
1317 	 * Further all the discovery is done in handled in callback mode
1318 	 * (not polled mode); In a specific case such as this, the discovery
1319 	 * is required to happen in polled mode. The easiest way out is
1320 	 * to bail out port thread and get started. Come back and fix this
1321 	 * to do on demand discovery initiated by ULPs. ULPs such as FCP
1322 	 * will do on-demand discovery during pre-power-up busctl handling
1323 	 * which will only be possible when SCSA provides a new HBA vector
1324 	 * for sending down the PM busctl requests.
1325 	 */
1326 	(void) callb_generic_cpr(&port->fp_cpr_info, CB_CODE_CPR_RESUME);
1327 
1328 	rval = fp_resume_all(port, FC_CMD_RESUME);
1329 	if (rval != DDI_SUCCESS) {
1330 		mutex_enter(&port->fp_mutex);
1331 		port->fp_soft_state |= FP_SOFT_SUSPEND;
1332 		mutex_exit(&port->fp_mutex);
1333 		(void) callb_generic_cpr(&port->fp_cpr_info,
1334 		    CB_CODE_CPR_CHKPT);
1335 	}
1336 
1337 	return (rval);
1338 }
1339 
1340 /*
1341  * Perform FC Port power on initialization
1342  */
1343 static int
1344 fp_power_up(fc_local_port_t *port)
1345 {
1346 	int	rval;
1347 
1348 	ASSERT(MUTEX_HELD(&port->fp_mutex));
1349 
1350 	ASSERT((port->fp_soft_state & FP_SOFT_SUSPEND) == 0);
1351 	ASSERT(port->fp_soft_state & FP_SOFT_POWER_DOWN);
1352 
1353 	port->fp_soft_state &= ~FP_SOFT_POWER_DOWN;
1354 
1355 	mutex_exit(&port->fp_mutex);
1356 
1357 	rval = fp_resume_all(port, FC_CMD_POWER_UP);
1358 	if (rval != DDI_SUCCESS) {
1359 		mutex_enter(&port->fp_mutex);
1360 		port->fp_soft_state |= FP_SOFT_POWER_DOWN;
1361 	} else {
1362 		mutex_enter(&port->fp_mutex);
1363 	}
1364 
1365 	return (rval);
1366 }
1367 
1368 
1369 /*
1370  * It is important to note that the power may possibly be removed between
1371  * SUSPEND and the ensuing RESUME operation. In such a context the underlying
1372  * FC port hardware would have gone through an OFFLINE to ONLINE transition
1373  * (hardware state). In this case, the port driver may need to rediscover the
1374  * topology, perform LOGINs, register with the name server again and perform
1375  * any such port initialization procedures. To perform LOGINs, the driver could
1376  * use the port device handle to see if a LOGIN needs to be performed and use
1377  * the D_ID and WWN in it. The LOGINs may fail (if the hardware is reconfigured
1378  * or removed) which will be reflected in the map the ULPs will see.
1379  */
1380 static int
1381 fp_resume_all(fc_local_port_t *port, fc_attach_cmd_t cmd)
1382 {
1383 
1384 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
1385 
1386 	if (fp_bind_callbacks(port) != DDI_SUCCESS) {
1387 		return (DDI_FAILURE);
1388 	}
1389 
1390 	mutex_enter(&port->fp_mutex);
1391 
1392 	/*
1393 	 * If there are commands queued for delayed retry, instead of
1394 	 * working the hard way to figure out which ones are good for
1395 	 * restart and which ones not (ELSs are definitely not good
1396 	 * as the port will have to go through a new spin of rediscovery
1397 	 * now), so just flush them out.
1398 	 */
1399 	if (port->fp_restore & FP_RESTORE_WAIT_TIMEOUT) {
1400 		fp_cmd_t	*cmd;
1401 
1402 		port->fp_restore &= ~FP_RESTORE_WAIT_TIMEOUT;
1403 
1404 		mutex_exit(&port->fp_mutex);
1405 		while ((cmd = fp_deque_cmd(port)) != NULL) {
1406 			cmd->cmd_pkt.pkt_state = FC_PKT_TRAN_ERROR;
1407 			fp_iodone(cmd);
1408 		}
1409 		mutex_enter(&port->fp_mutex);
1410 	}
1411 
1412 	if (FC_PORT_STATE_MASK(port->fp_bind_state) == FC_STATE_OFFLINE) {
1413 		if ((port->fp_restore & FP_RESTORE_OFFLINE_TIMEOUT) ||
1414 		    port->fp_dev_count) {
1415 			port->fp_restore &= ~FP_RESTORE_OFFLINE_TIMEOUT;
1416 			port->fp_offline_tid = timeout(fp_offline_timeout,
1417 			    (caddr_t)port, fp_offline_ticks);
1418 		}
1419 		if (port->fp_job_head) {
1420 			cv_signal(&port->fp_cv);
1421 		}
1422 		mutex_exit(&port->fp_mutex);
1423 		fctl_attach_ulps(port, cmd, &modlinkage);
1424 	} else {
1425 		struct job_request *job;
1426 
1427 		/*
1428 		 * If an OFFLINE timer was running at the time of
1429 		 * suspending, there is no need to restart it as
1430 		 * the port is ONLINE now.
1431 		 */
1432 		port->fp_restore &= ~FP_RESTORE_OFFLINE_TIMEOUT;
1433 		if (port->fp_statec_busy == 0) {
1434 			port->fp_soft_state |= FP_SOFT_IN_STATEC_CB;
1435 		}
1436 		port->fp_statec_busy++;
1437 		mutex_exit(&port->fp_mutex);
1438 
1439 		job = fctl_alloc_job(JOB_PORT_ONLINE,
1440 		    JOB_CANCEL_ULP_NOTIFICATION, NULL, NULL, KM_SLEEP);
1441 		fctl_enque_job(port, job);
1442 
1443 		fctl_jobwait(job);
1444 		fctl_remove_oldies(port);
1445 
1446 		fctl_attach_ulps(port, cmd, &modlinkage);
1447 		fctl_dealloc_job(job);
1448 	}
1449 
1450 	return (DDI_SUCCESS);
1451 }
1452 
1453 
1454 /*
1455  * At this time, there shouldn't be any I/O requests on this port.
1456  * But the unsolicited callbacks from the underlying FCA port need
1457  * to be handled very carefully. The steps followed to handle the
1458  * DDI_DETACH are:
1459  *	+	Grab the port driver mutex, check if the unsolicited
1460  *		callback is currently under processing. If true, fail
1461  *		the DDI_DETACH request by printing a message; If false
1462  *		mark the DDI_DETACH as under progress, so that any
1463  *		further unsolicited callbacks get bounced.
1464  *	+	Perform PRLO/LOGO if necessary, cleanup all the data
1465  *		structures.
1466  *	+	Get the job_handler thread to gracefully exit.
1467  *	+	Unregister callbacks with the FCA port.
1468  *	+	Now that some peace is found, notify all the ULPs of
1469  *		DDI_DETACH request (using ulp_port_detach entry point)
1470  *	+	Free all mutexes, semaphores, conditional variables.
1471  *	+	Free the soft state, return success.
1472  *
1473  * Important considerations:
1474  *		Port driver de-registers state change and unsolicited
1475  *		callbacks before taking up the task of notifying ULPs
1476  *		and performing PRLO and LOGOs.
1477  *
1478  *		A port may go offline at the time PRLO/LOGO is being
1479  *		requested. It is expected of all FCA drivers to fail
1480  *		such requests either immediately with a FC_OFFLINE
1481  *		return code to fc_fca_transport() or return the packet
1482  *		asynchronously with pkt state set to FC_PKT_PORT_OFFLINE
1483  */
1484 static int
1485 fp_detach_handler(fc_local_port_t *port)
1486 {
1487 	job_request_t	*job;
1488 	uint32_t	delay_count;
1489 	fc_orphan_t	*orp, *tmporp;
1490 
1491 	/*
1492 	 * In a Fabric topology with many host ports connected to
1493 	 * a switch, another detaching instance of fp might have
1494 	 * triggered a LOGO (which is an unsolicited request to
1495 	 * this instance). So in order to be able to successfully
1496 	 * detach by taking care of such cases a delay of about
1497 	 * 30 seconds is introduced.
1498 	 */
1499 	delay_count = 0;
1500 	mutex_enter(&port->fp_mutex);
1501 	if (port->fp_out_fpcmds != 0) {
1502 		/*
1503 		 * At this time we can only check fp internal commands, because
1504 		 * sd/ssd/scsi_vhci should have finsihed all their commands,
1505 		 * fcp/fcip/fcsm should have finished all their commands.
1506 		 *
1507 		 * It seems that all fp internal commands are asynchronous now.
1508 		 */
1509 		port->fp_soft_state &= ~FP_DETACH_INPROGRESS;
1510 		mutex_exit(&port->fp_mutex);
1511 
1512 		cmn_err(CE_WARN, "fp(%d): %d fp_cmd(s) is/are in progress"
1513 		    " Failing detach", port->fp_instance, port->fp_out_fpcmds);
1514 		return (DDI_FAILURE);
1515 	}
1516 
1517 	while ((port->fp_soft_state &
1518 	    (FP_SOFT_IN_STATEC_CB | FP_SOFT_IN_UNSOL_CB)) &&
1519 	    (delay_count < 30)) {
1520 		mutex_exit(&port->fp_mutex);
1521 		delay_count++;
1522 		delay(drv_usectohz(1000000));
1523 		mutex_enter(&port->fp_mutex);
1524 	}
1525 
1526 	if (port->fp_soft_state &
1527 	    (FP_SOFT_IN_STATEC_CB | FP_SOFT_IN_UNSOL_CB)) {
1528 		port->fp_soft_state &= ~FP_DETACH_INPROGRESS;
1529 		mutex_exit(&port->fp_mutex);
1530 
1531 		cmn_err(CE_WARN, "fp(%d): FCA callback in progress: "
1532 		    " Failing detach", port->fp_instance);
1533 		return (DDI_FAILURE);
1534 	}
1535 
1536 	port->fp_soft_state |= FP_SOFT_IN_DETACH;
1537 	port->fp_soft_state &= ~FP_DETACH_INPROGRESS;
1538 	mutex_exit(&port->fp_mutex);
1539 
1540 	/*
1541 	 * If we're powered down, we need to raise power prior to submitting
1542 	 * the JOB_PORT_SHUTDOWN job.  Otherwise, the job handler will never
1543 	 * process the shutdown job.
1544 	 */
1545 	if (fctl_busy_port(port) != 0) {
1546 		cmn_err(CE_WARN, "fp(%d): fctl_busy_port failed",
1547 		    port->fp_instance);
1548 		mutex_enter(&port->fp_mutex);
1549 		port->fp_soft_state &= ~FP_SOFT_IN_DETACH;
1550 		mutex_exit(&port->fp_mutex);
1551 		return (DDI_FAILURE);
1552 	}
1553 
1554 	/*
1555 	 * This will deallocate data structs and cause the "job" thread
1556 	 * to exit, in preparation for DDI_DETACH on the instance.
1557 	 * This can sleep for an arbitrary duration, since it waits for
1558 	 * commands over the wire, timeout(9F) callbacks, etc.
1559 	 *
1560 	 * CAUTION: There is still a race here, where the "job" thread
1561 	 * can still be executing code even tho the fctl_jobwait() call
1562 	 * below has returned to us.  In theory the fp driver could even be
1563 	 * modunloaded even tho the job thread isn't done executing.
1564 	 * without creating the race condition.
1565 	 */
1566 	job = fctl_alloc_job(JOB_PORT_SHUTDOWN, 0, NULL,
1567 	    (opaque_t)port, KM_SLEEP);
1568 	fctl_enque_job(port, job);
1569 	fctl_jobwait(job);
1570 	fctl_dealloc_job(job);
1571 
1572 
1573 	(void) pm_lower_power(port->fp_port_dip, FP_PM_COMPONENT,
1574 	    FP_PM_PORT_DOWN);
1575 
1576 	if (port->fp_taskq) {
1577 		taskq_destroy(port->fp_taskq);
1578 	}
1579 
1580 	ddi_prop_remove_all(port->fp_port_dip);
1581 
1582 	ddi_remove_minor_node(port->fp_port_dip, NULL);
1583 
1584 	fctl_remove_port(port);
1585 
1586 	fp_free_pkt(port->fp_els_resp_pkt);
1587 
1588 	if (port->fp_ub_tokens) {
1589 		if (fc_ulp_ubfree(port, port->fp_ub_count,
1590 		    port->fp_ub_tokens) != FC_SUCCESS) {
1591 			cmn_err(CE_WARN, "fp(%d): couldn't free "
1592 			    " unsolicited buffers", port->fp_instance);
1593 		}
1594 		kmem_free(port->fp_ub_tokens,
1595 		    sizeof (*port->fp_ub_tokens) * port->fp_ub_count);
1596 		port->fp_ub_tokens = NULL;
1597 	}
1598 
1599 	if (port->fp_pkt_cache != NULL) {
1600 		kmem_cache_destroy(port->fp_pkt_cache);
1601 	}
1602 
1603 	port->fp_fca_tran->fca_unbind_port(port->fp_fca_handle);
1604 
1605 	mutex_enter(&port->fp_mutex);
1606 	if (port->fp_did_table) {
1607 		kmem_free(port->fp_did_table, did_table_size *
1608 		    sizeof (struct d_id_hash));
1609 	}
1610 
1611 	if (port->fp_pwwn_table) {
1612 		kmem_free(port->fp_pwwn_table, pwwn_table_size *
1613 		    sizeof (struct pwwn_hash));
1614 	}
1615 	orp = port->fp_orphan_list;
1616 	while (orp) {
1617 		tmporp = orp;
1618 		orp = orp->orp_next;
1619 		kmem_free(tmporp, sizeof (*orp));
1620 	}
1621 
1622 	mutex_exit(&port->fp_mutex);
1623 
1624 	fp_log_port_event(port, ESC_SUNFC_PORT_DETACH);
1625 
1626 	mutex_destroy(&port->fp_mutex);
1627 	cv_destroy(&port->fp_attach_cv);
1628 	cv_destroy(&port->fp_cv);
1629 	ddi_soft_state_free(fp_driver_softstate, port->fp_instance);
1630 
1631 	return (DDI_SUCCESS);
1632 }
1633 
1634 
1635 /*
1636  * Steps to perform DDI_SUSPEND operation on a FC port
1637  *
1638  *	- If already suspended return DDI_FAILURE
1639  *	- If already power-suspended return DDI_SUCCESS
1640  *	- If an unsolicited callback or state change handling is in
1641  *	    in progress, throw a warning message, return DDI_FAILURE
1642  *	- Cancel timeouts
1643  *	- SUSPEND the job_handler thread (means do nothing as it is
1644  *	    taken care of by the CPR frame work)
1645  */
1646 static int
1647 fp_suspend_handler(fc_local_port_t *port)
1648 {
1649 	uint32_t	delay_count;
1650 
1651 	mutex_enter(&port->fp_mutex);
1652 
1653 	/*
1654 	 * The following should never happen, but
1655 	 * let the driver be more defensive here
1656 	 */
1657 	if (port->fp_soft_state & FP_SOFT_SUSPEND) {
1658 		mutex_exit(&port->fp_mutex);
1659 		return (DDI_FAILURE);
1660 	}
1661 
1662 	/*
1663 	 * If the port is already power suspended, there
1664 	 * is nothing else to do, So return DDI_SUCCESS,
1665 	 * but mark the SUSPEND bit in the soft state
1666 	 * before leaving.
1667 	 */
1668 	if (port->fp_soft_state & FP_SOFT_POWER_DOWN) {
1669 		port->fp_soft_state |= FP_SOFT_SUSPEND;
1670 		mutex_exit(&port->fp_mutex);
1671 		return (DDI_SUCCESS);
1672 	}
1673 
1674 	/*
1675 	 * Check if an unsolicited callback or state change handling is
1676 	 * in progress. If true, fail the suspend operation; also throw
1677 	 * a warning message notifying the failure. Note that Sun PCI
1678 	 * hotplug spec recommends messages in cases of failure (but
1679 	 * not flooding the console)
1680 	 *
1681 	 * Busy waiting for a short interval (500 millisecond ?) to see
1682 	 * if the callback processing completes may be another idea. Since
1683 	 * most of the callback processing involves a lot of work, it
1684 	 * is safe to just fail the SUSPEND operation. It is definitely
1685 	 * not bad to fail the SUSPEND operation if the driver is busy.
1686 	 */
1687 	delay_count = 0;
1688 	while ((port->fp_soft_state & (FP_SOFT_IN_STATEC_CB |
1689 	    FP_SOFT_IN_UNSOL_CB)) && (delay_count < 30)) {
1690 		mutex_exit(&port->fp_mutex);
1691 		delay_count++;
1692 		delay(drv_usectohz(1000000));
1693 		mutex_enter(&port->fp_mutex);
1694 	}
1695 
1696 	if (port->fp_soft_state & (FP_SOFT_IN_STATEC_CB |
1697 	    FP_SOFT_IN_UNSOL_CB)) {
1698 		mutex_exit(&port->fp_mutex);
1699 		cmn_err(CE_WARN, "fp(%d): FCA callback in progress: "
1700 		    " Failing suspend", port->fp_instance);
1701 		return (DDI_FAILURE);
1702 	}
1703 
1704 	/*
1705 	 * Check of FC port thread is busy
1706 	 */
1707 	if (port->fp_job_head) {
1708 		mutex_exit(&port->fp_mutex);
1709 		FP_TRACE(FP_NHEAD2(9, 0),
1710 		    "FC port thread is busy: Failing suspend");
1711 		return (DDI_FAILURE);
1712 	}
1713 	port->fp_soft_state |= FP_SOFT_SUSPEND;
1714 
1715 	fp_suspend_all(port);
1716 	mutex_exit(&port->fp_mutex);
1717 
1718 	return (DDI_SUCCESS);
1719 }
1720 
1721 
1722 /*
1723  * Prepare for graceful power down of a FC port
1724  */
1725 static int
1726 fp_power_down(fc_local_port_t *port)
1727 {
1728 	ASSERT(MUTEX_HELD(&port->fp_mutex));
1729 
1730 	/*
1731 	 * Power down request followed by a DDI_SUSPEND should
1732 	 * never happen; If it does return DDI_SUCCESS
1733 	 */
1734 	if (port->fp_soft_state & FP_SOFT_SUSPEND) {
1735 		port->fp_soft_state |= FP_SOFT_POWER_DOWN;
1736 		return (DDI_SUCCESS);
1737 	}
1738 
1739 	/*
1740 	 * If the port is already power suspended, there
1741 	 * is nothing else to do, So return DDI_SUCCESS,
1742 	 */
1743 	if (port->fp_soft_state & FP_SOFT_POWER_DOWN) {
1744 		return (DDI_SUCCESS);
1745 	}
1746 
1747 	/*
1748 	 * Check if an unsolicited callback or state change handling
1749 	 * is in progress. If true, fail the PM suspend operation.
1750 	 * But don't print a message unless the verbosity of the
1751 	 * driver desires otherwise.
1752 	 */
1753 	if ((port->fp_soft_state & FP_SOFT_IN_STATEC_CB) ||
1754 	    (port->fp_soft_state & FP_SOFT_IN_UNSOL_CB)) {
1755 		FP_TRACE(FP_NHEAD2(9, 0),
1756 		    "Unsolicited callback in progress: Failing power down");
1757 		return (DDI_FAILURE);
1758 	}
1759 
1760 	/*
1761 	 * Check of FC port thread is busy
1762 	 */
1763 	if (port->fp_job_head) {
1764 		FP_TRACE(FP_NHEAD2(9, 0),
1765 		    "FC port thread is busy: Failing power down");
1766 		return (DDI_FAILURE);
1767 	}
1768 	port->fp_soft_state |= FP_SOFT_POWER_DOWN;
1769 
1770 	/*
1771 	 * check if the ULPs are ready for power down
1772 	 */
1773 	mutex_exit(&port->fp_mutex);
1774 	if (fctl_detach_ulps(port, FC_CMD_POWER_DOWN,
1775 	    &modlinkage) != FC_SUCCESS) {
1776 		mutex_enter(&port->fp_mutex);
1777 		port->fp_soft_state &= ~FP_SOFT_POWER_DOWN;
1778 		mutex_exit(&port->fp_mutex);
1779 
1780 		/*
1781 		 * Power back up the obedient ULPs that went down
1782 		 */
1783 		fp_attach_ulps(port, FC_CMD_POWER_UP);
1784 
1785 		FP_TRACE(FP_NHEAD2(9, 0),
1786 		    "ULP(s) busy, detach_ulps failed. Failing power down");
1787 		mutex_enter(&port->fp_mutex);
1788 		return (DDI_FAILURE);
1789 	}
1790 	mutex_enter(&port->fp_mutex);
1791 
1792 	fp_suspend_all(port);
1793 
1794 	return (DDI_SUCCESS);
1795 }
1796 
1797 
1798 /*
1799  * Suspend the entire FC port
1800  */
1801 static void
1802 fp_suspend_all(fc_local_port_t *port)
1803 {
1804 	int			index;
1805 	struct pwwn_hash	*head;
1806 	fc_remote_port_t	*pd;
1807 
1808 	ASSERT(MUTEX_HELD(&port->fp_mutex));
1809 
1810 	if (port->fp_wait_tid != 0) {
1811 		timeout_id_t	tid;
1812 
1813 		tid = port->fp_wait_tid;
1814 		port->fp_wait_tid = (timeout_id_t)NULL;
1815 		mutex_exit(&port->fp_mutex);
1816 		(void) untimeout(tid);
1817 		mutex_enter(&port->fp_mutex);
1818 		port->fp_restore |= FP_RESTORE_WAIT_TIMEOUT;
1819 	}
1820 
1821 	if (port->fp_offline_tid) {
1822 		timeout_id_t	tid;
1823 
1824 		tid = port->fp_offline_tid;
1825 		port->fp_offline_tid = (timeout_id_t)NULL;
1826 		mutex_exit(&port->fp_mutex);
1827 		(void) untimeout(tid);
1828 		mutex_enter(&port->fp_mutex);
1829 		port->fp_restore |= FP_RESTORE_OFFLINE_TIMEOUT;
1830 	}
1831 	mutex_exit(&port->fp_mutex);
1832 	port->fp_fca_tran->fca_unbind_port(port->fp_fca_handle);
1833 	mutex_enter(&port->fp_mutex);
1834 
1835 	/*
1836 	 * Mark all devices as OLD, and reset the LOGIN state as well
1837 	 * (this will force the ULPs to perform a LOGIN after calling
1838 	 * fc_portgetmap() during RESUME/PM_RESUME)
1839 	 */
1840 	for (index = 0; index < pwwn_table_size; index++) {
1841 		head = &port->fp_pwwn_table[index];
1842 		pd = head->pwwn_head;
1843 		while (pd != NULL) {
1844 			mutex_enter(&pd->pd_mutex);
1845 			fp_remote_port_offline(pd);
1846 			fctl_delist_did_table(port, pd);
1847 			pd->pd_state = PORT_DEVICE_VALID;
1848 			pd->pd_login_count = 0;
1849 			mutex_exit(&pd->pd_mutex);
1850 			pd = pd->pd_wwn_hnext;
1851 		}
1852 	}
1853 }
1854 
1855 
1856 /*
1857  * fp_cache_constructor: Constructor function for kmem_cache_create(9F).
1858  * Performs intializations for fc_packet_t structs.
1859  * Returns 0 for success or -1 for failure.
1860  *
1861  * This function allocates DMA handles for both command and responses.
1862  * Most of the ELSs used have both command and responses so it is strongly
1863  * desired to move them to cache constructor routine.
1864  *
1865  * Context: Can sleep iff called with KM_SLEEP flag.
1866  */
1867 static int
1868 fp_cache_constructor(void *buf, void *cdarg, int kmflags)
1869 {
1870 	int		(*cb) (caddr_t);
1871 	fc_packet_t	*pkt;
1872 	fp_cmd_t	*cmd = (fp_cmd_t *)buf;
1873 	fc_local_port_t *port = (fc_local_port_t *)cdarg;
1874 
1875 	cb = (kmflags == KM_SLEEP) ? DDI_DMA_SLEEP : DDI_DMA_DONTWAIT;
1876 
1877 	cmd->cmd_next = NULL;
1878 	cmd->cmd_flags = 0;
1879 	cmd->cmd_dflags = 0;
1880 	cmd->cmd_job = NULL;
1881 	cmd->cmd_port = port;
1882 	pkt = &cmd->cmd_pkt;
1883 
1884 	if (!(port->fp_soft_state & FP_SOFT_FCA_IS_NODMA)) {
1885 		if (ddi_dma_alloc_handle(port->fp_fca_dip,
1886 		    port->fp_fca_tran->fca_dma_attr, cb, NULL,
1887 		    &pkt->pkt_cmd_dma) != DDI_SUCCESS) {
1888 			return (-1);
1889 		}
1890 
1891 		if (ddi_dma_alloc_handle(port->fp_fca_dip,
1892 		    port->fp_fca_tran->fca_dma_attr, cb, NULL,
1893 		    &pkt->pkt_resp_dma) != DDI_SUCCESS) {
1894 			ddi_dma_free_handle(&pkt->pkt_cmd_dma);
1895 			return (-1);
1896 		}
1897 	} else {
1898 		pkt->pkt_cmd_dma = 0;
1899 		pkt->pkt_resp_dma = 0;
1900 	}
1901 
1902 	pkt->pkt_cmd_acc = pkt->pkt_resp_acc = NULL;
1903 	pkt->pkt_cmd_cookie_cnt = pkt->pkt_resp_cookie_cnt =
1904 	    pkt->pkt_data_cookie_cnt = 0;
1905 	pkt->pkt_cmd_cookie = pkt->pkt_resp_cookie =
1906 	    pkt->pkt_data_cookie = NULL;
1907 	pkt->pkt_fca_private = (caddr_t)buf + sizeof (fp_cmd_t);
1908 
1909 	return (0);
1910 }
1911 
1912 
1913 /*
1914  * fp_cache_destructor: Destructor function for kmem_cache_create().
1915  * Performs un-intializations for fc_packet_t structs.
1916  */
1917 /* ARGSUSED */
1918 static void
1919 fp_cache_destructor(void *buf, void *cdarg)
1920 {
1921 	fp_cmd_t	*cmd = (fp_cmd_t *)buf;
1922 	fc_packet_t	*pkt;
1923 
1924 	pkt = &cmd->cmd_pkt;
1925 	if (pkt->pkt_cmd_dma) {
1926 		ddi_dma_free_handle(&pkt->pkt_cmd_dma);
1927 	}
1928 
1929 	if (pkt->pkt_resp_dma) {
1930 		ddi_dma_free_handle(&pkt->pkt_resp_dma);
1931 	}
1932 }
1933 
1934 
1935 /*
1936  * Packet allocation for ELS and any other port driver commands
1937  *
1938  * Some ELSs like FLOGI and PLOGI are critical for topology and
1939  * device discovery and a system's inability to allocate memory
1940  * or DVMA resources while performing some of these critical ELSs
1941  * cause a lot of problem. While memory allocation failures are
1942  * rare, DVMA resource failures are common as the applications
1943  * are becoming more and more powerful on huge servers.	 So it
1944  * is desirable to have a framework support to reserve a fragment
1945  * of DVMA. So until this is fixed the correct way, the suffering
1946  * is huge whenever a LIP happens at a time DVMA resources are
1947  * drained out completely - So an attempt needs to be made to
1948  * KM_SLEEP while requesting for these resources, hoping that
1949  * the requests won't hang forever.
1950  *
1951  * The fc_remote_port_t argument is stored into the pkt_pd field in the
1952  * fc_packet_t struct prior to the fc_ulp_init_packet() call.  This
1953  * ensures that the pd_ref_count for the fc_remote_port_t is valid.
1954  * If there is no fc_remote_port_t associated with the fc_packet_t, then
1955  * fp_alloc_pkt() must be called with pd set to NULL.
1956  *
1957  * fp/fctl will resue fp_cmd_t somewhere, and change pkt_cmdlen/rsplen,
1958  * actually, it's a design fault. But there's no problem for physical
1959  * FCAs. But it will cause memory leak or panic for virtual FCAs like fcoei.
1960  *
1961  * For FCAs that don't support DMA, such as fcoei, we will use
1962  * pkt_fctl_rsvd1/rsvd2 to keep the real cmd_len/resp_len.
1963  */
1964 
1965 static fp_cmd_t *
1966 fp_alloc_pkt(fc_local_port_t *port, int cmd_len, int resp_len, int kmflags,
1967     fc_remote_port_t *pd)
1968 {
1969 	int		rval;
1970 	ulong_t		real_len;
1971 	fp_cmd_t	*cmd;
1972 	fc_packet_t	*pkt;
1973 	int		(*cb) (caddr_t);
1974 	ddi_dma_cookie_t	pkt_cookie;
1975 	ddi_dma_cookie_t	*cp;
1976 	uint32_t		cnt;
1977 
1978 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
1979 
1980 	cb = (kmflags == KM_SLEEP) ? DDI_DMA_SLEEP : DDI_DMA_DONTWAIT;
1981 
1982 	cmd = (fp_cmd_t *)kmem_cache_alloc(port->fp_pkt_cache, kmflags);
1983 	if (cmd == NULL) {
1984 		return (cmd);
1985 	}
1986 
1987 	cmd->cmd_ulp_pkt = NULL;
1988 	cmd->cmd_flags = 0;
1989 	pkt = &cmd->cmd_pkt;
1990 	ASSERT(cmd->cmd_dflags == 0);
1991 
1992 	pkt->pkt_datalen = 0;
1993 	pkt->pkt_data = NULL;
1994 	pkt->pkt_state = 0;
1995 	pkt->pkt_action = 0;
1996 	pkt->pkt_reason = 0;
1997 	pkt->pkt_expln = 0;
1998 	pkt->pkt_cmd = NULL;
1999 	pkt->pkt_resp = NULL;
2000 	pkt->pkt_fctl_rsvd1 = NULL;
2001 	pkt->pkt_fctl_rsvd2 = NULL;
2002 
2003 	/*
2004 	 * Init pkt_pd with the given pointer; this must be done _before_
2005 	 * the call to fc_ulp_init_packet().
2006 	 */
2007 	pkt->pkt_pd = pd;
2008 
2009 	/* Now call the FCA driver to init its private, per-packet fields */
2010 	if (fc_ulp_init_packet((opaque_t)port, pkt, kmflags) != FC_SUCCESS) {
2011 		goto alloc_pkt_failed;
2012 	}
2013 
2014 	if (cmd_len && !(port->fp_soft_state & FP_SOFT_FCA_IS_NODMA)) {
2015 		ASSERT(pkt->pkt_cmd_dma != NULL);
2016 
2017 		rval = ddi_dma_mem_alloc(pkt->pkt_cmd_dma, cmd_len,
2018 		    port->fp_fca_tran->fca_acc_attr, DDI_DMA_CONSISTENT,
2019 		    cb, NULL, (caddr_t *)&pkt->pkt_cmd, &real_len,
2020 		    &pkt->pkt_cmd_acc);
2021 
2022 		if (rval != DDI_SUCCESS) {
2023 			goto alloc_pkt_failed;
2024 		}
2025 		cmd->cmd_dflags |= FP_CMD_VALID_DMA_MEM;
2026 
2027 		if (real_len < cmd_len) {
2028 			goto alloc_pkt_failed;
2029 		}
2030 
2031 		rval = ddi_dma_addr_bind_handle(pkt->pkt_cmd_dma, NULL,
2032 		    pkt->pkt_cmd, real_len, DDI_DMA_WRITE |
2033 		    DDI_DMA_CONSISTENT, cb, NULL,
2034 		    &pkt_cookie, &pkt->pkt_cmd_cookie_cnt);
2035 
2036 		if (rval != DDI_DMA_MAPPED) {
2037 			goto alloc_pkt_failed;
2038 		}
2039 
2040 		cmd->cmd_dflags |= FP_CMD_VALID_DMA_BIND;
2041 
2042 		if (pkt->pkt_cmd_cookie_cnt >
2043 		    port->fp_fca_tran->fca_dma_attr->dma_attr_sgllen) {
2044 			goto alloc_pkt_failed;
2045 		}
2046 
2047 		ASSERT(pkt->pkt_cmd_cookie_cnt != 0);
2048 
2049 		cp = pkt->pkt_cmd_cookie = (ddi_dma_cookie_t *)kmem_alloc(
2050 		    pkt->pkt_cmd_cookie_cnt * sizeof (pkt_cookie),
2051 		    KM_NOSLEEP);
2052 
2053 		if (cp == NULL) {
2054 			goto alloc_pkt_failed;
2055 		}
2056 
2057 		*cp = pkt_cookie;
2058 		cp++;
2059 		for (cnt = 1; cnt < pkt->pkt_cmd_cookie_cnt; cnt++, cp++) {
2060 			ddi_dma_nextcookie(pkt->pkt_cmd_dma, &pkt_cookie);
2061 			*cp = pkt_cookie;
2062 		}
2063 	} else if (cmd_len != 0) {
2064 		pkt->pkt_cmd = kmem_alloc(cmd_len, KM_SLEEP);
2065 		pkt->pkt_fctl_rsvd1 = (opaque_t)(uintptr_t)cmd_len;
2066 	}
2067 
2068 	if (resp_len && !(port->fp_soft_state & FP_SOFT_FCA_IS_NODMA)) {
2069 		ASSERT(pkt->pkt_resp_dma != NULL);
2070 
2071 		rval = ddi_dma_mem_alloc(pkt->pkt_resp_dma, resp_len,
2072 		    port->fp_fca_tran->fca_acc_attr,
2073 		    DDI_DMA_CONSISTENT, cb, NULL,
2074 		    (caddr_t *)&pkt->pkt_resp, &real_len,
2075 		    &pkt->pkt_resp_acc);
2076 
2077 		if (rval != DDI_SUCCESS) {
2078 			goto alloc_pkt_failed;
2079 		}
2080 		cmd->cmd_dflags |= FP_RESP_VALID_DMA_MEM;
2081 
2082 		if (real_len < resp_len) {
2083 			goto alloc_pkt_failed;
2084 		}
2085 
2086 		rval = ddi_dma_addr_bind_handle(pkt->pkt_resp_dma, NULL,
2087 		    pkt->pkt_resp, real_len, DDI_DMA_READ |
2088 		    DDI_DMA_CONSISTENT, cb, NULL,
2089 		    &pkt_cookie, &pkt->pkt_resp_cookie_cnt);
2090 
2091 		if (rval != DDI_DMA_MAPPED) {
2092 			goto alloc_pkt_failed;
2093 		}
2094 
2095 		cmd->cmd_dflags |= FP_RESP_VALID_DMA_BIND;
2096 
2097 		if (pkt->pkt_resp_cookie_cnt >
2098 		    port->fp_fca_tran->fca_dma_attr->dma_attr_sgllen) {
2099 			goto alloc_pkt_failed;
2100 		}
2101 
2102 		ASSERT(pkt->pkt_cmd_cookie_cnt != 0);
2103 
2104 		cp = pkt->pkt_resp_cookie = (ddi_dma_cookie_t *)kmem_alloc(
2105 		    pkt->pkt_resp_cookie_cnt * sizeof (pkt_cookie),
2106 		    KM_NOSLEEP);
2107 
2108 		if (cp == NULL) {
2109 			goto alloc_pkt_failed;
2110 		}
2111 
2112 		*cp = pkt_cookie;
2113 		cp++;
2114 		for (cnt = 1; cnt < pkt->pkt_resp_cookie_cnt; cnt++, cp++) {
2115 			ddi_dma_nextcookie(pkt->pkt_resp_dma, &pkt_cookie);
2116 			*cp = pkt_cookie;
2117 		}
2118 	} else if (resp_len != 0) {
2119 		pkt->pkt_resp = kmem_alloc(resp_len, KM_SLEEP);
2120 		pkt->pkt_fctl_rsvd2 = (opaque_t)(uintptr_t)resp_len;
2121 	}
2122 
2123 	pkt->pkt_cmdlen = cmd_len;
2124 	pkt->pkt_rsplen = resp_len;
2125 	pkt->pkt_ulp_private = cmd;
2126 
2127 	return (cmd);
2128 
2129 alloc_pkt_failed:
2130 
2131 	fp_free_dma(cmd);
2132 
2133 	if (pkt->pkt_cmd_cookie != NULL) {
2134 		kmem_free(pkt->pkt_cmd_cookie,
2135 		    pkt->pkt_cmd_cookie_cnt * sizeof (ddi_dma_cookie_t));
2136 		pkt->pkt_cmd_cookie = NULL;
2137 	}
2138 
2139 	if (pkt->pkt_resp_cookie != NULL) {
2140 		kmem_free(pkt->pkt_resp_cookie,
2141 		    pkt->pkt_resp_cookie_cnt * sizeof (ddi_dma_cookie_t));
2142 		pkt->pkt_resp_cookie = NULL;
2143 	}
2144 
2145 	if (port->fp_soft_state & FP_SOFT_FCA_IS_NODMA) {
2146 		if (pkt->pkt_cmd) {
2147 			kmem_free(pkt->pkt_cmd, cmd_len);
2148 		}
2149 
2150 		if (pkt->pkt_resp) {
2151 			kmem_free(pkt->pkt_resp, resp_len);
2152 		}
2153 	}
2154 
2155 	kmem_cache_free(port->fp_pkt_cache, cmd);
2156 
2157 	return (NULL);
2158 }
2159 
2160 
2161 /*
2162  * Free FC packet
2163  */
2164 static void
2165 fp_free_pkt(fp_cmd_t *cmd)
2166 {
2167 	fc_local_port_t *port;
2168 	fc_packet_t	*pkt;
2169 
2170 	ASSERT(!MUTEX_HELD(&cmd->cmd_port->fp_mutex));
2171 
2172 	cmd->cmd_next = NULL;
2173 	cmd->cmd_job = NULL;
2174 	pkt = &cmd->cmd_pkt;
2175 	pkt->pkt_ulp_private = 0;
2176 	pkt->pkt_tran_flags = 0;
2177 	pkt->pkt_tran_type = 0;
2178 	port = cmd->cmd_port;
2179 
2180 	if (pkt->pkt_cmd_cookie != NULL) {
2181 		kmem_free(pkt->pkt_cmd_cookie, pkt->pkt_cmd_cookie_cnt *
2182 		    sizeof (ddi_dma_cookie_t));
2183 		pkt->pkt_cmd_cookie = NULL;
2184 	}
2185 
2186 	if (pkt->pkt_resp_cookie != NULL) {
2187 		kmem_free(pkt->pkt_resp_cookie, pkt->pkt_resp_cookie_cnt *
2188 		    sizeof (ddi_dma_cookie_t));
2189 		pkt->pkt_resp_cookie = NULL;
2190 	}
2191 
2192 	if (port->fp_soft_state & FP_SOFT_FCA_IS_NODMA) {
2193 		if (pkt->pkt_cmd) {
2194 			kmem_free(pkt->pkt_cmd,
2195 			    (uint32_t)(uintptr_t)pkt->pkt_fctl_rsvd1);
2196 		}
2197 
2198 		if (pkt->pkt_resp) {
2199 			kmem_free(pkt->pkt_resp,
2200 			    (uint32_t)(uintptr_t)pkt->pkt_fctl_rsvd2);
2201 		}
2202 	}
2203 
2204 	fp_free_dma(cmd);
2205 	(void) fc_ulp_uninit_packet((opaque_t)port, pkt);
2206 	kmem_cache_free(port->fp_pkt_cache, (void *)cmd);
2207 }
2208 
2209 
2210 /*
2211  * Release DVMA resources
2212  */
2213 static void
2214 fp_free_dma(fp_cmd_t *cmd)
2215 {
2216 	fc_packet_t *pkt = &cmd->cmd_pkt;
2217 
2218 	pkt->pkt_cmdlen = 0;
2219 	pkt->pkt_rsplen = 0;
2220 	pkt->pkt_tran_type = 0;
2221 	pkt->pkt_tran_flags = 0;
2222 
2223 	if (cmd->cmd_dflags & FP_CMD_VALID_DMA_BIND) {
2224 		(void) ddi_dma_unbind_handle(pkt->pkt_cmd_dma);
2225 	}
2226 
2227 	if (cmd->cmd_dflags & FP_CMD_VALID_DMA_MEM) {
2228 		if (pkt->pkt_cmd_acc) {
2229 			ddi_dma_mem_free(&pkt->pkt_cmd_acc);
2230 		}
2231 	}
2232 
2233 	if (cmd->cmd_dflags & FP_RESP_VALID_DMA_BIND) {
2234 		(void) ddi_dma_unbind_handle(pkt->pkt_resp_dma);
2235 	}
2236 
2237 	if (cmd->cmd_dflags & FP_RESP_VALID_DMA_MEM) {
2238 		if (pkt->pkt_resp_acc) {
2239 			ddi_dma_mem_free(&pkt->pkt_resp_acc);
2240 		}
2241 	}
2242 	cmd->cmd_dflags = 0;
2243 }
2244 
2245 
2246 /*
2247  * Dedicated thread to perform various activities.  One thread for
2248  * each fc_local_port_t (driver soft state) instance.
2249  * Note, this effectively works out to one thread for each local
2250  * port, but there are also some Solaris taskq threads in use on a per-local
2251  * port basis; these also need to be taken into consideration.
2252  */
2253 static void
2254 fp_job_handler(fc_local_port_t *port)
2255 {
2256 	int			rval;
2257 	uint32_t		*d_id;
2258 	fc_remote_port_t	*pd;
2259 	job_request_t		*job;
2260 
2261 #ifndef	__lock_lint
2262 	/*
2263 	 * Solaris-internal stuff for proper operation of kernel threads
2264 	 * with Solaris CPR.
2265 	 */
2266 	CALLB_CPR_INIT(&port->fp_cpr_info, &port->fp_mutex,
2267 	    callb_generic_cpr, "fp_job_handler");
2268 #endif
2269 
2270 
2271 	/* Loop forever waiting for work to do */
2272 	for (;;) {
2273 
2274 		mutex_enter(&port->fp_mutex);
2275 
2276 		/*
2277 		 * Sleep if no work to do right now, or if we want
2278 		 * to suspend or power-down.
2279 		 */
2280 		while (port->fp_job_head == NULL ||
2281 		    (port->fp_soft_state & (FP_SOFT_POWER_DOWN |
2282 		    FP_SOFT_SUSPEND))) {
2283 			CALLB_CPR_SAFE_BEGIN(&port->fp_cpr_info);
2284 			cv_wait(&port->fp_cv, &port->fp_mutex);
2285 			CALLB_CPR_SAFE_END(&port->fp_cpr_info, &port->fp_mutex);
2286 		}
2287 
2288 		/*
2289 		 * OK, we've just been woken up, so retrieve the next entry
2290 		 * from the head of the job queue for this local port.
2291 		 */
2292 		job = fctl_deque_job(port);
2293 
2294 		/*
2295 		 * Handle all the fp driver's supported job codes here
2296 		 * in this big honkin' switch.
2297 		 */
2298 		switch (job->job_code) {
2299 		case JOB_PORT_SHUTDOWN:
2300 			/*
2301 			 * fp_port_shutdown() is only called from here. This
2302 			 * will prepare the local port instance (softstate)
2303 			 * for detaching.  This cancels timeout callbacks,
2304 			 * executes LOGOs with remote ports, cleans up tables,
2305 			 * and deallocates data structs.
2306 			 */
2307 			fp_port_shutdown(port, job);
2308 
2309 			/*
2310 			 * This will exit the job thread.
2311 			 */
2312 #ifndef __lock_lint
2313 			CALLB_CPR_EXIT(&(port->fp_cpr_info));
2314 #else
2315 			mutex_exit(&port->fp_mutex);
2316 #endif
2317 			fctl_jobdone(job);
2318 			thread_exit();
2319 
2320 			/* NOTREACHED */
2321 
2322 		case JOB_ATTACH_ULP: {
2323 			/*
2324 			 * This job is spawned in response to a ULP calling
2325 			 * fc_ulp_add().
2326 			 */
2327 
2328 			boolean_t do_attach_ulps = B_TRUE;
2329 
2330 			/*
2331 			 * If fp is detaching, we don't want to call
2332 			 * fp_startup_done as this asynchronous
2333 			 * notification may interfere with the re-attach.
2334 			 */
2335 
2336 			if (port->fp_soft_state & (FP_DETACH_INPROGRESS |
2337 			    FP_SOFT_IN_DETACH | FP_DETACH_FAILED)) {
2338 				do_attach_ulps = B_FALSE;
2339 			} else {
2340 				/*
2341 				 * We are going to force the transport
2342 				 * to attach to the ULPs, so set
2343 				 * fp_ulp_attach.  This will keep any
2344 				 * potential detach from occurring until
2345 				 * we are done.
2346 				 */
2347 				port->fp_ulp_attach = 1;
2348 			}
2349 
2350 			mutex_exit(&port->fp_mutex);
2351 
2352 			/*
2353 			 * NOTE: Since we just dropped the mutex, there is now
2354 			 * a race window where the fp_soft_state check above
2355 			 * could change here.  This race is covered because an
2356 			 * additional check was added in the functions hidden
2357 			 * under fp_startup_done().
2358 			 */
2359 			if (do_attach_ulps == B_TRUE) {
2360 				/*
2361 				 * This goes thru a bit of a convoluted call
2362 				 * chain before spawning off a DDI taskq
2363 				 * request to perform the actual attach
2364 				 * operations. Blocking can occur at a number
2365 				 * of points.
2366 				 */
2367 				fp_startup_done((opaque_t)port, FC_PKT_SUCCESS);
2368 			}
2369 			job->job_result = FC_SUCCESS;
2370 			fctl_jobdone(job);
2371 			break;
2372 		}
2373 
2374 		case JOB_ULP_NOTIFY: {
2375 			/*
2376 			 * Pass state change notifications up to any/all
2377 			 * registered ULPs.
2378 			 */
2379 			uint32_t statec;
2380 
2381 			statec = job->job_ulp_listlen;
2382 			if (statec == FC_STATE_RESET_REQUESTED) {
2383 				port->fp_last_task = port->fp_task;
2384 				port->fp_task = FP_TASK_OFFLINE;
2385 				fp_port_offline(port, 0);
2386 				port->fp_task = port->fp_last_task;
2387 				port->fp_last_task = FP_TASK_IDLE;
2388 			}
2389 
2390 			if (--port->fp_statec_busy == 0) {
2391 				port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
2392 			}
2393 
2394 			mutex_exit(&port->fp_mutex);
2395 
2396 			job->job_result = fp_ulp_notify(port, statec, KM_SLEEP);
2397 			fctl_jobdone(job);
2398 			break;
2399 		}
2400 
2401 		case JOB_PLOGI_ONE:
2402 			/*
2403 			 * Issue a PLOGI to a single remote port. Multiple
2404 			 * PLOGIs to different remote ports may occur in
2405 			 * parallel.
2406 			 * This can create the fc_remote_port_t if it does not
2407 			 * already exist.
2408 			 */
2409 
2410 			mutex_exit(&port->fp_mutex);
2411 			d_id = (uint32_t *)job->job_private;
2412 			pd = fctl_get_remote_port_by_did(port, *d_id);
2413 
2414 			if (pd) {
2415 				mutex_enter(&pd->pd_mutex);
2416 				if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
2417 					pd->pd_login_count++;
2418 					mutex_exit(&pd->pd_mutex);
2419 					job->job_result = FC_SUCCESS;
2420 					fctl_jobdone(job);
2421 					break;
2422 				}
2423 				mutex_exit(&pd->pd_mutex);
2424 			} else {
2425 				mutex_enter(&port->fp_mutex);
2426 				if (FC_IS_TOP_SWITCH(port->fp_topology)) {
2427 					mutex_exit(&port->fp_mutex);
2428 					pd = fp_create_remote_port_by_ns(port,
2429 					    *d_id, KM_SLEEP);
2430 					if (pd == NULL) {
2431 						job->job_result = FC_FAILURE;
2432 						fctl_jobdone(job);
2433 						break;
2434 					}
2435 				} else {
2436 					mutex_exit(&port->fp_mutex);
2437 				}
2438 			}
2439 
2440 			job->job_flags |= JOB_TYPE_FP_ASYNC;
2441 			job->job_counter = 1;
2442 
2443 			rval = fp_port_login(port, *d_id, job,
2444 			    FP_CMD_PLOGI_RETAIN, KM_SLEEP, pd, NULL);
2445 
2446 			if (rval != FC_SUCCESS) {
2447 				job->job_result = rval;
2448 				fctl_jobdone(job);
2449 			}
2450 			break;
2451 
2452 		case JOB_LOGO_ONE: {
2453 			/*
2454 			 * Issue a PLOGO to a single remote port. Multiple
2455 			 * PLOGOs to different remote ports may occur in
2456 			 * parallel.
2457 			 */
2458 			fc_remote_port_t *pd;
2459 
2460 #ifndef	__lock_lint
2461 			ASSERT(job->job_counter > 0);
2462 #endif
2463 
2464 			pd = (fc_remote_port_t *)job->job_ulp_pkts;
2465 
2466 			mutex_enter(&pd->pd_mutex);
2467 			if (pd->pd_state != PORT_DEVICE_LOGGED_IN) {
2468 				mutex_exit(&pd->pd_mutex);
2469 				job->job_result = FC_LOGINREQ;
2470 				mutex_exit(&port->fp_mutex);
2471 				fctl_jobdone(job);
2472 				break;
2473 			}
2474 			if (pd->pd_login_count > 1) {
2475 				pd->pd_login_count--;
2476 				mutex_exit(&pd->pd_mutex);
2477 				job->job_result = FC_SUCCESS;
2478 				mutex_exit(&port->fp_mutex);
2479 				fctl_jobdone(job);
2480 				break;
2481 			}
2482 			mutex_exit(&pd->pd_mutex);
2483 			mutex_exit(&port->fp_mutex);
2484 			job->job_flags |= JOB_TYPE_FP_ASYNC;
2485 			(void) fp_logout(port, pd, job);
2486 			break;
2487 		}
2488 
2489 		case JOB_FCIO_LOGIN:
2490 			/*
2491 			 * PLOGI initiated at ioctl request.
2492 			 */
2493 			mutex_exit(&port->fp_mutex);
2494 			job->job_result =
2495 			    fp_fcio_login(port, job->job_private, job);
2496 			fctl_jobdone(job);
2497 			break;
2498 
2499 		case JOB_FCIO_LOGOUT:
2500 			/*
2501 			 * PLOGO initiated at ioctl request.
2502 			 */
2503 			mutex_exit(&port->fp_mutex);
2504 			job->job_result =
2505 			    fp_fcio_logout(port, job->job_private, job);
2506 			fctl_jobdone(job);
2507 			break;
2508 
2509 		case JOB_PORT_GETMAP:
2510 		case JOB_PORT_GETMAP_PLOGI_ALL: {
2511 			port->fp_last_task = port->fp_task;
2512 			port->fp_task = FP_TASK_GETMAP;
2513 
2514 			switch (port->fp_topology) {
2515 			case FC_TOP_PRIVATE_LOOP:
2516 				job->job_counter = 1;
2517 
2518 				fp_get_loopmap(port, job);
2519 				mutex_exit(&port->fp_mutex);
2520 				fp_jobwait(job);
2521 				fctl_fillout_map(port,
2522 				    (fc_portmap_t **)job->job_private,
2523 				    (uint32_t *)job->job_arg, 1, 0, 0);
2524 				fctl_jobdone(job);
2525 				mutex_enter(&port->fp_mutex);
2526 				break;
2527 
2528 			case FC_TOP_PUBLIC_LOOP:
2529 			case FC_TOP_FABRIC:
2530 				mutex_exit(&port->fp_mutex);
2531 				job->job_counter = 1;
2532 
2533 				job->job_result = fp_ns_getmap(port,
2534 				    job, (fc_portmap_t **)job->job_private,
2535 				    (uint32_t *)job->job_arg,
2536 				    FCTL_GAN_START_ID);
2537 				fctl_jobdone(job);
2538 				mutex_enter(&port->fp_mutex);
2539 				break;
2540 
2541 			case FC_TOP_PT_PT:
2542 				mutex_exit(&port->fp_mutex);
2543 				fctl_fillout_map(port,
2544 				    (fc_portmap_t **)job->job_private,
2545 				    (uint32_t *)job->job_arg, 1, 0, 0);
2546 				fctl_jobdone(job);
2547 				mutex_enter(&port->fp_mutex);
2548 				break;
2549 
2550 			default:
2551 				mutex_exit(&port->fp_mutex);
2552 				fctl_jobdone(job);
2553 				mutex_enter(&port->fp_mutex);
2554 				break;
2555 			}
2556 			port->fp_task = port->fp_last_task;
2557 			port->fp_last_task = FP_TASK_IDLE;
2558 			mutex_exit(&port->fp_mutex);
2559 			break;
2560 		}
2561 
2562 		case JOB_PORT_OFFLINE: {
2563 			fp_log_port_event(port, ESC_SUNFC_PORT_OFFLINE);
2564 
2565 			port->fp_last_task = port->fp_task;
2566 			port->fp_task = FP_TASK_OFFLINE;
2567 
2568 			if (port->fp_statec_busy > 2) {
2569 				job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION;
2570 				fp_port_offline(port, 0);
2571 				if (--port->fp_statec_busy == 0) {
2572 					port->fp_soft_state &=
2573 					    ~FP_SOFT_IN_STATEC_CB;
2574 				}
2575 			} else {
2576 				fp_port_offline(port, 1);
2577 			}
2578 
2579 			port->fp_task = port->fp_last_task;
2580 			port->fp_last_task = FP_TASK_IDLE;
2581 
2582 			mutex_exit(&port->fp_mutex);
2583 
2584 			fctl_jobdone(job);
2585 			break;
2586 		}
2587 
2588 		case JOB_PORT_STARTUP: {
2589 			if ((rval = fp_port_startup(port, job)) != FC_SUCCESS) {
2590 				if (port->fp_statec_busy > 1) {
2591 					mutex_exit(&port->fp_mutex);
2592 					break;
2593 				}
2594 				mutex_exit(&port->fp_mutex);
2595 
2596 				FP_TRACE(FP_NHEAD2(9, rval),
2597 				    "Topology discovery failed");
2598 				break;
2599 			}
2600 
2601 			/*
2602 			 * Attempt building device handles in case
2603 			 * of private Loop.
2604 			 */
2605 			if (port->fp_topology == FC_TOP_PRIVATE_LOOP) {
2606 				job->job_counter = 1;
2607 
2608 				fp_get_loopmap(port, job);
2609 				mutex_exit(&port->fp_mutex);
2610 				fp_jobwait(job);
2611 				mutex_enter(&port->fp_mutex);
2612 				if (port->fp_lilp_map.lilp_magic < MAGIC_LIRP) {
2613 					ASSERT(port->fp_total_devices == 0);
2614 					port->fp_total_devices =
2615 					    port->fp_dev_count;
2616 				}
2617 			} else if (FC_IS_TOP_SWITCH(port->fp_topology)) {
2618 				/*
2619 				 * Hack to avoid state changes going up early
2620 				 */
2621 				port->fp_statec_busy++;
2622 				port->fp_soft_state |= FP_SOFT_IN_STATEC_CB;
2623 
2624 				job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION;
2625 				fp_fabric_online(port, job);
2626 				job->job_flags &= ~JOB_CANCEL_ULP_NOTIFICATION;
2627 			}
2628 			mutex_exit(&port->fp_mutex);
2629 			fctl_jobdone(job);
2630 			break;
2631 		}
2632 
2633 		case JOB_PORT_ONLINE: {
2634 			char		*newtop;
2635 			char		*oldtop;
2636 			uint32_t	old_top;
2637 
2638 			fp_log_port_event(port, ESC_SUNFC_PORT_ONLINE);
2639 
2640 			/*
2641 			 * Bail out early if there are a lot of
2642 			 * state changes in the pipeline
2643 			 */
2644 			if (port->fp_statec_busy > 1) {
2645 				--port->fp_statec_busy;
2646 				mutex_exit(&port->fp_mutex);
2647 				fctl_jobdone(job);
2648 				break;
2649 			}
2650 
2651 			switch (old_top = port->fp_topology) {
2652 			case FC_TOP_PRIVATE_LOOP:
2653 				oldtop = "Private Loop";
2654 				break;
2655 
2656 			case FC_TOP_PUBLIC_LOOP:
2657 				oldtop = "Public Loop";
2658 				break;
2659 
2660 			case FC_TOP_PT_PT:
2661 				oldtop = "Point to Point";
2662 				break;
2663 
2664 			case FC_TOP_FABRIC:
2665 				oldtop = "Fabric";
2666 				break;
2667 
2668 			default:
2669 				oldtop = NULL;
2670 				break;
2671 			}
2672 
2673 			port->fp_last_task = port->fp_task;
2674 			port->fp_task = FP_TASK_ONLINE;
2675 
2676 			if ((rval = fp_port_startup(port, job)) != FC_SUCCESS) {
2677 
2678 				port->fp_task = port->fp_last_task;
2679 				port->fp_last_task = FP_TASK_IDLE;
2680 
2681 				if (port->fp_statec_busy > 1) {
2682 					--port->fp_statec_busy;
2683 					mutex_exit(&port->fp_mutex);
2684 					break;
2685 				}
2686 
2687 				port->fp_state = FC_STATE_OFFLINE;
2688 
2689 				FP_TRACE(FP_NHEAD2(9, rval),
2690 				    "Topology discovery failed");
2691 
2692 				if (--port->fp_statec_busy == 0) {
2693 					port->fp_soft_state &=
2694 					    ~FP_SOFT_IN_STATEC_CB;
2695 				}
2696 
2697 				if (port->fp_offline_tid == NULL) {
2698 					port->fp_offline_tid =
2699 					    timeout(fp_offline_timeout,
2700 					    (caddr_t)port, fp_offline_ticks);
2701 				}
2702 
2703 				mutex_exit(&port->fp_mutex);
2704 				break;
2705 			}
2706 
2707 			switch (port->fp_topology) {
2708 			case FC_TOP_PRIVATE_LOOP:
2709 				newtop = "Private Loop";
2710 				break;
2711 
2712 			case FC_TOP_PUBLIC_LOOP:
2713 				newtop = "Public Loop";
2714 				break;
2715 
2716 			case FC_TOP_PT_PT:
2717 				newtop = "Point to Point";
2718 				break;
2719 
2720 			case FC_TOP_FABRIC:
2721 				newtop = "Fabric";
2722 				break;
2723 
2724 			default:
2725 				newtop = NULL;
2726 				break;
2727 			}
2728 
2729 			if (oldtop && newtop && strcmp(oldtop, newtop)) {
2730 				fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
2731 				    "Change in FC Topology old = %s new = %s",
2732 				    oldtop, newtop);
2733 			}
2734 
2735 			switch (port->fp_topology) {
2736 			case FC_TOP_PRIVATE_LOOP: {
2737 				int orphan = (old_top == FC_TOP_FABRIC ||
2738 				    old_top == FC_TOP_PUBLIC_LOOP) ? 1 : 0;
2739 
2740 				mutex_exit(&port->fp_mutex);
2741 				fp_loop_online(port, job, orphan);
2742 				break;
2743 			}
2744 
2745 			case FC_TOP_PUBLIC_LOOP:
2746 				/* FALLTHROUGH */
2747 			case FC_TOP_FABRIC:
2748 				fp_fabric_online(port, job);
2749 				mutex_exit(&port->fp_mutex);
2750 				break;
2751 
2752 			case FC_TOP_PT_PT:
2753 				fp_p2p_online(port, job);
2754 				mutex_exit(&port->fp_mutex);
2755 				break;
2756 
2757 			default:
2758 				if (--port->fp_statec_busy != 0) {
2759 					/*
2760 					 * Watch curiously at what the next
2761 					 * state transition can do.
2762 					 */
2763 					mutex_exit(&port->fp_mutex);
2764 					break;
2765 				}
2766 
2767 				FP_TRACE(FP_NHEAD2(9, 0),
2768 				    "Topology Unknown, Offlining the port..");
2769 
2770 				port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
2771 				port->fp_state = FC_STATE_OFFLINE;
2772 
2773 				if (port->fp_offline_tid == NULL) {
2774 					port->fp_offline_tid =
2775 					    timeout(fp_offline_timeout,
2776 					    (caddr_t)port, fp_offline_ticks);
2777 				}
2778 				mutex_exit(&port->fp_mutex);
2779 				break;
2780 			}
2781 
2782 			mutex_enter(&port->fp_mutex);
2783 
2784 			port->fp_task = port->fp_last_task;
2785 			port->fp_last_task = FP_TASK_IDLE;
2786 
2787 			mutex_exit(&port->fp_mutex);
2788 
2789 			fctl_jobdone(job);
2790 			break;
2791 		}
2792 
2793 		case JOB_PLOGI_GROUP: {
2794 			mutex_exit(&port->fp_mutex);
2795 			fp_plogi_group(port, job);
2796 			break;
2797 		}
2798 
2799 		case JOB_UNSOL_REQUEST: {
2800 			mutex_exit(&port->fp_mutex);
2801 			fp_handle_unsol_buf(port,
2802 			    (fc_unsol_buf_t *)job->job_private, job);
2803 			fctl_dealloc_job(job);
2804 			break;
2805 		}
2806 
2807 		case JOB_NS_CMD: {
2808 			fctl_ns_req_t *ns_cmd;
2809 
2810 			mutex_exit(&port->fp_mutex);
2811 
2812 			job->job_flags |= JOB_TYPE_FP_ASYNC;
2813 			ns_cmd = (fctl_ns_req_t *)job->job_private;
2814 			if (ns_cmd->ns_cmd_code < NS_GA_NXT ||
2815 			    ns_cmd->ns_cmd_code > NS_DA_ID) {
2816 				job->job_result = FC_BADCMD;
2817 				fctl_jobdone(job);
2818 				break;
2819 			}
2820 
2821 			if (FC_IS_CMD_A_REG(ns_cmd->ns_cmd_code)) {
2822 				if (ns_cmd->ns_pd != NULL) {
2823 					job->job_result = FC_BADOBJECT;
2824 					fctl_jobdone(job);
2825 					break;
2826 				}
2827 
2828 				job->job_counter = 1;
2829 
2830 				rval = fp_ns_reg(port, ns_cmd->ns_pd,
2831 				    ns_cmd->ns_cmd_code, job, 0, KM_SLEEP);
2832 
2833 				if (rval != FC_SUCCESS) {
2834 					job->job_result = rval;
2835 					fctl_jobdone(job);
2836 				}
2837 				break;
2838 			}
2839 			job->job_result = FC_SUCCESS;
2840 			job->job_counter = 1;
2841 
2842 			rval = fp_ns_query(port, ns_cmd, job, 0, KM_SLEEP);
2843 			if (rval != FC_SUCCESS) {
2844 				fctl_jobdone(job);
2845 			}
2846 			break;
2847 		}
2848 
2849 		case JOB_LINK_RESET: {
2850 			la_wwn_t *pwwn;
2851 			uint32_t topology;
2852 
2853 			pwwn = (la_wwn_t *)job->job_private;
2854 			ASSERT(pwwn != NULL);
2855 
2856 			topology = port->fp_topology;
2857 			mutex_exit(&port->fp_mutex);
2858 
2859 			if (fctl_is_wwn_zero(pwwn) == FC_SUCCESS ||
2860 			    topology == FC_TOP_PRIVATE_LOOP) {
2861 				job->job_flags |= JOB_TYPE_FP_ASYNC;
2862 				rval = port->fp_fca_tran->fca_reset(
2863 				    port->fp_fca_handle, FC_FCA_LINK_RESET);
2864 				job->job_result = rval;
2865 				fp_jobdone(job);
2866 			} else {
2867 				ASSERT((job->job_flags &
2868 				    JOB_TYPE_FP_ASYNC) == 0);
2869 
2870 				if (FC_IS_TOP_SWITCH(topology)) {
2871 					rval = fp_remote_lip(port, pwwn,
2872 					    KM_SLEEP, job);
2873 				} else {
2874 					rval = FC_FAILURE;
2875 				}
2876 				if (rval != FC_SUCCESS) {
2877 					job->job_result = rval;
2878 				}
2879 				fctl_jobdone(job);
2880 			}
2881 			break;
2882 		}
2883 
2884 		default:
2885 			mutex_exit(&port->fp_mutex);
2886 			job->job_result = FC_BADCMD;
2887 			fctl_jobdone(job);
2888 			break;
2889 		}
2890 	}
2891 	/* NOTREACHED */
2892 }
2893 
2894 
2895 /*
2896  * Perform FC port bring up initialization
2897  */
2898 static int
2899 fp_port_startup(fc_local_port_t *port, job_request_t *job)
2900 {
2901 	int		rval;
2902 	uint32_t	state;
2903 	uint32_t	src_id;
2904 	fc_lilpmap_t	*lilp_map;
2905 
2906 	ASSERT(MUTEX_HELD(&port->fp_mutex));
2907 	ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
2908 
2909 	FP_DTRACE(FP_NHEAD1(2, 0), "Entering fp_port_startup;"
2910 	    " port=%p, job=%p", port, job);
2911 
2912 	port->fp_topology = FC_TOP_UNKNOWN;
2913 	port->fp_port_id.port_id = 0;
2914 	state = FC_PORT_STATE_MASK(port->fp_state);
2915 
2916 	if (state == FC_STATE_OFFLINE) {
2917 		port->fp_port_type.port_type = FC_NS_PORT_UNKNOWN;
2918 		job->job_result = FC_OFFLINE;
2919 		mutex_exit(&port->fp_mutex);
2920 		fctl_jobdone(job);
2921 		mutex_enter(&port->fp_mutex);
2922 		return (FC_OFFLINE);
2923 	}
2924 
2925 	if (state == FC_STATE_LOOP) {
2926 		port->fp_port_type.port_type = FC_NS_PORT_NL;
2927 		mutex_exit(&port->fp_mutex);
2928 
2929 		lilp_map = &port->fp_lilp_map;
2930 		if ((rval = fp_get_lilpmap(port, lilp_map)) != FC_SUCCESS) {
2931 			job->job_result = FC_FAILURE;
2932 			fctl_jobdone(job);
2933 
2934 			FP_TRACE(FP_NHEAD1(9, rval),
2935 			    "LILP map Invalid or not present");
2936 			mutex_enter(&port->fp_mutex);
2937 			return (FC_FAILURE);
2938 		}
2939 
2940 		if (lilp_map->lilp_length == 0) {
2941 			job->job_result = FC_NO_MAP;
2942 			fctl_jobdone(job);
2943 			fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
2944 			    "LILP map length zero");
2945 			mutex_enter(&port->fp_mutex);
2946 			return (FC_NO_MAP);
2947 		}
2948 		src_id = lilp_map->lilp_myalpa & 0xFF;
2949 	} else {
2950 		fc_remote_port_t	*pd;
2951 		fc_fca_pm_t		pm;
2952 		fc_fca_p2p_info_t	p2p_info;
2953 		int			pd_recepient;
2954 
2955 		/*
2956 		 * Get P2P remote port info if possible
2957 		 */
2958 		bzero((caddr_t)&pm, sizeof (pm));
2959 
2960 		pm.pm_cmd_flags = FC_FCA_PM_READ;
2961 		pm.pm_cmd_code = FC_PORT_GET_P2P_INFO;
2962 		pm.pm_data_len = sizeof (fc_fca_p2p_info_t);
2963 		pm.pm_data_buf = (caddr_t)&p2p_info;
2964 
2965 		rval = port->fp_fca_tran->fca_port_manage(
2966 		    port->fp_fca_handle, &pm);
2967 
2968 		if (rval == FC_SUCCESS) {
2969 			port->fp_port_id.port_id = p2p_info.fca_d_id;
2970 			port->fp_port_type.port_type = FC_NS_PORT_N;
2971 			port->fp_topology = FC_TOP_PT_PT;
2972 			port->fp_total_devices = 1;
2973 			pd_recepient = fctl_wwn_cmp(
2974 			    &port->fp_service_params.nport_ww_name,
2975 			    &p2p_info.pwwn) < 0 ?
2976 			    PD_PLOGI_RECEPIENT : PD_PLOGI_INITIATOR;
2977 			mutex_exit(&port->fp_mutex);
2978 			pd = fctl_create_remote_port(port,
2979 			    &p2p_info.nwwn,
2980 			    &p2p_info.pwwn,
2981 			    p2p_info.d_id,
2982 			    pd_recepient, KM_NOSLEEP);
2983 			FP_DTRACE(FP_NHEAD1(2, 0), "Exiting fp_port_startup;"
2984 			    " P2P port=%p pd=%p fp %x pd %x", port, pd,
2985 			    port->fp_port_id.port_id, p2p_info.d_id);
2986 			mutex_enter(&port->fp_mutex);
2987 			return (FC_SUCCESS);
2988 		}
2989 		port->fp_port_type.port_type = FC_NS_PORT_N;
2990 		mutex_exit(&port->fp_mutex);
2991 		src_id = 0;
2992 	}
2993 
2994 	job->job_counter = 1;
2995 	job->job_result = FC_SUCCESS;
2996 
2997 	if ((rval = fp_fabric_login(port, src_id, job, FP_CMD_PLOGI_DONT_CARE,
2998 	    KM_SLEEP)) != FC_SUCCESS) {
2999 		port->fp_port_type.port_type = FC_NS_PORT_UNKNOWN;
3000 		job->job_result = FC_FAILURE;
3001 		fctl_jobdone(job);
3002 
3003 		mutex_enter(&port->fp_mutex);
3004 		if (port->fp_statec_busy <= 1) {
3005 			mutex_exit(&port->fp_mutex);
3006 			fp_printf(port, CE_NOTE, FP_LOG_ONLY, rval, NULL,
3007 			    "Couldn't transport FLOGI");
3008 			mutex_enter(&port->fp_mutex);
3009 		}
3010 		return (FC_FAILURE);
3011 	}
3012 
3013 	fp_jobwait(job);
3014 
3015 	mutex_enter(&port->fp_mutex);
3016 	if (job->job_result == FC_SUCCESS) {
3017 		if (FC_IS_TOP_SWITCH(port->fp_topology)) {
3018 			mutex_exit(&port->fp_mutex);
3019 			fp_ns_init(port, job, KM_SLEEP);
3020 			mutex_enter(&port->fp_mutex);
3021 		}
3022 	} else {
3023 		if (state == FC_STATE_LOOP) {
3024 			port->fp_topology = FC_TOP_PRIVATE_LOOP;
3025 			port->fp_port_id.port_id =
3026 			    port->fp_lilp_map.lilp_myalpa & 0xFF;
3027 		}
3028 	}
3029 
3030 	FP_DTRACE(FP_NHEAD1(2, 0), "Exiting fp_port_startup; port=%p, job=%p",
3031 	    port, job);
3032 
3033 	return (FC_SUCCESS);
3034 }
3035 
3036 
3037 /*
3038  * Perform ULP invocations following FC port startup
3039  */
3040 /* ARGSUSED */
3041 static void
3042 fp_startup_done(opaque_t arg, uchar_t result)
3043 {
3044 	fc_local_port_t *port = arg;
3045 
3046 	fp_attach_ulps(port, FC_CMD_ATTACH);
3047 
3048 	FP_DTRACE(FP_NHEAD1(2, 0), "fp_startup almost complete; port=%p", port);
3049 }
3050 
3051 
3052 /*
3053  * Perform ULP port attach
3054  */
3055 static void
3056 fp_ulp_port_attach(void *arg)
3057 {
3058 	fp_soft_attach_t *att = (fp_soft_attach_t *)arg;
3059 	fc_local_port_t	 *port = att->att_port;
3060 
3061 	FP_DTRACE(FP_NHEAD1(1, 0), "port attach of"
3062 	    " ULPs begin; port=%p, cmd=%x", port, att->att_cmd);
3063 
3064 	fctl_attach_ulps(att->att_port, att->att_cmd, &modlinkage);
3065 
3066 	if (att->att_need_pm_idle == B_TRUE) {
3067 		fctl_idle_port(port);
3068 	}
3069 
3070 	FP_DTRACE(FP_NHEAD1(1, 0), "port attach of"
3071 	    " ULPs end; port=%p, cmd=%x", port, att->att_cmd);
3072 
3073 	mutex_enter(&att->att_port->fp_mutex);
3074 	att->att_port->fp_ulp_attach = 0;
3075 
3076 	port->fp_task = port->fp_last_task;
3077 	port->fp_last_task = FP_TASK_IDLE;
3078 
3079 	cv_signal(&att->att_port->fp_attach_cv);
3080 
3081 	mutex_exit(&att->att_port->fp_mutex);
3082 
3083 	kmem_free(att, sizeof (fp_soft_attach_t));
3084 }
3085 
3086 /*
3087  * Entry point to funnel all requests down to FCAs
3088  */
3089 static int
3090 fp_sendcmd(fc_local_port_t *port, fp_cmd_t *cmd, opaque_t fca_handle)
3091 {
3092 	int rval;
3093 
3094 	mutex_enter(&port->fp_mutex);
3095 	if (port->fp_statec_busy > 1 || (cmd->cmd_ulp_pkt != NULL &&
3096 	    (port->fp_statec_busy || FC_PORT_STATE_MASK(port->fp_state) ==
3097 	    FC_STATE_OFFLINE))) {
3098 		/*
3099 		 * This means there is more than one state change
3100 		 * at this point of time - Since they are processed
3101 		 * serially, any processing of the current one should
3102 		 * be failed, failed and move up in processing the next
3103 		 */
3104 		cmd->cmd_pkt.pkt_state = FC_PKT_ELS_IN_PROGRESS;
3105 		cmd->cmd_pkt.pkt_reason = FC_REASON_OFFLINE;
3106 		if (cmd->cmd_job) {
3107 			/*
3108 			 * A state change that is going to be invalidated
3109 			 * by another one already in the port driver's queue
3110 			 * need not go up to all ULPs. This will minimize
3111 			 * needless processing and ripples in ULP modules
3112 			 */
3113 			cmd->cmd_job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION;
3114 		}
3115 		mutex_exit(&port->fp_mutex);
3116 		return (FC_STATEC_BUSY);
3117 	}
3118 
3119 	if (FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) {
3120 		cmd->cmd_pkt.pkt_state = FC_PKT_PORT_OFFLINE;
3121 		cmd->cmd_pkt.pkt_reason = FC_REASON_OFFLINE;
3122 		mutex_exit(&port->fp_mutex);
3123 
3124 		return (FC_OFFLINE);
3125 	}
3126 	mutex_exit(&port->fp_mutex);
3127 
3128 	rval = cmd->cmd_transport(fca_handle, &cmd->cmd_pkt);
3129 	if (rval != FC_SUCCESS) {
3130 		if (rval == FC_TRAN_BUSY) {
3131 			cmd->cmd_retry_interval = fp_retry_delay;
3132 			rval = fp_retry_cmd(&cmd->cmd_pkt);
3133 			if (rval == FC_FAILURE) {
3134 				cmd->cmd_pkt.pkt_state = FC_PKT_TRAN_BSY;
3135 			}
3136 		}
3137 	} else {
3138 		mutex_enter(&port->fp_mutex);
3139 		port->fp_out_fpcmds++;
3140 		mutex_exit(&port->fp_mutex);
3141 	}
3142 
3143 	return (rval);
3144 }
3145 
3146 
3147 /*
3148  * Each time a timeout kicks in, walk the wait queue, decrement the
3149  * the retry_interval, when the retry_interval becomes less than
3150  * or equal to zero, re-transport the command: If the re-transport
3151  * fails with BUSY, enqueue the command in the wait queue.
3152  *
3153  * In order to prevent looping forever because of commands enqueued
3154  * from within this function itself, save the current tail pointer
3155  * (in cur_tail) and exit the loop after serving this command.
3156  */
3157 static void
3158 fp_resendcmd(void *port_handle)
3159 {
3160 	int		rval;
3161 	fc_local_port_t	*port;
3162 	fp_cmd_t	*cmd;
3163 	fp_cmd_t	*cur_tail;
3164 
3165 	port = port_handle;
3166 	mutex_enter(&port->fp_mutex);
3167 	cur_tail = port->fp_wait_tail;
3168 	mutex_exit(&port->fp_mutex);
3169 
3170 	while ((cmd = fp_deque_cmd(port)) != NULL) {
3171 		cmd->cmd_retry_interval -= fp_retry_ticker;
3172 		/* Check if we are detaching */
3173 		if (port->fp_soft_state &
3174 		    (FP_SOFT_IN_DETACH | FP_DETACH_INPROGRESS)) {
3175 			cmd->cmd_pkt.pkt_state = FC_PKT_TRAN_ERROR;
3176 			cmd->cmd_pkt.pkt_reason = 0;
3177 			fp_iodone(cmd);
3178 		} else if (cmd->cmd_retry_interval <= 0) {
3179 			rval = cmd->cmd_transport(port->fp_fca_handle,
3180 			    &cmd->cmd_pkt);
3181 
3182 			if (rval != FC_SUCCESS) {
3183 				if (cmd->cmd_pkt.pkt_state == FC_PKT_TRAN_BSY) {
3184 					if (--cmd->cmd_retry_count) {
3185 						fp_enque_cmd(port, cmd);
3186 						if (cmd == cur_tail) {
3187 							break;
3188 						}
3189 						continue;
3190 					}
3191 					cmd->cmd_pkt.pkt_state =
3192 					    FC_PKT_TRAN_BSY;
3193 				} else {
3194 					cmd->cmd_pkt.pkt_state =
3195 					    FC_PKT_TRAN_ERROR;
3196 				}
3197 				cmd->cmd_pkt.pkt_reason = 0;
3198 				fp_iodone(cmd);
3199 			} else {
3200 				mutex_enter(&port->fp_mutex);
3201 				port->fp_out_fpcmds++;
3202 				mutex_exit(&port->fp_mutex);
3203 			}
3204 		} else {
3205 			fp_enque_cmd(port, cmd);
3206 		}
3207 
3208 		if (cmd == cur_tail) {
3209 			break;
3210 		}
3211 	}
3212 
3213 	mutex_enter(&port->fp_mutex);
3214 	if (port->fp_wait_head) {
3215 		timeout_id_t tid;
3216 
3217 		mutex_exit(&port->fp_mutex);
3218 		tid = timeout(fp_resendcmd, (caddr_t)port,
3219 		    fp_retry_ticks);
3220 		mutex_enter(&port->fp_mutex);
3221 		port->fp_wait_tid = tid;
3222 	} else {
3223 		port->fp_wait_tid = NULL;
3224 	}
3225 	mutex_exit(&port->fp_mutex);
3226 }
3227 
3228 
3229 /*
3230  * Handle Local, Fabric, N_Port, Transport (whatever that means) BUSY here.
3231  *
3232  * Yes, as you can see below, cmd_retry_count is used here too.	 That means
3233  * the retries for BUSY are less if there were transport failures (transport
3234  * failure means fca_transport failure). The goal is not to exceed overall
3235  * retries set in the cmd_retry_count (whatever may be the reason for retry)
3236  *
3237  * Return Values:
3238  *	FC_SUCCESS
3239  *	FC_FAILURE
3240  */
3241 static int
3242 fp_retry_cmd(fc_packet_t *pkt)
3243 {
3244 	fp_cmd_t *cmd;
3245 
3246 	cmd = pkt->pkt_ulp_private;
3247 
3248 	if (--cmd->cmd_retry_count) {
3249 		fp_enque_cmd(cmd->cmd_port, cmd);
3250 		return (FC_SUCCESS);
3251 	} else {
3252 		return (FC_FAILURE);
3253 	}
3254 }
3255 
3256 
3257 /*
3258  * Queue up FC packet for deferred retry
3259  */
3260 static void
3261 fp_enque_cmd(fc_local_port_t *port, fp_cmd_t *cmd)
3262 {
3263 	timeout_id_t tid;
3264 
3265 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
3266 
3267 #ifdef	DEBUG
3268 	fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, &cmd->cmd_pkt,
3269 	    "Retrying ELS for %x", cmd->cmd_pkt.pkt_cmd_fhdr.d_id);
3270 #endif
3271 
3272 	mutex_enter(&port->fp_mutex);
3273 	if (port->fp_wait_tail) {
3274 		port->fp_wait_tail->cmd_next = cmd;
3275 		port->fp_wait_tail = cmd;
3276 	} else {
3277 		ASSERT(port->fp_wait_head == NULL);
3278 		port->fp_wait_head = port->fp_wait_tail = cmd;
3279 		if (port->fp_wait_tid == NULL) {
3280 			mutex_exit(&port->fp_mutex);
3281 			tid = timeout(fp_resendcmd, (caddr_t)port,
3282 			    fp_retry_ticks);
3283 			mutex_enter(&port->fp_mutex);
3284 			port->fp_wait_tid = tid;
3285 		}
3286 	}
3287 	mutex_exit(&port->fp_mutex);
3288 }
3289 
3290 
3291 /*
3292  * Handle all RJT codes
3293  */
3294 static int
3295 fp_handle_reject(fc_packet_t *pkt)
3296 {
3297 	int		rval = FC_FAILURE;
3298 	uchar_t		next_class;
3299 	fp_cmd_t	*cmd;
3300 	fc_local_port_t *port;
3301 
3302 	cmd = pkt->pkt_ulp_private;
3303 	port = cmd->cmd_port;
3304 
3305 	switch (pkt->pkt_state) {
3306 	case FC_PKT_FABRIC_RJT:
3307 	case FC_PKT_NPORT_RJT:
3308 		if (pkt->pkt_reason == FC_REASON_CLASS_NOT_SUPP) {
3309 			next_class = fp_get_nextclass(cmd->cmd_port,
3310 			    FC_TRAN_CLASS(pkt->pkt_tran_flags));
3311 
3312 			if (next_class == FC_TRAN_CLASS_INVALID) {
3313 				return (rval);
3314 			}
3315 			pkt->pkt_tran_flags = FC_TRAN_INTR | next_class;
3316 			pkt->pkt_tran_type = FC_PKT_EXCHANGE;
3317 
3318 			rval = fp_sendcmd(cmd->cmd_port, cmd,
3319 			    cmd->cmd_port->fp_fca_handle);
3320 
3321 			if (rval != FC_SUCCESS) {
3322 				pkt->pkt_state = FC_PKT_TRAN_ERROR;
3323 			}
3324 		}
3325 		break;
3326 
3327 	case FC_PKT_LS_RJT:
3328 	case FC_PKT_BA_RJT:
3329 		if ((pkt->pkt_reason == FC_REASON_LOGICAL_ERROR) ||
3330 		    (pkt->pkt_reason == FC_REASON_LOGICAL_BSY)) {
3331 			cmd->cmd_retry_interval = fp_retry_delay;
3332 			rval = fp_retry_cmd(pkt);
3333 		}
3334 		break;
3335 
3336 	case FC_PKT_FS_RJT:
3337 		if ((pkt->pkt_reason == FC_REASON_FS_LOGICAL_BUSY) ||
3338 		    ((pkt->pkt_reason == FC_REASON_FS_CMD_UNABLE) &&
3339 		    (pkt->pkt_expln == 0x00))) {
3340 			cmd->cmd_retry_interval = fp_retry_delay;
3341 			rval = fp_retry_cmd(pkt);
3342 		}
3343 		break;
3344 
3345 	case FC_PKT_LOCAL_RJT:
3346 		if (pkt->pkt_reason == FC_REASON_QFULL) {
3347 			cmd->cmd_retry_interval = fp_retry_delay;
3348 			rval = fp_retry_cmd(pkt);
3349 		}
3350 		break;
3351 
3352 	default:
3353 		FP_TRACE(FP_NHEAD1(1, 0),
3354 		    "fp_handle_reject(): Invalid pkt_state");
3355 		break;
3356 	}
3357 
3358 	return (rval);
3359 }
3360 
3361 
3362 /*
3363  * Return the next class of service supported by the FCA
3364  */
3365 static uchar_t
3366 fp_get_nextclass(fc_local_port_t *port, uchar_t cur_class)
3367 {
3368 	uchar_t next_class;
3369 
3370 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
3371 
3372 	switch (cur_class) {
3373 	case FC_TRAN_CLASS_INVALID:
3374 		if (port->fp_cos & FC_NS_CLASS1) {
3375 			next_class = FC_TRAN_CLASS1;
3376 			break;
3377 		}
3378 		/* FALLTHROUGH */
3379 
3380 	case FC_TRAN_CLASS1:
3381 		if (port->fp_cos & FC_NS_CLASS2) {
3382 			next_class = FC_TRAN_CLASS2;
3383 			break;
3384 		}
3385 		/* FALLTHROUGH */
3386 
3387 	case FC_TRAN_CLASS2:
3388 		if (port->fp_cos & FC_NS_CLASS3) {
3389 			next_class = FC_TRAN_CLASS3;
3390 			break;
3391 		}
3392 		/* FALLTHROUGH */
3393 
3394 	case FC_TRAN_CLASS3:
3395 	default:
3396 		next_class = FC_TRAN_CLASS_INVALID;
3397 		break;
3398 	}
3399 
3400 	return (next_class);
3401 }
3402 
3403 
3404 /*
3405  * Determine if a class of service is supported by the FCA
3406  */
3407 static int
3408 fp_is_class_supported(uint32_t cos, uchar_t tran_class)
3409 {
3410 	int rval;
3411 
3412 	switch (tran_class) {
3413 	case FC_TRAN_CLASS1:
3414 		if (cos & FC_NS_CLASS1) {
3415 			rval = FC_SUCCESS;
3416 		} else {
3417 			rval = FC_FAILURE;
3418 		}
3419 		break;
3420 
3421 	case FC_TRAN_CLASS2:
3422 		if (cos & FC_NS_CLASS2) {
3423 			rval = FC_SUCCESS;
3424 		} else {
3425 			rval = FC_FAILURE;
3426 		}
3427 		break;
3428 
3429 	case FC_TRAN_CLASS3:
3430 		if (cos & FC_NS_CLASS3) {
3431 			rval = FC_SUCCESS;
3432 		} else {
3433 			rval = FC_FAILURE;
3434 		}
3435 		break;
3436 
3437 	default:
3438 		rval = FC_FAILURE;
3439 		break;
3440 	}
3441 
3442 	return (rval);
3443 }
3444 
3445 
3446 /*
3447  * Dequeue FC packet for retry
3448  */
3449 static fp_cmd_t *
3450 fp_deque_cmd(fc_local_port_t *port)
3451 {
3452 	fp_cmd_t *cmd;
3453 
3454 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
3455 
3456 	mutex_enter(&port->fp_mutex);
3457 
3458 	if (port->fp_wait_head == NULL) {
3459 		/*
3460 		 * To avoid races, NULL the fp_wait_tid as
3461 		 * we are about to exit the timeout thread.
3462 		 */
3463 		port->fp_wait_tid = NULL;
3464 		mutex_exit(&port->fp_mutex);
3465 		return (NULL);
3466 	}
3467 
3468 	cmd = port->fp_wait_head;
3469 	port->fp_wait_head = cmd->cmd_next;
3470 	cmd->cmd_next = NULL;
3471 
3472 	if (port->fp_wait_head == NULL) {
3473 		port->fp_wait_tail = NULL;
3474 	}
3475 	mutex_exit(&port->fp_mutex);
3476 
3477 	return (cmd);
3478 }
3479 
3480 
3481 /*
3482  * Wait for job completion
3483  */
3484 static void
3485 fp_jobwait(job_request_t *job)
3486 {
3487 	sema_p(&job->job_port_sema);
3488 }
3489 
3490 
3491 /*
3492  * Convert FC packet state to FC errno
3493  */
3494 int
3495 fp_state_to_rval(uchar_t state)
3496 {
3497 	int count;
3498 
3499 	for (count = 0; count < sizeof (fp_xlat) /
3500 	    sizeof (fp_xlat[0]); count++) {
3501 		if (fp_xlat[count].xlat_state == state) {
3502 			return (fp_xlat[count].xlat_rval);
3503 		}
3504 	}
3505 
3506 	return (FC_FAILURE);
3507 }
3508 
3509 
3510 /*
3511  * For Synchronous I/O requests, the caller is
3512  * expected to do fctl_jobdone(if necessary)
3513  *
3514  * We want to preserve at least one failure in the
3515  * job_result if it happens.
3516  *
3517  */
3518 static void
3519 fp_iodone(fp_cmd_t *cmd)
3520 {
3521 	fc_packet_t		*ulp_pkt = cmd->cmd_ulp_pkt;
3522 	job_request_t		*job = cmd->cmd_job;
3523 	fc_remote_port_t	*pd = cmd->cmd_pkt.pkt_pd;
3524 
3525 	ASSERT(job != NULL);
3526 	ASSERT(cmd->cmd_port != NULL);
3527 	ASSERT(&cmd->cmd_pkt != NULL);
3528 
3529 	mutex_enter(&job->job_mutex);
3530 	if (job->job_result == FC_SUCCESS) {
3531 		job->job_result = fp_state_to_rval(cmd->cmd_pkt.pkt_state);
3532 	}
3533 	mutex_exit(&job->job_mutex);
3534 
3535 	if (pd) {
3536 		mutex_enter(&pd->pd_mutex);
3537 		pd->pd_flags = PD_IDLE;
3538 		mutex_exit(&pd->pd_mutex);
3539 	}
3540 
3541 	if (ulp_pkt) {
3542 		if (pd && cmd->cmd_flags & FP_CMD_DELDEV_ON_ERROR &&
3543 		    FP_IS_PKT_ERROR(ulp_pkt)) {
3544 			fc_local_port_t		*port;
3545 			fc_remote_node_t	*node;
3546 
3547 			port = cmd->cmd_port;
3548 
3549 			mutex_enter(&pd->pd_mutex);
3550 			pd->pd_state = PORT_DEVICE_INVALID;
3551 			pd->pd_ref_count--;
3552 			node = pd->pd_remote_nodep;
3553 			mutex_exit(&pd->pd_mutex);
3554 
3555 			ASSERT(node != NULL);
3556 			ASSERT(port != NULL);
3557 
3558 			if (fctl_destroy_remote_port(port, pd) == 0) {
3559 				fctl_destroy_remote_node(node);
3560 			}
3561 
3562 			ulp_pkt->pkt_pd = NULL;
3563 		}
3564 
3565 		ulp_pkt->pkt_comp(ulp_pkt);
3566 	}
3567 
3568 	fp_free_pkt(cmd);
3569 	fp_jobdone(job);
3570 }
3571 
3572 
3573 /*
3574  * Job completion handler
3575  */
3576 static void
3577 fp_jobdone(job_request_t *job)
3578 {
3579 	mutex_enter(&job->job_mutex);
3580 	ASSERT(job->job_counter > 0);
3581 
3582 	if (--job->job_counter != 0) {
3583 		mutex_exit(&job->job_mutex);
3584 		return;
3585 	}
3586 
3587 	if (job->job_ulp_pkts) {
3588 		ASSERT(job->job_ulp_listlen > 0);
3589 		kmem_free(job->job_ulp_pkts,
3590 		    sizeof (fc_packet_t *) * job->job_ulp_listlen);
3591 	}
3592 
3593 	if (job->job_flags & JOB_TYPE_FP_ASYNC) {
3594 		mutex_exit(&job->job_mutex);
3595 		fctl_jobdone(job);
3596 	} else {
3597 		mutex_exit(&job->job_mutex);
3598 		sema_v(&job->job_port_sema);
3599 	}
3600 }
3601 
3602 
3603 /*
3604  * Try to perform shutdown of a port during a detach. No return
3605  * value since the detach should not fail because the port shutdown
3606  * failed.
3607  */
3608 static void
3609 fp_port_shutdown(fc_local_port_t *port, job_request_t *job)
3610 {
3611 	int			index;
3612 	int			count;
3613 	int			flags;
3614 	fp_cmd_t		*cmd;
3615 	struct pwwn_hash	*head;
3616 	fc_remote_port_t	*pd;
3617 
3618 	ASSERT(MUTEX_HELD(&port->fp_mutex));
3619 
3620 	job->job_result = FC_SUCCESS;
3621 
3622 	if (port->fp_taskq) {
3623 		/*
3624 		 * We must release the mutex here to ensure that other
3625 		 * potential jobs can complete their processing.  Many
3626 		 * also need this mutex.
3627 		 */
3628 		mutex_exit(&port->fp_mutex);
3629 		taskq_wait(port->fp_taskq);
3630 		mutex_enter(&port->fp_mutex);
3631 	}
3632 
3633 	if (port->fp_offline_tid) {
3634 		timeout_id_t tid;
3635 
3636 		tid = port->fp_offline_tid;
3637 		port->fp_offline_tid = NULL;
3638 		mutex_exit(&port->fp_mutex);
3639 		(void) untimeout(tid);
3640 		mutex_enter(&port->fp_mutex);
3641 	}
3642 
3643 	if (port->fp_wait_tid) {
3644 		timeout_id_t tid;
3645 
3646 		tid = port->fp_wait_tid;
3647 		port->fp_wait_tid = NULL;
3648 		mutex_exit(&port->fp_mutex);
3649 		(void) untimeout(tid);
3650 	} else {
3651 		mutex_exit(&port->fp_mutex);
3652 	}
3653 
3654 	/*
3655 	 * While we cancel the timeout, let's also return the
3656 	 * the outstanding requests back to the callers.
3657 	 */
3658 	while ((cmd = fp_deque_cmd(port)) != NULL) {
3659 		ASSERT(cmd->cmd_job != NULL);
3660 		cmd->cmd_job->job_result = FC_OFFLINE;
3661 		fp_iodone(cmd);
3662 	}
3663 
3664 	/*
3665 	 * Gracefully LOGO with all the devices logged in.
3666 	 */
3667 	mutex_enter(&port->fp_mutex);
3668 
3669 	for (count = index = 0; index < pwwn_table_size; index++) {
3670 		head = &port->fp_pwwn_table[index];
3671 		pd = head->pwwn_head;
3672 		while (pd != NULL) {
3673 			mutex_enter(&pd->pd_mutex);
3674 			if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
3675 				count++;
3676 			}
3677 			mutex_exit(&pd->pd_mutex);
3678 			pd = pd->pd_wwn_hnext;
3679 		}
3680 	}
3681 
3682 	if (job->job_flags & JOB_TYPE_FP_ASYNC) {
3683 		flags = job->job_flags;
3684 		job->job_flags &= ~JOB_TYPE_FP_ASYNC;
3685 	} else {
3686 		flags = 0;
3687 	}
3688 	if (count) {
3689 		job->job_counter = count;
3690 
3691 		for (index = 0; index < pwwn_table_size; index++) {
3692 			head = &port->fp_pwwn_table[index];
3693 			pd = head->pwwn_head;
3694 			while (pd != NULL) {
3695 				mutex_enter(&pd->pd_mutex);
3696 				if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
3697 					ASSERT(pd->pd_login_count > 0);
3698 					/*
3699 					 * Force the counter to ONE in order
3700 					 * for us to really send LOGO els.
3701 					 */
3702 					pd->pd_login_count = 1;
3703 					mutex_exit(&pd->pd_mutex);
3704 					mutex_exit(&port->fp_mutex);
3705 					(void) fp_logout(port, pd, job);
3706 					mutex_enter(&port->fp_mutex);
3707 				} else {
3708 					mutex_exit(&pd->pd_mutex);
3709 				}
3710 				pd = pd->pd_wwn_hnext;
3711 			}
3712 		}
3713 		mutex_exit(&port->fp_mutex);
3714 		fp_jobwait(job);
3715 	} else {
3716 		mutex_exit(&port->fp_mutex);
3717 	}
3718 
3719 	if (job->job_result != FC_SUCCESS) {
3720 		FP_TRACE(FP_NHEAD1(9, 0),
3721 		    "Can't logout all devices. Proceeding with"
3722 		    " port shutdown");
3723 		job->job_result = FC_SUCCESS;
3724 	}
3725 
3726 	fctl_destroy_all_remote_ports(port);
3727 
3728 	mutex_enter(&port->fp_mutex);
3729 	if (FC_IS_TOP_SWITCH(port->fp_topology)) {
3730 		mutex_exit(&port->fp_mutex);
3731 		fp_ns_fini(port, job);
3732 	} else {
3733 		mutex_exit(&port->fp_mutex);
3734 	}
3735 
3736 	if (flags) {
3737 		job->job_flags = flags;
3738 	}
3739 
3740 	mutex_enter(&port->fp_mutex);
3741 
3742 }
3743 
3744 
3745 /*
3746  * Build the port driver's data structures based on the AL_PA list
3747  */
3748 static void
3749 fp_get_loopmap(fc_local_port_t *port, job_request_t *job)
3750 {
3751 	int			rval;
3752 	int			flag;
3753 	int			count;
3754 	uint32_t		d_id;
3755 	fc_remote_port_t	*pd;
3756 	fc_lilpmap_t		*lilp_map;
3757 
3758 	ASSERT(MUTEX_HELD(&port->fp_mutex));
3759 
3760 	if (FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) {
3761 		job->job_result = FC_OFFLINE;
3762 		mutex_exit(&port->fp_mutex);
3763 		fp_jobdone(job);
3764 		mutex_enter(&port->fp_mutex);
3765 		return;
3766 	}
3767 
3768 	if (port->fp_lilp_map.lilp_length == 0) {
3769 		mutex_exit(&port->fp_mutex);
3770 		job->job_result = FC_NO_MAP;
3771 		fp_jobdone(job);
3772 		mutex_enter(&port->fp_mutex);
3773 		return;
3774 	}
3775 	mutex_exit(&port->fp_mutex);
3776 
3777 	lilp_map = &port->fp_lilp_map;
3778 	job->job_counter = lilp_map->lilp_length;
3779 
3780 	if (job->job_code == JOB_PORT_GETMAP_PLOGI_ALL) {
3781 		flag = FP_CMD_PLOGI_RETAIN;
3782 	} else {
3783 		flag = FP_CMD_PLOGI_DONT_CARE;
3784 	}
3785 
3786 	for (count = 0; count < lilp_map->lilp_length; count++) {
3787 		d_id = lilp_map->lilp_alpalist[count];
3788 
3789 		if (d_id == (lilp_map->lilp_myalpa & 0xFF)) {
3790 			fp_jobdone(job);
3791 			continue;
3792 		}
3793 
3794 		pd = fctl_get_remote_port_by_did(port, d_id);
3795 		if (pd) {
3796 			mutex_enter(&pd->pd_mutex);
3797 			if (flag == FP_CMD_PLOGI_DONT_CARE ||
3798 			    pd->pd_state == PORT_DEVICE_LOGGED_IN) {
3799 				mutex_exit(&pd->pd_mutex);
3800 				fp_jobdone(job);
3801 				continue;
3802 			}
3803 			mutex_exit(&pd->pd_mutex);
3804 		}
3805 
3806 		rval = fp_port_login(port, d_id, job, flag,
3807 		    KM_SLEEP, pd, NULL);
3808 		if (rval != FC_SUCCESS) {
3809 			fp_jobdone(job);
3810 		}
3811 	}
3812 
3813 	mutex_enter(&port->fp_mutex);
3814 }
3815 
3816 
3817 /*
3818  * Perform loop ONLINE processing
3819  */
3820 static void
3821 fp_loop_online(fc_local_port_t *port, job_request_t *job, int orphan)
3822 {
3823 	int			count;
3824 	int			rval;
3825 	uint32_t		d_id;
3826 	uint32_t		listlen;
3827 	fc_lilpmap_t		*lilp_map;
3828 	fc_remote_port_t	*pd;
3829 	fc_portmap_t		*changelist;
3830 
3831 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
3832 
3833 	FP_TRACE(FP_NHEAD1(1, 0), "fp_loop_online begin; port=%p, job=%p",
3834 	    port, job);
3835 
3836 	lilp_map = &port->fp_lilp_map;
3837 
3838 	if (lilp_map->lilp_length) {
3839 		mutex_enter(&port->fp_mutex);
3840 		if (port->fp_soft_state & FP_SOFT_IN_FCA_RESET) {
3841 			port->fp_soft_state &= ~FP_SOFT_IN_FCA_RESET;
3842 			mutex_exit(&port->fp_mutex);
3843 			delay(drv_usectohz(PLDA_RR_TOV * 1000 * 1000));
3844 		} else {
3845 			mutex_exit(&port->fp_mutex);
3846 		}
3847 
3848 		job->job_counter = lilp_map->lilp_length;
3849 
3850 		for (count = 0; count < lilp_map->lilp_length; count++) {
3851 			d_id = lilp_map->lilp_alpalist[count];
3852 
3853 			if (d_id == (lilp_map->lilp_myalpa & 0xFF)) {
3854 				fp_jobdone(job);
3855 				continue;
3856 			}
3857 
3858 			pd = fctl_get_remote_port_by_did(port, d_id);
3859 			if (pd != NULL) {
3860 #ifdef	DEBUG
3861 				mutex_enter(&pd->pd_mutex);
3862 				if (pd->pd_recepient == PD_PLOGI_INITIATOR) {
3863 					ASSERT(pd->pd_type != PORT_DEVICE_OLD);
3864 				}
3865 				mutex_exit(&pd->pd_mutex);
3866 #endif
3867 				fp_jobdone(job);
3868 				continue;
3869 			}
3870 
3871 			rval = fp_port_login(port, d_id, job,
3872 			    FP_CMD_PLOGI_DONT_CARE, KM_SLEEP, pd, NULL);
3873 
3874 			if (rval != FC_SUCCESS) {
3875 				fp_jobdone(job);
3876 			}
3877 		}
3878 		fp_jobwait(job);
3879 	}
3880 	listlen = 0;
3881 	changelist = NULL;
3882 
3883 	if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) {
3884 		mutex_enter(&port->fp_mutex);
3885 		ASSERT(port->fp_statec_busy > 0);
3886 		if (port->fp_statec_busy == 1) {
3887 			mutex_exit(&port->fp_mutex);
3888 			fctl_fillout_map(port, &changelist, &listlen,
3889 			    1, 0, orphan);
3890 
3891 			mutex_enter(&port->fp_mutex);
3892 			if (port->fp_lilp_map.lilp_magic < MAGIC_LIRP) {
3893 				ASSERT(port->fp_total_devices == 0);
3894 				port->fp_total_devices = port->fp_dev_count;
3895 			}
3896 		} else {
3897 			job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION;
3898 		}
3899 		mutex_exit(&port->fp_mutex);
3900 	}
3901 
3902 	if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) {
3903 		(void) fp_ulp_statec_cb(port, FC_STATE_ONLINE, changelist,
3904 		    listlen, listlen, KM_SLEEP);
3905 	} else {
3906 		mutex_enter(&port->fp_mutex);
3907 		if (--port->fp_statec_busy == 0) {
3908 			port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
3909 		}
3910 		ASSERT(changelist == NULL && listlen == 0);
3911 		mutex_exit(&port->fp_mutex);
3912 	}
3913 
3914 	FP_TRACE(FP_NHEAD1(1, 0), "fp_loop_online end; port=%p, job=%p",
3915 	    port, job);
3916 }
3917 
3918 
3919 /*
3920  * Get an Arbitrated Loop map from the underlying FCA
3921  */
3922 static int
3923 fp_get_lilpmap(fc_local_port_t *port, fc_lilpmap_t *lilp_map)
3924 {
3925 	int rval;
3926 
3927 	FP_TRACE(FP_NHEAD1(1, 0), "fp_get_lilpmap Begin; port=%p, map=%p",
3928 	    port, lilp_map);
3929 
3930 	bzero((caddr_t)lilp_map, sizeof (fc_lilpmap_t));
3931 	rval = port->fp_fca_tran->fca_getmap(port->fp_fca_handle, lilp_map);
3932 	lilp_map->lilp_magic &= 0xFF;	/* Ignore upper byte */
3933 
3934 	if (rval != FC_SUCCESS) {
3935 		rval = FC_NO_MAP;
3936 	} else if (lilp_map->lilp_length == 0 &&
3937 	    (lilp_map->lilp_magic >= MAGIC_LISM &&
3938 	    lilp_map->lilp_magic < MAGIC_LIRP)) {
3939 		uchar_t lilp_length;
3940 
3941 		/*
3942 		 * Since the map length is zero, provide all
3943 		 * the valid AL_PAs for NL_ports discovery.
3944 		 */
3945 		lilp_length = sizeof (fp_valid_alpas) /
3946 		    sizeof (fp_valid_alpas[0]);
3947 		lilp_map->lilp_length = lilp_length;
3948 		bcopy(fp_valid_alpas, lilp_map->lilp_alpalist,
3949 		    lilp_length);
3950 	} else {
3951 		rval = fp_validate_lilp_map(lilp_map);
3952 
3953 		if (rval == FC_SUCCESS) {
3954 			mutex_enter(&port->fp_mutex);
3955 			port->fp_total_devices = lilp_map->lilp_length - 1;
3956 			mutex_exit(&port->fp_mutex);
3957 		}
3958 	}
3959 
3960 	mutex_enter(&port->fp_mutex);
3961 	if (rval != FC_SUCCESS && !(port->fp_soft_state & FP_SOFT_BAD_LINK)) {
3962 		port->fp_soft_state |= FP_SOFT_BAD_LINK;
3963 		mutex_exit(&port->fp_mutex);
3964 
3965 		if (port->fp_fca_tran->fca_reset(port->fp_fca_handle,
3966 		    FC_FCA_RESET_CORE) != FC_SUCCESS) {
3967 			FP_TRACE(FP_NHEAD1(9, 0),
3968 			    "FCA reset failed after LILP map was found"
3969 			    " to be invalid");
3970 		}
3971 	} else if (rval == FC_SUCCESS) {
3972 		port->fp_soft_state &= ~FP_SOFT_BAD_LINK;
3973 		mutex_exit(&port->fp_mutex);
3974 	} else {
3975 		mutex_exit(&port->fp_mutex);
3976 	}
3977 
3978 	FP_TRACE(FP_NHEAD1(1, 0), "fp_get_lilpmap End; port=%p, map=%p", port,
3979 	    lilp_map);
3980 
3981 	return (rval);
3982 }
3983 
3984 
3985 /*
3986  * Perform Fabric Login:
3987  *
3988  * Return Values:
3989  *		FC_SUCCESS
3990  *		FC_FAILURE
3991  *		FC_NOMEM
3992  *		FC_TRANSPORT_ERROR
3993  *		and a lot others defined in fc_error.h
3994  */
3995 static int
3996 fp_fabric_login(fc_local_port_t *port, uint32_t s_id, job_request_t *job,
3997     int flag, int sleep)
3998 {
3999 	int		rval;
4000 	fp_cmd_t	*cmd;
4001 	uchar_t		class;
4002 
4003 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
4004 
4005 	FP_TRACE(FP_NHEAD1(1, 0), "fp_fabric_login Begin; port=%p, job=%p",
4006 	    port, job);
4007 
4008 	class = fp_get_nextclass(port, FC_TRAN_CLASS_INVALID);
4009 	if (class == FC_TRAN_CLASS_INVALID) {
4010 		return (FC_ELS_BAD);
4011 	}
4012 
4013 	cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t),
4014 	    sizeof (la_els_logi_t), sleep, NULL);
4015 	if (cmd == NULL) {
4016 		return (FC_NOMEM);
4017 	}
4018 
4019 	cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class;
4020 	cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
4021 	cmd->cmd_flags = flag;
4022 	cmd->cmd_retry_count = fp_retry_count;
4023 	cmd->cmd_ulp_pkt = NULL;
4024 
4025 	fp_xlogi_init(port, cmd, s_id, 0xFFFFFE, fp_flogi_intr,
4026 	    job, LA_ELS_FLOGI);
4027 
4028 	rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
4029 	if (rval != FC_SUCCESS) {
4030 		fp_free_pkt(cmd);
4031 	}
4032 
4033 	FP_TRACE(FP_NHEAD1(1, 0), "fp_fabric_login End; port=%p, job=%p",
4034 	    port, job);
4035 
4036 	return (rval);
4037 }
4038 
4039 
4040 /*
4041  * In some scenarios such as private loop device discovery period
4042  * the fc_remote_port_t data structure isn't allocated. The allocation
4043  * is done when the PLOGI is successful. In some other scenarios
4044  * such as Fabric topology, the fc_remote_port_t is already created
4045  * and initialized with appropriate values (as the NS provides
4046  * them)
4047  */
4048 static int
4049 fp_port_login(fc_local_port_t *port, uint32_t d_id, job_request_t *job,
4050     int cmd_flag, int sleep, fc_remote_port_t *pd, fc_packet_t *ulp_pkt)
4051 {
4052 	uchar_t class;
4053 	fp_cmd_t *cmd;
4054 	uint32_t src_id;
4055 	fc_remote_port_t *tmp_pd;
4056 	int relogin;
4057 	int found = 0;
4058 
4059 #ifdef	DEBUG
4060 	if (pd == NULL) {
4061 		ASSERT(fctl_get_remote_port_by_did(port, d_id) == NULL);
4062 	}
4063 #endif
4064 	ASSERT(job->job_counter > 0);
4065 
4066 	class = fp_get_nextclass(port, FC_TRAN_CLASS_INVALID);
4067 	if (class == FC_TRAN_CLASS_INVALID) {
4068 		return (FC_ELS_BAD);
4069 	}
4070 
4071 	mutex_enter(&port->fp_mutex);
4072 	tmp_pd = fctl_lookup_pd_by_did(port, d_id);
4073 	mutex_exit(&port->fp_mutex);
4074 
4075 	relogin = 1;
4076 	if (tmp_pd) {
4077 		mutex_enter(&tmp_pd->pd_mutex);
4078 		if ((tmp_pd->pd_aux_flags & PD_DISABLE_RELOGIN) &&
4079 		    !(tmp_pd->pd_aux_flags & PD_LOGGED_OUT)) {
4080 			tmp_pd->pd_state = PORT_DEVICE_LOGGED_IN;
4081 			relogin = 0;
4082 		}
4083 		mutex_exit(&tmp_pd->pd_mutex);
4084 	}
4085 
4086 	if (!relogin) {
4087 		mutex_enter(&tmp_pd->pd_mutex);
4088 		if (tmp_pd->pd_state == PORT_DEVICE_LOGGED_IN) {
4089 			cmd_flag |= FP_CMD_PLOGI_RETAIN;
4090 		}
4091 		mutex_exit(&tmp_pd->pd_mutex);
4092 
4093 		cmd = fp_alloc_pkt(port, sizeof (la_els_adisc_t),
4094 		    sizeof (la_els_adisc_t), sleep, tmp_pd);
4095 		if (cmd == NULL) {
4096 			return (FC_NOMEM);
4097 		}
4098 
4099 		cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class;
4100 		cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
4101 		cmd->cmd_flags = cmd_flag;
4102 		cmd->cmd_retry_count = fp_retry_count;
4103 		cmd->cmd_ulp_pkt = ulp_pkt;
4104 
4105 		mutex_enter(&port->fp_mutex);
4106 		mutex_enter(&tmp_pd->pd_mutex);
4107 		fp_adisc_init(cmd, job);
4108 		mutex_exit(&tmp_pd->pd_mutex);
4109 		mutex_exit(&port->fp_mutex);
4110 
4111 		cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_adisc_t);
4112 		cmd->cmd_pkt.pkt_rsplen = sizeof (la_els_adisc_t);
4113 
4114 	} else {
4115 		cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t),
4116 		    sizeof (la_els_logi_t), sleep, pd);
4117 		if (cmd == NULL) {
4118 			return (FC_NOMEM);
4119 		}
4120 
4121 		cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class;
4122 		cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
4123 		cmd->cmd_flags = cmd_flag;
4124 		cmd->cmd_retry_count = fp_retry_count;
4125 		cmd->cmd_ulp_pkt = ulp_pkt;
4126 
4127 		mutex_enter(&port->fp_mutex);
4128 		src_id = port->fp_port_id.port_id;
4129 		mutex_exit(&port->fp_mutex);
4130 
4131 		fp_xlogi_init(port, cmd, src_id, d_id, fp_plogi_intr,
4132 		    job, LA_ELS_PLOGI);
4133 	}
4134 
4135 	if (pd) {
4136 		mutex_enter(&pd->pd_mutex);
4137 		pd->pd_flags = PD_ELS_IN_PROGRESS;
4138 		mutex_exit(&pd->pd_mutex);
4139 	}
4140 
4141 	/* npiv check to make sure we don't log into ourself */
4142 	if (relogin &&
4143 	    ((port->fp_npiv_type == FC_NPIV_PORT) ||
4144 	    (port->fp_npiv_flag == FC_NPIV_ENABLE))) {
4145 		if ((d_id & 0xffff00) ==
4146 		    (port->fp_port_id.port_id & 0xffff00)) {
4147 			found = 1;
4148 		}
4149 	}
4150 
4151 	if (found ||
4152 	    (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS)) {
4153 		if (found) {
4154 			fc_packet_t *pkt = &cmd->cmd_pkt;
4155 			pkt->pkt_state = FC_PKT_NPORT_RJT;
4156 		}
4157 		if (pd) {
4158 			mutex_enter(&pd->pd_mutex);
4159 			pd->pd_flags = PD_IDLE;
4160 			mutex_exit(&pd->pd_mutex);
4161 		}
4162 
4163 		if (ulp_pkt) {
4164 			fc_packet_t *pkt = &cmd->cmd_pkt;
4165 
4166 			ulp_pkt->pkt_state = pkt->pkt_state;
4167 			ulp_pkt->pkt_reason = pkt->pkt_reason;
4168 			ulp_pkt->pkt_action = pkt->pkt_action;
4169 			ulp_pkt->pkt_expln = pkt->pkt_expln;
4170 		}
4171 
4172 		fp_iodone(cmd);
4173 	}
4174 
4175 	return (FC_SUCCESS);
4176 }
4177 
4178 
4179 /*
4180  * Register the LOGIN parameters with a port device
4181  */
4182 static void
4183 fp_register_login(ddi_acc_handle_t *handle, fc_remote_port_t *pd,
4184     la_els_logi_t *acc, uchar_t class)
4185 {
4186 	fc_remote_node_t	*node;
4187 
4188 	ASSERT(pd != NULL);
4189 
4190 	mutex_enter(&pd->pd_mutex);
4191 	node = pd->pd_remote_nodep;
4192 	if (pd->pd_login_count == 0) {
4193 		pd->pd_login_count++;
4194 	}
4195 
4196 	if (handle) {
4197 		FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)&pd->pd_csp,
4198 		    (uint8_t *)&acc->common_service,
4199 		    sizeof (acc->common_service), DDI_DEV_AUTOINCR);
4200 		FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)&pd->pd_clsp1,
4201 		    (uint8_t *)&acc->class_1, sizeof (acc->class_1),
4202 		    DDI_DEV_AUTOINCR);
4203 		FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)&pd->pd_clsp2,
4204 		    (uint8_t *)&acc->class_2, sizeof (acc->class_2),
4205 		    DDI_DEV_AUTOINCR);
4206 		FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)&pd->pd_clsp3,
4207 		    (uint8_t *)&acc->class_3, sizeof (acc->class_3),
4208 		    DDI_DEV_AUTOINCR);
4209 	} else {
4210 		pd->pd_csp = acc->common_service;
4211 		pd->pd_clsp1 = acc->class_1;
4212 		pd->pd_clsp2 = acc->class_2;
4213 		pd->pd_clsp3 = acc->class_3;
4214 	}
4215 
4216 	pd->pd_state = PORT_DEVICE_LOGGED_IN;
4217 	pd->pd_login_class = class;
4218 	mutex_exit(&pd->pd_mutex);
4219 
4220 #ifndef	__lock_lint
4221 	ASSERT(fctl_get_remote_port_by_did(pd->pd_port,
4222 	    pd->pd_port_id.port_id) == pd);
4223 #endif
4224 
4225 	mutex_enter(&node->fd_mutex);
4226 	if (handle) {
4227 		FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)node->fd_vv,
4228 		    (uint8_t *)acc->vendor_version, sizeof (node->fd_vv),
4229 		    DDI_DEV_AUTOINCR);
4230 	} else {
4231 		bcopy(acc->vendor_version, node->fd_vv, sizeof (node->fd_vv));
4232 	}
4233 	mutex_exit(&node->fd_mutex);
4234 }
4235 
4236 
4237 /*
4238  * Mark the remote port as OFFLINE
4239  */
4240 static void
4241 fp_remote_port_offline(fc_remote_port_t *pd)
4242 {
4243 	ASSERT(MUTEX_HELD(&pd->pd_mutex));
4244 	if (pd->pd_login_count &&
4245 	    ((pd->pd_aux_flags & PD_DISABLE_RELOGIN) == 0)) {
4246 		bzero((caddr_t)&pd->pd_csp, sizeof (struct common_service));
4247 		bzero((caddr_t)&pd->pd_clsp1, sizeof (struct service_param));
4248 		bzero((caddr_t)&pd->pd_clsp2, sizeof (struct service_param));
4249 		bzero((caddr_t)&pd->pd_clsp3, sizeof (struct service_param));
4250 		pd->pd_login_class = 0;
4251 	}
4252 	pd->pd_type = PORT_DEVICE_OLD;
4253 	pd->pd_flags = PD_IDLE;
4254 	fctl_tc_reset(&pd->pd_logo_tc);
4255 }
4256 
4257 
4258 /*
4259  * Deregistration of a port device
4260  */
4261 static void
4262 fp_unregister_login(fc_remote_port_t *pd)
4263 {
4264 	fc_remote_node_t *node;
4265 
4266 	ASSERT(pd != NULL);
4267 
4268 	mutex_enter(&pd->pd_mutex);
4269 	pd->pd_login_count = 0;
4270 	bzero((caddr_t)&pd->pd_csp, sizeof (struct common_service));
4271 	bzero((caddr_t)&pd->pd_clsp1, sizeof (struct service_param));
4272 	bzero((caddr_t)&pd->pd_clsp2, sizeof (struct service_param));
4273 	bzero((caddr_t)&pd->pd_clsp3, sizeof (struct service_param));
4274 
4275 	pd->pd_state = PORT_DEVICE_VALID;
4276 	pd->pd_login_class = 0;
4277 	node = pd->pd_remote_nodep;
4278 	mutex_exit(&pd->pd_mutex);
4279 
4280 	mutex_enter(&node->fd_mutex);
4281 	bzero(node->fd_vv, sizeof (node->fd_vv));
4282 	mutex_exit(&node->fd_mutex);
4283 }
4284 
4285 
4286 /*
4287  * Handle OFFLINE state of an FCA port
4288  */
4289 static void
4290 fp_port_offline(fc_local_port_t *port, int notify)
4291 {
4292 	int			index;
4293 	int			statec;
4294 	timeout_id_t		tid;
4295 	struct pwwn_hash	*head;
4296 	fc_remote_port_t	*pd;
4297 
4298 	ASSERT(MUTEX_HELD(&port->fp_mutex));
4299 
4300 	for (index = 0; index < pwwn_table_size; index++) {
4301 		head = &port->fp_pwwn_table[index];
4302 		pd = head->pwwn_head;
4303 		while (pd != NULL) {
4304 			mutex_enter(&pd->pd_mutex);
4305 			fp_remote_port_offline(pd);
4306 			fctl_delist_did_table(port, pd);
4307 			mutex_exit(&pd->pd_mutex);
4308 			pd = pd->pd_wwn_hnext;
4309 		}
4310 	}
4311 	port->fp_total_devices = 0;
4312 
4313 	statec = 0;
4314 	if (notify) {
4315 		/*
4316 		 * Decrement the statec busy counter as we
4317 		 * are almost done with handling the state
4318 		 * change
4319 		 */
4320 		ASSERT(port->fp_statec_busy > 0);
4321 		if (--port->fp_statec_busy == 0) {
4322 			port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
4323 		}
4324 		mutex_exit(&port->fp_mutex);
4325 		(void) fp_ulp_statec_cb(port, FC_STATE_OFFLINE, NULL,
4326 		    0, 0, KM_SLEEP);
4327 		mutex_enter(&port->fp_mutex);
4328 
4329 		if (port->fp_statec_busy) {
4330 			statec++;
4331 		}
4332 	} else if (port->fp_statec_busy > 1) {
4333 		statec++;
4334 	}
4335 
4336 	if ((tid = port->fp_offline_tid) != NULL) {
4337 		mutex_exit(&port->fp_mutex);
4338 		(void) untimeout(tid);
4339 		mutex_enter(&port->fp_mutex);
4340 	}
4341 
4342 	if (!statec) {
4343 		port->fp_offline_tid = timeout(fp_offline_timeout,
4344 		    (caddr_t)port, fp_offline_ticks);
4345 	}
4346 }
4347 
4348 
4349 /*
4350  * Offline devices and send up a state change notification to ULPs
4351  */
4352 static void
4353 fp_offline_timeout(void *port_handle)
4354 {
4355 	int		ret;
4356 	fc_local_port_t *port = port_handle;
4357 	uint32_t	listlen = 0;
4358 	fc_portmap_t	*changelist = NULL;
4359 
4360 	mutex_enter(&port->fp_mutex);
4361 
4362 	if ((FC_PORT_STATE_MASK(port->fp_state) != FC_STATE_OFFLINE) ||
4363 	    (port->fp_soft_state &
4364 	    (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN)) ||
4365 	    port->fp_dev_count == 0 || port->fp_statec_busy) {
4366 		port->fp_offline_tid = NULL;
4367 		mutex_exit(&port->fp_mutex);
4368 		return;
4369 	}
4370 
4371 	mutex_exit(&port->fp_mutex);
4372 
4373 	FP_TRACE(FP_NHEAD2(9, 0), "OFFLINE timeout");
4374 
4375 	if (port->fp_options & FP_CORE_ON_OFFLINE_TIMEOUT) {
4376 		if ((ret = port->fp_fca_tran->fca_reset(port->fp_fca_handle,
4377 		    FC_FCA_CORE)) != FC_SUCCESS) {
4378 			FP_TRACE(FP_NHEAD1(9, ret),
4379 			    "Failed to force adapter dump");
4380 		} else {
4381 			FP_TRACE(FP_NHEAD1(9, 0),
4382 			    "Forced adapter dump successfully");
4383 		}
4384 	} else if (port->fp_options & FP_RESET_CORE_ON_OFFLINE_TIMEOUT) {
4385 		if ((ret = port->fp_fca_tran->fca_reset(port->fp_fca_handle,
4386 		    FC_FCA_RESET_CORE)) != FC_SUCCESS) {
4387 			FP_TRACE(FP_NHEAD1(9, ret),
4388 			    "Failed to force adapter dump and reset");
4389 		} else {
4390 			FP_TRACE(FP_NHEAD1(9, 0),
4391 			    "Forced adapter dump and reset successfully");
4392 		}
4393 	}
4394 
4395 	fctl_fillout_map(port, &changelist, &listlen, 1, 0, 0);
4396 	(void) fp_ulp_statec_cb(port, FC_STATE_OFFLINE, changelist,
4397 	    listlen, listlen, KM_SLEEP);
4398 
4399 	mutex_enter(&port->fp_mutex);
4400 	port->fp_offline_tid = NULL;
4401 	mutex_exit(&port->fp_mutex);
4402 }
4403 
4404 
4405 /*
4406  * Perform general purpose ELS request initialization
4407  */
4408 static void
4409 fp_els_init(fp_cmd_t *cmd, uint32_t s_id, uint32_t d_id,
4410     void (*comp) (), job_request_t *job)
4411 {
4412 	fc_packet_t *pkt;
4413 
4414 	pkt = &cmd->cmd_pkt;
4415 	cmd->cmd_job = job;
4416 
4417 	pkt->pkt_cmd_fhdr.r_ctl = R_CTL_ELS_REQ;
4418 	pkt->pkt_cmd_fhdr.d_id = d_id;
4419 	pkt->pkt_cmd_fhdr.s_id = s_id;
4420 	pkt->pkt_cmd_fhdr.type = FC_TYPE_EXTENDED_LS;
4421 	pkt->pkt_cmd_fhdr.f_ctl = F_CTL_SEQ_INITIATIVE | F_CTL_FIRST_SEQ;
4422 	pkt->pkt_cmd_fhdr.seq_id = 0;
4423 	pkt->pkt_cmd_fhdr.df_ctl  = 0;
4424 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
4425 	pkt->pkt_cmd_fhdr.ox_id = 0xffff;
4426 	pkt->pkt_cmd_fhdr.rx_id = 0xffff;
4427 	pkt->pkt_cmd_fhdr.ro = 0;
4428 	pkt->pkt_cmd_fhdr.rsvd = 0;
4429 	pkt->pkt_comp = comp;
4430 	pkt->pkt_timeout = FP_ELS_TIMEOUT;
4431 }
4432 
4433 
4434 /*
4435  * Initialize PLOGI/FLOGI ELS request
4436  */
4437 static void
4438 fp_xlogi_init(fc_local_port_t *port, fp_cmd_t *cmd, uint32_t s_id,
4439     uint32_t d_id, void (*intr) (), job_request_t *job, uchar_t ls_code)
4440 {
4441 	ls_code_t	payload;
4442 
4443 	fp_els_init(cmd, s_id, d_id, intr, job);
4444 	cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
4445 
4446 	payload.ls_code = ls_code;
4447 	payload.mbz = 0;
4448 
4449 	FC_SET_CMD(port, cmd->cmd_pkt.pkt_cmd_acc,
4450 	    (uint8_t *)&port->fp_service_params,
4451 	    (uint8_t *)cmd->cmd_pkt.pkt_cmd, sizeof (port->fp_service_params),
4452 	    DDI_DEV_AUTOINCR);
4453 
4454 	FC_SET_CMD(port, cmd->cmd_pkt.pkt_cmd_acc, (uint8_t *)&payload,
4455 	    (uint8_t *)cmd->cmd_pkt.pkt_cmd, sizeof (payload),
4456 	    DDI_DEV_AUTOINCR);
4457 }
4458 
4459 
4460 /*
4461  * Initialize LOGO ELS request
4462  */
4463 static void
4464 fp_logo_init(fc_remote_port_t *pd, fp_cmd_t *cmd, job_request_t *job)
4465 {
4466 	fc_local_port_t	*port;
4467 	fc_packet_t	*pkt;
4468 	la_els_logo_t	payload;
4469 
4470 	port = pd->pd_port;
4471 	pkt = &cmd->cmd_pkt;
4472 	ASSERT(MUTEX_HELD(&port->fp_mutex));
4473 	ASSERT(MUTEX_HELD(&pd->pd_mutex));
4474 
4475 	fp_els_init(cmd, port->fp_port_id.port_id, pd->pd_port_id.port_id,
4476 	    fp_logo_intr, job);
4477 
4478 	cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
4479 
4480 	pkt->pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
4481 	pkt->pkt_tran_type = FC_PKT_EXCHANGE;
4482 
4483 	payload.ls_code.ls_code = LA_ELS_LOGO;
4484 	payload.ls_code.mbz = 0;
4485 	payload.nport_ww_name = port->fp_service_params.nport_ww_name;
4486 	payload.nport_id = port->fp_port_id;
4487 
4488 	FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
4489 	    (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
4490 }
4491 
4492 /*
4493  * Initialize RNID ELS request
4494  */
4495 static void
4496 fp_rnid_init(fp_cmd_t *cmd, uint16_t flag, job_request_t *job)
4497 {
4498 	fc_local_port_t	*port;
4499 	fc_packet_t	*pkt;
4500 	la_els_rnid_t	payload;
4501 	fc_remote_port_t	*pd;
4502 
4503 	pkt = &cmd->cmd_pkt;
4504 	pd = pkt->pkt_pd;
4505 	port = pd->pd_port;
4506 
4507 	ASSERT(MUTEX_HELD(&port->fp_mutex));
4508 	ASSERT(MUTEX_HELD(&pd->pd_mutex));
4509 
4510 	fp_els_init(cmd, port->fp_port_id.port_id, pd->pd_port_id.port_id,
4511 	    fp_rnid_intr, job);
4512 
4513 	cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
4514 	pkt->pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
4515 	pkt->pkt_tran_type = FC_PKT_EXCHANGE;
4516 
4517 	payload.ls_code.ls_code = LA_ELS_RNID;
4518 	payload.ls_code.mbz = 0;
4519 	payload.data_format = flag;
4520 
4521 	FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
4522 	    (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
4523 }
4524 
4525 /*
4526  * Initialize RLS ELS request
4527  */
4528 static void
4529 fp_rls_init(fp_cmd_t *cmd, job_request_t *job)
4530 {
4531 	fc_local_port_t	*port;
4532 	fc_packet_t	*pkt;
4533 	la_els_rls_t	payload;
4534 	fc_remote_port_t	*pd;
4535 
4536 	pkt = &cmd->cmd_pkt;
4537 	pd = pkt->pkt_pd;
4538 	port = pd->pd_port;
4539 
4540 	ASSERT(MUTEX_HELD(&port->fp_mutex));
4541 	ASSERT(MUTEX_HELD(&pd->pd_mutex));
4542 
4543 	fp_els_init(cmd, port->fp_port_id.port_id, pd->pd_port_id.port_id,
4544 	    fp_rls_intr, job);
4545 
4546 	cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
4547 	pkt->pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
4548 	pkt->pkt_tran_type = FC_PKT_EXCHANGE;
4549 
4550 	payload.ls_code.ls_code = LA_ELS_RLS;
4551 	payload.ls_code.mbz = 0;
4552 	payload.rls_portid = port->fp_port_id;
4553 
4554 	FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
4555 	    (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
4556 }
4557 
4558 
4559 /*
4560  * Initialize an ADISC ELS request
4561  */
4562 static void
4563 fp_adisc_init(fp_cmd_t *cmd, job_request_t *job)
4564 {
4565 	fc_local_port_t *port;
4566 	fc_packet_t	*pkt;
4567 	la_els_adisc_t	payload;
4568 	fc_remote_port_t	*pd;
4569 
4570 	pkt = &cmd->cmd_pkt;
4571 	pd = pkt->pkt_pd;
4572 	port = pd->pd_port;
4573 
4574 	ASSERT(MUTEX_HELD(&pd->pd_mutex));
4575 	ASSERT(MUTEX_HELD(&pd->pd_port->fp_mutex));
4576 
4577 	fp_els_init(cmd, port->fp_port_id.port_id, pd->pd_port_id.port_id,
4578 	    fp_adisc_intr, job);
4579 
4580 	cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
4581 	pkt->pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
4582 	pkt->pkt_tran_type = FC_PKT_EXCHANGE;
4583 
4584 	payload.ls_code.ls_code = LA_ELS_ADISC;
4585 	payload.ls_code.mbz = 0;
4586 	payload.nport_id = port->fp_port_id;
4587 	payload.port_wwn = port->fp_service_params.nport_ww_name;
4588 	payload.node_wwn = port->fp_service_params.node_ww_name;
4589 	payload.hard_addr = port->fp_hard_addr;
4590 
4591 	FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
4592 	    (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
4593 }
4594 
4595 
4596 /*
4597  * Send up a state change notification to ULPs.
4598  * Spawns a call to fctl_ulp_statec_cb in a taskq thread.
4599  */
4600 static int
4601 fp_ulp_statec_cb(fc_local_port_t *port, uint32_t state,
4602     fc_portmap_t *changelist, uint32_t listlen, uint32_t alloc_len, int sleep)
4603 {
4604 	fc_port_clist_t		*clist;
4605 	fc_remote_port_t	*pd;
4606 	int			count;
4607 
4608 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
4609 
4610 	clist = kmem_zalloc(sizeof (*clist), sleep);
4611 	if (clist == NULL) {
4612 		kmem_free(changelist, alloc_len * sizeof (*changelist));
4613 		return (FC_NOMEM);
4614 	}
4615 
4616 	clist->clist_state = state;
4617 
4618 	mutex_enter(&port->fp_mutex);
4619 	clist->clist_flags = port->fp_topology;
4620 	mutex_exit(&port->fp_mutex);
4621 
4622 	clist->clist_port = (opaque_t)port;
4623 	clist->clist_len = listlen;
4624 	clist->clist_size = alloc_len;
4625 	clist->clist_map = changelist;
4626 
4627 	/*
4628 	 * Bump the reference count of each fc_remote_port_t in this changelist.
4629 	 * This is necessary since these devices will be sitting in a taskq
4630 	 * and referenced later.  When the state change notification is
4631 	 * complete, the reference counts will be decremented.
4632 	 */
4633 	for (count = 0; count < clist->clist_len; count++) {
4634 		pd = clist->clist_map[count].map_pd;
4635 
4636 		if (pd != NULL) {
4637 			mutex_enter(&pd->pd_mutex);
4638 			ASSERT((pd->pd_ref_count >= 0) ||
4639 			    (pd->pd_aux_flags & PD_GIVEN_TO_ULPS));
4640 			pd->pd_ref_count++;
4641 
4642 			if (clist->clist_map[count].map_state !=
4643 			    PORT_DEVICE_INVALID) {
4644 				pd->pd_aux_flags |= PD_GIVEN_TO_ULPS;
4645 			}
4646 
4647 			mutex_exit(&pd->pd_mutex);
4648 		}
4649 	}
4650 
4651 #ifdef	DEBUG
4652 	/*
4653 	 * Sanity check for presence of OLD devices in the hash lists
4654 	 */
4655 	if (clist->clist_size) {
4656 		ASSERT(clist->clist_map != NULL);
4657 		for (count = 0; count < clist->clist_len; count++) {
4658 			if (clist->clist_map[count].map_state ==
4659 			    PORT_DEVICE_INVALID) {
4660 				la_wwn_t	pwwn;
4661 				fc_portid_t	d_id;
4662 
4663 				pd = clist->clist_map[count].map_pd;
4664 				ASSERT(pd != NULL);
4665 
4666 				mutex_enter(&pd->pd_mutex);
4667 				pwwn = pd->pd_port_name;
4668 				d_id = pd->pd_port_id;
4669 				mutex_exit(&pd->pd_mutex);
4670 
4671 				pd = fctl_get_remote_port_by_pwwn(port, &pwwn);
4672 				ASSERT(pd != clist->clist_map[count].map_pd);
4673 
4674 				pd = fctl_get_remote_port_by_did(port,
4675 				    d_id.port_id);
4676 				ASSERT(pd != clist->clist_map[count].map_pd);
4677 			}
4678 		}
4679 	}
4680 #endif
4681 
4682 	mutex_enter(&port->fp_mutex);
4683 
4684 	if (state == FC_STATE_ONLINE) {
4685 		if (--port->fp_statec_busy == 0) {
4686 			port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
4687 		}
4688 	}
4689 	mutex_exit(&port->fp_mutex);
4690 
4691 	(void) taskq_dispatch(port->fp_taskq, fctl_ulp_statec_cb,
4692 	    clist, KM_SLEEP);
4693 
4694 	FP_TRACE(FP_NHEAD1(4, 0), "fp_ulp_statec fired; Port=%p,"
4695 	    "state=%x, len=%d", port, state, listlen);
4696 
4697 	return (FC_SUCCESS);
4698 }
4699 
4700 
4701 /*
4702  * Send up a FC_STATE_DEVICE_CHANGE state notification to ULPs
4703  */
4704 static int
4705 fp_ulp_devc_cb(fc_local_port_t *port, fc_portmap_t *changelist,
4706     uint32_t listlen, uint32_t alloc_len, int sleep, int sync)
4707 {
4708 	int		ret;
4709 	fc_port_clist_t *clist;
4710 
4711 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
4712 
4713 	clist = kmem_zalloc(sizeof (*clist), sleep);
4714 	if (clist == NULL) {
4715 		kmem_free(changelist, alloc_len * sizeof (*changelist));
4716 		return (FC_NOMEM);
4717 	}
4718 
4719 	clist->clist_state = FC_STATE_DEVICE_CHANGE;
4720 
4721 	mutex_enter(&port->fp_mutex);
4722 	clist->clist_flags = port->fp_topology;
4723 	mutex_exit(&port->fp_mutex);
4724 
4725 	clist->clist_port = (opaque_t)port;
4726 	clist->clist_len = listlen;
4727 	clist->clist_size = alloc_len;
4728 	clist->clist_map = changelist;
4729 
4730 	/* Send sysevents for target state changes */
4731 
4732 	if (clist->clist_size) {
4733 		int			count;
4734 		fc_remote_port_t	*pd;
4735 
4736 		ASSERT(clist->clist_map != NULL);
4737 		for (count = 0; count < clist->clist_len; count++) {
4738 			pd = clist->clist_map[count].map_pd;
4739 
4740 			/*
4741 			 * Bump reference counts on all fc_remote_port_t
4742 			 * structs in this list.  We don't know when the task
4743 			 * will fire, and we don't need these fc_remote_port_t
4744 			 * structs going away behind our back.
4745 			 */
4746 			if (pd) {
4747 				mutex_enter(&pd->pd_mutex);
4748 				ASSERT((pd->pd_ref_count >= 0) ||
4749 				    (pd->pd_aux_flags & PD_GIVEN_TO_ULPS));
4750 				pd->pd_ref_count++;
4751 				mutex_exit(&pd->pd_mutex);
4752 			}
4753 
4754 			if (clist->clist_map[count].map_state ==
4755 			    PORT_DEVICE_VALID) {
4756 				if (clist->clist_map[count].map_type ==
4757 				    PORT_DEVICE_NEW) {
4758 					/* Update our state change counter */
4759 					mutex_enter(&port->fp_mutex);
4760 					port->fp_last_change++;
4761 					mutex_exit(&port->fp_mutex);
4762 
4763 					/* Additions */
4764 					fp_log_target_event(port,
4765 					    ESC_SUNFC_TARGET_ADD,
4766 					    clist->clist_map[count].map_pwwn,
4767 					    clist->clist_map[count].map_did.
4768 					    port_id);
4769 				}
4770 
4771 			} else if ((clist->clist_map[count].map_type ==
4772 			    PORT_DEVICE_OLD) &&
4773 			    (clist->clist_map[count].map_state ==
4774 			    PORT_DEVICE_INVALID)) {
4775 				/* Update our state change counter */
4776 				mutex_enter(&port->fp_mutex);
4777 				port->fp_last_change++;
4778 				mutex_exit(&port->fp_mutex);
4779 
4780 				/*
4781 				 * For removals, we don't decrement
4782 				 * pd_ref_count until after the ULP's
4783 				 * state change callback function has
4784 				 * completed.
4785 				 */
4786 
4787 				/* Removals */
4788 				fp_log_target_event(port,
4789 				    ESC_SUNFC_TARGET_REMOVE,
4790 				    clist->clist_map[count].map_pwwn,
4791 				    clist->clist_map[count].map_did.port_id);
4792 			}
4793 
4794 			if (clist->clist_map[count].map_state !=
4795 			    PORT_DEVICE_INVALID) {
4796 				/*
4797 				 * Indicate that the ULPs are now aware of
4798 				 * this device.
4799 				 */
4800 
4801 				mutex_enter(&pd->pd_mutex);
4802 				pd->pd_aux_flags |= PD_GIVEN_TO_ULPS;
4803 				mutex_exit(&pd->pd_mutex);
4804 			}
4805 
4806 #ifdef	DEBUG
4807 			/*
4808 			 * Sanity check for OLD devices in the hash lists
4809 			 */
4810 			if (pd && clist->clist_map[count].map_state ==
4811 			    PORT_DEVICE_INVALID) {
4812 				la_wwn_t	pwwn;
4813 				fc_portid_t	d_id;
4814 
4815 				mutex_enter(&pd->pd_mutex);
4816 				pwwn = pd->pd_port_name;
4817 				d_id = pd->pd_port_id;
4818 				mutex_exit(&pd->pd_mutex);
4819 
4820 				/*
4821 				 * This overwrites the 'pd' local variable.
4822 				 * Beware of this if 'pd' ever gets
4823 				 * referenced below this block.
4824 				 */
4825 				pd = fctl_get_remote_port_by_pwwn(port, &pwwn);
4826 				ASSERT(pd != clist->clist_map[count].map_pd);
4827 
4828 				pd = fctl_get_remote_port_by_did(port,
4829 				    d_id.port_id);
4830 				ASSERT(pd != clist->clist_map[count].map_pd);
4831 			}
4832 #endif
4833 		}
4834 	}
4835 
4836 	if (sync) {
4837 		clist->clist_wait = 1;
4838 		mutex_init(&clist->clist_mutex, NULL, MUTEX_DRIVER, NULL);
4839 		cv_init(&clist->clist_cv, NULL, CV_DRIVER, NULL);
4840 	}
4841 
4842 	ret = taskq_dispatch(port->fp_taskq, fctl_ulp_statec_cb, clist, sleep);
4843 	if (sync && ret) {
4844 		mutex_enter(&clist->clist_mutex);
4845 		while (clist->clist_wait) {
4846 			cv_wait(&clist->clist_cv, &clist->clist_mutex);
4847 		}
4848 		mutex_exit(&clist->clist_mutex);
4849 
4850 		mutex_destroy(&clist->clist_mutex);
4851 		cv_destroy(&clist->clist_cv);
4852 		kmem_free(clist, sizeof (*clist));
4853 	}
4854 
4855 	if (!ret) {
4856 		FP_TRACE(FP_NHEAD1(4, 0), "fp_ulp_devc dispatch failed; "
4857 		    "port=%p", port);
4858 		kmem_free(clist->clist_map,
4859 		    sizeof (*(clist->clist_map)) * clist->clist_size);
4860 		kmem_free(clist, sizeof (*clist));
4861 	} else {
4862 		FP_TRACE(FP_NHEAD1(4, 0), "fp_ulp_devc fired; port=%p, len=%d",
4863 		    port, listlen);
4864 	}
4865 
4866 	return (FC_SUCCESS);
4867 }
4868 
4869 
4870 /*
4871  * Perform PLOGI to the group of devices for ULPs
4872  */
4873 static void
4874 fp_plogi_group(fc_local_port_t *port, job_request_t *job)
4875 {
4876 	int			offline;
4877 	int			count;
4878 	int			rval;
4879 	uint32_t		listlen;
4880 	uint32_t		done;
4881 	uint32_t		d_id;
4882 	fc_remote_node_t	*node;
4883 	fc_remote_port_t	*pd;
4884 	fc_remote_port_t	*tmp_pd;
4885 	fc_packet_t		*ulp_pkt;
4886 	la_els_logi_t		*els_data;
4887 	ls_code_t		ls_code;
4888 
4889 	FP_TRACE(FP_NHEAD1(1, 0), "fp_plogi_group begin; port=%p, job=%p",
4890 	    port, job);
4891 
4892 	done = 0;
4893 	listlen = job->job_ulp_listlen;
4894 	job->job_counter = job->job_ulp_listlen;
4895 
4896 	mutex_enter(&port->fp_mutex);
4897 	offline = (port->fp_statec_busy ||
4898 	    FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) ? 1 : 0;
4899 	mutex_exit(&port->fp_mutex);
4900 
4901 	for (count = 0; count < listlen; count++) {
4902 		ASSERT(job->job_ulp_pkts[count]->pkt_rsplen >=
4903 		    sizeof (la_els_logi_t));
4904 
4905 		ulp_pkt = job->job_ulp_pkts[count];
4906 		pd = ulp_pkt->pkt_pd;
4907 		d_id = ulp_pkt->pkt_cmd_fhdr.d_id;
4908 
4909 		if (offline) {
4910 			done++;
4911 
4912 			ulp_pkt->pkt_state = FC_PKT_PORT_OFFLINE;
4913 			ulp_pkt->pkt_reason = FC_REASON_OFFLINE;
4914 			ulp_pkt->pkt_pd = NULL;
4915 			ulp_pkt->pkt_comp(ulp_pkt);
4916 
4917 			job->job_ulp_pkts[count] = NULL;
4918 
4919 			fp_jobdone(job);
4920 			continue;
4921 		}
4922 
4923 		if (pd == NULL) {
4924 			pd = fctl_get_remote_port_by_did(port, d_id);
4925 			if (pd == NULL) {
4926 				/* reset later */
4927 				ulp_pkt->pkt_state = FC_PKT_FAILURE;
4928 				continue;
4929 			}
4930 			mutex_enter(&pd->pd_mutex);
4931 			if (pd->pd_flags == PD_ELS_IN_PROGRESS) {
4932 				mutex_exit(&pd->pd_mutex);
4933 				ulp_pkt->pkt_state = FC_PKT_ELS_IN_PROGRESS;
4934 				done++;
4935 				ulp_pkt->pkt_comp(ulp_pkt);
4936 				job->job_ulp_pkts[count] = NULL;
4937 				fp_jobdone(job);
4938 			} else {
4939 				ulp_pkt->pkt_state = FC_PKT_FAILURE;
4940 				mutex_exit(&pd->pd_mutex);
4941 			}
4942 			continue;
4943 		}
4944 
4945 		switch (ulp_pkt->pkt_state) {
4946 		case FC_PKT_ELS_IN_PROGRESS:
4947 			ulp_pkt->pkt_reason = FC_REASON_OFFLINE;
4948 			/* FALLTHRU */
4949 		case FC_PKT_LOCAL_RJT:
4950 			done++;
4951 			ulp_pkt->pkt_comp(ulp_pkt);
4952 			job->job_ulp_pkts[count] = NULL;
4953 			fp_jobdone(job);
4954 			continue;
4955 		default:
4956 			break;
4957 		}
4958 
4959 		/*
4960 		 * Validate the pd corresponding to the d_id passed
4961 		 * by the ULPs
4962 		 */
4963 		tmp_pd = fctl_get_remote_port_by_did(port, d_id);
4964 		if ((tmp_pd == NULL) || (pd != tmp_pd)) {
4965 			done++;
4966 			ulp_pkt->pkt_state = FC_PKT_FAILURE;
4967 			ulp_pkt->pkt_reason = FC_REASON_NO_CONNECTION;
4968 			ulp_pkt->pkt_pd = NULL;
4969 			ulp_pkt->pkt_comp(ulp_pkt);
4970 			job->job_ulp_pkts[count] = NULL;
4971 			fp_jobdone(job);
4972 			continue;
4973 		}
4974 
4975 		FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_group contd; "
4976 		    "port=%p, pd=%p", port, pd);
4977 
4978 		mutex_enter(&pd->pd_mutex);
4979 
4980 		if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
4981 			done++;
4982 			els_data = (la_els_logi_t *)ulp_pkt->pkt_resp;
4983 
4984 			ls_code.ls_code = LA_ELS_ACC;
4985 			ls_code.mbz = 0;
4986 
4987 			FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
4988 			    (uint8_t *)&ls_code, (uint8_t *)&els_data->ls_code,
4989 			    sizeof (ls_code_t), DDI_DEV_AUTOINCR);
4990 
4991 			FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
4992 			    (uint8_t *)&pd->pd_csp,
4993 			    (uint8_t *)&els_data->common_service,
4994 			    sizeof (pd->pd_csp), DDI_DEV_AUTOINCR);
4995 
4996 			FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
4997 			    (uint8_t *)&pd->pd_port_name,
4998 			    (uint8_t *)&els_data->nport_ww_name,
4999 			    sizeof (pd->pd_port_name), DDI_DEV_AUTOINCR);
5000 
5001 			FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
5002 			    (uint8_t *)&pd->pd_clsp1,
5003 			    (uint8_t *)&els_data->class_1,
5004 			    sizeof (pd->pd_clsp1), DDI_DEV_AUTOINCR);
5005 
5006 			FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
5007 			    (uint8_t *)&pd->pd_clsp2,
5008 			    (uint8_t *)&els_data->class_2,
5009 			    sizeof (pd->pd_clsp2), DDI_DEV_AUTOINCR);
5010 
5011 			FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
5012 			    (uint8_t *)&pd->pd_clsp3,
5013 			    (uint8_t *)&els_data->class_3,
5014 			    sizeof (pd->pd_clsp3), DDI_DEV_AUTOINCR);
5015 
5016 			node = pd->pd_remote_nodep;
5017 			pd->pd_login_count++;
5018 			pd->pd_flags = PD_IDLE;
5019 			ulp_pkt->pkt_pd = pd;
5020 			mutex_exit(&pd->pd_mutex);
5021 
5022 			mutex_enter(&node->fd_mutex);
5023 			FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
5024 			    (uint8_t *)&node->fd_node_name,
5025 			    (uint8_t *)(&els_data->node_ww_name),
5026 			    sizeof (node->fd_node_name), DDI_DEV_AUTOINCR);
5027 
5028 			FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
5029 			    (uint8_t *)&node->fd_vv,
5030 			    (uint8_t *)(&els_data->vendor_version),
5031 			    sizeof (node->fd_vv), DDI_DEV_AUTOINCR);
5032 
5033 			mutex_exit(&node->fd_mutex);
5034 			ulp_pkt->pkt_state = FC_PKT_SUCCESS;
5035 		} else {
5036 
5037 			ulp_pkt->pkt_state = FC_PKT_FAILURE; /* reset later */
5038 			mutex_exit(&pd->pd_mutex);
5039 		}
5040 
5041 		if (ulp_pkt->pkt_state != FC_PKT_FAILURE) {
5042 			ulp_pkt->pkt_comp(ulp_pkt);
5043 			job->job_ulp_pkts[count] = NULL;
5044 			fp_jobdone(job);
5045 		}
5046 	}
5047 
5048 	if (done == listlen) {
5049 		fp_jobwait(job);
5050 		fctl_jobdone(job);
5051 		return;
5052 	}
5053 
5054 	job->job_counter = listlen - done;
5055 
5056 	for (count = 0; count < listlen; count++) {
5057 		int cmd_flags;
5058 
5059 		if ((ulp_pkt = job->job_ulp_pkts[count]) == NULL) {
5060 			continue;
5061 		}
5062 
5063 		ASSERT(ulp_pkt->pkt_state == FC_PKT_FAILURE);
5064 
5065 		cmd_flags = FP_CMD_PLOGI_RETAIN;
5066 
5067 		d_id = ulp_pkt->pkt_cmd_fhdr.d_id;
5068 		ASSERT(d_id != 0);
5069 
5070 		pd = fctl_get_remote_port_by_did(port, d_id);
5071 
5072 		/*
5073 		 * We need to properly adjust the port device
5074 		 * reference counter before we assign the pd
5075 		 * to the ULP packets port device pointer.
5076 		 */
5077 		if (pd != NULL && ulp_pkt->pkt_pd == NULL) {
5078 			mutex_enter(&pd->pd_mutex);
5079 			pd->pd_ref_count++;
5080 			mutex_exit(&pd->pd_mutex);
5081 			FP_TRACE(FP_NHEAD1(3, 0),
5082 			    "fp_plogi_group: DID = 0x%x using new pd %p \
5083 			    old pd NULL\n", d_id, pd);
5084 		} else if (pd != NULL && ulp_pkt->pkt_pd != NULL &&
5085 		    ulp_pkt->pkt_pd != pd) {
5086 			mutex_enter(&pd->pd_mutex);
5087 			pd->pd_ref_count++;
5088 			mutex_exit(&pd->pd_mutex);
5089 			mutex_enter(&ulp_pkt->pkt_pd->pd_mutex);
5090 			ulp_pkt->pkt_pd->pd_ref_count--;
5091 			mutex_exit(&ulp_pkt->pkt_pd->pd_mutex);
5092 			FP_TRACE(FP_NHEAD1(3, 0),
5093 			    "fp_plogi_group: DID = 0x%x pkt_pd %p != pd %p\n",
5094 			    d_id, ulp_pkt->pkt_pd, pd);
5095 		} else if (pd == NULL && ulp_pkt->pkt_pd != NULL) {
5096 			mutex_enter(&ulp_pkt->pkt_pd->pd_mutex);
5097 			ulp_pkt->pkt_pd->pd_ref_count--;
5098 			mutex_exit(&ulp_pkt->pkt_pd->pd_mutex);
5099 			FP_TRACE(FP_NHEAD1(3, 0),
5100 			    "fp_plogi_group: DID = 0x%x pd is NULL and \
5101 			    pkt_pd = %p\n", d_id, ulp_pkt->pkt_pd);
5102 		}
5103 
5104 		ulp_pkt->pkt_pd = pd;
5105 
5106 		if (pd != NULL) {
5107 			mutex_enter(&pd->pd_mutex);
5108 			d_id = pd->pd_port_id.port_id;
5109 			pd->pd_flags = PD_ELS_IN_PROGRESS;
5110 			mutex_exit(&pd->pd_mutex);
5111 		} else {
5112 			d_id = ulp_pkt->pkt_cmd_fhdr.d_id;
5113 #ifdef	DEBUG
5114 			pd = fctl_get_remote_port_by_did(port, d_id);
5115 			ASSERT(pd == NULL);
5116 #endif
5117 			/*
5118 			 * In the Fabric topology, use NS to create
5119 			 * port device, and if that fails still try
5120 			 * with PLOGI - which will make yet another
5121 			 * attempt to create after successful PLOGI
5122 			 */
5123 			mutex_enter(&port->fp_mutex);
5124 			if (FC_IS_TOP_SWITCH(port->fp_topology)) {
5125 				mutex_exit(&port->fp_mutex);
5126 				pd = fp_create_remote_port_by_ns(port,
5127 				    d_id, KM_SLEEP);
5128 				if (pd) {
5129 					cmd_flags |= FP_CMD_DELDEV_ON_ERROR;
5130 
5131 					mutex_enter(&pd->pd_mutex);
5132 					pd->pd_flags = PD_ELS_IN_PROGRESS;
5133 					mutex_exit(&pd->pd_mutex);
5134 
5135 					FP_TRACE(FP_NHEAD1(3, 0),
5136 					    "fp_plogi_group;"
5137 					    " NS created PD port=%p, job=%p,"
5138 					    " pd=%p", port, job, pd);
5139 				}
5140 			} else {
5141 				mutex_exit(&port->fp_mutex);
5142 			}
5143 			if ((ulp_pkt->pkt_pd == NULL) && (pd != NULL)) {
5144 				FP_TRACE(FP_NHEAD1(3, 0),
5145 				    "fp_plogi_group;"
5146 				    "ulp_pkt's pd is NULL, get a pd %p",
5147 				    pd);
5148 				mutex_enter(&pd->pd_mutex);
5149 				pd->pd_ref_count++;
5150 				mutex_exit(&pd->pd_mutex);
5151 			}
5152 			ulp_pkt->pkt_pd = pd;
5153 		}
5154 
5155 		rval = fp_port_login(port, d_id, job, cmd_flags,
5156 		    KM_SLEEP, pd, ulp_pkt);
5157 
5158 		if (rval == FC_SUCCESS) {
5159 			continue;
5160 		}
5161 
5162 		if (rval == FC_STATEC_BUSY) {
5163 			ulp_pkt->pkt_state = FC_PKT_PORT_OFFLINE;
5164 			ulp_pkt->pkt_reason = FC_REASON_OFFLINE;
5165 		} else {
5166 			ulp_pkt->pkt_state = FC_PKT_FAILURE;
5167 		}
5168 
5169 		if (pd) {
5170 			mutex_enter(&pd->pd_mutex);
5171 			pd->pd_flags = PD_IDLE;
5172 			mutex_exit(&pd->pd_mutex);
5173 		}
5174 
5175 		if (cmd_flags & FP_CMD_DELDEV_ON_ERROR) {
5176 			ASSERT(pd != NULL);
5177 
5178 			FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_group: NS created,"
5179 			    " PD removed; port=%p, job=%p", port, job);
5180 
5181 			mutex_enter(&pd->pd_mutex);
5182 			pd->pd_ref_count--;
5183 			node = pd->pd_remote_nodep;
5184 			mutex_exit(&pd->pd_mutex);
5185 
5186 			ASSERT(node != NULL);
5187 
5188 			if (fctl_destroy_remote_port(port, pd) == 0) {
5189 				fctl_destroy_remote_node(node);
5190 			}
5191 			ulp_pkt->pkt_pd = NULL;
5192 		}
5193 		ulp_pkt->pkt_comp(ulp_pkt);
5194 		fp_jobdone(job);
5195 	}
5196 
5197 	fp_jobwait(job);
5198 	fctl_jobdone(job);
5199 
5200 	FP_TRACE(FP_NHEAD1(1, 0), "fp_plogi_group end: port=%p, job=%p",
5201 	    port, job);
5202 }
5203 
5204 
5205 /*
5206  * Name server request initialization
5207  */
5208 static void
5209 fp_ns_init(fc_local_port_t *port, job_request_t *job, int sleep)
5210 {
5211 	int rval;
5212 	int count;
5213 	int size;
5214 
5215 	ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
5216 
5217 	job->job_counter = 1;
5218 	job->job_result = FC_SUCCESS;
5219 
5220 	rval = fp_port_login(port, 0xFFFFFC, job, FP_CMD_PLOGI_RETAIN,
5221 	    KM_SLEEP, NULL, NULL);
5222 
5223 	if (rval != FC_SUCCESS) {
5224 		mutex_enter(&port->fp_mutex);
5225 		port->fp_topology = FC_TOP_NO_NS;
5226 		mutex_exit(&port->fp_mutex);
5227 		return;
5228 	}
5229 
5230 	fp_jobwait(job);
5231 
5232 	if (job->job_result != FC_SUCCESS) {
5233 		mutex_enter(&port->fp_mutex);
5234 		port->fp_topology = FC_TOP_NO_NS;
5235 		mutex_exit(&port->fp_mutex);
5236 		return;
5237 	}
5238 
5239 	/*
5240 	 * At this time, we'll do NS registration for objects in the
5241 	 * ns_reg_cmds (see top of this file) array.
5242 	 *
5243 	 * Each time a ULP module registers with the transport, the
5244 	 * appropriate fc4 bit is set fc4 types and registered with
5245 	 * the NS for this support. Also, ULPs and FC admin utilities
5246 	 * may do registration for objects like IP address, symbolic
5247 	 * port/node name, Initial process associator at run time.
5248 	 */
5249 	size = sizeof (ns_reg_cmds) / sizeof (ns_reg_cmds[0]);
5250 	job->job_counter = size;
5251 	job->job_result = FC_SUCCESS;
5252 
5253 	for (count = 0; count < size; count++) {
5254 		if (fp_ns_reg(port, NULL, ns_reg_cmds[count],
5255 		    job, 0, sleep) != FC_SUCCESS) {
5256 			fp_jobdone(job);
5257 		}
5258 	}
5259 	if (size) {
5260 		fp_jobwait(job);
5261 	}
5262 
5263 	job->job_result = FC_SUCCESS;
5264 
5265 	(void) fp_ns_get_devcount(port, job, 0, KM_SLEEP);
5266 
5267 	if (port->fp_dev_count < FP_MAX_DEVICES) {
5268 		(void) fp_ns_get_devcount(port, job, 1, KM_SLEEP);
5269 	}
5270 
5271 	job->job_counter = 1;
5272 
5273 	if (fp_ns_scr(port, job, FC_SCR_FULL_REGISTRATION,
5274 	    sleep) == FC_SUCCESS) {
5275 		fp_jobwait(job);
5276 	}
5277 }
5278 
5279 
5280 /*
5281  * Name server finish:
5282  *	Unregister for RSCNs
5283  *	Unregister all the host port objects in the Name Server
5284  *	Perform LOGO with the NS;
5285  */
5286 static void
5287 fp_ns_fini(fc_local_port_t *port, job_request_t *job)
5288 {
5289 	fp_cmd_t	*cmd;
5290 	uchar_t		class;
5291 	uint32_t	s_id;
5292 	fc_packet_t	*pkt;
5293 	la_els_logo_t	payload;
5294 
5295 	ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
5296 
5297 	job->job_counter = 1;
5298 
5299 	if (fp_ns_scr(port, job, FC_SCR_CLEAR_REGISTRATION, KM_SLEEP) !=
5300 	    FC_SUCCESS) {
5301 		fp_jobdone(job);
5302 	}
5303 	fp_jobwait(job);
5304 
5305 	job->job_counter = 1;
5306 
5307 	if (fp_ns_reg(port, NULL, NS_DA_ID, job, 0, KM_SLEEP) != FC_SUCCESS) {
5308 		fp_jobdone(job);
5309 	}
5310 	fp_jobwait(job);
5311 
5312 	job->job_counter = 1;
5313 
5314 	cmd = fp_alloc_pkt(port, sizeof (la_els_logo_t),
5315 	    FP_PORT_IDENTIFIER_LEN, KM_SLEEP, NULL);
5316 	pkt = &cmd->cmd_pkt;
5317 
5318 	mutex_enter(&port->fp_mutex);
5319 	class = port->fp_ns_login_class;
5320 	s_id = port->fp_port_id.port_id;
5321 	payload.nport_id = port->fp_port_id;
5322 	mutex_exit(&port->fp_mutex);
5323 
5324 	cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class;
5325 	cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
5326 	cmd->cmd_flags = FP_CMD_PLOGI_DONT_CARE;
5327 	cmd->cmd_retry_count = 1;
5328 	cmd->cmd_ulp_pkt = NULL;
5329 
5330 	if (port->fp_npiv_type == FC_NPIV_PORT) {
5331 		fp_els_init(cmd, s_id, 0xFFFFFE, fp_logo_intr, job);
5332 	} else {
5333 		fp_els_init(cmd, s_id, 0xFFFFFC, fp_logo_intr, job);
5334 	}
5335 
5336 	cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
5337 
5338 	payload.ls_code.ls_code = LA_ELS_LOGO;
5339 	payload.ls_code.mbz = 0;
5340 	payload.nport_ww_name = port->fp_service_params.nport_ww_name;
5341 
5342 	FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
5343 	    (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
5344 
5345 	if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
5346 		fp_iodone(cmd);
5347 	}
5348 	fp_jobwait(job);
5349 }
5350 
5351 
5352 /*
5353  * NS Registration function.
5354  *
5355  *	It should be seriously noted that FC-GS-2 currently doesn't support
5356  *	an Object Registration by a D_ID other than the owner of the object.
5357  *	What we are aiming at currently is to at least allow Symbolic Node/Port
5358  *	Name registration for any N_Port Identifier by the host software.
5359  *
5360  *	Anyway, if the second argument (fc_remote_port_t *) is NULL, this
5361  *	function treats the request as Host NS Object.
5362  */
5363 static int
5364 fp_ns_reg(fc_local_port_t *port, fc_remote_port_t *pd, uint16_t cmd_code,
5365     job_request_t *job, int polled, int sleep)
5366 {
5367 	int		rval;
5368 	fc_portid_t	s_id;
5369 	fc_packet_t	*pkt;
5370 	fp_cmd_t	*cmd;
5371 
5372 	if (pd == NULL) {
5373 		mutex_enter(&port->fp_mutex);
5374 		s_id = port->fp_port_id;
5375 		mutex_exit(&port->fp_mutex);
5376 	} else {
5377 		mutex_enter(&pd->pd_mutex);
5378 		s_id = pd->pd_port_id;
5379 		mutex_exit(&pd->pd_mutex);
5380 	}
5381 
5382 	if (polled) {
5383 		job->job_counter = 1;
5384 	}
5385 
5386 	switch (cmd_code) {
5387 	case NS_RPN_ID:
5388 	case NS_RNN_ID: {
5389 		ns_rxn_req_t rxn;
5390 
5391 		cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
5392 		    sizeof (ns_rxn_req_t), sizeof (fc_reg_resp_t), sleep, NULL);
5393 		if (cmd == NULL) {
5394 			return (FC_NOMEM);
5395 		}
5396 		fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5397 		pkt = &cmd->cmd_pkt;
5398 
5399 		if (pd == NULL) {
5400 			rxn.rxn_xname = ((cmd_code == NS_RPN_ID) ?
5401 			    (port->fp_service_params.nport_ww_name) :
5402 			    (port->fp_service_params.node_ww_name));
5403 		} else {
5404 			if (cmd_code == NS_RPN_ID) {
5405 				mutex_enter(&pd->pd_mutex);
5406 				rxn.rxn_xname = pd->pd_port_name;
5407 				mutex_exit(&pd->pd_mutex);
5408 			} else {
5409 				fc_remote_node_t *node;
5410 
5411 				mutex_enter(&pd->pd_mutex);
5412 				node = pd->pd_remote_nodep;
5413 				mutex_exit(&pd->pd_mutex);
5414 
5415 				mutex_enter(&node->fd_mutex);
5416 				rxn.rxn_xname = node->fd_node_name;
5417 				mutex_exit(&node->fd_mutex);
5418 			}
5419 		}
5420 		rxn.rxn_port_id = s_id;
5421 
5422 		FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rxn,
5423 		    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
5424 		    sizeof (rxn), DDI_DEV_AUTOINCR);
5425 
5426 		break;
5427 	}
5428 
5429 	case NS_RCS_ID: {
5430 		ns_rcos_t rcos;
5431 
5432 		cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
5433 		    sizeof (ns_rcos_t), sizeof (fc_reg_resp_t), sleep, NULL);
5434 		if (cmd == NULL) {
5435 			return (FC_NOMEM);
5436 		}
5437 		fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5438 		pkt = &cmd->cmd_pkt;
5439 
5440 		if (pd == NULL) {
5441 			rcos.rcos_cos = port->fp_cos;
5442 		} else {
5443 			mutex_enter(&pd->pd_mutex);
5444 			rcos.rcos_cos = pd->pd_cos;
5445 			mutex_exit(&pd->pd_mutex);
5446 		}
5447 		rcos.rcos_port_id = s_id;
5448 
5449 		FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rcos,
5450 		    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
5451 		    sizeof (rcos), DDI_DEV_AUTOINCR);
5452 
5453 		break;
5454 	}
5455 
5456 	case NS_RFT_ID: {
5457 		ns_rfc_type_t rfc;
5458 
5459 		cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
5460 		    sizeof (ns_rfc_type_t), sizeof (fc_reg_resp_t), sleep,
5461 		    NULL);
5462 		if (cmd == NULL) {
5463 			return (FC_NOMEM);
5464 		}
5465 		fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5466 		pkt = &cmd->cmd_pkt;
5467 
5468 		if (pd == NULL) {
5469 			mutex_enter(&port->fp_mutex);
5470 			bcopy(port->fp_fc4_types, rfc.rfc_types,
5471 			    sizeof (port->fp_fc4_types));
5472 			mutex_exit(&port->fp_mutex);
5473 		} else {
5474 			mutex_enter(&pd->pd_mutex);
5475 			bcopy(pd->pd_fc4types, rfc.rfc_types,
5476 			    sizeof (pd->pd_fc4types));
5477 			mutex_exit(&pd->pd_mutex);
5478 		}
5479 		rfc.rfc_port_id = s_id;
5480 
5481 		FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rfc,
5482 		    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
5483 		    sizeof (rfc), DDI_DEV_AUTOINCR);
5484 
5485 		break;
5486 	}
5487 
5488 	case NS_RSPN_ID: {
5489 		uchar_t		name_len;
5490 		int		pl_size;
5491 		fc_portid_t	spn;
5492 
5493 		if (pd == NULL) {
5494 			mutex_enter(&port->fp_mutex);
5495 			name_len = port->fp_sym_port_namelen;
5496 			mutex_exit(&port->fp_mutex);
5497 		} else {
5498 			mutex_enter(&pd->pd_mutex);
5499 			name_len = pd->pd_spn_len;
5500 			mutex_exit(&pd->pd_mutex);
5501 		}
5502 
5503 		pl_size = sizeof (fc_portid_t) + name_len + 1;
5504 
5505 		cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) + pl_size,
5506 		    sizeof (fc_reg_resp_t), sleep, NULL);
5507 		if (cmd == NULL) {
5508 			return (FC_NOMEM);
5509 		}
5510 
5511 		fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5512 
5513 		pkt = &cmd->cmd_pkt;
5514 
5515 		spn = s_id;
5516 
5517 		FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&spn, (uint8_t *)
5518 		    (pkt->pkt_cmd + sizeof (fc_ct_header_t)), sizeof (spn),
5519 		    DDI_DEV_AUTOINCR);
5520 		FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&name_len,
5521 		    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)
5522 		    + sizeof (fc_portid_t)), 1, DDI_DEV_AUTOINCR);
5523 
5524 		if (pd == NULL) {
5525 			mutex_enter(&port->fp_mutex);
5526 			FC_SET_CMD(port, pkt->pkt_cmd_acc,
5527 			    (uint8_t *)port->fp_sym_port_name, (uint8_t *)
5528 			    (pkt->pkt_cmd + sizeof (fc_ct_header_t) +
5529 			    sizeof (spn) + 1), name_len, DDI_DEV_AUTOINCR);
5530 			mutex_exit(&port->fp_mutex);
5531 		} else {
5532 			mutex_enter(&pd->pd_mutex);
5533 			FC_SET_CMD(port, pkt->pkt_cmd_acc,
5534 			    (uint8_t *)pd->pd_spn,
5535 			    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t) +
5536 			    sizeof (spn) + 1), name_len, DDI_DEV_AUTOINCR);
5537 			mutex_exit(&pd->pd_mutex);
5538 		}
5539 		break;
5540 	}
5541 
5542 	case NS_RPT_ID: {
5543 		ns_rpt_t rpt;
5544 
5545 		cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
5546 		    sizeof (ns_rpt_t), sizeof (fc_reg_resp_t), sleep, NULL);
5547 		if (cmd == NULL) {
5548 			return (FC_NOMEM);
5549 		}
5550 		fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5551 		pkt = &cmd->cmd_pkt;
5552 
5553 		if (pd == NULL) {
5554 			rpt.rpt_type = port->fp_port_type;
5555 		} else {
5556 			mutex_enter(&pd->pd_mutex);
5557 			rpt.rpt_type = pd->pd_porttype;
5558 			mutex_exit(&pd->pd_mutex);
5559 		}
5560 		rpt.rpt_port_id = s_id;
5561 
5562 		FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rpt,
5563 		    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
5564 		    sizeof (rpt), DDI_DEV_AUTOINCR);
5565 
5566 		break;
5567 	}
5568 
5569 	case NS_RIP_NN: {
5570 		ns_rip_t rip;
5571 
5572 		cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
5573 		    sizeof (ns_rip_t), sizeof (fc_reg_resp_t), sleep, NULL);
5574 		if (cmd == NULL) {
5575 			return (FC_NOMEM);
5576 		}
5577 		fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5578 		pkt = &cmd->cmd_pkt;
5579 
5580 		if (pd == NULL) {
5581 			rip.rip_node_name =
5582 			    port->fp_service_params.node_ww_name;
5583 			bcopy(port->fp_ip_addr, rip.rip_ip_addr,
5584 			    sizeof (port->fp_ip_addr));
5585 		} else {
5586 			fc_remote_node_t *node;
5587 
5588 			/*
5589 			 * The most correct implementation should have the IP
5590 			 * address in the fc_remote_node_t structure; I believe
5591 			 * Node WWN and IP address should have one to one
5592 			 * correlation (but guess what this is changing in
5593 			 * FC-GS-2 latest draft)
5594 			 */
5595 			mutex_enter(&pd->pd_mutex);
5596 			node = pd->pd_remote_nodep;
5597 			bcopy(pd->pd_ip_addr, rip.rip_ip_addr,
5598 			    sizeof (pd->pd_ip_addr));
5599 			mutex_exit(&pd->pd_mutex);
5600 
5601 			mutex_enter(&node->fd_mutex);
5602 			rip.rip_node_name = node->fd_node_name;
5603 			mutex_exit(&node->fd_mutex);
5604 		}
5605 
5606 		FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rip,
5607 		    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
5608 		    sizeof (rip), DDI_DEV_AUTOINCR);
5609 
5610 		break;
5611 	}
5612 
5613 	case NS_RIPA_NN: {
5614 		ns_ipa_t ipa;
5615 
5616 		cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
5617 		    sizeof (ns_ipa_t), sizeof (fc_reg_resp_t), sleep, NULL);
5618 		if (cmd == NULL) {
5619 			return (FC_NOMEM);
5620 		}
5621 		fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5622 		pkt = &cmd->cmd_pkt;
5623 
5624 		if (pd == NULL) {
5625 			ipa.ipa_node_name =
5626 			    port->fp_service_params.node_ww_name;
5627 			bcopy(port->fp_ipa, ipa.ipa_value,
5628 			    sizeof (port->fp_ipa));
5629 		} else {
5630 			fc_remote_node_t *node;
5631 
5632 			mutex_enter(&pd->pd_mutex);
5633 			node = pd->pd_remote_nodep;
5634 			mutex_exit(&pd->pd_mutex);
5635 
5636 			mutex_enter(&node->fd_mutex);
5637 			ipa.ipa_node_name = node->fd_node_name;
5638 			bcopy(node->fd_ipa, ipa.ipa_value,
5639 			    sizeof (node->fd_ipa));
5640 			mutex_exit(&node->fd_mutex);
5641 		}
5642 
5643 		FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&ipa,
5644 		    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
5645 		    sizeof (ipa), DDI_DEV_AUTOINCR);
5646 
5647 		break;
5648 	}
5649 
5650 	case NS_RSNN_NN: {
5651 		uchar_t			name_len;
5652 		int			pl_size;
5653 		la_wwn_t		snn;
5654 		fc_remote_node_t	*node = NULL;
5655 
5656 		if (pd == NULL) {
5657 			mutex_enter(&port->fp_mutex);
5658 			name_len = port->fp_sym_node_namelen;
5659 			mutex_exit(&port->fp_mutex);
5660 		} else {
5661 			mutex_enter(&pd->pd_mutex);
5662 			node = pd->pd_remote_nodep;
5663 			mutex_exit(&pd->pd_mutex);
5664 
5665 			mutex_enter(&node->fd_mutex);
5666 			name_len = node->fd_snn_len;
5667 			mutex_exit(&node->fd_mutex);
5668 		}
5669 
5670 		pl_size = sizeof (la_wwn_t) + name_len + 1;
5671 
5672 		cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
5673 		    pl_size, sizeof (fc_reg_resp_t), sleep, NULL);
5674 		if (cmd == NULL) {
5675 			return (FC_NOMEM);
5676 		}
5677 		fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5678 
5679 		pkt = &cmd->cmd_pkt;
5680 
5681 		bcopy(&port->fp_service_params.node_ww_name,
5682 		    &snn, sizeof (la_wwn_t));
5683 
5684 		if (pd == NULL) {
5685 			mutex_enter(&port->fp_mutex);
5686 			FC_SET_CMD(port, pkt->pkt_cmd_acc,
5687 			    (uint8_t *)port->fp_sym_node_name, (uint8_t *)
5688 			    (pkt->pkt_cmd + sizeof (fc_ct_header_t) +
5689 			    sizeof (snn) + 1), name_len, DDI_DEV_AUTOINCR);
5690 			mutex_exit(&port->fp_mutex);
5691 		} else {
5692 			ASSERT(node != NULL);
5693 			mutex_enter(&node->fd_mutex);
5694 			FC_SET_CMD(port, pkt->pkt_cmd_acc,
5695 			    (uint8_t *)node->fd_snn,
5696 			    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t) +
5697 			    sizeof (snn) + 1), name_len, DDI_DEV_AUTOINCR);
5698 			mutex_exit(&node->fd_mutex);
5699 		}
5700 
5701 		FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&snn,
5702 		    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
5703 		    sizeof (snn), DDI_DEV_AUTOINCR);
5704 		FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&name_len,
5705 		    (uint8_t *)(pkt->pkt_cmd
5706 		    + sizeof (fc_ct_header_t) + sizeof (snn)),
5707 		    1, DDI_DEV_AUTOINCR);
5708 
5709 		break;
5710 	}
5711 
5712 	case NS_DA_ID: {
5713 		ns_remall_t rall;
5714 		char tmp[4] = {0};
5715 		char *ptr;
5716 
5717 		cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
5718 		    sizeof (ns_remall_t), sizeof (fc_reg_resp_t), sleep, NULL);
5719 
5720 		if (cmd == NULL) {
5721 			return (FC_NOMEM);
5722 		}
5723 
5724 		fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5725 		pkt = &cmd->cmd_pkt;
5726 
5727 		ptr = (char *)(&s_id);
5728 		tmp[3] = *ptr++;
5729 		tmp[2] = *ptr++;
5730 		tmp[1] = *ptr++;
5731 		tmp[0] = *ptr;
5732 #if defined(_BIT_FIELDS_LTOH)
5733 		bcopy((caddr_t)tmp, (caddr_t)(&rall.rem_port_id), 4);
5734 #else
5735 		rall.rem_port_id = s_id;
5736 #endif
5737 		FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rall,
5738 		    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
5739 		    sizeof (rall), DDI_DEV_AUTOINCR);
5740 
5741 		break;
5742 	}
5743 
5744 	default:
5745 		return (FC_FAILURE);
5746 	}
5747 
5748 	rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
5749 
5750 	if (rval != FC_SUCCESS) {
5751 		job->job_result = rval;
5752 		fp_iodone(cmd);
5753 	}
5754 
5755 	if (polled) {
5756 		ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
5757 		fp_jobwait(job);
5758 	} else {
5759 		rval = FC_SUCCESS;
5760 	}
5761 
5762 	return (rval);
5763 }
5764 
5765 
5766 /*
5767  * Common interrupt handler
5768  */
5769 static int
5770 fp_common_intr(fc_packet_t *pkt, int iodone)
5771 {
5772 	int		rval = FC_FAILURE;
5773 	fp_cmd_t	*cmd;
5774 	fc_local_port_t	*port;
5775 
5776 	cmd = pkt->pkt_ulp_private;
5777 	port = cmd->cmd_port;
5778 
5779 	/*
5780 	 * Fail fast the upper layer requests if
5781 	 * a state change has occurred amidst.
5782 	 */
5783 	mutex_enter(&port->fp_mutex);
5784 	if (cmd->cmd_ulp_pkt != NULL && port->fp_statec_busy) {
5785 		mutex_exit(&port->fp_mutex);
5786 		cmd->cmd_ulp_pkt->pkt_state = FC_PKT_PORT_OFFLINE;
5787 		cmd->cmd_ulp_pkt->pkt_reason = FC_REASON_OFFLINE;
5788 	} else if (!(port->fp_soft_state &
5789 	    (FP_SOFT_IN_DETACH | FP_DETACH_INPROGRESS))) {
5790 		mutex_exit(&port->fp_mutex);
5791 
5792 		switch (pkt->pkt_state) {
5793 		case FC_PKT_LOCAL_BSY:
5794 		case FC_PKT_FABRIC_BSY:
5795 		case FC_PKT_NPORT_BSY:
5796 		case FC_PKT_TIMEOUT:
5797 			cmd->cmd_retry_interval = (pkt->pkt_state ==
5798 			    FC_PKT_TIMEOUT) ? 0 : fp_retry_delay;
5799 			rval = fp_retry_cmd(pkt);
5800 			break;
5801 
5802 		case FC_PKT_FABRIC_RJT:
5803 		case FC_PKT_NPORT_RJT:
5804 		case FC_PKT_LOCAL_RJT:
5805 		case FC_PKT_LS_RJT:
5806 		case FC_PKT_FS_RJT:
5807 		case FC_PKT_BA_RJT:
5808 			rval = fp_handle_reject(pkt);
5809 			break;
5810 
5811 		default:
5812 			if (pkt->pkt_resp_resid) {
5813 				cmd->cmd_retry_interval = 0;
5814 				rval = fp_retry_cmd(pkt);
5815 			}
5816 			break;
5817 		}
5818 	} else {
5819 		mutex_exit(&port->fp_mutex);
5820 	}
5821 
5822 	if (rval != FC_SUCCESS && iodone) {
5823 		fp_iodone(cmd);
5824 		rval = FC_SUCCESS;
5825 	}
5826 
5827 	return (rval);
5828 }
5829 
5830 
5831 /*
5832  * Some not so long winding theory on point to point topology:
5833  *
5834  *	In the ACC payload, if the D_ID is ZERO and the common service
5835  *	parameters indicate N_Port, then the topology is POINT TO POINT.
5836  *
5837  *	In a point to point topology with an N_Port, during Fabric Login,
5838  *	the destination N_Port will check with our WWN and decide if it
5839  *	needs to issue PLOGI or not. That means, FLOGI could potentially
5840  *	trigger an unsolicited PLOGI from an N_Port. The Unsolicited
5841  *	PLOGI creates the device handles.
5842  *
5843  *	Assuming that the host port WWN is greater than the other N_Port
5844  *	WWN, then we become the master (be aware that this isn't the word
5845  *	used in the FC standards) and initiate the PLOGI.
5846  *
5847  */
5848 static void
5849 fp_flogi_intr(fc_packet_t *pkt)
5850 {
5851 	int			state;
5852 	int			f_port;
5853 	uint32_t		s_id;
5854 	uint32_t		d_id;
5855 	fp_cmd_t		*cmd;
5856 	fc_local_port_t		*port;
5857 	la_wwn_t		*swwn;
5858 	la_wwn_t		dwwn;
5859 	la_wwn_t		nwwn;
5860 	fc_remote_port_t	*pd;
5861 	la_els_logi_t		*acc;
5862 	com_svc_t		csp;
5863 	ls_code_t		resp;
5864 
5865 	cmd = pkt->pkt_ulp_private;
5866 	port = cmd->cmd_port;
5867 
5868 	mutex_enter(&port->fp_mutex);
5869 	port->fp_out_fpcmds--;
5870 	mutex_exit(&port->fp_mutex);
5871 
5872 	FP_TRACE(FP_NHEAD1(1, 0), "fp_flogi_intr; port=%p, pkt=%p, state=%x",
5873 	    port, pkt, pkt->pkt_state);
5874 
5875 	if (FP_IS_PKT_ERROR(pkt)) {
5876 		(void) fp_common_intr(pkt, 1);
5877 		return;
5878 	}
5879 
5880 	/*
5881 	 * Currently, we don't need to swap bytes here because qlc is faking the
5882 	 * response for us and so endianness is getting taken care of. But we
5883 	 * have to fix this and generalize this at some point
5884 	 */
5885 	acc = (la_els_logi_t *)pkt->pkt_resp;
5886 
5887 	FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp, (uint8_t *)acc,
5888 	    sizeof (resp), DDI_DEV_AUTOINCR);
5889 
5890 	ASSERT(resp.ls_code == LA_ELS_ACC);
5891 	if (resp.ls_code != LA_ELS_ACC) {
5892 		(void) fp_common_intr(pkt, 1);
5893 		return;
5894 	}
5895 
5896 	FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&csp,
5897 	    (uint8_t *)&acc->common_service, sizeof (csp), DDI_DEV_AUTOINCR);
5898 
5899 	f_port = FP_IS_F_PORT(csp.cmn_features) ? 1 : 0;
5900 
5901 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
5902 
5903 	mutex_enter(&port->fp_mutex);
5904 	state = FC_PORT_STATE_MASK(port->fp_state);
5905 	mutex_exit(&port->fp_mutex);
5906 
5907 	if (f_port == 0) {
5908 		if (state != FC_STATE_LOOP) {
5909 			swwn = &port->fp_service_params.nport_ww_name;
5910 
5911 			FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&dwwn,
5912 			    (uint8_t *)&acc->nport_ww_name, sizeof (la_wwn_t),
5913 			    DDI_DEV_AUTOINCR);
5914 
5915 			FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&nwwn,
5916 			    (uint8_t *)&acc->node_ww_name, sizeof (la_wwn_t),
5917 			    DDI_DEV_AUTOINCR);
5918 
5919 			mutex_enter(&port->fp_mutex);
5920 
5921 			port->fp_topology = FC_TOP_PT_PT;
5922 			port->fp_total_devices = 1;
5923 			if (fctl_wwn_cmp(swwn, &dwwn) >= 0) {
5924 				port->fp_ptpt_master = 1;
5925 				/*
5926 				 * Let us choose 'X' as S_ID and 'Y'
5927 				 * as D_ID and that'll work; hopefully
5928 				 * If not, it will get changed.
5929 				 */
5930 				s_id = port->fp_instance + FP_DEFAULT_SID;
5931 				d_id = port->fp_instance + FP_DEFAULT_DID;
5932 				port->fp_port_id.port_id = s_id;
5933 				mutex_exit(&port->fp_mutex);
5934 
5935 				FP_TRACE(FP_NHEAD1(1, 0), "fp_flogi_intr: fp %x"
5936 				    "pd %x", port->fp_port_id.port_id, d_id);
5937 				pd = fctl_create_remote_port(port,
5938 				    &nwwn, &dwwn, d_id, PD_PLOGI_INITIATOR,
5939 				    KM_NOSLEEP);
5940 				if (pd == NULL) {
5941 					fp_printf(port, CE_NOTE, FP_LOG_ONLY,
5942 					    0, NULL, "couldn't create device"
5943 					    " d_id=%X", d_id);
5944 					fp_iodone(cmd);
5945 					return;
5946 				}
5947 
5948 				cmd->cmd_pkt.pkt_tran_flags =
5949 				    pkt->pkt_tran_flags;
5950 				cmd->cmd_pkt.pkt_tran_type = pkt->pkt_tran_type;
5951 				cmd->cmd_flags = FP_CMD_PLOGI_RETAIN;
5952 				cmd->cmd_retry_count = fp_retry_count;
5953 
5954 				fp_xlogi_init(port, cmd, s_id, d_id,
5955 				    fp_plogi_intr, cmd->cmd_job, LA_ELS_PLOGI);
5956 
5957 				(&cmd->cmd_pkt)->pkt_pd = pd;
5958 
5959 				/*
5960 				 * We've just created this fc_remote_port_t, and
5961 				 * we're about to use it to send a PLOGI, so
5962 				 * bump the reference count right now.	When
5963 				 * the packet is freed, the reference count will
5964 				 * be decremented.  The ULP may also start using
5965 				 * it, so mark it as given away as well.
5966 				 */
5967 				pd->pd_ref_count++;
5968 				pd->pd_aux_flags |= PD_GIVEN_TO_ULPS;
5969 
5970 				if (fp_sendcmd(port, cmd,
5971 				    port->fp_fca_handle) == FC_SUCCESS) {
5972 					return;
5973 				}
5974 			} else {
5975 				/*
5976 				 * The device handles will be created when the
5977 				 * unsolicited PLOGI is completed successfully
5978 				 */
5979 				port->fp_ptpt_master = 0;
5980 				mutex_exit(&port->fp_mutex);
5981 			}
5982 		}
5983 		pkt->pkt_state = FC_PKT_FAILURE;
5984 	} else {
5985 		if (f_port) {
5986 			mutex_enter(&port->fp_mutex);
5987 			if (state == FC_STATE_LOOP) {
5988 				port->fp_topology = FC_TOP_PUBLIC_LOOP;
5989 			} else {
5990 				port->fp_topology = FC_TOP_FABRIC;
5991 
5992 				FC_GET_RSP(port, pkt->pkt_resp_acc,
5993 				    (uint8_t *)&port->fp_fabric_name,
5994 				    (uint8_t *)&acc->node_ww_name,
5995 				    sizeof (la_wwn_t),
5996 				    DDI_DEV_AUTOINCR);
5997 			}
5998 			port->fp_port_id.port_id = pkt->pkt_resp_fhdr.d_id;
5999 			mutex_exit(&port->fp_mutex);
6000 		} else {
6001 			pkt->pkt_state = FC_PKT_FAILURE;
6002 		}
6003 	}
6004 	fp_iodone(cmd);
6005 }
6006 
6007 
6008 /*
6009  * Handle solicited PLOGI response
6010  */
6011 static void
6012 fp_plogi_intr(fc_packet_t *pkt)
6013 {
6014 	int			nl_port;
6015 	int			bailout;
6016 	uint32_t		d_id;
6017 	fp_cmd_t		*cmd;
6018 	la_els_logi_t		*acc;
6019 	fc_local_port_t		*port;
6020 	fc_remote_port_t	*pd;
6021 	la_wwn_t		nwwn;
6022 	la_wwn_t		pwwn;
6023 	ls_code_t		resp;
6024 
6025 	nl_port = 0;
6026 	cmd = pkt->pkt_ulp_private;
6027 	port = cmd->cmd_port;
6028 	d_id = pkt->pkt_cmd_fhdr.d_id;
6029 
6030 #ifndef	__lock_lint
6031 	ASSERT(cmd->cmd_job && cmd->cmd_job->job_counter);
6032 #endif
6033 
6034 	FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_intr: port=%p, job=%p, d_id=%x,"
6035 	    " jcount=%d pkt=%p, state=%x", port, cmd->cmd_job, d_id,
6036 	    cmd->cmd_job->job_counter, pkt, pkt->pkt_state);
6037 
6038 	/*
6039 	 * Bail out early on ULP initiated requests if the
6040 	 * state change has occurred
6041 	 */
6042 	mutex_enter(&port->fp_mutex);
6043 	port->fp_out_fpcmds--;
6044 	bailout = ((port->fp_statec_busy ||
6045 	    FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) &&
6046 	    cmd->cmd_ulp_pkt) ? 1 : 0;
6047 	mutex_exit(&port->fp_mutex);
6048 
6049 	if (FP_IS_PKT_ERROR(pkt) || bailout) {
6050 		int skip_msg = 0;
6051 		int giveup = 0;
6052 
6053 		if (cmd->cmd_ulp_pkt) {
6054 			cmd->cmd_ulp_pkt->pkt_state = pkt->pkt_state;
6055 			cmd->cmd_ulp_pkt->pkt_reason = pkt->pkt_reason;
6056 			cmd->cmd_ulp_pkt->pkt_action = pkt->pkt_action;
6057 			cmd->cmd_ulp_pkt->pkt_expln = pkt->pkt_expln;
6058 		}
6059 
6060 		/*
6061 		 * If an unsolicited cross login already created
6062 		 * a device speed up the discovery by not retrying
6063 		 * the command mindlessly.
6064 		 */
6065 		if (pkt->pkt_pd == NULL &&
6066 		    fctl_get_remote_port_by_did(port, d_id) != NULL) {
6067 			fp_iodone(cmd);
6068 			return;
6069 		}
6070 
6071 		if (pkt->pkt_pd != NULL) {
6072 			giveup = (pkt->pkt_pd->pd_recepient ==
6073 			    PD_PLOGI_RECEPIENT) ? 1 : 0;
6074 			if (giveup) {
6075 				/*
6076 				 * This pd is marked as plogi
6077 				 * recipient, stop retrying
6078 				 */
6079 				FP_TRACE(FP_NHEAD1(3, 0),
6080 				    "fp_plogi_intr: stop retry as"
6081 				    " a cross login was accepted"
6082 				    " from d_id=%x, port=%p.",
6083 				    d_id, port);
6084 				fp_iodone(cmd);
6085 				return;
6086 			}
6087 		}
6088 
6089 		if (fp_common_intr(pkt, 0) == FC_SUCCESS) {
6090 			return;
6091 		}
6092 
6093 		if ((pd = fctl_get_remote_port_by_did(port, d_id)) != NULL) {
6094 			mutex_enter(&pd->pd_mutex);
6095 			if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
6096 				skip_msg++;
6097 			}
6098 			mutex_exit(&pd->pd_mutex);
6099 		}
6100 
6101 		mutex_enter(&port->fp_mutex);
6102 		if (!bailout && !(skip_msg && port->fp_statec_busy) &&
6103 		    port->fp_statec_busy <= 1 &&
6104 		    pkt->pkt_reason != FC_REASON_FCAL_OPN_FAIL) {
6105 			mutex_exit(&port->fp_mutex);
6106 			/*
6107 			 * In case of Login Collisions, JNI HBAs returns the
6108 			 * FC pkt back to the Initiator with the state set to
6109 			 * FC_PKT_LS_RJT and reason to FC_REASON_LOGICAL_ERROR.
6110 			 * QLC HBAs handles such cases in the FW and doesnot
6111 			 * return the LS_RJT with Logical error when
6112 			 * login collision happens.
6113 			 */
6114 			if ((pkt->pkt_state != FC_PKT_LS_RJT) ||
6115 			    (pkt->pkt_reason != FC_REASON_LOGICAL_ERROR)) {
6116 				fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, pkt,
6117 				    "PLOGI to %x failed", d_id);
6118 			}
6119 			FP_TRACE(FP_NHEAD2(9, 0),
6120 			    "PLOGI to %x failed. state=%x reason=%x.",
6121 			    d_id, pkt->pkt_state, pkt->pkt_reason);
6122 		} else {
6123 			mutex_exit(&port->fp_mutex);
6124 		}
6125 
6126 		fp_iodone(cmd);
6127 		return;
6128 	}
6129 
6130 	acc = (la_els_logi_t *)pkt->pkt_resp;
6131 
6132 	FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp, (uint8_t *)acc,
6133 	    sizeof (resp), DDI_DEV_AUTOINCR);
6134 
6135 	ASSERT(resp.ls_code == LA_ELS_ACC);
6136 	if (resp.ls_code != LA_ELS_ACC) {
6137 		(void) fp_common_intr(pkt, 1);
6138 		return;
6139 	}
6140 
6141 	if (d_id == FS_NAME_SERVER || d_id == FS_FABRIC_CONTROLLER) {
6142 		mutex_enter(&port->fp_mutex);
6143 		port->fp_ns_login_class = FC_TRAN_CLASS(pkt->pkt_tran_flags);
6144 		mutex_exit(&port->fp_mutex);
6145 		fp_iodone(cmd);
6146 		return;
6147 	}
6148 
6149 	ASSERT(acc == (la_els_logi_t *)pkt->pkt_resp);
6150 
6151 	FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&pwwn,
6152 	    (uint8_t *)&acc->nport_ww_name, sizeof (la_wwn_t),
6153 	    DDI_DEV_AUTOINCR);
6154 
6155 	FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&nwwn,
6156 	    (uint8_t *)&acc->node_ww_name, sizeof (la_wwn_t),
6157 	    DDI_DEV_AUTOINCR);
6158 
6159 	ASSERT(fctl_is_wwn_zero(&pwwn) == FC_FAILURE);
6160 	ASSERT(fctl_is_wwn_zero(&nwwn) == FC_FAILURE);
6161 
6162 	if ((pd = pkt->pkt_pd) == NULL) {
6163 		pd = fctl_get_remote_port_by_pwwn(port, &pwwn);
6164 		if (pd == NULL) {
6165 			FP_TRACE(FP_NHEAD2(9, 0), "fp_plogi_intr: fp %x pd %x",
6166 			    port->fp_port_id.port_id, d_id);
6167 			pd = fctl_create_remote_port(port, &nwwn, &pwwn, d_id,
6168 			    PD_PLOGI_INITIATOR, KM_NOSLEEP);
6169 			if (pd == NULL) {
6170 				fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
6171 				    "couldn't create port device handles"
6172 				    " d_id=%x", d_id);
6173 				fp_iodone(cmd);
6174 				return;
6175 			}
6176 		} else {
6177 			fc_remote_port_t *tmp_pd;
6178 
6179 			tmp_pd = fctl_get_remote_port_by_did(port, d_id);
6180 			if (tmp_pd != NULL) {
6181 				fp_iodone(cmd);
6182 				return;
6183 			}
6184 
6185 			mutex_enter(&port->fp_mutex);
6186 			mutex_enter(&pd->pd_mutex);
6187 			if ((pd->pd_state == PORT_DEVICE_LOGGED_IN) ||
6188 			    (pd->pd_aux_flags & PD_LOGGED_OUT)) {
6189 				cmd->cmd_flags |= FP_CMD_PLOGI_RETAIN;
6190 			}
6191 
6192 			if (pd->pd_type == PORT_DEVICE_OLD) {
6193 				if (pd->pd_port_id.port_id != d_id) {
6194 					fctl_delist_did_table(port, pd);
6195 					pd->pd_type = PORT_DEVICE_CHANGED;
6196 					pd->pd_port_id.port_id = d_id;
6197 				} else {
6198 					pd->pd_type = PORT_DEVICE_NOCHANGE;
6199 				}
6200 			}
6201 
6202 			if (pd->pd_aux_flags & PD_IN_DID_QUEUE) {
6203 				char ww_name[17];
6204 
6205 				fc_wwn_to_str(&pd->pd_port_name, ww_name);
6206 
6207 				mutex_exit(&pd->pd_mutex);
6208 				mutex_exit(&port->fp_mutex);
6209 				FP_TRACE(FP_NHEAD2(9, 0),
6210 				    "Possible Duplicate name or address"
6211 				    " identifiers in the PLOGI response"
6212 				    " D_ID=%x, PWWN=%s: Please check the"
6213 				    " configuration", d_id, ww_name);
6214 				fp_iodone(cmd);
6215 				return;
6216 			}
6217 			fctl_enlist_did_table(port, pd);
6218 			pd->pd_aux_flags &= ~PD_LOGGED_OUT;
6219 			mutex_exit(&pd->pd_mutex);
6220 			mutex_exit(&port->fp_mutex);
6221 		}
6222 	} else {
6223 		fc_remote_port_t *tmp_pd, *new_wwn_pd;
6224 
6225 		tmp_pd = fctl_get_remote_port_by_did(port, d_id);
6226 		new_wwn_pd = fctl_get_remote_port_by_pwwn(port, &pwwn);
6227 
6228 		mutex_enter(&port->fp_mutex);
6229 		mutex_enter(&pd->pd_mutex);
6230 		if (fctl_wwn_cmp(&pd->pd_port_name, &pwwn) == 0) {
6231 			FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_intr: d_id=%x,"
6232 			    " pd_state=%x pd_type=%x", d_id, pd->pd_state,
6233 			    pd->pd_type);
6234 			if ((pd->pd_state == PORT_DEVICE_LOGGED_IN &&
6235 			    pd->pd_type == PORT_DEVICE_OLD) ||
6236 			    (pd->pd_aux_flags & PD_LOGGED_OUT)) {
6237 				pd->pd_type = PORT_DEVICE_NOCHANGE;
6238 			} else if (pd->pd_state != PORT_DEVICE_LOGGED_IN) {
6239 				pd->pd_type = PORT_DEVICE_NEW;
6240 			}
6241 		} else {
6242 			char	old_name[17];
6243 			char	new_name[17];
6244 
6245 			fc_wwn_to_str(&pd->pd_port_name, old_name);
6246 			fc_wwn_to_str(&pwwn, new_name);
6247 
6248 			FP_TRACE(FP_NHEAD1(9, 0),
6249 			    "fp_plogi_intr: PWWN of a device with D_ID=%x "
6250 			    "changed. New PWWN = %s, OLD PWWN = %s ; tmp_pd:%p "
6251 			    "pd:%p new_wwn_pd:%p, cmd_ulp_pkt:%p, bailout:0x%x",
6252 			    d_id, new_name, old_name, tmp_pd, pd, new_wwn_pd,
6253 			    cmd->cmd_ulp_pkt, bailout);
6254 
6255 			FP_TRACE(FP_NHEAD2(9, 0),
6256 			    "PWWN of a device with D_ID=%x changed."
6257 			    " New PWWN = %s, OLD PWWN = %s", d_id,
6258 			    new_name, old_name);
6259 
6260 			if (cmd->cmd_ulp_pkt && !bailout) {
6261 				fc_remote_node_t	*rnodep;
6262 				fc_portmap_t	*changelist;
6263 				fc_portmap_t	*listptr;
6264 				int		len = 1;
6265 				/* # entries in changelist */
6266 
6267 				fctl_delist_pwwn_table(port, pd);
6268 
6269 				/*
6270 				 * Lets now check if there already is a pd with
6271 				 * this new WWN in the table. If so, we'll mark
6272 				 * it as invalid
6273 				 */
6274 
6275 				if (new_wwn_pd) {
6276 					/*
6277 					 * There is another pd with in the pwwn
6278 					 * table with the same WWN that we got
6279 					 * in the PLOGI payload. We have to get
6280 					 * it out of the pwwn table, update the
6281 					 * pd's state (fp_fillout_old_map does
6282 					 * this for us) and add it to the
6283 					 * changelist that goes up to ULPs.
6284 					 *
6285 					 * len is length of changelist and so
6286 					 * increment it.
6287 					 */
6288 					len++;
6289 
6290 					if (tmp_pd != pd) {
6291 						/*
6292 						 * Odd case where pwwn and did
6293 						 * tables are out of sync but
6294 						 * we will handle that too. See
6295 						 * more comments below.
6296 						 *
6297 						 * One more device that ULPs
6298 						 * should know about and so len
6299 						 * gets incremented again.
6300 						 */
6301 						len++;
6302 					}
6303 
6304 					listptr = changelist = kmem_zalloc(len *
6305 					    sizeof (*changelist), KM_SLEEP);
6306 
6307 					mutex_enter(&new_wwn_pd->pd_mutex);
6308 					rnodep = new_wwn_pd->pd_remote_nodep;
6309 					mutex_exit(&new_wwn_pd->pd_mutex);
6310 
6311 					/*
6312 					 * Hold the fd_mutex since
6313 					 * fctl_copy_portmap_held expects it.
6314 					 * Preserve lock hierarchy by grabbing
6315 					 * fd_mutex before pd_mutex
6316 					 */
6317 					if (rnodep) {
6318 						mutex_enter(&rnodep->fd_mutex);
6319 					}
6320 					mutex_enter(&new_wwn_pd->pd_mutex);
6321 					fp_fillout_old_map_held(listptr++,
6322 					    new_wwn_pd, 0);
6323 					mutex_exit(&new_wwn_pd->pd_mutex);
6324 					if (rnodep) {
6325 						mutex_exit(&rnodep->fd_mutex);
6326 					}
6327 
6328 					/*
6329 					 * Safety check :
6330 					 * Lets ensure that the pwwn and did
6331 					 * tables are in sync. Ideally, we
6332 					 * should not find that these two pd's
6333 					 * are different.
6334 					 */
6335 					if (tmp_pd != pd) {
6336 						mutex_enter(&tmp_pd->pd_mutex);
6337 						rnodep =
6338 						    tmp_pd->pd_remote_nodep;
6339 						mutex_exit(&tmp_pd->pd_mutex);
6340 
6341 						/* As above grab fd_mutex */
6342 						if (rnodep) {
6343 							mutex_enter(&rnodep->
6344 							    fd_mutex);
6345 						}
6346 						mutex_enter(&tmp_pd->pd_mutex);
6347 
6348 						fp_fillout_old_map_held(
6349 						    listptr++, tmp_pd, 0);
6350 
6351 						mutex_exit(&tmp_pd->pd_mutex);
6352 						if (rnodep) {
6353 							mutex_exit(&rnodep->
6354 							    fd_mutex);
6355 						}
6356 
6357 						/*
6358 						 * Now add "pd" (not tmp_pd)
6359 						 * to fp_did_table to sync it up
6360 						 * with fp_pwwn_table
6361 						 *
6362 						 * pd->pd_mutex is already held
6363 						 * at this point
6364 						 */
6365 						fctl_enlist_did_table(port, pd);
6366 					}
6367 				} else {
6368 					listptr = changelist = kmem_zalloc(
6369 					    sizeof (*changelist), KM_SLEEP);
6370 				}
6371 
6372 				ASSERT(changelist != NULL);
6373 
6374 				fp_fillout_changed_map(listptr, pd, &d_id,
6375 				    &pwwn);
6376 				fctl_enlist_pwwn_table(port, pd);
6377 
6378 				mutex_exit(&pd->pd_mutex);
6379 				mutex_exit(&port->fp_mutex);
6380 
6381 				fp_iodone(cmd);
6382 
6383 				(void) fp_ulp_devc_cb(port, changelist, len,
6384 				    len, KM_NOSLEEP, 0);
6385 
6386 				return;
6387 			}
6388 		}
6389 
6390 		if (pd->pd_porttype.port_type == FC_NS_PORT_NL) {
6391 			nl_port = 1;
6392 		}
6393 		if (pd->pd_aux_flags & PD_DISABLE_RELOGIN) {
6394 			pd->pd_aux_flags &= ~PD_LOGGED_OUT;
6395 		}
6396 
6397 		mutex_exit(&pd->pd_mutex);
6398 		mutex_exit(&port->fp_mutex);
6399 
6400 		if (tmp_pd == NULL) {
6401 			mutex_enter(&port->fp_mutex);
6402 			mutex_enter(&pd->pd_mutex);
6403 			if (pd->pd_aux_flags & PD_IN_DID_QUEUE) {
6404 				char ww_name[17];
6405 
6406 				fc_wwn_to_str(&pd->pd_port_name, ww_name);
6407 				mutex_exit(&pd->pd_mutex);
6408 				mutex_exit(&port->fp_mutex);
6409 				FP_TRACE(FP_NHEAD2(9, 0),
6410 				    "Possible Duplicate name or address"
6411 				    " identifiers in the PLOGI response"
6412 				    " D_ID=%x, PWWN=%s: Please check the"
6413 				    " configuration", d_id, ww_name);
6414 				fp_iodone(cmd);
6415 				return;
6416 			}
6417 			fctl_enlist_did_table(port, pd);
6418 			pd->pd_aux_flags &= ~PD_LOGGED_OUT;
6419 			mutex_exit(&pd->pd_mutex);
6420 			mutex_exit(&port->fp_mutex);
6421 		}
6422 	}
6423 	fp_register_login(&pkt->pkt_resp_acc, pd, acc,
6424 	    FC_TRAN_CLASS(pkt->pkt_tran_flags));
6425 
6426 	if (cmd->cmd_ulp_pkt) {
6427 		cmd->cmd_ulp_pkt->pkt_state = pkt->pkt_state;
6428 		cmd->cmd_ulp_pkt->pkt_action = pkt->pkt_action;
6429 		cmd->cmd_ulp_pkt->pkt_expln = pkt->pkt_expln;
6430 		if (cmd->cmd_ulp_pkt->pkt_pd == NULL) {
6431 			if (pd != NULL) {
6432 				FP_TRACE(FP_NHEAD1(9, 0),
6433 				    "fp_plogi_intr;"
6434 				    "ulp_pkt's pd is NULL, get a pd %p",
6435 				    pd);
6436 				mutex_enter(&pd->pd_mutex);
6437 				pd->pd_ref_count++;
6438 				mutex_exit(&pd->pd_mutex);
6439 			}
6440 			cmd->cmd_ulp_pkt->pkt_pd = pd;
6441 		}
6442 		bcopy((caddr_t)&pkt->pkt_resp_fhdr,
6443 		    (caddr_t)&cmd->cmd_ulp_pkt->pkt_resp_fhdr,
6444 		    sizeof (fc_frame_hdr_t));
6445 		bcopy((caddr_t)pkt->pkt_resp,
6446 		    (caddr_t)cmd->cmd_ulp_pkt->pkt_resp,
6447 		    sizeof (la_els_logi_t));
6448 	}
6449 
6450 	mutex_enter(&port->fp_mutex);
6451 	if (port->fp_topology == FC_TOP_PRIVATE_LOOP || nl_port) {
6452 		mutex_enter(&pd->pd_mutex);
6453 
6454 		cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
6455 		cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
6456 		cmd->cmd_retry_count = fp_retry_count;
6457 
6458 		/*
6459 		 * If the fc_remote_port_t pointer is not set in the given
6460 		 * fc_packet_t, then this fc_remote_port_t must have just
6461 		 * been created.  Save the pointer and also increment the
6462 		 * fc_remote_port_t reference count.
6463 		 */
6464 		if (pkt->pkt_pd == NULL) {
6465 			pkt->pkt_pd = pd;
6466 			pd->pd_ref_count++;	/* It's in use! */
6467 		}
6468 
6469 		fp_adisc_init(cmd, cmd->cmd_job);
6470 
6471 		pkt->pkt_cmdlen = sizeof (la_els_adisc_t);
6472 		pkt->pkt_rsplen = sizeof (la_els_adisc_t);
6473 
6474 		mutex_exit(&pd->pd_mutex);
6475 		mutex_exit(&port->fp_mutex);
6476 
6477 		if (fp_sendcmd(port, cmd, port->fp_fca_handle) == FC_SUCCESS) {
6478 			return;
6479 		}
6480 	} else {
6481 		mutex_exit(&port->fp_mutex);
6482 	}
6483 
6484 	if ((cmd->cmd_flags & FP_CMD_PLOGI_RETAIN) == 0) {
6485 		mutex_enter(&port->fp_mutex);
6486 		mutex_enter(&pd->pd_mutex);
6487 
6488 		cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
6489 		cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
6490 		cmd->cmd_retry_count = fp_retry_count;
6491 
6492 		fp_logo_init(pd, cmd, cmd->cmd_job);
6493 
6494 		pkt->pkt_cmdlen = sizeof (la_els_logo_t);
6495 		pkt->pkt_rsplen = FP_PORT_IDENTIFIER_LEN;
6496 
6497 		mutex_exit(&pd->pd_mutex);
6498 		mutex_exit(&port->fp_mutex);
6499 
6500 		if (fp_sendcmd(port, cmd, port->fp_fca_handle) == FC_SUCCESS) {
6501 			return;
6502 		}
6503 
6504 	}
6505 	fp_iodone(cmd);
6506 }
6507 
6508 
6509 /*
6510  * Handle solicited ADISC response
6511  */
6512 static void
6513 fp_adisc_intr(fc_packet_t *pkt)
6514 {
6515 	int			rval;
6516 	int			bailout;
6517 	fp_cmd_t		*cmd;
6518 	fc_local_port_t		*port;
6519 	fc_remote_port_t	*pd;
6520 	la_els_adisc_t		*acc;
6521 	ls_code_t		resp;
6522 	fc_hardaddr_t		ha;
6523 	fc_portmap_t		*changelist;
6524 	int			initiator, adiscfail = 0;
6525 
6526 	pd = pkt->pkt_pd;
6527 	cmd = pkt->pkt_ulp_private;
6528 	port = cmd->cmd_port;
6529 
6530 #ifndef	__lock_lint
6531 	ASSERT(cmd->cmd_job && cmd->cmd_job->job_counter);
6532 #endif
6533 
6534 	ASSERT(pd != NULL && port != NULL && cmd != NULL);
6535 
6536 	mutex_enter(&port->fp_mutex);
6537 	port->fp_out_fpcmds--;
6538 	bailout = ((port->fp_statec_busy ||
6539 	    FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) &&
6540 	    cmd->cmd_ulp_pkt) ? 1 : 0;
6541 	mutex_exit(&port->fp_mutex);
6542 
6543 	if (bailout) {
6544 		fp_iodone(cmd);
6545 		return;
6546 	}
6547 
6548 	if (pkt->pkt_state == FC_PKT_SUCCESS && pkt->pkt_resp_resid == 0) {
6549 		acc = (la_els_adisc_t *)pkt->pkt_resp;
6550 
6551 		FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp,
6552 		    (uint8_t *)acc, sizeof (resp), DDI_DEV_AUTOINCR);
6553 
6554 		if (resp.ls_code == LA_ELS_ACC) {
6555 			int	is_private;
6556 
6557 			FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&ha,
6558 			    (uint8_t *)&acc->hard_addr, sizeof (ha),
6559 			    DDI_DEV_AUTOINCR);
6560 
6561 			mutex_enter(&port->fp_mutex);
6562 
6563 			is_private =
6564 			    (port->fp_topology == FC_TOP_PRIVATE_LOOP) ? 1 : 0;
6565 
6566 			mutex_enter(&pd->pd_mutex);
6567 			if ((pd->pd_aux_flags & PD_IN_DID_QUEUE) == 0) {
6568 				fctl_enlist_did_table(port, pd);
6569 			}
6570 			mutex_exit(&pd->pd_mutex);
6571 
6572 			mutex_exit(&port->fp_mutex);
6573 
6574 			mutex_enter(&pd->pd_mutex);
6575 			if (pd->pd_type != PORT_DEVICE_NEW) {
6576 				if (is_private && (pd->pd_hard_addr.hard_addr !=
6577 				    ha.hard_addr)) {
6578 					pd->pd_type = PORT_DEVICE_CHANGED;
6579 				} else {
6580 					pd->pd_type = PORT_DEVICE_NOCHANGE;
6581 				}
6582 			}
6583 
6584 			if (is_private && (ha.hard_addr &&
6585 			    pd->pd_port_id.port_id != ha.hard_addr)) {
6586 				char ww_name[17];
6587 
6588 				fc_wwn_to_str(&pd->pd_port_name, ww_name);
6589 
6590 				fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
6591 				    "NL_Port Identifier %x doesn't match"
6592 				    " with Hard Address %x, Will use Port"
6593 				    " WWN %s", pd->pd_port_id.port_id,
6594 				    ha.hard_addr, ww_name);
6595 
6596 				pd->pd_hard_addr.hard_addr = 0;
6597 			} else {
6598 				pd->pd_hard_addr.hard_addr = ha.hard_addr;
6599 			}
6600 			mutex_exit(&pd->pd_mutex);
6601 		} else {
6602 			if (fp_common_intr(pkt, 0) == FC_SUCCESS) {
6603 				return;
6604 			}
6605 		}
6606 	} else {
6607 		if (fp_common_intr(pkt, 0) == FC_SUCCESS) {
6608 			return;
6609 		}
6610 
6611 		mutex_enter(&port->fp_mutex);
6612 		if (port->fp_statec_busy <= 1) {
6613 			mutex_exit(&port->fp_mutex);
6614 			fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, pkt,
6615 			    "ADISC to %x failed, cmd_flags=%x",
6616 			    pkt->pkt_cmd_fhdr.d_id, cmd->cmd_flags);
6617 			cmd->cmd_flags &= ~FP_CMD_PLOGI_RETAIN;
6618 			adiscfail = 1;
6619 		} else {
6620 			mutex_exit(&port->fp_mutex);
6621 		}
6622 	}
6623 
6624 	if (cmd->cmd_ulp_pkt) {
6625 		cmd->cmd_ulp_pkt->pkt_state = pkt->pkt_state;
6626 		cmd->cmd_ulp_pkt->pkt_action = pkt->pkt_action;
6627 		cmd->cmd_ulp_pkt->pkt_expln = pkt->pkt_expln;
6628 		if (cmd->cmd_ulp_pkt->pkt_pd == NULL) {
6629 			cmd->cmd_ulp_pkt->pkt_pd = pd;
6630 			FP_TRACE(FP_NHEAD1(9, 0),
6631 			    "fp_adisc__intr;"
6632 			    "ulp_pkt's pd is NULL, get a pd %p",
6633 			    pd);
6634 
6635 		}
6636 		bcopy((caddr_t)&pkt->pkt_resp_fhdr,
6637 		    (caddr_t)&cmd->cmd_ulp_pkt->pkt_resp_fhdr,
6638 		    sizeof (fc_frame_hdr_t));
6639 		bcopy((caddr_t)pkt->pkt_resp,
6640 		    (caddr_t)cmd->cmd_ulp_pkt->pkt_resp,
6641 		    sizeof (la_els_adisc_t));
6642 	}
6643 
6644 	if ((cmd->cmd_flags & FP_CMD_PLOGI_RETAIN) == 0) {
6645 		FP_TRACE(FP_NHEAD1(9, 0),
6646 		    "fp_adisc_intr: Perform LOGO.cmd_flags=%x, "
6647 		    "fp_retry_count=%x, ulp_pkt=%p",
6648 		    cmd->cmd_flags, fp_retry_count, cmd->cmd_ulp_pkt);
6649 
6650 		mutex_enter(&port->fp_mutex);
6651 		mutex_enter(&pd->pd_mutex);
6652 
6653 		cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
6654 		cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
6655 		cmd->cmd_retry_count = fp_retry_count;
6656 
6657 		fp_logo_init(pd, cmd, cmd->cmd_job);
6658 
6659 		pkt->pkt_cmdlen = sizeof (la_els_logo_t);
6660 		pkt->pkt_rsplen = FP_PORT_IDENTIFIER_LEN;
6661 
6662 		mutex_exit(&pd->pd_mutex);
6663 		mutex_exit(&port->fp_mutex);
6664 
6665 		rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
6666 		if (adiscfail) {
6667 			mutex_enter(&pd->pd_mutex);
6668 			initiator =
6669 			    ((pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0);
6670 			pd->pd_state = PORT_DEVICE_VALID;
6671 			pd->pd_aux_flags |= PD_LOGGED_OUT;
6672 			if (pd->pd_aux_flags & PD_DISABLE_RELOGIN) {
6673 				pd->pd_type = PORT_DEVICE_NEW;
6674 			} else {
6675 				pd->pd_type = PORT_DEVICE_NOCHANGE;
6676 			}
6677 			mutex_exit(&pd->pd_mutex);
6678 
6679 			changelist =
6680 			    kmem_zalloc(sizeof (*changelist), KM_SLEEP);
6681 
6682 			if (initiator) {
6683 				fp_unregister_login(pd);
6684 				fctl_copy_portmap(changelist, pd);
6685 			} else {
6686 				fp_fillout_old_map(changelist, pd, 0);
6687 			}
6688 
6689 			FP_TRACE(FP_NHEAD1(9, 0),
6690 			    "fp_adisc_intr: Dev change notification "
6691 			    "to ULP port=%p, pd=%p, map_type=%x map_state=%x "
6692 			    "map_flags=%x initiator=%d", port, pd,
6693 			    changelist->map_type, changelist->map_state,
6694 			    changelist->map_flags, initiator);
6695 
6696 			(void) fp_ulp_devc_cb(port, changelist,
6697 			    1, 1, KM_SLEEP, 0);
6698 		}
6699 		if (rval == FC_SUCCESS) {
6700 			return;
6701 		}
6702 	}
6703 	fp_iodone(cmd);
6704 }
6705 
6706 
6707 /*
6708  * Handle solicited LOGO response
6709  */
6710 static void
6711 fp_logo_intr(fc_packet_t *pkt)
6712 {
6713 	ls_code_t	resp;
6714 	fc_local_port_t *port = ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port;
6715 
6716 	mutex_enter(&((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_mutex);
6717 	((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_out_fpcmds--;
6718 	mutex_exit(&((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_mutex);
6719 
6720 	FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp,
6721 	    (uint8_t *)pkt->pkt_resp, sizeof (resp), DDI_DEV_AUTOINCR);
6722 
6723 	if (FP_IS_PKT_ERROR(pkt)) {
6724 		(void) fp_common_intr(pkt, 1);
6725 		return;
6726 	}
6727 
6728 	ASSERT(resp.ls_code == LA_ELS_ACC);
6729 	if (resp.ls_code != LA_ELS_ACC) {
6730 		(void) fp_common_intr(pkt, 1);
6731 		return;
6732 	}
6733 
6734 	if (pkt->pkt_pd != NULL) {
6735 		fp_unregister_login(pkt->pkt_pd);
6736 	}
6737 
6738 	fp_iodone(pkt->pkt_ulp_private);
6739 }
6740 
6741 
6742 /*
6743  * Handle solicited RNID response
6744  */
6745 static void
6746 fp_rnid_intr(fc_packet_t *pkt)
6747 {
6748 	ls_code_t		resp;
6749 	job_request_t		*job;
6750 	fp_cmd_t		*cmd;
6751 	la_els_rnid_acc_t	*acc;
6752 	fc_local_port_t *port = ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port;
6753 
6754 	FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp,
6755 	    (uint8_t *)pkt->pkt_resp, sizeof (resp), DDI_DEV_AUTOINCR);
6756 	cmd = pkt->pkt_ulp_private;
6757 
6758 	mutex_enter(&cmd->cmd_port->fp_mutex);
6759 	cmd->cmd_port->fp_out_fpcmds--;
6760 	mutex_exit(&cmd->cmd_port->fp_mutex);
6761 
6762 	job = cmd->cmd_job;
6763 	ASSERT(job->job_private != NULL);
6764 
6765 	/* If failure or LS_RJT then retry the packet, if needed */
6766 	if (pkt->pkt_state != FC_PKT_SUCCESS || resp.ls_code != LA_ELS_ACC) {
6767 		(void) fp_common_intr(pkt, 1);
6768 		return;
6769 	}
6770 
6771 	/* Save node_id memory allocated in ioctl code */
6772 	acc = (la_els_rnid_acc_t *)pkt->pkt_resp;
6773 
6774 	FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)job->job_private,
6775 	    (uint8_t *)acc, sizeof (la_els_rnid_acc_t), DDI_DEV_AUTOINCR);
6776 
6777 	/* wakeup the ioctl thread and free the pkt */
6778 	fp_iodone(cmd);
6779 }
6780 
6781 
6782 /*
6783  * Handle solicited RLS response
6784  */
6785 static void
6786 fp_rls_intr(fc_packet_t *pkt)
6787 {
6788 	ls_code_t		resp;
6789 	job_request_t		*job;
6790 	fp_cmd_t		*cmd;
6791 	la_els_rls_acc_t	*acc;
6792 	fc_local_port_t *port = ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port;
6793 
6794 	FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp,
6795 	    (uint8_t *)pkt->pkt_resp, sizeof (resp), DDI_DEV_AUTOINCR);
6796 	cmd = pkt->pkt_ulp_private;
6797 
6798 	mutex_enter(&cmd->cmd_port->fp_mutex);
6799 	cmd->cmd_port->fp_out_fpcmds--;
6800 	mutex_exit(&cmd->cmd_port->fp_mutex);
6801 
6802 	job = cmd->cmd_job;
6803 	ASSERT(job->job_private != NULL);
6804 
6805 	/* If failure or LS_RJT then retry the packet, if needed */
6806 	if (FP_IS_PKT_ERROR(pkt) || resp.ls_code != LA_ELS_ACC) {
6807 		(void) fp_common_intr(pkt, 1);
6808 		return;
6809 	}
6810 
6811 	/* Save link error status block in memory allocated in ioctl code */
6812 	acc = (la_els_rls_acc_t *)pkt->pkt_resp;
6813 
6814 	FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)job->job_private,
6815 	    (uint8_t *)&acc->rls_link_params, sizeof (fc_rls_acc_t),
6816 	    DDI_DEV_AUTOINCR);
6817 
6818 	/* wakeup the ioctl thread and free the pkt */
6819 	fp_iodone(cmd);
6820 }
6821 
6822 
6823 /*
6824  * A solicited command completion interrupt (mostly for commands
6825  * that require almost no post processing such as SCR ELS)
6826  */
6827 static void
6828 fp_intr(fc_packet_t *pkt)
6829 {
6830 	mutex_enter(&((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_mutex);
6831 	((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_out_fpcmds--;
6832 	mutex_exit(&((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_mutex);
6833 
6834 	if (FP_IS_PKT_ERROR(pkt)) {
6835 		(void) fp_common_intr(pkt, 1);
6836 		return;
6837 	}
6838 	fp_iodone(pkt->pkt_ulp_private);
6839 }
6840 
6841 
6842 /*
6843  * Handle the underlying port's state change
6844  */
6845 static void
6846 fp_statec_cb(opaque_t port_handle, uint32_t state)
6847 {
6848 	fc_local_port_t *port = port_handle;
6849 	job_request_t	*job;
6850 
6851 	/*
6852 	 * If it is not possible to process the callbacks
6853 	 * just drop the callback on the floor; Don't bother
6854 	 * to do something that isn't safe at this time
6855 	 */
6856 	mutex_enter(&port->fp_mutex);
6857 	if ((port->fp_soft_state &
6858 	    (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN)) ||
6859 	    (FC_PORT_STATE_MASK(port->fp_state) == FC_PORT_STATE_MASK(state))) {
6860 		mutex_exit(&port->fp_mutex);
6861 		return;
6862 	}
6863 
6864 	if (port->fp_statec_busy == 0) {
6865 		port->fp_soft_state |= FP_SOFT_IN_STATEC_CB;
6866 #ifdef	DEBUG
6867 	} else {
6868 		ASSERT(port->fp_soft_state & FP_SOFT_IN_STATEC_CB);
6869 #endif
6870 	}
6871 
6872 	port->fp_statec_busy++;
6873 
6874 	/*
6875 	 * For now, force the trusted method of device authentication (by
6876 	 * PLOGI) when LIPs do not involve OFFLINE to ONLINE transition.
6877 	 */
6878 	if (FC_PORT_STATE_MASK(state) == FC_STATE_LIP ||
6879 	    FC_PORT_STATE_MASK(state) == FC_STATE_LIP_LBIT_SET) {
6880 		state = FC_PORT_SPEED_MASK(port->fp_state) | FC_STATE_LOOP;
6881 		fp_port_offline(port, 0);
6882 	}
6883 	mutex_exit(&port->fp_mutex);
6884 
6885 	switch (FC_PORT_STATE_MASK(state)) {
6886 	case FC_STATE_OFFLINE:
6887 		job = fctl_alloc_job(JOB_PORT_OFFLINE,
6888 		    JOB_TYPE_FCTL_ASYNC, NULL, NULL, KM_NOSLEEP);
6889 		if (job == NULL) {
6890 			fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
6891 			    " fp_statec_cb() couldn't submit a job "
6892 			    " to the thread: failing..");
6893 			mutex_enter(&port->fp_mutex);
6894 			if (--port->fp_statec_busy == 0) {
6895 				port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
6896 			}
6897 			mutex_exit(&port->fp_mutex);
6898 			return;
6899 		}
6900 		mutex_enter(&port->fp_mutex);
6901 		/*
6902 		 * Zero out this field so that we do not retain
6903 		 * the fabric name as its no longer valid
6904 		 */
6905 		bzero(&port->fp_fabric_name, sizeof (la_wwn_t));
6906 		port->fp_state = state;
6907 		mutex_exit(&port->fp_mutex);
6908 
6909 		fctl_enque_job(port, job);
6910 		break;
6911 
6912 	case FC_STATE_ONLINE:
6913 	case FC_STATE_LOOP:
6914 		mutex_enter(&port->fp_mutex);
6915 		port->fp_state = state;
6916 
6917 		if (port->fp_offline_tid) {
6918 			timeout_id_t tid;
6919 
6920 			tid = port->fp_offline_tid;
6921 			port->fp_offline_tid = NULL;
6922 			mutex_exit(&port->fp_mutex);
6923 			(void) untimeout(tid);
6924 		} else {
6925 			mutex_exit(&port->fp_mutex);
6926 		}
6927 
6928 		job = fctl_alloc_job(JOB_PORT_ONLINE,
6929 		    JOB_TYPE_FCTL_ASYNC, NULL, NULL, KM_NOSLEEP);
6930 		if (job == NULL) {
6931 			fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
6932 			    "fp_statec_cb() couldn't submit a job "
6933 			    "to the thread: failing..");
6934 
6935 			mutex_enter(&port->fp_mutex);
6936 			if (--port->fp_statec_busy == 0) {
6937 				port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
6938 			}
6939 			mutex_exit(&port->fp_mutex);
6940 			return;
6941 		}
6942 		fctl_enque_job(port, job);
6943 		break;
6944 
6945 	case FC_STATE_RESET_REQUESTED:
6946 		mutex_enter(&port->fp_mutex);
6947 		port->fp_state = FC_STATE_OFFLINE;
6948 		port->fp_soft_state |= FP_SOFT_IN_FCA_RESET;
6949 		mutex_exit(&port->fp_mutex);
6950 		/* FALLTHROUGH */
6951 
6952 	case FC_STATE_RESET:
6953 		job = fctl_alloc_job(JOB_ULP_NOTIFY,
6954 		    JOB_TYPE_FCTL_ASYNC, NULL, NULL, KM_NOSLEEP);
6955 		if (job == NULL) {
6956 			fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
6957 			    "fp_statec_cb() couldn't submit a job"
6958 			    " to the thread: failing..");
6959 
6960 			mutex_enter(&port->fp_mutex);
6961 			if (--port->fp_statec_busy == 0) {
6962 				port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
6963 			}
6964 			mutex_exit(&port->fp_mutex);
6965 			return;
6966 		}
6967 
6968 		/* squeeze into some field in the job structure */
6969 		job->job_ulp_listlen = FC_PORT_STATE_MASK(state);
6970 		fctl_enque_job(port, job);
6971 		break;
6972 
6973 	case FC_STATE_TARGET_PORT_RESET:
6974 		(void) fp_ulp_notify(port, state, KM_NOSLEEP);
6975 		/* FALLTHROUGH */
6976 
6977 	case FC_STATE_NAMESERVICE:
6978 		/* FALLTHROUGH */
6979 
6980 	default:
6981 		mutex_enter(&port->fp_mutex);
6982 		if (--port->fp_statec_busy == 0) {
6983 			port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
6984 		}
6985 		mutex_exit(&port->fp_mutex);
6986 		break;
6987 	}
6988 }
6989 
6990 
6991 /*
6992  * Register with the Name Server for RSCNs
6993  */
6994 static int
6995 fp_ns_scr(fc_local_port_t *port, job_request_t *job, uchar_t scr_func,
6996     int sleep)
6997 {
6998 	uint32_t	s_id;
6999 	uchar_t		class;
7000 	fc_scr_req_t	payload;
7001 	fp_cmd_t	*cmd;
7002 	fc_packet_t	*pkt;
7003 
7004 	mutex_enter(&port->fp_mutex);
7005 	s_id = port->fp_port_id.port_id;
7006 	class = port->fp_ns_login_class;
7007 	mutex_exit(&port->fp_mutex);
7008 
7009 	cmd = fp_alloc_pkt(port, sizeof (fc_scr_req_t),
7010 	    sizeof (fc_scr_resp_t), sleep, NULL);
7011 	if (cmd == NULL) {
7012 		return (FC_NOMEM);
7013 	}
7014 
7015 	cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class;
7016 	cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
7017 	cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
7018 	cmd->cmd_retry_count = fp_retry_count;
7019 	cmd->cmd_ulp_pkt = NULL;
7020 
7021 	pkt = &cmd->cmd_pkt;
7022 	cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
7023 
7024 	fp_els_init(cmd, s_id, 0xFFFFFD, fp_intr, job);
7025 
7026 	payload.ls_code.ls_code = LA_ELS_SCR;
7027 	payload.ls_code.mbz = 0;
7028 	payload.scr_rsvd = 0;
7029 	payload.scr_func = scr_func;
7030 
7031 	FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
7032 	    (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
7033 
7034 	job->job_counter = 1;
7035 
7036 	if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
7037 		fp_iodone(cmd);
7038 	}
7039 
7040 	return (FC_SUCCESS);
7041 }
7042 
7043 
7044 /*
7045  * There are basically two methods to determine the total number of
7046  * devices out in the NS database; Reading the details of the two
7047  * methods described below, it shouldn't be hard to identify which
7048  * of the two methods is better.
7049  *
7050  *	Method 1.
7051  *		Iteratively issue GANs until all ports identifiers are walked
7052  *
7053  *	Method 2.
7054  *		Issue GID_PT (get port Identifiers) with Maximum residual
7055  *		field in the request CT HEADER set to accommodate only the
7056  *		CT HEADER in the response frame. And if FC-GS2 has been
7057  *		carefully read, the NS here has a chance to FS_ACC the
7058  *		request and indicate the residual size in the FS_ACC.
7059  *
7060  *	Method 2 is wonderful, although it's not mandatory for the NS
7061  *	to update the Maximum/Residual Field as can be seen in 4.3.1.6
7062  *	(note with particular care the use of the auxiliary verb 'may')
7063  *
7064  */
7065 static int
7066 fp_ns_get_devcount(fc_local_port_t *port, job_request_t *job, int create,
7067     int sleep)
7068 {
7069 	int		flags;
7070 	int		rval;
7071 	uint32_t	src_id;
7072 	fctl_ns_req_t	*ns_cmd;
7073 
7074 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
7075 
7076 	mutex_enter(&port->fp_mutex);
7077 	src_id = port->fp_port_id.port_id;
7078 	mutex_exit(&port->fp_mutex);
7079 
7080 	if (!create && (port->fp_options & FP_NS_SMART_COUNT)) {
7081 		ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pt_t),
7082 		    sizeof (ns_resp_gid_pt_t), 0,
7083 		    (FCTL_NS_GET_DEV_COUNT | FCTL_NS_NO_DATA_BUF), sleep);
7084 
7085 		if (ns_cmd == NULL) {
7086 			return (FC_NOMEM);
7087 		}
7088 
7089 		ns_cmd->ns_cmd_code = NS_GID_PT;
7090 		((ns_req_gid_pt_t *)(ns_cmd->ns_cmd_buf))->port_type.port_type
7091 		    = FC_NS_PORT_NX;	/* All port types */
7092 		((ns_req_gid_pt_t *)(ns_cmd->ns_cmd_buf))->port_type.rsvd = 0;
7093 
7094 	} else {
7095 		uint32_t ns_flags;
7096 
7097 		ns_flags = FCTL_NS_GET_DEV_COUNT | FCTL_NS_NO_DATA_BUF;
7098 		if (create) {
7099 			ns_flags |= FCTL_NS_CREATE_DEVICE;
7100 		}
7101 		ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t),
7102 		    sizeof (ns_resp_gan_t), sizeof (int), ns_flags, sleep);
7103 
7104 		if (ns_cmd == NULL) {
7105 			return (FC_NOMEM);
7106 		}
7107 		ns_cmd->ns_gan_index = 0;
7108 		ns_cmd->ns_gan_sid = FCTL_GAN_START_ID;
7109 		ns_cmd->ns_cmd_code = NS_GA_NXT;
7110 		ns_cmd->ns_gan_max = 0xFFFF;
7111 
7112 		((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.port_id = src_id;
7113 		((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.priv_lilp_posit = 0;
7114 	}
7115 
7116 	flags = job->job_flags;
7117 	job->job_flags &= ~JOB_TYPE_FP_ASYNC;
7118 	job->job_counter = 1;
7119 
7120 	rval = fp_ns_query(port, ns_cmd, job, 1, sleep);
7121 	job->job_flags = flags;
7122 
7123 	if (!create && (port->fp_options & FP_NS_SMART_COUNT)) {
7124 		uint16_t max_resid;
7125 
7126 		/*
7127 		 * Revert to scanning the NS if NS_GID_PT isn't
7128 		 * helping us figure out total number of devices.
7129 		 */
7130 		if (job->job_result != FC_SUCCESS ||
7131 		    ns_cmd->ns_resp_hdr.ct_cmdrsp != FS_ACC_IU) {
7132 			mutex_enter(&port->fp_mutex);
7133 			port->fp_options &= ~FP_NS_SMART_COUNT;
7134 			mutex_exit(&port->fp_mutex);
7135 
7136 			fctl_free_ns_cmd(ns_cmd);
7137 			return (fp_ns_get_devcount(port, job, create, sleep));
7138 		}
7139 
7140 		mutex_enter(&port->fp_mutex);
7141 		port->fp_total_devices = 1;
7142 		max_resid = ns_cmd->ns_resp_hdr.ct_aiusize;
7143 		if (max_resid) {
7144 			/*
7145 			 * Since port identifier is 4 bytes and max_resid
7146 			 * is also in WORDS, max_resid simply indicates
7147 			 * the total number of port identifiers	not
7148 			 * transferred
7149 			 */
7150 			port->fp_total_devices += max_resid;
7151 		}
7152 		mutex_exit(&port->fp_mutex);
7153 	}
7154 	mutex_enter(&port->fp_mutex);
7155 	port->fp_total_devices = *((int *)ns_cmd->ns_data_buf);
7156 	mutex_exit(&port->fp_mutex);
7157 	fctl_free_ns_cmd(ns_cmd);
7158 
7159 	return (rval);
7160 }
7161 
7162 /*
7163  * One heck of a function to serve userland.
7164  */
7165 static int
7166 fp_fciocmd(fc_local_port_t *port, intptr_t data, int mode, fcio_t *fcio)
7167 {
7168 	int		rval = 0;
7169 	int		jcode;
7170 	uint32_t	ret;
7171 	uchar_t		open_flag;
7172 	fcio_t		*kfcio;
7173 	job_request_t	*job;
7174 	boolean_t	use32 = B_FALSE;
7175 
7176 #ifdef _MULTI_DATAMODEL
7177 	switch (ddi_model_convert_from(mode & FMODELS)) {
7178 	case DDI_MODEL_ILP32:
7179 		use32 = B_TRUE;
7180 		break;
7181 
7182 	case DDI_MODEL_NONE:
7183 	default:
7184 		break;
7185 	}
7186 #endif
7187 
7188 	mutex_enter(&port->fp_mutex);
7189 	if (port->fp_soft_state & (FP_SOFT_IN_STATEC_CB |
7190 	    FP_SOFT_IN_UNSOL_CB)) {
7191 		fcio->fcio_errno = FC_STATEC_BUSY;
7192 		mutex_exit(&port->fp_mutex);
7193 		rval = EAGAIN;
7194 		if (fp_fcio_copyout(fcio, data, mode)) {
7195 			rval = EFAULT;
7196 		}
7197 		return (rval);
7198 	}
7199 	open_flag = port->fp_flag;
7200 	mutex_exit(&port->fp_mutex);
7201 
7202 	if (fp_check_perms(open_flag, fcio->fcio_cmd) != FC_SUCCESS) {
7203 		fcio->fcio_errno = FC_FAILURE;
7204 		rval = EACCES;
7205 		if (fp_fcio_copyout(fcio, data, mode)) {
7206 			rval = EFAULT;
7207 		}
7208 		return (rval);
7209 	}
7210 
7211 	/*
7212 	 * If an exclusive open was demanded during open, don't let
7213 	 * either innocuous or devil threads to share the file
7214 	 * descriptor and fire down exclusive access commands
7215 	 */
7216 	mutex_enter(&port->fp_mutex);
7217 	if (port->fp_flag & FP_EXCL) {
7218 		if (port->fp_flag & FP_EXCL_BUSY) {
7219 			mutex_exit(&port->fp_mutex);
7220 			fcio->fcio_errno = FC_FAILURE;
7221 			return (EBUSY);
7222 		}
7223 		port->fp_flag |= FP_EXCL_BUSY;
7224 	}
7225 	mutex_exit(&port->fp_mutex);
7226 
7227 	switch (fcio->fcio_cmd) {
7228 	case FCIO_GET_HOST_PARAMS: {
7229 		fc_port_dev_t	*val;
7230 		fc_port_dev32_t	*val32;
7231 		int		index;
7232 		int		lilp_device_count;
7233 		fc_lilpmap_t	*lilp_map;
7234 		uchar_t		*alpa_list;
7235 
7236 		if (use32 == B_TRUE) {
7237 			if (fcio->fcio_olen != sizeof (*val32) ||
7238 			    fcio->fcio_xfer != FCIO_XFER_READ) {
7239 				rval = EINVAL;
7240 				break;
7241 			}
7242 		} else {
7243 			if (fcio->fcio_olen != sizeof (*val) ||
7244 			    fcio->fcio_xfer != FCIO_XFER_READ) {
7245 				rval = EINVAL;
7246 				break;
7247 			}
7248 		}
7249 
7250 		val = kmem_zalloc(sizeof (*val), KM_SLEEP);
7251 
7252 		mutex_enter(&port->fp_mutex);
7253 		val->dev_did = port->fp_port_id;
7254 		val->dev_hard_addr = port->fp_hard_addr;
7255 		val->dev_pwwn = port->fp_service_params.nport_ww_name;
7256 		val->dev_nwwn = port->fp_service_params.node_ww_name;
7257 		val->dev_state = port->fp_state;
7258 
7259 		lilp_map = &port->fp_lilp_map;
7260 		alpa_list = &lilp_map->lilp_alpalist[0];
7261 		lilp_device_count = lilp_map->lilp_length;
7262 		for (index = 0; index < lilp_device_count; index++) {
7263 			uint32_t d_id;
7264 
7265 			d_id = alpa_list[index];
7266 			if (d_id == port->fp_port_id.port_id) {
7267 				break;
7268 			}
7269 		}
7270 		val->dev_did.priv_lilp_posit = (uint8_t)(index & 0xff);
7271 
7272 		bcopy(port->fp_fc4_types, val->dev_type,
7273 		    sizeof (port->fp_fc4_types));
7274 		mutex_exit(&port->fp_mutex);
7275 
7276 		if (use32 == B_TRUE) {
7277 			val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP);
7278 
7279 			val32->dev_did = val->dev_did;
7280 			val32->dev_hard_addr = val->dev_hard_addr;
7281 			val32->dev_pwwn = val->dev_pwwn;
7282 			val32->dev_nwwn = val->dev_nwwn;
7283 			val32->dev_state = val->dev_state;
7284 			val32->dev_did.priv_lilp_posit =
7285 			    val->dev_did.priv_lilp_posit;
7286 
7287 			bcopy(val->dev_type, val32->dev_type,
7288 			    sizeof (port->fp_fc4_types));
7289 
7290 			if (fp_copyout((void *)val32, (void *)fcio->fcio_obuf,
7291 			    fcio->fcio_olen, mode) == 0) {
7292 				if (fp_fcio_copyout(fcio, data, mode)) {
7293 					rval = EFAULT;
7294 				}
7295 			} else {
7296 				rval = EFAULT;
7297 			}
7298 
7299 			kmem_free(val32, sizeof (*val32));
7300 		} else {
7301 			if (fp_copyout((void *)val, (void *)fcio->fcio_obuf,
7302 			    fcio->fcio_olen, mode) == 0) {
7303 				if (fp_fcio_copyout(fcio, data, mode)) {
7304 					rval = EFAULT;
7305 				}
7306 			} else {
7307 				rval = EFAULT;
7308 			}
7309 		}
7310 
7311 		/* need to free "val" here */
7312 		kmem_free(val, sizeof (*val));
7313 		break;
7314 	}
7315 
7316 	case FCIO_GET_OTHER_ADAPTER_PORTS: {
7317 		uint32_t    index;
7318 		char	    *tmpPath;
7319 		fc_local_port_t	  *tmpPort;
7320 
7321 		if (fcio->fcio_olen < MAXPATHLEN ||
7322 		    fcio->fcio_ilen != sizeof (uint32_t)) {
7323 			rval = EINVAL;
7324 			break;
7325 		}
7326 		if (ddi_copyin(fcio->fcio_ibuf, &index, sizeof (index), mode)) {
7327 			rval = EFAULT;
7328 			break;
7329 		}
7330 
7331 		tmpPort = fctl_get_adapter_port_by_index(port, index);
7332 		if (tmpPort == NULL) {
7333 			FP_TRACE(FP_NHEAD1(9, 0),
7334 			    "User supplied index out of range");
7335 			fcio->fcio_errno = FC_BADPORT;
7336 			rval = EFAULT;
7337 			if (fp_fcio_copyout(fcio, data, mode)) {
7338 				rval = EFAULT;
7339 			}
7340 			break;
7341 		}
7342 
7343 		tmpPath = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
7344 		(void) ddi_pathname(tmpPort->fp_port_dip, tmpPath);
7345 		if (fp_copyout((void *)tmpPath, (void *)fcio->fcio_obuf,
7346 		    MAXPATHLEN, mode) == 0) {
7347 			if (fp_fcio_copyout(fcio, data, mode)) {
7348 				rval = EFAULT;
7349 			}
7350 		} else {
7351 			rval = EFAULT;
7352 		}
7353 		kmem_free(tmpPath, MAXPATHLEN);
7354 		break;
7355 	}
7356 
7357 	case FCIO_NPIV_GET_ADAPTER_ATTRIBUTES:
7358 	case FCIO_GET_ADAPTER_ATTRIBUTES: {
7359 		fc_hba_adapter_attributes_t	*val;
7360 		fc_hba_adapter_attributes32_t	*val32;
7361 
7362 		if (use32 == B_TRUE) {
7363 			if (fcio->fcio_olen < sizeof (*val32) ||
7364 			    fcio->fcio_xfer != FCIO_XFER_READ) {
7365 				rval = EINVAL;
7366 				break;
7367 			}
7368 		} else {
7369 			if (fcio->fcio_olen < sizeof (*val) ||
7370 			    fcio->fcio_xfer != FCIO_XFER_READ) {
7371 				rval = EINVAL;
7372 				break;
7373 			}
7374 		}
7375 
7376 		val = kmem_zalloc(sizeof (*val), KM_SLEEP);
7377 		val->version = FC_HBA_ADAPTER_ATTRIBUTES_VERSION;
7378 		mutex_enter(&port->fp_mutex);
7379 		bcopy(port->fp_hba_port_attrs.manufacturer,
7380 		    val->Manufacturer,
7381 		    sizeof (val->Manufacturer));
7382 		bcopy(port->fp_hba_port_attrs.serial_number,
7383 		    val->SerialNumber,
7384 		    sizeof (val->SerialNumber));
7385 		bcopy(port->fp_hba_port_attrs.model,
7386 		    val->Model,
7387 		    sizeof (val->Model));
7388 		bcopy(port->fp_hba_port_attrs.model_description,
7389 		    val->ModelDescription,
7390 		    sizeof (val->ModelDescription));
7391 		bcopy(port->fp_sym_node_name, val->NodeSymbolicName,
7392 		    port->fp_sym_node_namelen);
7393 		bcopy(port->fp_hba_port_attrs.hardware_version,
7394 		    val->HardwareVersion,
7395 		    sizeof (val->HardwareVersion));
7396 		bcopy(port->fp_hba_port_attrs.option_rom_version,
7397 		    val->OptionROMVersion,
7398 		    sizeof (val->OptionROMVersion));
7399 		bcopy(port->fp_hba_port_attrs.firmware_version,
7400 		    val->FirmwareVersion,
7401 		    sizeof (val->FirmwareVersion));
7402 		val->VendorSpecificID =
7403 		    port->fp_hba_port_attrs.vendor_specific_id;
7404 		bcopy(&port->fp_service_params.node_ww_name.raw_wwn,
7405 		    &val->NodeWWN.raw_wwn,
7406 		    sizeof (val->NodeWWN.raw_wwn));
7407 
7408 
7409 		bcopy(port->fp_hba_port_attrs.driver_name,
7410 		    val->DriverName,
7411 		    sizeof (val->DriverName));
7412 		bcopy(port->fp_hba_port_attrs.driver_version,
7413 		    val->DriverVersion,
7414 		    sizeof (val->DriverVersion));
7415 		mutex_exit(&port->fp_mutex);
7416 
7417 		if (fcio->fcio_cmd == FCIO_GET_ADAPTER_ATTRIBUTES) {
7418 			val->NumberOfPorts = fctl_count_fru_ports(port, 0);
7419 		} else {
7420 			val->NumberOfPorts = fctl_count_fru_ports(port, 1);
7421 		}
7422 
7423 		if (use32 == B_TRUE) {
7424 			val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP);
7425 			val32->version = val->version;
7426 			bcopy(val->Manufacturer, val32->Manufacturer,
7427 			    sizeof (val->Manufacturer));
7428 			bcopy(val->SerialNumber, val32->SerialNumber,
7429 			    sizeof (val->SerialNumber));
7430 			bcopy(val->Model, val32->Model,
7431 			    sizeof (val->Model));
7432 			bcopy(val->ModelDescription, val32->ModelDescription,
7433 			    sizeof (val->ModelDescription));
7434 			bcopy(val->NodeSymbolicName, val32->NodeSymbolicName,
7435 			    sizeof (val->NodeSymbolicName));
7436 			bcopy(val->HardwareVersion, val32->HardwareVersion,
7437 			    sizeof (val->HardwareVersion));
7438 			bcopy(val->OptionROMVersion, val32->OptionROMVersion,
7439 			    sizeof (val->OptionROMVersion));
7440 			bcopy(val->FirmwareVersion, val32->FirmwareVersion,
7441 			    sizeof (val->FirmwareVersion));
7442 			val32->VendorSpecificID = val->VendorSpecificID;
7443 			bcopy(&val->NodeWWN.raw_wwn, &val32->NodeWWN.raw_wwn,
7444 			    sizeof (val->NodeWWN.raw_wwn));
7445 			bcopy(val->DriverName, val32->DriverName,
7446 			    sizeof (val->DriverName));
7447 			bcopy(val->DriverVersion, val32->DriverVersion,
7448 			    sizeof (val->DriverVersion));
7449 
7450 			val32->NumberOfPorts = val->NumberOfPorts;
7451 
7452 			if (fp_copyout((void *)val32, (void *)fcio->fcio_obuf,
7453 			    fcio->fcio_olen, mode) == 0) {
7454 				if (fp_fcio_copyout(fcio, data, mode)) {
7455 					rval = EFAULT;
7456 				}
7457 			} else {
7458 				rval = EFAULT;
7459 			}
7460 
7461 			kmem_free(val32, sizeof (*val32));
7462 		} else {
7463 			if (fp_copyout((void *)val, (void *)fcio->fcio_obuf,
7464 			    fcio->fcio_olen, mode) == 0) {
7465 				if (fp_fcio_copyout(fcio, data, mode)) {
7466 					rval = EFAULT;
7467 				}
7468 			} else {
7469 				rval = EFAULT;
7470 			}
7471 		}
7472 
7473 		kmem_free(val, sizeof (*val));
7474 		break;
7475 	}
7476 
7477 	case FCIO_GET_NPIV_ATTRIBUTES: {
7478 		fc_hba_npiv_attributes_t *attrs;
7479 
7480 		attrs = kmem_zalloc(sizeof (*attrs), KM_SLEEP);
7481 		mutex_enter(&port->fp_mutex);
7482 		bcopy(&port->fp_service_params.node_ww_name.raw_wwn,
7483 		    &attrs->NodeWWN.raw_wwn,
7484 		    sizeof (attrs->NodeWWN.raw_wwn));
7485 		bcopy(&port->fp_service_params.nport_ww_name.raw_wwn,
7486 		    &attrs->PortWWN.raw_wwn,
7487 		    sizeof (attrs->PortWWN.raw_wwn));
7488 		mutex_exit(&port->fp_mutex);
7489 		if (fp_copyout((void *)attrs, (void *)fcio->fcio_obuf,
7490 		    fcio->fcio_olen, mode) == 0) {
7491 			if (fp_fcio_copyout(fcio, data, mode)) {
7492 				rval = EFAULT;
7493 			}
7494 		} else {
7495 			rval = EFAULT;
7496 		}
7497 		kmem_free(attrs, sizeof (*attrs));
7498 		break;
7499 	}
7500 
7501 	case FCIO_DELETE_NPIV_PORT: {
7502 		fc_local_port_t *tmpport;
7503 		char	ww_pname[17];
7504 		la_wwn_t	vwwn[1];
7505 
7506 		FP_TRACE(FP_NHEAD1(1, 0), "Delete NPIV Port");
7507 		if (ddi_copyin(fcio->fcio_ibuf,
7508 		    &vwwn, sizeof (la_wwn_t), mode)) {
7509 			rval = EFAULT;
7510 			break;
7511 		}
7512 
7513 		fc_wwn_to_str(&vwwn[0], ww_pname);
7514 		FP_TRACE(FP_NHEAD1(3, 0),
7515 		    "Delete NPIV Port %s", ww_pname);
7516 		tmpport = fc_delete_npiv_port(port, &vwwn[0]);
7517 		if (tmpport == NULL) {
7518 			FP_TRACE(FP_NHEAD1(3, 0),
7519 			    "Delete NPIV Port : no found");
7520 			rval = EFAULT;
7521 		} else {
7522 			fc_local_port_t *nextport = tmpport->fp_port_next;
7523 			fc_local_port_t *prevport = tmpport->fp_port_prev;
7524 			int portlen, portindex, ret;
7525 
7526 			portlen = sizeof (portindex);
7527 			ret = ddi_prop_op(DDI_DEV_T_ANY,
7528 			    tmpport->fp_port_dip, PROP_LEN_AND_VAL_BUF,
7529 			    DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "port",
7530 			    (caddr_t)&portindex, &portlen);
7531 			if (ret != DDI_SUCCESS) {
7532 				rval = EFAULT;
7533 				break;
7534 			}
7535 			if (ndi_devi_offline(tmpport->fp_port_dip,
7536 			    NDI_DEVI_REMOVE) != DDI_SUCCESS) {
7537 				FP_TRACE(FP_NHEAD1(1, 0),
7538 				    "Delete NPIV Port failed");
7539 				mutex_enter(&port->fp_mutex);
7540 				tmpport->fp_npiv_state = 0;
7541 				mutex_exit(&port->fp_mutex);
7542 				rval = EFAULT;
7543 			} else {
7544 				mutex_enter(&port->fp_mutex);
7545 				nextport->fp_port_prev = prevport;
7546 				prevport->fp_port_next = nextport;
7547 				if (port == port->fp_port_next) {
7548 					port->fp_port_next =
7549 					    port->fp_port_prev = NULL;
7550 				}
7551 				port->fp_npiv_portnum--;
7552 				FP_TRACE(FP_NHEAD1(3, 0),
7553 				    "Delete NPIV Port %d", portindex);
7554 				port->fp_npiv_portindex[portindex-1] = 0;
7555 				mutex_exit(&port->fp_mutex);
7556 			}
7557 		}
7558 		break;
7559 	}
7560 
7561 	case FCIO_CREATE_NPIV_PORT: {
7562 		char ww_nname[17], ww_pname[17];
7563 		la_npiv_create_entry_t entrybuf;
7564 		uint32_t vportindex = 0;
7565 		int npiv_ret = 0;
7566 		char *portname, *fcaname;
7567 
7568 		portname = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
7569 		(void) ddi_pathname(port->fp_port_dip, portname);
7570 		fcaname = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
7571 		(void) ddi_pathname(port->fp_fca_dip, fcaname);
7572 		FP_TRACE(FP_NHEAD1(1, 0),
7573 		    "Create NPIV port %s %s %s", portname, fcaname,
7574 		    ddi_driver_name(port->fp_fca_dip));
7575 		kmem_free(portname, MAXPATHLEN);
7576 		kmem_free(fcaname, MAXPATHLEN);
7577 		if (ddi_copyin(fcio->fcio_ibuf,
7578 		    &entrybuf, sizeof (la_npiv_create_entry_t), mode)) {
7579 			rval = EFAULT;
7580 			break;
7581 		}
7582 
7583 		fc_wwn_to_str(&entrybuf.VNodeWWN, ww_nname);
7584 		fc_wwn_to_str(&entrybuf.VPortWWN, ww_pname);
7585 		vportindex = entrybuf.vindex;
7586 		FP_TRACE(FP_NHEAD1(3, 0),
7587 		    "Create NPIV Port %s %s %d",
7588 		    ww_nname, ww_pname, vportindex);
7589 
7590 		if (fc_get_npiv_port(port, &entrybuf.VPortWWN)) {
7591 			rval = EFAULT;
7592 			break;
7593 		}
7594 		npiv_ret = fctl_fca_create_npivport(port->fp_fca_dip,
7595 		    port->fp_port_dip, ww_nname, ww_pname, &vportindex);
7596 		if (npiv_ret == NDI_SUCCESS) {
7597 			mutex_enter(&port->fp_mutex);
7598 			port->fp_npiv_portnum++;
7599 			mutex_exit(&port->fp_mutex);
7600 			if (fp_copyout((void *)&vportindex,
7601 			    (void *)fcio->fcio_obuf,
7602 			    fcio->fcio_olen, mode) == 0) {
7603 				if (fp_fcio_copyout(fcio, data, mode)) {
7604 					rval = EFAULT;
7605 				}
7606 			} else {
7607 				rval = EFAULT;
7608 			}
7609 		} else {
7610 			rval = EFAULT;
7611 		}
7612 		FP_TRACE(FP_NHEAD1(3, 0),
7613 		    "Create NPIV Port %d %d", npiv_ret, vportindex);
7614 		break;
7615 	}
7616 
7617 	case FCIO_GET_NPIV_PORT_LIST: {
7618 		fc_hba_npiv_port_list_t *list;
7619 		int count;
7620 
7621 		if ((fcio->fcio_xfer != FCIO_XFER_READ) ||
7622 		    (fcio->fcio_olen == 0) || (fcio->fcio_obuf == 0)) {
7623 			rval = EINVAL;
7624 			break;
7625 		}
7626 
7627 		list = kmem_zalloc(fcio->fcio_olen, KM_SLEEP);
7628 		list->version = FC_HBA_LIST_VERSION;
7629 		/* build npiv port list */
7630 		count = fc_ulp_get_npiv_port_list(port, (char *)list->hbaPaths);
7631 		if (count < 0) {
7632 			rval = ENXIO;
7633 			FP_TRACE(FP_NHEAD1(1, 0), "Build NPIV Port List error");
7634 			kmem_free(list, fcio->fcio_olen);
7635 			break;
7636 		}
7637 		list->numAdapters = count;
7638 
7639 		if (fp_copyout((void *)list, (void *)fcio->fcio_obuf,
7640 		    fcio->fcio_olen, mode) == 0) {
7641 			if (fp_fcio_copyout(fcio, data, mode)) {
7642 				FP_TRACE(FP_NHEAD1(1, 0),
7643 				    "Copy NPIV Port data error");
7644 				rval = EFAULT;
7645 			}
7646 		} else {
7647 			FP_TRACE(FP_NHEAD1(1, 0), "Copy NPIV Port List error");
7648 			rval = EFAULT;
7649 		}
7650 		kmem_free(list, fcio->fcio_olen);
7651 		break;
7652 	}
7653 
7654 	case FCIO_GET_ADAPTER_PORT_NPIV_ATTRIBUTES: {
7655 		fc_hba_port_npiv_attributes_t	*val;
7656 
7657 		val = kmem_zalloc(sizeof (*val), KM_SLEEP);
7658 		val->version = FC_HBA_PORT_NPIV_ATTRIBUTES_VERSION;
7659 
7660 		mutex_enter(&port->fp_mutex);
7661 		val->npivflag = port->fp_npiv_flag;
7662 		val->lastChange = port->fp_last_change;
7663 		bcopy(&port->fp_service_params.nport_ww_name.raw_wwn,
7664 		    &val->PortWWN.raw_wwn,
7665 		    sizeof (val->PortWWN.raw_wwn));
7666 		bcopy(&port->fp_service_params.node_ww_name.raw_wwn,
7667 		    &val->NodeWWN.raw_wwn,
7668 		    sizeof (val->NodeWWN.raw_wwn));
7669 		mutex_exit(&port->fp_mutex);
7670 
7671 		val->NumberOfNPIVPorts = fc_ulp_get_npiv_port_num(port);
7672 		if (port->fp_npiv_type != FC_NPIV_PORT) {
7673 			val->MaxNumberOfNPIVPorts =
7674 			    port->fp_fca_tran->fca_num_npivports;
7675 		} else {
7676 			val->MaxNumberOfNPIVPorts = 0;
7677 		}
7678 
7679 		if (fp_copyout((void *)val, (void *)fcio->fcio_obuf,
7680 		    fcio->fcio_olen, mode) == 0) {
7681 			if (fp_fcio_copyout(fcio, data, mode)) {
7682 				rval = EFAULT;
7683 			}
7684 		} else {
7685 			rval = EFAULT;
7686 		}
7687 		kmem_free(val, sizeof (*val));
7688 		break;
7689 	}
7690 
7691 	case FCIO_GET_ADAPTER_PORT_ATTRIBUTES: {
7692 		fc_hba_port_attributes_t	*val;
7693 		fc_hba_port_attributes32_t	*val32;
7694 
7695 		if (use32 == B_TRUE) {
7696 			if (fcio->fcio_olen < sizeof (*val32) ||
7697 			    fcio->fcio_xfer != FCIO_XFER_READ) {
7698 				rval = EINVAL;
7699 				break;
7700 			}
7701 		} else {
7702 			if (fcio->fcio_olen < sizeof (*val) ||
7703 			    fcio->fcio_xfer != FCIO_XFER_READ) {
7704 				rval = EINVAL;
7705 				break;
7706 			}
7707 		}
7708 
7709 		val = kmem_zalloc(sizeof (*val), KM_SLEEP);
7710 		val->version = FC_HBA_PORT_ATTRIBUTES_VERSION;
7711 		mutex_enter(&port->fp_mutex);
7712 		val->lastChange = port->fp_last_change;
7713 		val->fp_minor = port->fp_instance;
7714 
7715 		bcopy(&port->fp_service_params.nport_ww_name.raw_wwn,
7716 		    &val->PortWWN.raw_wwn,
7717 		    sizeof (val->PortWWN.raw_wwn));
7718 		bcopy(&port->fp_service_params.node_ww_name.raw_wwn,
7719 		    &val->NodeWWN.raw_wwn,
7720 		    sizeof (val->NodeWWN.raw_wwn));
7721 		bcopy(&port->fp_fabric_name, &val->FabricName.raw_wwn,
7722 		    sizeof (val->FabricName.raw_wwn));
7723 
7724 		val->PortFcId = port->fp_port_id.port_id;
7725 
7726 		switch (FC_PORT_STATE_MASK(port->fp_state)) {
7727 		case FC_STATE_OFFLINE:
7728 			val->PortState = FC_HBA_PORTSTATE_OFFLINE;
7729 			break;
7730 		case FC_STATE_ONLINE:
7731 		case FC_STATE_LOOP:
7732 		case FC_STATE_NAMESERVICE:
7733 			val->PortState = FC_HBA_PORTSTATE_ONLINE;
7734 			break;
7735 		default:
7736 			val->PortState = FC_HBA_PORTSTATE_UNKNOWN;
7737 			break;
7738 		}
7739 
7740 		/* Translate from LV to FC-HBA port type codes */
7741 		switch (port->fp_port_type.port_type) {
7742 		case FC_NS_PORT_N:
7743 			val->PortType = FC_HBA_PORTTYPE_NPORT;
7744 			break;
7745 		case FC_NS_PORT_NL:
7746 			/* Actually means loop for us */
7747 			val->PortType = FC_HBA_PORTTYPE_LPORT;
7748 			break;
7749 		case FC_NS_PORT_F:
7750 			val->PortType = FC_HBA_PORTTYPE_FPORT;
7751 			break;
7752 		case FC_NS_PORT_FL:
7753 			val->PortType = FC_HBA_PORTTYPE_FLPORT;
7754 			break;
7755 		case FC_NS_PORT_E:
7756 			val->PortType = FC_HBA_PORTTYPE_EPORT;
7757 			break;
7758 		default:
7759 			val->PortType = FC_HBA_PORTTYPE_OTHER;
7760 			break;
7761 		}
7762 
7763 
7764 		/*
7765 		 * If fp has decided that the topology is public loop,
7766 		 * we will indicate that using the appropriate
7767 		 * FC HBA API constant.
7768 		 */
7769 		switch (port->fp_topology) {
7770 		case FC_TOP_PUBLIC_LOOP:
7771 			val->PortType = FC_HBA_PORTTYPE_NLPORT;
7772 			break;
7773 
7774 		case FC_TOP_PT_PT:
7775 			val->PortType = FC_HBA_PORTTYPE_PTP;
7776 			break;
7777 
7778 		case FC_TOP_UNKNOWN:
7779 			/*
7780 			 * This should cover the case where nothing is connected
7781 			 * to the port. Crystal+ is p'bly an exception here.
7782 			 * For Crystal+, port 0 will come up as private loop
7783 			 * (i.e fp_bind_state will be FC_STATE_LOOP) even when
7784 			 * nothing is connected to it.
7785 			 * Current plan is to let userland handle this.
7786 			 */
7787 			if (port->fp_bind_state == FC_STATE_OFFLINE) {
7788 				val->PortType = FC_HBA_PORTTYPE_UNKNOWN;
7789 			}
7790 			break;
7791 
7792 		default:
7793 			/*
7794 			 * Do Nothing.
7795 			 * Unused:
7796 			 *   val->PortType = FC_HBA_PORTTYPE_GPORT;
7797 			 */
7798 			break;
7799 		}
7800 
7801 		val->PortSupportedClassofService =
7802 		    port->fp_hba_port_attrs.supported_cos;
7803 		val->PortSupportedFc4Types[0] = 0;
7804 		bcopy(port->fp_fc4_types, val->PortActiveFc4Types,
7805 		    sizeof (val->PortActiveFc4Types));
7806 		bcopy(port->fp_sym_port_name, val->PortSymbolicName,
7807 		    port->fp_sym_port_namelen);
7808 		val->PortSupportedSpeed =
7809 		    port->fp_hba_port_attrs.supported_speed;
7810 
7811 		switch (FC_PORT_SPEED_MASK(port->fp_state)) {
7812 		case FC_STATE_1GBIT_SPEED:
7813 			val->PortSpeed = FC_HBA_PORTSPEED_1GBIT;
7814 			break;
7815 		case FC_STATE_2GBIT_SPEED:
7816 			val->PortSpeed = FC_HBA_PORTSPEED_2GBIT;
7817 			break;
7818 		case FC_STATE_4GBIT_SPEED:
7819 			val->PortSpeed = FC_HBA_PORTSPEED_4GBIT;
7820 			break;
7821 		case FC_STATE_8GBIT_SPEED:
7822 			val->PortSpeed = FC_HBA_PORTSPEED_8GBIT;
7823 			break;
7824 		case FC_STATE_10GBIT_SPEED:
7825 			val->PortSpeed = FC_HBA_PORTSPEED_10GBIT;
7826 			break;
7827 		case FC_STATE_16GBIT_SPEED:
7828 			val->PortSpeed = FC_HBA_PORTSPEED_16GBIT;
7829 			break;
7830 		default:
7831 			val->PortSpeed = FC_HBA_PORTSPEED_UNKNOWN;
7832 			break;
7833 		}
7834 		val->PortMaxFrameSize = port->fp_hba_port_attrs.max_frame_size;
7835 		val->NumberofDiscoveredPorts = port->fp_dev_count;
7836 		mutex_exit(&port->fp_mutex);
7837 
7838 		if (use32 == B_TRUE) {
7839 			val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP);
7840 			val32->version = val->version;
7841 			val32->lastChange = val->lastChange;
7842 			val32->fp_minor = val->fp_minor;
7843 
7844 			bcopy(&val->PortWWN.raw_wwn, &val32->PortWWN.raw_wwn,
7845 			    sizeof (val->PortWWN.raw_wwn));
7846 			bcopy(&val->NodeWWN.raw_wwn, &val32->NodeWWN.raw_wwn,
7847 			    sizeof (val->NodeWWN.raw_wwn));
7848 			val32->PortFcId = val->PortFcId;
7849 			val32->PortState = val->PortState;
7850 			val32->PortType = val->PortType;
7851 
7852 			val32->PortSupportedClassofService =
7853 			    val->PortSupportedClassofService;
7854 			bcopy(val->PortActiveFc4Types,
7855 			    val32->PortActiveFc4Types,
7856 			    sizeof (val->PortActiveFc4Types));
7857 			bcopy(val->PortSymbolicName, val32->PortSymbolicName,
7858 			    sizeof (val->PortSymbolicName));
7859 			bcopy(&val->FabricName, &val32->FabricName,
7860 			    sizeof (val->FabricName.raw_wwn));
7861 			val32->PortSupportedSpeed = val->PortSupportedSpeed;
7862 			val32->PortSpeed = val->PortSpeed;
7863 
7864 			val32->PortMaxFrameSize = val->PortMaxFrameSize;
7865 			val32->NumberofDiscoveredPorts =
7866 			    val->NumberofDiscoveredPorts;
7867 
7868 			if (fp_copyout((void *)val32, (void *)fcio->fcio_obuf,
7869 			    fcio->fcio_olen, mode) == 0) {
7870 				if (fp_fcio_copyout(fcio, data, mode)) {
7871 					rval = EFAULT;
7872 				}
7873 			} else {
7874 				rval = EFAULT;
7875 			}
7876 
7877 			kmem_free(val32, sizeof (*val32));
7878 		} else {
7879 			if (fp_copyout((void *)val, (void *)fcio->fcio_obuf,
7880 			    fcio->fcio_olen, mode) == 0) {
7881 				if (fp_fcio_copyout(fcio, data, mode)) {
7882 					rval = EFAULT;
7883 				}
7884 			} else {
7885 				rval = EFAULT;
7886 			}
7887 		}
7888 
7889 		kmem_free(val, sizeof (*val));
7890 		break;
7891 	}
7892 
7893 	case FCIO_GET_DISCOVERED_PORT_ATTRIBUTES: {
7894 		fc_hba_port_attributes_t	*val;
7895 		fc_hba_port_attributes32_t	*val32;
7896 		uint32_t	index = 0;
7897 		fc_remote_port_t *tmp_pd;
7898 
7899 		if (use32 == B_TRUE) {
7900 			if (fcio->fcio_olen < sizeof (*val32) ||
7901 			    fcio->fcio_xfer != FCIO_XFER_READ) {
7902 				rval = EINVAL;
7903 				break;
7904 			}
7905 		} else {
7906 			if (fcio->fcio_olen < sizeof (*val) ||
7907 			    fcio->fcio_xfer != FCIO_XFER_READ) {
7908 				rval = EINVAL;
7909 				break;
7910 			}
7911 		}
7912 
7913 		if (ddi_copyin(fcio->fcio_ibuf, &index, sizeof (index), mode)) {
7914 			rval = EFAULT;
7915 			break;
7916 		}
7917 
7918 		if (index >= port->fp_dev_count) {
7919 			FP_TRACE(FP_NHEAD1(9, 0),
7920 			    "User supplied index out of range");
7921 			fcio->fcio_errno = FC_OUTOFBOUNDS;
7922 			rval = EINVAL;
7923 			if (fp_fcio_copyout(fcio, data, mode)) {
7924 				rval = EFAULT;
7925 			}
7926 			break;
7927 		}
7928 
7929 		val = kmem_zalloc(sizeof (*val), KM_SLEEP);
7930 		val->version = FC_HBA_PORT_ATTRIBUTES_VERSION;
7931 
7932 		mutex_enter(&port->fp_mutex);
7933 		tmp_pd = fctl_lookup_pd_by_index(port, index);
7934 
7935 		if (tmp_pd == NULL) {
7936 			fcio->fcio_errno = FC_BADPORT;
7937 			rval = EINVAL;
7938 		} else {
7939 			val->lastChange = port->fp_last_change;
7940 			val->fp_minor = port->fp_instance;
7941 
7942 			mutex_enter(&tmp_pd->pd_mutex);
7943 			bcopy(&tmp_pd->pd_port_name.raw_wwn,
7944 			    &val->PortWWN.raw_wwn,
7945 			    sizeof (val->PortWWN.raw_wwn));
7946 			bcopy(&tmp_pd->pd_remote_nodep->fd_node_name.raw_wwn,
7947 			    &val->NodeWWN.raw_wwn,
7948 			    sizeof (val->NodeWWN.raw_wwn));
7949 			val->PortFcId = tmp_pd->pd_port_id.port_id;
7950 			bcopy(tmp_pd->pd_spn, val->PortSymbolicName,
7951 			    tmp_pd->pd_spn_len);
7952 			val->PortSupportedClassofService = tmp_pd->pd_cos;
7953 			/*
7954 			 * we will assume the sizeof these pd_fc4types and
7955 			 * portActiveFc4Types will remain the same.  we could
7956 			 * add in a check for it, but we decided it was unneeded
7957 			 */
7958 			bcopy((caddr_t)tmp_pd->pd_fc4types,
7959 			    val->PortActiveFc4Types,
7960 			    sizeof (tmp_pd->pd_fc4types));
7961 			val->PortState =
7962 			    fp_map_remote_port_state(tmp_pd->pd_state);
7963 			mutex_exit(&tmp_pd->pd_mutex);
7964 
7965 			val->PortType = FC_HBA_PORTTYPE_UNKNOWN;
7966 			val->PortSupportedFc4Types[0] = 0;
7967 			val->PortSupportedSpeed = FC_HBA_PORTSPEED_UNKNOWN;
7968 			val->PortSpeed = FC_HBA_PORTSPEED_UNKNOWN;
7969 			val->PortMaxFrameSize = 0;
7970 			val->NumberofDiscoveredPorts = 0;
7971 
7972 			if (use32 == B_TRUE) {
7973 				val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP);
7974 				val32->version = val->version;
7975 				val32->lastChange = val->lastChange;
7976 				val32->fp_minor = val->fp_minor;
7977 
7978 				bcopy(&val->PortWWN.raw_wwn,
7979 				    &val32->PortWWN.raw_wwn,
7980 				    sizeof (val->PortWWN.raw_wwn));
7981 				bcopy(&val->NodeWWN.raw_wwn,
7982 				    &val32->NodeWWN.raw_wwn,
7983 				    sizeof (val->NodeWWN.raw_wwn));
7984 				val32->PortFcId = val->PortFcId;
7985 				bcopy(val->PortSymbolicName,
7986 				    val32->PortSymbolicName,
7987 				    sizeof (val->PortSymbolicName));
7988 				val32->PortSupportedClassofService =
7989 				    val->PortSupportedClassofService;
7990 				bcopy(val->PortActiveFc4Types,
7991 				    val32->PortActiveFc4Types,
7992 				    sizeof (tmp_pd->pd_fc4types));
7993 
7994 				val32->PortType = val->PortType;
7995 				val32->PortState = val->PortState;
7996 				val32->PortSupportedFc4Types[0] =
7997 				    val->PortSupportedFc4Types[0];
7998 				val32->PortSupportedSpeed =
7999 				    val->PortSupportedSpeed;
8000 				val32->PortSpeed = val->PortSpeed;
8001 				val32->PortMaxFrameSize =
8002 				    val->PortMaxFrameSize;
8003 				val32->NumberofDiscoveredPorts =
8004 				    val->NumberofDiscoveredPorts;
8005 
8006 				if (fp_copyout((void *)val32,
8007 				    (void *)fcio->fcio_obuf,
8008 				    fcio->fcio_olen, mode) == 0) {
8009 					if (fp_fcio_copyout(fcio,
8010 					    data, mode)) {
8011 						rval = EFAULT;
8012 					}
8013 				} else {
8014 					rval = EFAULT;
8015 				}
8016 
8017 				kmem_free(val32, sizeof (*val32));
8018 			} else {
8019 				if (fp_copyout((void *)val,
8020 				    (void *)fcio->fcio_obuf,
8021 				    fcio->fcio_olen, mode) == 0) {
8022 					if (fp_fcio_copyout(fcio, data, mode)) {
8023 						rval = EFAULT;
8024 					}
8025 				} else {
8026 					rval = EFAULT;
8027 				}
8028 			}
8029 		}
8030 
8031 		mutex_exit(&port->fp_mutex);
8032 		kmem_free(val, sizeof (*val));
8033 		break;
8034 	}
8035 
8036 	case FCIO_GET_PORT_ATTRIBUTES: {
8037 		fc_hba_port_attributes_t    *val;
8038 		fc_hba_port_attributes32_t  *val32;
8039 		la_wwn_t		    wwn;
8040 		fc_remote_port_t	    *tmp_pd;
8041 
8042 		if (use32 == B_TRUE) {
8043 			if (fcio->fcio_olen < sizeof (*val32) ||
8044 			    fcio->fcio_xfer != FCIO_XFER_READ) {
8045 				rval = EINVAL;
8046 				break;
8047 			}
8048 		} else {
8049 			if (fcio->fcio_olen < sizeof (*val) ||
8050 			    fcio->fcio_xfer != FCIO_XFER_READ) {
8051 				rval = EINVAL;
8052 				break;
8053 			}
8054 		}
8055 
8056 		if (ddi_copyin(fcio->fcio_ibuf, &wwn, sizeof (wwn), mode)) {
8057 			rval = EFAULT;
8058 			break;
8059 		}
8060 
8061 		val = kmem_zalloc(sizeof (*val), KM_SLEEP);
8062 		val->version = FC_HBA_PORT_ATTRIBUTES_VERSION;
8063 
8064 		mutex_enter(&port->fp_mutex);
8065 		tmp_pd = fctl_lookup_pd_by_wwn(port, wwn);
8066 		val->lastChange = port->fp_last_change;
8067 		val->fp_minor = port->fp_instance;
8068 		mutex_exit(&port->fp_mutex);
8069 
8070 		if (tmp_pd == NULL) {
8071 			fcio->fcio_errno = FC_BADWWN;
8072 			rval = EINVAL;
8073 		} else {
8074 			mutex_enter(&tmp_pd->pd_mutex);
8075 			bcopy(&tmp_pd->pd_port_name.raw_wwn,
8076 			    &val->PortWWN.raw_wwn,
8077 			    sizeof (val->PortWWN.raw_wwn));
8078 			bcopy(&tmp_pd->pd_remote_nodep->fd_node_name.raw_wwn,
8079 			    &val->NodeWWN.raw_wwn,
8080 			    sizeof (val->NodeWWN.raw_wwn));
8081 			val->PortFcId = tmp_pd->pd_port_id.port_id;
8082 			bcopy(tmp_pd->pd_spn, val->PortSymbolicName,
8083 			    tmp_pd->pd_spn_len);
8084 			val->PortSupportedClassofService = tmp_pd->pd_cos;
8085 			val->PortType = FC_HBA_PORTTYPE_UNKNOWN;
8086 			val->PortState =
8087 			    fp_map_remote_port_state(tmp_pd->pd_state);
8088 			val->PortSupportedFc4Types[0] = 0;
8089 			/*
8090 			 * we will assume the sizeof these pd_fc4types and
8091 			 * portActiveFc4Types will remain the same.  we could
8092 			 * add in a check for it, but we decided it was unneeded
8093 			 */
8094 			bcopy((caddr_t)tmp_pd->pd_fc4types,
8095 			    val->PortActiveFc4Types,
8096 			    sizeof (tmp_pd->pd_fc4types));
8097 			val->PortSupportedSpeed = FC_HBA_PORTSPEED_UNKNOWN;
8098 			val->PortSpeed = FC_HBA_PORTSPEED_UNKNOWN;
8099 			val->PortMaxFrameSize = 0;
8100 			val->NumberofDiscoveredPorts = 0;
8101 			mutex_exit(&tmp_pd->pd_mutex);
8102 
8103 			if (use32 == B_TRUE) {
8104 				val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP);
8105 				val32->version = val->version;
8106 				val32->lastChange = val->lastChange;
8107 				val32->fp_minor = val->fp_minor;
8108 				bcopy(&val->PortWWN.raw_wwn,
8109 				    &val32->PortWWN.raw_wwn,
8110 				    sizeof (val->PortWWN.raw_wwn));
8111 				bcopy(&val->NodeWWN.raw_wwn,
8112 				    &val32->NodeWWN.raw_wwn,
8113 				    sizeof (val->NodeWWN.raw_wwn));
8114 				val32->PortFcId = val->PortFcId;
8115 				bcopy(val->PortSymbolicName,
8116 				    val32->PortSymbolicName,
8117 				    sizeof (val->PortSymbolicName));
8118 				val32->PortSupportedClassofService =
8119 				    val->PortSupportedClassofService;
8120 				val32->PortType = val->PortType;
8121 				val32->PortState = val->PortState;
8122 				val32->PortSupportedFc4Types[0] =
8123 				    val->PortSupportedFc4Types[0];
8124 				bcopy(val->PortActiveFc4Types,
8125 				    val32->PortActiveFc4Types,
8126 				    sizeof (tmp_pd->pd_fc4types));
8127 				val32->PortSupportedSpeed =
8128 				    val->PortSupportedSpeed;
8129 				val32->PortSpeed = val->PortSpeed;
8130 				val32->PortMaxFrameSize = val->PortMaxFrameSize;
8131 				val32->NumberofDiscoveredPorts =
8132 				    val->NumberofDiscoveredPorts;
8133 
8134 				if (fp_copyout((void *)val32,
8135 				    (void *)fcio->fcio_obuf,
8136 				    fcio->fcio_olen, mode) == 0) {
8137 					if (fp_fcio_copyout(fcio, data, mode)) {
8138 						rval = EFAULT;
8139 					}
8140 				} else {
8141 					rval = EFAULT;
8142 				}
8143 
8144 				kmem_free(val32, sizeof (*val32));
8145 			} else {
8146 				if (fp_copyout((void *)val,
8147 				    (void *)fcio->fcio_obuf,
8148 				    fcio->fcio_olen, mode) == 0) {
8149 					if (fp_fcio_copyout(fcio, data, mode)) {
8150 						rval = EFAULT;
8151 					}
8152 				} else {
8153 					rval = EFAULT;
8154 				}
8155 			}
8156 		}
8157 		kmem_free(val, sizeof (*val));
8158 		break;
8159 	}
8160 
8161 	case FCIO_GET_NUM_DEVS: {
8162 		int num_devices;
8163 
8164 		if (fcio->fcio_olen != sizeof (num_devices) ||
8165 		    fcio->fcio_xfer != FCIO_XFER_READ) {
8166 			rval = EINVAL;
8167 			break;
8168 		}
8169 
8170 		mutex_enter(&port->fp_mutex);
8171 		switch (port->fp_topology) {
8172 		case FC_TOP_PRIVATE_LOOP:
8173 		case FC_TOP_PT_PT:
8174 			num_devices = port->fp_total_devices;
8175 			fcio->fcio_errno = FC_SUCCESS;
8176 			break;
8177 
8178 		case FC_TOP_PUBLIC_LOOP:
8179 		case FC_TOP_FABRIC:
8180 			mutex_exit(&port->fp_mutex);
8181 			job = fctl_alloc_job(JOB_NS_CMD, 0, NULL,
8182 			    NULL, KM_SLEEP);
8183 			ASSERT(job != NULL);
8184 
8185 			/*
8186 			 * In FC-GS-2 the Name Server doesn't send out
8187 			 * RSCNs for any Name Server Database updates
8188 			 * When it is finally fixed there is no need
8189 			 * to probe as below and should be removed.
8190 			 */
8191 			(void) fp_ns_get_devcount(port, job, 0, KM_SLEEP);
8192 			fctl_dealloc_job(job);
8193 
8194 			mutex_enter(&port->fp_mutex);
8195 			num_devices = port->fp_total_devices;
8196 			fcio->fcio_errno = FC_SUCCESS;
8197 			break;
8198 
8199 		case FC_TOP_NO_NS:
8200 			/* FALLTHROUGH */
8201 		case FC_TOP_UNKNOWN:
8202 			/* FALLTHROUGH */
8203 		default:
8204 			num_devices = 0;
8205 			fcio->fcio_errno = FC_SUCCESS;
8206 			break;
8207 		}
8208 		mutex_exit(&port->fp_mutex);
8209 
8210 		if (fp_copyout((void *)&num_devices,
8211 		    (void *)fcio->fcio_obuf, fcio->fcio_olen,
8212 		    mode) == 0) {
8213 			if (fp_fcio_copyout(fcio, data, mode)) {
8214 				rval = EFAULT;
8215 			}
8216 		} else {
8217 			rval = EFAULT;
8218 		}
8219 		break;
8220 	}
8221 
8222 	case FCIO_GET_DEV_LIST: {
8223 		int num_devices;
8224 		int new_count;
8225 		int map_size;
8226 
8227 		if (fcio->fcio_xfer != FCIO_XFER_READ ||
8228 		    fcio->fcio_alen != sizeof (new_count)) {
8229 			rval = EINVAL;
8230 			break;
8231 		}
8232 
8233 		num_devices = fcio->fcio_olen / sizeof (fc_port_dev_t);
8234 
8235 		mutex_enter(&port->fp_mutex);
8236 		if (num_devices < port->fp_total_devices) {
8237 			fcio->fcio_errno = FC_TOOMANY;
8238 			new_count = port->fp_total_devices;
8239 			mutex_exit(&port->fp_mutex);
8240 
8241 			if (fp_copyout((void *)&new_count,
8242 			    (void *)fcio->fcio_abuf,
8243 			    sizeof (new_count), mode)) {
8244 				rval = EFAULT;
8245 				break;
8246 			}
8247 
8248 			if (fp_fcio_copyout(fcio, data, mode)) {
8249 				rval = EFAULT;
8250 				break;
8251 			}
8252 			rval = EINVAL;
8253 			break;
8254 		}
8255 
8256 		if (port->fp_total_devices <= 0) {
8257 			fcio->fcio_errno = FC_NO_MAP;
8258 			new_count = port->fp_total_devices;
8259 			mutex_exit(&port->fp_mutex);
8260 
8261 			if (fp_copyout((void *)&new_count,
8262 			    (void *)fcio->fcio_abuf,
8263 			    sizeof (new_count), mode)) {
8264 				rval = EFAULT;
8265 				break;
8266 			}
8267 
8268 			if (fp_fcio_copyout(fcio, data, mode)) {
8269 				rval = EFAULT;
8270 				break;
8271 			}
8272 			rval = EINVAL;
8273 			break;
8274 		}
8275 
8276 		switch (port->fp_topology) {
8277 		case FC_TOP_PRIVATE_LOOP:
8278 			if (fp_fillout_loopmap(port, fcio,
8279 			    mode) != FC_SUCCESS) {
8280 				rval = EFAULT;
8281 				break;
8282 			}
8283 			if (fp_fcio_copyout(fcio, data, mode)) {
8284 				rval = EFAULT;
8285 			}
8286 			break;
8287 
8288 		case FC_TOP_PT_PT:
8289 			if (fp_fillout_p2pmap(port, fcio,
8290 			    mode) != FC_SUCCESS) {
8291 				rval = EFAULT;
8292 				break;
8293 			}
8294 			if (fp_fcio_copyout(fcio, data, mode)) {
8295 				rval = EFAULT;
8296 			}
8297 			break;
8298 
8299 		case FC_TOP_PUBLIC_LOOP:
8300 		case FC_TOP_FABRIC: {
8301 			fctl_ns_req_t *ns_cmd;
8302 
8303 			map_size =
8304 			    sizeof (fc_port_dev_t) * port->fp_total_devices;
8305 
8306 			mutex_exit(&port->fp_mutex);
8307 
8308 			ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t),
8309 			    sizeof (ns_resp_gan_t), map_size,
8310 			    (FCTL_NS_FILL_NS_MAP | FCTL_NS_BUF_IS_USERLAND),
8311 			    KM_SLEEP);
8312 			ASSERT(ns_cmd != NULL);
8313 
8314 			ns_cmd->ns_gan_index = 0;
8315 			ns_cmd->ns_gan_sid = FCTL_GAN_START_ID;
8316 			ns_cmd->ns_cmd_code = NS_GA_NXT;
8317 			ns_cmd->ns_gan_max = map_size / sizeof (fc_port_dev_t);
8318 
8319 			job = fctl_alloc_job(JOB_PORT_GETMAP, 0, NULL,
8320 			    NULL, KM_SLEEP);
8321 			ASSERT(job != NULL);
8322 
8323 			ret = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP);
8324 
8325 			if (ret != FC_SUCCESS ||
8326 			    job->job_result != FC_SUCCESS) {
8327 				fctl_free_ns_cmd(ns_cmd);
8328 
8329 				fcio->fcio_errno = job->job_result;
8330 				new_count = 0;
8331 				if (fp_copyout((void *)&new_count,
8332 				    (void *)fcio->fcio_abuf,
8333 				    sizeof (new_count), mode)) {
8334 					fctl_dealloc_job(job);
8335 					mutex_enter(&port->fp_mutex);
8336 					rval = EFAULT;
8337 					break;
8338 				}
8339 
8340 				if (fp_fcio_copyout(fcio, data, mode)) {
8341 					fctl_dealloc_job(job);
8342 					mutex_enter(&port->fp_mutex);
8343 					rval = EFAULT;
8344 					break;
8345 				}
8346 				rval = EIO;
8347 				mutex_enter(&port->fp_mutex);
8348 				break;
8349 			}
8350 			fctl_dealloc_job(job);
8351 
8352 			new_count = ns_cmd->ns_gan_index;
8353 			if (fp_copyout((void *)&new_count,
8354 			    (void *)fcio->fcio_abuf, sizeof (new_count),
8355 			    mode)) {
8356 				rval = EFAULT;
8357 				fctl_free_ns_cmd(ns_cmd);
8358 				mutex_enter(&port->fp_mutex);
8359 				break;
8360 			}
8361 
8362 			if (fp_copyout((void *)ns_cmd->ns_data_buf,
8363 			    (void *)fcio->fcio_obuf, sizeof (fc_port_dev_t) *
8364 			    ns_cmd->ns_gan_index, mode)) {
8365 				rval = EFAULT;
8366 				fctl_free_ns_cmd(ns_cmd);
8367 				mutex_enter(&port->fp_mutex);
8368 				break;
8369 			}
8370 			fctl_free_ns_cmd(ns_cmd);
8371 
8372 			if (fp_fcio_copyout(fcio, data, mode)) {
8373 				rval = EFAULT;
8374 			}
8375 			mutex_enter(&port->fp_mutex);
8376 			break;
8377 		}
8378 
8379 		case FC_TOP_NO_NS:
8380 			/* FALLTHROUGH */
8381 		case FC_TOP_UNKNOWN:
8382 			/* FALLTHROUGH */
8383 		default:
8384 			fcio->fcio_errno = FC_NO_MAP;
8385 			num_devices = port->fp_total_devices;
8386 
8387 			if (fp_copyout((void *)&new_count,
8388 			    (void *)fcio->fcio_abuf,
8389 			    sizeof (new_count), mode)) {
8390 				rval = EFAULT;
8391 				break;
8392 			}
8393 
8394 			if (fp_fcio_copyout(fcio, data, mode)) {
8395 				rval = EFAULT;
8396 				break;
8397 			}
8398 			rval = EINVAL;
8399 			break;
8400 		}
8401 		mutex_exit(&port->fp_mutex);
8402 		break;
8403 	}
8404 
8405 	case FCIO_GET_SYM_PNAME: {
8406 		rval = ENOTSUP;
8407 		break;
8408 	}
8409 
8410 	case FCIO_GET_SYM_NNAME: {
8411 		rval = ENOTSUP;
8412 		break;
8413 	}
8414 
8415 	case FCIO_SET_SYM_PNAME: {
8416 		rval = ENOTSUP;
8417 		break;
8418 	}
8419 
8420 	case FCIO_SET_SYM_NNAME: {
8421 		rval = ENOTSUP;
8422 		break;
8423 	}
8424 
8425 	case FCIO_GET_LOGI_PARAMS: {
8426 		la_wwn_t		pwwn;
8427 		la_wwn_t		*my_pwwn;
8428 		la_els_logi_t		*params;
8429 		la_els_logi32_t		*params32;
8430 		fc_remote_node_t	*node;
8431 		fc_remote_port_t	*pd;
8432 
8433 		if (fcio->fcio_ilen != sizeof (la_wwn_t) ||
8434 		    (fcio->fcio_xfer & FCIO_XFER_READ) == 0 ||
8435 		    (fcio->fcio_xfer & FCIO_XFER_WRITE) == 0) {
8436 			rval = EINVAL;
8437 			break;
8438 		}
8439 
8440 		if (use32 == B_TRUE) {
8441 			if (fcio->fcio_olen != sizeof (la_els_logi32_t)) {
8442 				rval = EINVAL;
8443 				break;
8444 			}
8445 		} else {
8446 			if (fcio->fcio_olen != sizeof (la_els_logi_t)) {
8447 				rval = EINVAL;
8448 				break;
8449 			}
8450 		}
8451 
8452 		if (ddi_copyin(fcio->fcio_ibuf, &pwwn, sizeof (pwwn), mode)) {
8453 			rval = EFAULT;
8454 			break;
8455 		}
8456 
8457 		pd = fctl_hold_remote_port_by_pwwn(port, &pwwn);
8458 		if (pd == NULL) {
8459 			mutex_enter(&port->fp_mutex);
8460 			my_pwwn = &port->fp_service_params.nport_ww_name;
8461 			mutex_exit(&port->fp_mutex);
8462 
8463 			if (fctl_wwn_cmp(&pwwn, my_pwwn) != 0) {
8464 				rval = ENXIO;
8465 				break;
8466 			}
8467 
8468 			params = kmem_zalloc(sizeof (*params), KM_SLEEP);
8469 			mutex_enter(&port->fp_mutex);
8470 			*params = port->fp_service_params;
8471 			mutex_exit(&port->fp_mutex);
8472 		} else {
8473 			params = kmem_zalloc(sizeof (*params), KM_SLEEP);
8474 
8475 			mutex_enter(&pd->pd_mutex);
8476 			params->ls_code.mbz = params->ls_code.ls_code = 0;
8477 			params->common_service = pd->pd_csp;
8478 			params->nport_ww_name = pd->pd_port_name;
8479 			params->class_1 = pd->pd_clsp1;
8480 			params->class_2 = pd->pd_clsp2;
8481 			params->class_3 = pd->pd_clsp3;
8482 			node = pd->pd_remote_nodep;
8483 			mutex_exit(&pd->pd_mutex);
8484 
8485 			bzero(params->reserved, sizeof (params->reserved));
8486 
8487 			mutex_enter(&node->fd_mutex);
8488 			bcopy(node->fd_vv, params->vendor_version,
8489 			    sizeof (node->fd_vv));
8490 			params->node_ww_name = node->fd_node_name;
8491 			mutex_exit(&node->fd_mutex);
8492 
8493 			fctl_release_remote_port(pd);
8494 		}
8495 
8496 		if (use32 == B_TRUE) {
8497 			params32 = kmem_zalloc(sizeof (*params32), KM_SLEEP);
8498 
8499 			params32->ls_code.mbz = params->ls_code.mbz;
8500 			params32->common_service = params->common_service;
8501 			params32->nport_ww_name = params->nport_ww_name;
8502 			params32->class_1 = params->class_1;
8503 			params32->class_2 = params->class_2;
8504 			params32->class_3 = params->class_3;
8505 			bzero(params32->reserved, sizeof (params32->reserved));
8506 			bcopy(params->vendor_version, params32->vendor_version,
8507 			    sizeof (node->fd_vv));
8508 			params32->node_ww_name = params->node_ww_name;
8509 
8510 			if (ddi_copyout((void *)params32,
8511 			    (void *)fcio->fcio_obuf,
8512 			    sizeof (*params32), mode)) {
8513 				rval = EFAULT;
8514 			}
8515 
8516 			kmem_free(params32, sizeof (*params32));
8517 		} else {
8518 			if (ddi_copyout((void *)params, (void *)fcio->fcio_obuf,
8519 			    sizeof (*params), mode)) {
8520 				rval = EFAULT;
8521 			}
8522 		}
8523 
8524 		kmem_free(params, sizeof (*params));
8525 		if (fp_fcio_copyout(fcio, data, mode)) {
8526 			rval = EFAULT;
8527 		}
8528 		break;
8529 	}
8530 
8531 	case FCIO_DEV_LOGOUT:
8532 	case FCIO_DEV_LOGIN:
8533 		if (fcio->fcio_ilen != sizeof (la_wwn_t) ||
8534 		    fcio->fcio_xfer != FCIO_XFER_WRITE) {
8535 			rval = EINVAL;
8536 
8537 			if (fp_fcio_copyout(fcio, data, mode)) {
8538 				rval = EFAULT;
8539 			}
8540 			break;
8541 		}
8542 
8543 		if (fcio->fcio_cmd == FCIO_DEV_LOGIN) {
8544 			jcode = JOB_FCIO_LOGIN;
8545 		} else {
8546 			jcode = JOB_FCIO_LOGOUT;
8547 		}
8548 
8549 		kfcio = kmem_zalloc(sizeof (*kfcio), KM_SLEEP);
8550 		bcopy(fcio, kfcio, sizeof (*fcio));
8551 
8552 		if (kfcio->fcio_ilen) {
8553 			kfcio->fcio_ibuf = kmem_zalloc(kfcio->fcio_ilen,
8554 			    KM_SLEEP);
8555 
8556 			if (ddi_copyin((void *)fcio->fcio_ibuf,
8557 			    (void *)kfcio->fcio_ibuf, kfcio->fcio_ilen,
8558 			    mode)) {
8559 				rval = EFAULT;
8560 
8561 				kmem_free(kfcio->fcio_ibuf, kfcio->fcio_ilen);
8562 				kmem_free(kfcio, sizeof (*kfcio));
8563 				fcio->fcio_errno = job->job_result;
8564 				if (fp_fcio_copyout(fcio, data, mode)) {
8565 					rval = EFAULT;
8566 				}
8567 				break;
8568 			}
8569 		}
8570 
8571 		job = fctl_alloc_job(jcode, 0, NULL, NULL, KM_SLEEP);
8572 		job->job_private = kfcio;
8573 
8574 		fctl_enque_job(port, job);
8575 		fctl_jobwait(job);
8576 
8577 		rval = job->job_result;
8578 
8579 		fcio->fcio_errno = kfcio->fcio_errno;
8580 		if (fp_fcio_copyout(fcio, data, mode)) {
8581 			rval = EFAULT;
8582 		}
8583 
8584 		kmem_free(kfcio->fcio_ibuf, kfcio->fcio_ilen);
8585 		kmem_free(kfcio, sizeof (*kfcio));
8586 		fctl_dealloc_job(job);
8587 		break;
8588 
8589 	case FCIO_GET_STATE: {
8590 		la_wwn_t		pwwn;
8591 		uint32_t		state;
8592 		fc_remote_port_t	*pd;
8593 		fctl_ns_req_t		*ns_cmd;
8594 
8595 		if (fcio->fcio_ilen != sizeof (la_wwn_t) ||
8596 		    fcio->fcio_olen != sizeof (state) ||
8597 		    (fcio->fcio_xfer & FCIO_XFER_WRITE) == 0 ||
8598 		    (fcio->fcio_xfer & FCIO_XFER_READ) == 0) {
8599 			rval = EINVAL;
8600 			break;
8601 		}
8602 
8603 		if (ddi_copyin(fcio->fcio_ibuf, &pwwn, sizeof (pwwn), mode)) {
8604 			rval = EFAULT;
8605 			break;
8606 		}
8607 		fcio->fcio_errno = 0;
8608 
8609 		pd = fctl_hold_remote_port_by_pwwn(port, &pwwn);
8610 		if (pd == NULL) {
8611 			mutex_enter(&port->fp_mutex);
8612 			if (FC_IS_TOP_SWITCH(port->fp_topology)) {
8613 				mutex_exit(&port->fp_mutex);
8614 				job = fctl_alloc_job(JOB_PLOGI_ONE, 0,
8615 				    NULL, NULL, KM_SLEEP);
8616 
8617 				job->job_counter = 1;
8618 				job->job_result = FC_SUCCESS;
8619 
8620 				ns_cmd = fctl_alloc_ns_cmd(
8621 				    sizeof (ns_req_gid_pn_t),
8622 				    sizeof (ns_resp_gid_pn_t),
8623 				    sizeof (ns_resp_gid_pn_t),
8624 				    FCTL_NS_BUF_IS_USERLAND, KM_SLEEP);
8625 				ASSERT(ns_cmd != NULL);
8626 
8627 				ns_cmd->ns_cmd_code = NS_GID_PN;
8628 				((ns_req_gid_pn_t *)
8629 				    (ns_cmd->ns_cmd_buf))->pwwn = pwwn;
8630 
8631 				ret = fp_ns_query(port, ns_cmd, job,
8632 				    1, KM_SLEEP);
8633 
8634 				if (ret != FC_SUCCESS || job->job_result !=
8635 				    FC_SUCCESS) {
8636 					if (ret != FC_SUCCESS) {
8637 						fcio->fcio_errno = ret;
8638 					} else {
8639 						fcio->fcio_errno =
8640 						    job->job_result;
8641 					}
8642 					rval = EIO;
8643 				} else {
8644 					state = PORT_DEVICE_INVALID;
8645 				}
8646 				fctl_free_ns_cmd(ns_cmd);
8647 				fctl_dealloc_job(job);
8648 			} else {
8649 				mutex_exit(&port->fp_mutex);
8650 				fcio->fcio_errno = FC_BADWWN;
8651 				rval = ENXIO;
8652 			}
8653 		} else {
8654 			mutex_enter(&pd->pd_mutex);
8655 			state = pd->pd_state;
8656 			mutex_exit(&pd->pd_mutex);
8657 
8658 			fctl_release_remote_port(pd);
8659 		}
8660 
8661 		if (!rval) {
8662 			if (ddi_copyout((void *)&state,
8663 			    (void *)fcio->fcio_obuf, sizeof (state),
8664 			    mode)) {
8665 				rval = EFAULT;
8666 			}
8667 		}
8668 		if (fp_fcio_copyout(fcio, data, mode)) {
8669 			rval = EFAULT;
8670 		}
8671 		break;
8672 	}
8673 
8674 	case FCIO_DEV_REMOVE: {
8675 		la_wwn_t	pwwn;
8676 		fc_portmap_t	*changelist;
8677 		fc_remote_port_t *pd;
8678 
8679 		if (fcio->fcio_ilen != sizeof (la_wwn_t) ||
8680 		    fcio->fcio_xfer != FCIO_XFER_WRITE) {
8681 			rval = EINVAL;
8682 			break;
8683 		}
8684 
8685 		if (ddi_copyin(fcio->fcio_ibuf, &pwwn, sizeof (pwwn), mode)) {
8686 			rval = EFAULT;
8687 			break;
8688 		}
8689 
8690 		pd = fctl_hold_remote_port_by_pwwn(port, &pwwn);
8691 		if (pd == NULL) {
8692 			rval = ENXIO;
8693 			fcio->fcio_errno = FC_BADWWN;
8694 			if (fp_fcio_copyout(fcio, data, mode)) {
8695 				rval = EFAULT;
8696 			}
8697 			break;
8698 		}
8699 
8700 		mutex_enter(&pd->pd_mutex);
8701 		if (pd->pd_ref_count > 1) {
8702 			mutex_exit(&pd->pd_mutex);
8703 
8704 			rval = EBUSY;
8705 			fcio->fcio_errno = FC_FAILURE;
8706 			fctl_release_remote_port(pd);
8707 
8708 			if (fp_fcio_copyout(fcio, data, mode)) {
8709 				rval = EFAULT;
8710 			}
8711 			break;
8712 		}
8713 		mutex_exit(&pd->pd_mutex);
8714 
8715 		changelist = kmem_zalloc(sizeof (*changelist), KM_SLEEP);
8716 
8717 		fctl_copy_portmap(changelist, pd);
8718 		changelist->map_type = PORT_DEVICE_USER_LOGOUT;
8719 		(void) fp_ulp_devc_cb(port, changelist, 1, 1, KM_SLEEP, 1);
8720 
8721 		fctl_release_remote_port(pd);
8722 		break;
8723 	}
8724 
8725 	case FCIO_GET_FCODE_REV: {
8726 		caddr_t		fcode_rev;
8727 		fc_fca_pm_t	pm;
8728 
8729 		if (fcio->fcio_olen < FC_FCODE_REV_SIZE ||
8730 		    fcio->fcio_xfer != FCIO_XFER_READ) {
8731 			rval = EINVAL;
8732 			break;
8733 		}
8734 		bzero((caddr_t)&pm, sizeof (pm));
8735 
8736 		fcode_rev = kmem_zalloc(fcio->fcio_olen, KM_SLEEP);
8737 
8738 		pm.pm_cmd_flags = FC_FCA_PM_READ;
8739 		pm.pm_cmd_code = FC_PORT_GET_FCODE_REV;
8740 		pm.pm_data_len = fcio->fcio_olen;
8741 		pm.pm_data_buf = fcode_rev;
8742 
8743 		ret = port->fp_fca_tran->fca_port_manage(
8744 		    port->fp_fca_handle, &pm);
8745 
8746 		if (ret == FC_SUCCESS) {
8747 			if (ddi_copyout((void *)fcode_rev,
8748 			    (void *)fcio->fcio_obuf,
8749 			    fcio->fcio_olen, mode) == 0) {
8750 				if (fp_fcio_copyout(fcio, data, mode)) {
8751 					rval = EFAULT;
8752 				}
8753 			} else {
8754 				rval = EFAULT;
8755 			}
8756 		} else {
8757 			/*
8758 			 * check if buffer was not large enough to obtain
8759 			 * FCODE version.
8760 			 */
8761 			if (pm.pm_data_len > fcio->fcio_olen) {
8762 				rval = ENOMEM;
8763 			} else {
8764 				rval = EIO;
8765 			}
8766 			fcio->fcio_errno = ret;
8767 			if (fp_fcio_copyout(fcio, data, mode)) {
8768 				rval = EFAULT;
8769 			}
8770 		}
8771 		kmem_free(fcode_rev, fcio->fcio_olen);
8772 		break;
8773 	}
8774 
8775 	case FCIO_GET_FW_REV: {
8776 		caddr_t		fw_rev;
8777 		fc_fca_pm_t	pm;
8778 
8779 		if (fcio->fcio_olen < FC_FW_REV_SIZE ||
8780 		    fcio->fcio_xfer != FCIO_XFER_READ) {
8781 			rval = EINVAL;
8782 			break;
8783 		}
8784 		bzero((caddr_t)&pm, sizeof (pm));
8785 
8786 		fw_rev = kmem_zalloc(fcio->fcio_olen, KM_SLEEP);
8787 
8788 		pm.pm_cmd_flags = FC_FCA_PM_READ;
8789 		pm.pm_cmd_code = FC_PORT_GET_FW_REV;
8790 		pm.pm_data_len = fcio->fcio_olen;
8791 		pm.pm_data_buf = fw_rev;
8792 
8793 		ret = port->fp_fca_tran->fca_port_manage(
8794 		    port->fp_fca_handle, &pm);
8795 
8796 		if (ret == FC_SUCCESS) {
8797 			if (ddi_copyout((void *)fw_rev,
8798 			    (void *)fcio->fcio_obuf,
8799 			    fcio->fcio_olen, mode) == 0) {
8800 				if (fp_fcio_copyout(fcio, data, mode)) {
8801 					rval = EFAULT;
8802 				}
8803 			} else {
8804 				rval = EFAULT;
8805 			}
8806 		} else {
8807 			if (fp_fcio_copyout(fcio, data, mode)) {
8808 				rval = EFAULT;
8809 			}
8810 			rval = EIO;
8811 		}
8812 		kmem_free(fw_rev, fcio->fcio_olen);
8813 		break;
8814 	}
8815 
8816 	case FCIO_GET_DUMP_SIZE: {
8817 		uint32_t	dump_size;
8818 		fc_fca_pm_t	pm;
8819 
8820 		if (fcio->fcio_olen != sizeof (dump_size) ||
8821 		    fcio->fcio_xfer != FCIO_XFER_READ) {
8822 			rval = EINVAL;
8823 			break;
8824 		}
8825 		bzero((caddr_t)&pm, sizeof (pm));
8826 		pm.pm_cmd_flags = FC_FCA_PM_READ;
8827 		pm.pm_cmd_code = FC_PORT_GET_DUMP_SIZE;
8828 		pm.pm_data_len = sizeof (dump_size);
8829 		pm.pm_data_buf = (caddr_t)&dump_size;
8830 
8831 		ret = port->fp_fca_tran->fca_port_manage(
8832 		    port->fp_fca_handle, &pm);
8833 
8834 		if (ret == FC_SUCCESS) {
8835 			if (ddi_copyout((void *)&dump_size,
8836 			    (void *)fcio->fcio_obuf, sizeof (dump_size),
8837 			    mode) == 0) {
8838 				if (fp_fcio_copyout(fcio, data, mode)) {
8839 					rval = EFAULT;
8840 				}
8841 			} else {
8842 				rval = EFAULT;
8843 			}
8844 		} else {
8845 			fcio->fcio_errno = ret;
8846 			rval = EIO;
8847 			if (fp_fcio_copyout(fcio, data, mode)) {
8848 				rval = EFAULT;
8849 			}
8850 		}
8851 		break;
8852 	}
8853 
8854 	case FCIO_DOWNLOAD_FW: {
8855 		caddr_t		firmware;
8856 		fc_fca_pm_t	pm;
8857 
8858 		if (fcio->fcio_ilen <= 0 ||
8859 		    fcio->fcio_xfer != FCIO_XFER_WRITE) {
8860 			rval = EINVAL;
8861 			break;
8862 		}
8863 
8864 		firmware = kmem_zalloc(fcio->fcio_ilen, KM_SLEEP);
8865 		if (ddi_copyin(fcio->fcio_ibuf, firmware,
8866 		    fcio->fcio_ilen, mode)) {
8867 			rval = EFAULT;
8868 			kmem_free(firmware, fcio->fcio_ilen);
8869 			break;
8870 		}
8871 
8872 		bzero((caddr_t)&pm, sizeof (pm));
8873 		pm.pm_cmd_flags = FC_FCA_PM_WRITE;
8874 		pm.pm_cmd_code = FC_PORT_DOWNLOAD_FW;
8875 		pm.pm_data_len = fcio->fcio_ilen;
8876 		pm.pm_data_buf = firmware;
8877 
8878 		ret = port->fp_fca_tran->fca_port_manage(
8879 		    port->fp_fca_handle, &pm);
8880 
8881 		kmem_free(firmware, fcio->fcio_ilen);
8882 
8883 		if (ret != FC_SUCCESS) {
8884 			fcio->fcio_errno = ret;
8885 			rval = EIO;
8886 			if (fp_fcio_copyout(fcio, data, mode)) {
8887 				rval = EFAULT;
8888 			}
8889 		}
8890 		break;
8891 	}
8892 
8893 	case FCIO_DOWNLOAD_FCODE: {
8894 		caddr_t		fcode;
8895 		fc_fca_pm_t	pm;
8896 
8897 		if (fcio->fcio_ilen <= 0 ||
8898 		    fcio->fcio_xfer != FCIO_XFER_WRITE) {
8899 			rval = EINVAL;
8900 			break;
8901 		}
8902 
8903 		fcode = kmem_zalloc(fcio->fcio_ilen, KM_SLEEP);
8904 		if (ddi_copyin(fcio->fcio_ibuf, fcode,
8905 		    fcio->fcio_ilen, mode)) {
8906 			rval = EFAULT;
8907 			kmem_free(fcode, fcio->fcio_ilen);
8908 			break;
8909 		}
8910 
8911 		bzero((caddr_t)&pm, sizeof (pm));
8912 		pm.pm_cmd_flags = FC_FCA_PM_WRITE;
8913 		pm.pm_cmd_code = FC_PORT_DOWNLOAD_FCODE;
8914 		pm.pm_data_len = fcio->fcio_ilen;
8915 		pm.pm_data_buf = fcode;
8916 
8917 		ret = port->fp_fca_tran->fca_port_manage(
8918 		    port->fp_fca_handle, &pm);
8919 
8920 		kmem_free(fcode, fcio->fcio_ilen);
8921 
8922 		if (ret != FC_SUCCESS) {
8923 			fcio->fcio_errno = ret;
8924 			rval = EIO;
8925 			if (fp_fcio_copyout(fcio, data, mode)) {
8926 				rval = EFAULT;
8927 			}
8928 		}
8929 		break;
8930 	}
8931 
8932 	case FCIO_FORCE_DUMP:
8933 		ret = port->fp_fca_tran->fca_reset(
8934 		    port->fp_fca_handle, FC_FCA_CORE);
8935 
8936 		if (ret != FC_SUCCESS) {
8937 			fcio->fcio_errno = ret;
8938 			rval = EIO;
8939 			if (fp_fcio_copyout(fcio, data, mode)) {
8940 				rval = EFAULT;
8941 			}
8942 		}
8943 		break;
8944 
8945 	case FCIO_GET_DUMP: {
8946 		caddr_t		dump;
8947 		uint32_t	dump_size;
8948 		fc_fca_pm_t	pm;
8949 
8950 		if (fcio->fcio_xfer != FCIO_XFER_READ) {
8951 			rval = EINVAL;
8952 			break;
8953 		}
8954 		bzero((caddr_t)&pm, sizeof (pm));
8955 
8956 		pm.pm_cmd_flags = FC_FCA_PM_READ;
8957 		pm.pm_cmd_code = FC_PORT_GET_DUMP_SIZE;
8958 		pm.pm_data_len = sizeof (dump_size);
8959 		pm.pm_data_buf = (caddr_t)&dump_size;
8960 
8961 		ret = port->fp_fca_tran->fca_port_manage(
8962 		    port->fp_fca_handle, &pm);
8963 
8964 		if (ret != FC_SUCCESS) {
8965 			fcio->fcio_errno = ret;
8966 			rval = EIO;
8967 			if (fp_fcio_copyout(fcio, data, mode)) {
8968 				rval = EFAULT;
8969 			}
8970 			break;
8971 		}
8972 		if (fcio->fcio_olen != dump_size) {
8973 			fcio->fcio_errno = FC_NOMEM;
8974 			rval = EINVAL;
8975 			if (fp_fcio_copyout(fcio, data, mode)) {
8976 				rval = EFAULT;
8977 			}
8978 			break;
8979 		}
8980 
8981 		dump = kmem_zalloc(dump_size, KM_SLEEP);
8982 
8983 		bzero((caddr_t)&pm, sizeof (pm));
8984 		pm.pm_cmd_flags = FC_FCA_PM_READ;
8985 		pm.pm_cmd_code = FC_PORT_GET_DUMP;
8986 		pm.pm_data_len = dump_size;
8987 		pm.pm_data_buf = dump;
8988 
8989 		ret = port->fp_fca_tran->fca_port_manage(
8990 		    port->fp_fca_handle, &pm);
8991 
8992 		if (ret == FC_SUCCESS) {
8993 			if (ddi_copyout((void *)dump, (void *)fcio->fcio_obuf,
8994 			    dump_size, mode) == 0) {
8995 				if (fp_fcio_copyout(fcio, data, mode)) {
8996 					rval = EFAULT;
8997 				}
8998 			} else {
8999 				rval = EFAULT;
9000 			}
9001 		} else {
9002 			fcio->fcio_errno = ret;
9003 			rval = EIO;
9004 			if (fp_fcio_copyout(fcio, data, mode)) {
9005 				rval = EFAULT;
9006 			}
9007 		}
9008 		kmem_free(dump, dump_size);
9009 		break;
9010 	}
9011 
9012 	case FCIO_GET_TOPOLOGY: {
9013 		uint32_t user_topology;
9014 
9015 		if (fcio->fcio_xfer != FCIO_XFER_READ ||
9016 		    fcio->fcio_olen != sizeof (user_topology)) {
9017 			rval = EINVAL;
9018 			break;
9019 		}
9020 
9021 		mutex_enter(&port->fp_mutex);
9022 		if (FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) {
9023 			user_topology = FC_TOP_UNKNOWN;
9024 		} else {
9025 			user_topology = port->fp_topology;
9026 		}
9027 		mutex_exit(&port->fp_mutex);
9028 
9029 		if (ddi_copyout((void *)&user_topology,
9030 		    (void *)fcio->fcio_obuf, sizeof (user_topology),
9031 		    mode)) {
9032 			rval = EFAULT;
9033 		}
9034 		break;
9035 	}
9036 
9037 	case FCIO_RESET_LINK: {
9038 		la_wwn_t pwwn;
9039 
9040 		/*
9041 		 * Look at the output buffer field; if this field has zero
9042 		 * bytes then attempt to reset the local link/loop. If the
9043 		 * fcio_ibuf field points to a WWN, see if it's an NL_Port,
9044 		 * and if yes, determine the LFA and reset the remote LIP
9045 		 * by LINIT ELS.
9046 		 */
9047 
9048 		if (fcio->fcio_xfer != FCIO_XFER_WRITE ||
9049 		    fcio->fcio_ilen != sizeof (pwwn)) {
9050 			rval = EINVAL;
9051 			break;
9052 		}
9053 
9054 		if (ddi_copyin(fcio->fcio_ibuf, &pwwn,
9055 		    sizeof (pwwn), mode)) {
9056 			rval = EFAULT;
9057 			break;
9058 		}
9059 
9060 		mutex_enter(&port->fp_mutex);
9061 		if (port->fp_soft_state & FP_SOFT_IN_LINK_RESET) {
9062 			mutex_exit(&port->fp_mutex);
9063 			break;
9064 		}
9065 		port->fp_soft_state |= FP_SOFT_IN_LINK_RESET;
9066 		mutex_exit(&port->fp_mutex);
9067 
9068 		job = fctl_alloc_job(JOB_LINK_RESET, 0, NULL, NULL, KM_SLEEP);
9069 		if (job == NULL) {
9070 			rval = ENOMEM;
9071 			break;
9072 		}
9073 		job->job_counter = 1;
9074 		job->job_private = (void *)&pwwn;
9075 
9076 		fctl_enque_job(port, job);
9077 		fctl_jobwait(job);
9078 
9079 		mutex_enter(&port->fp_mutex);
9080 		port->fp_soft_state &= ~FP_SOFT_IN_LINK_RESET;
9081 		mutex_exit(&port->fp_mutex);
9082 
9083 		if (job->job_result != FC_SUCCESS) {
9084 			fcio->fcio_errno = job->job_result;
9085 			rval = EIO;
9086 			if (fp_fcio_copyout(fcio, data, mode)) {
9087 				rval = EFAULT;
9088 			}
9089 		}
9090 		fctl_dealloc_job(job);
9091 		break;
9092 	}
9093 
9094 	case FCIO_RESET_HARD:
9095 		ret = port->fp_fca_tran->fca_reset(
9096 		    port->fp_fca_handle, FC_FCA_RESET);
9097 		if (ret != FC_SUCCESS) {
9098 			fcio->fcio_errno = ret;
9099 			rval = EIO;
9100 			if (fp_fcio_copyout(fcio, data, mode)) {
9101 				rval = EFAULT;
9102 			}
9103 		}
9104 		break;
9105 
9106 	case FCIO_RESET_HARD_CORE:
9107 		ret = port->fp_fca_tran->fca_reset(
9108 		    port->fp_fca_handle, FC_FCA_RESET_CORE);
9109 		if (ret != FC_SUCCESS) {
9110 			rval = EIO;
9111 			fcio->fcio_errno = ret;
9112 			if (fp_fcio_copyout(fcio, data, mode)) {
9113 				rval = EFAULT;
9114 			}
9115 		}
9116 		break;
9117 
9118 	case FCIO_DIAG: {
9119 		fc_fca_pm_t pm;
9120 
9121 		bzero((caddr_t)&pm, sizeof (fc_fca_pm_t));
9122 
9123 		/* Validate user buffer from ioctl call. */
9124 		if (((fcio->fcio_ilen > 0) && (fcio->fcio_ibuf == NULL)) ||
9125 		    ((fcio->fcio_ilen <= 0) && (fcio->fcio_ibuf != NULL)) ||
9126 		    ((fcio->fcio_alen > 0) && (fcio->fcio_abuf == NULL)) ||
9127 		    ((fcio->fcio_alen <= 0) && (fcio->fcio_abuf != NULL)) ||
9128 		    ((fcio->fcio_olen > 0) && (fcio->fcio_obuf == NULL)) ||
9129 		    ((fcio->fcio_olen <= 0) && (fcio->fcio_obuf != NULL))) {
9130 			rval = EFAULT;
9131 			break;
9132 		}
9133 
9134 		if ((pm.pm_cmd_len = fcio->fcio_ilen) > 0) {
9135 			pm.pm_cmd_buf = kmem_zalloc(fcio->fcio_ilen, KM_SLEEP);
9136 			if (ddi_copyin(fcio->fcio_ibuf, pm.pm_cmd_buf,
9137 			    fcio->fcio_ilen, mode)) {
9138 				rval = EFAULT;
9139 				goto fp_fcio_diag_cleanup;
9140 			}
9141 		}
9142 
9143 		if ((pm.pm_data_len = fcio->fcio_alen) > 0) {
9144 			pm.pm_data_buf = kmem_zalloc(fcio->fcio_alen, KM_SLEEP);
9145 			if (ddi_copyin(fcio->fcio_abuf, pm.pm_data_buf,
9146 			    fcio->fcio_alen, mode)) {
9147 				rval = EFAULT;
9148 				goto fp_fcio_diag_cleanup;
9149 			}
9150 		}
9151 
9152 		if ((pm.pm_stat_len = fcio->fcio_olen) > 0) {
9153 			pm.pm_stat_buf = kmem_zalloc(fcio->fcio_olen, KM_SLEEP);
9154 		}
9155 
9156 		pm.pm_cmd_code = FC_PORT_DIAG;
9157 		pm.pm_cmd_flags = fcio->fcio_cmd_flags;
9158 
9159 		ret = port->fp_fca_tran->fca_port_manage(
9160 		    port->fp_fca_handle, &pm);
9161 
9162 		if (ret != FC_SUCCESS) {
9163 			if (ret == FC_INVALID_REQUEST) {
9164 				rval = ENOTTY;
9165 			} else {
9166 				rval = EIO;
9167 			}
9168 
9169 			fcio->fcio_errno = ret;
9170 			if (fp_fcio_copyout(fcio, data, mode)) {
9171 				rval = EFAULT;
9172 			}
9173 			goto fp_fcio_diag_cleanup;
9174 		}
9175 
9176 		/*
9177 		 * pm_stat_len will contain the number of status bytes
9178 		 * an FCA driver requires to return the complete status
9179 		 * of the requested diag operation. If the user buffer
9180 		 * is not large enough to hold the entire status, We
9181 		 * copy only the portion of data the fits in the buffer and
9182 		 * return a ENOMEM to the user application.
9183 		 */
9184 		if (pm.pm_stat_len > fcio->fcio_olen) {
9185 			fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
9186 			    "fp:FCIO_DIAG:status buffer too small\n");
9187 
9188 			rval = ENOMEM;
9189 			if (ddi_copyout(pm.pm_stat_buf, fcio->fcio_obuf,
9190 			    fcio->fcio_olen, mode)) {
9191 				rval = EFAULT;
9192 				goto fp_fcio_diag_cleanup;
9193 			}
9194 		} else {
9195 			/*
9196 			 * Copy only data pm_stat_len bytes of data
9197 			 */
9198 			if (ddi_copyout(pm.pm_stat_buf, fcio->fcio_obuf,
9199 			    pm.pm_stat_len, mode)) {
9200 				rval = EFAULT;
9201 				goto fp_fcio_diag_cleanup;
9202 			}
9203 		}
9204 
9205 		if (fp_fcio_copyout(fcio, data, mode)) {
9206 			rval = EFAULT;
9207 		}
9208 
9209 		fp_fcio_diag_cleanup:
9210 		if (pm.pm_cmd_buf != NULL) {
9211 			kmem_free(pm.pm_cmd_buf, fcio->fcio_ilen);
9212 		}
9213 		if (pm.pm_data_buf != NULL) {
9214 			kmem_free(pm.pm_data_buf, fcio->fcio_alen);
9215 		}
9216 		if (pm.pm_stat_buf != NULL) {
9217 			kmem_free(pm.pm_stat_buf, fcio->fcio_olen);
9218 		}
9219 
9220 		break;
9221 	}
9222 
9223 	case FCIO_GET_NODE_ID: {
9224 		/* validate parameters */
9225 		if (fcio->fcio_xfer != FCIO_XFER_READ ||
9226 		    fcio->fcio_olen < sizeof (fc_rnid_t)) {
9227 			rval = EINVAL;
9228 			break;
9229 		}
9230 
9231 		rval = fp_get_rnid(port, data, mode, fcio);
9232 
9233 		/* ioctl handling is over */
9234 		break;
9235 	}
9236 
9237 	case FCIO_SEND_NODE_ID: {
9238 		la_wwn_t		pwwn;
9239 
9240 		/* validate parameters */
9241 		if (fcio->fcio_ilen != sizeof (la_wwn_t) ||
9242 		    fcio->fcio_xfer != FCIO_XFER_READ) {
9243 			rval = EINVAL;
9244 			break;
9245 		}
9246 
9247 		if (ddi_copyin(fcio->fcio_ibuf, &pwwn,
9248 		    sizeof (la_wwn_t), mode)) {
9249 			rval = EFAULT;
9250 			break;
9251 		}
9252 
9253 		rval = fp_send_rnid(port, data, mode, fcio, &pwwn);
9254 
9255 		/* ioctl handling is over */
9256 		break;
9257 	}
9258 
9259 	case FCIO_SET_NODE_ID: {
9260 		if (fcio->fcio_ilen != sizeof (fc_rnid_t) ||
9261 		    (fcio->fcio_xfer != FCIO_XFER_WRITE)) {
9262 			rval = EINVAL;
9263 			break;
9264 		}
9265 
9266 		rval = fp_set_rnid(port, data, mode, fcio);
9267 		break;
9268 	}
9269 
9270 	case FCIO_LINK_STATUS: {
9271 		fc_portid_t		rls_req;
9272 		fc_rls_acc_t		*rls_acc;
9273 		fc_fca_pm_t		pm;
9274 		uint32_t		dest, src_id;
9275 		fp_cmd_t		*cmd;
9276 		fc_remote_port_t	*pd;
9277 		uchar_t			pd_flags;
9278 
9279 		/* validate parameters */
9280 		if (fcio->fcio_ilen != sizeof (fc_portid_t) ||
9281 		    fcio->fcio_olen != sizeof (fc_rls_acc_t) ||
9282 		    fcio->fcio_xfer != FCIO_XFER_RW) {
9283 			rval = EINVAL;
9284 			break;
9285 		}
9286 
9287 		if ((fcio->fcio_cmd_flags != FCIO_CFLAGS_RLS_DEST_FPORT) &&
9288 		    (fcio->fcio_cmd_flags != FCIO_CFLAGS_RLS_DEST_NPORT)) {
9289 			rval = EINVAL;
9290 			break;
9291 		}
9292 
9293 		if (ddi_copyin((void *)fcio->fcio_ibuf, (void *)&rls_req,
9294 		    sizeof (fc_portid_t), mode)) {
9295 			rval = EFAULT;
9296 			break;
9297 		}
9298 
9299 
9300 		/* Determine the destination of the RLS frame */
9301 		if (fcio->fcio_cmd_flags == FCIO_CFLAGS_RLS_DEST_FPORT) {
9302 			dest = FS_FABRIC_F_PORT;
9303 		} else {
9304 			dest = rls_req.port_id;
9305 		}
9306 
9307 		mutex_enter(&port->fp_mutex);
9308 		src_id = port->fp_port_id.port_id;
9309 		mutex_exit(&port->fp_mutex);
9310 
9311 		/* If dest is zero OR same as FCA ID, then use port_manage() */
9312 		if (dest == 0 || dest == src_id) {
9313 
9314 			/* Allocate memory for link error status block */
9315 			rls_acc = kmem_zalloc(sizeof (*rls_acc), KM_SLEEP);
9316 			ASSERT(rls_acc != NULL);
9317 
9318 			/* Prepare the port management structure */
9319 			bzero((caddr_t)&pm, sizeof (pm));
9320 
9321 			pm.pm_cmd_flags = FC_FCA_PM_READ;
9322 			pm.pm_cmd_code	= FC_PORT_RLS;
9323 			pm.pm_data_len	= sizeof (*rls_acc);
9324 			pm.pm_data_buf	= (caddr_t)rls_acc;
9325 
9326 			/* Get the adapter's link error status block */
9327 			ret = port->fp_fca_tran->fca_port_manage(
9328 			    port->fp_fca_handle, &pm);
9329 
9330 			if (ret == FC_SUCCESS) {
9331 				/* xfer link status block to userland */
9332 				if (ddi_copyout((void *)rls_acc,
9333 				    (void *)fcio->fcio_obuf,
9334 				    sizeof (*rls_acc), mode) == 0) {
9335 					if (fp_fcio_copyout(fcio, data,
9336 					    mode)) {
9337 						rval = EFAULT;
9338 					}
9339 				} else {
9340 					rval = EFAULT;
9341 				}
9342 			} else {
9343 				rval = EIO;
9344 				fcio->fcio_errno = ret;
9345 				if (fp_fcio_copyout(fcio, data, mode)) {
9346 					rval = EFAULT;
9347 				}
9348 			}
9349 
9350 			kmem_free(rls_acc, sizeof (*rls_acc));
9351 
9352 			/* ioctl handling is over */
9353 			break;
9354 		}
9355 
9356 		/*
9357 		 * Send RLS to the destination port.
9358 		 * Having RLS frame destination is as FPORT is not yet
9359 		 * supported and will be implemented in future, if needed.
9360 		 * Following call to get "pd" will fail if dest is FPORT
9361 		 */
9362 		pd = fctl_hold_remote_port_by_did(port, dest);
9363 		if (pd == NULL) {
9364 			fcio->fcio_errno = FC_BADOBJECT;
9365 			rval = ENXIO;
9366 			if (fp_fcio_copyout(fcio, data, mode)) {
9367 				rval = EFAULT;
9368 			}
9369 			break;
9370 		}
9371 
9372 		mutex_enter(&pd->pd_mutex);
9373 		if (pd->pd_state != PORT_DEVICE_LOGGED_IN) {
9374 			mutex_exit(&pd->pd_mutex);
9375 			fctl_release_remote_port(pd);
9376 
9377 			fcio->fcio_errno = FC_LOGINREQ;
9378 			rval = EINVAL;
9379 			if (fp_fcio_copyout(fcio, data, mode)) {
9380 				rval = EFAULT;
9381 			}
9382 			break;
9383 		}
9384 		ASSERT(pd->pd_login_count >= 1);
9385 		mutex_exit(&pd->pd_mutex);
9386 
9387 		/*
9388 		 * Allocate job structure and set job_code as DUMMY,
9389 		 * because we will not go through the job thread.
9390 		 * Instead fp_sendcmd() is called directly here.
9391 		 */
9392 		job = fctl_alloc_job(JOB_DUMMY, JOB_TYPE_FP_ASYNC,
9393 		    NULL, NULL, KM_SLEEP);
9394 		ASSERT(job != NULL);
9395 
9396 		job->job_counter = 1;
9397 
9398 		cmd = fp_alloc_pkt(port, sizeof (la_els_rls_t),
9399 		    sizeof (la_els_rls_acc_t), KM_SLEEP, pd);
9400 		if (cmd == NULL) {
9401 			fcio->fcio_errno = FC_NOMEM;
9402 			rval = ENOMEM;
9403 
9404 			fctl_release_remote_port(pd);
9405 
9406 			fctl_dealloc_job(job);
9407 			if (fp_fcio_copyout(fcio, data, mode)) {
9408 				rval = EFAULT;
9409 			}
9410 			break;
9411 		}
9412 
9413 		/* Allocate memory for link error status block */
9414 		rls_acc = kmem_zalloc(sizeof (*rls_acc), KM_SLEEP);
9415 
9416 		mutex_enter(&port->fp_mutex);
9417 		mutex_enter(&pd->pd_mutex);
9418 
9419 		cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
9420 		cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
9421 		cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
9422 		cmd->cmd_retry_count = 1;
9423 		cmd->cmd_ulp_pkt = NULL;
9424 
9425 		fp_rls_init(cmd, job);
9426 
9427 		job->job_private = (void *)rls_acc;
9428 
9429 		pd_flags = pd->pd_flags;
9430 		pd->pd_flags = PD_ELS_IN_PROGRESS;
9431 
9432 		mutex_exit(&pd->pd_mutex);
9433 		mutex_exit(&port->fp_mutex);
9434 
9435 		if (fp_sendcmd(port, cmd, port->fp_fca_handle) == FC_SUCCESS) {
9436 			fctl_jobwait(job);
9437 
9438 			fcio->fcio_errno = job->job_result;
9439 			if (job->job_result == FC_SUCCESS) {
9440 				ASSERT(pd != NULL);
9441 				/*
9442 				 * link error status block is now available.
9443 				 * Copy it to userland
9444 				 */
9445 				ASSERT(job->job_private == (void *)rls_acc);
9446 				if (ddi_copyout((void *)rls_acc,
9447 				    (void *)fcio->fcio_obuf,
9448 				    sizeof (*rls_acc), mode) == 0) {
9449 					if (fp_fcio_copyout(fcio, data,
9450 					    mode)) {
9451 						rval = EFAULT;
9452 					}
9453 				} else {
9454 					rval = EFAULT;
9455 				}
9456 			} else {
9457 				rval = EIO;
9458 			}
9459 		} else {
9460 			rval = EIO;
9461 			fp_free_pkt(cmd);
9462 		}
9463 
9464 		if (rval) {
9465 			mutex_enter(&port->fp_mutex);
9466 			mutex_enter(&pd->pd_mutex);
9467 			if (pd->pd_flags == PD_ELS_IN_PROGRESS) {
9468 				pd->pd_flags = pd_flags;
9469 			}
9470 			mutex_exit(&pd->pd_mutex);
9471 			mutex_exit(&port->fp_mutex);
9472 		}
9473 
9474 		fctl_release_remote_port(pd);
9475 		fctl_dealloc_job(job);
9476 		kmem_free(rls_acc, sizeof (*rls_acc));
9477 
9478 		if (fp_fcio_copyout(fcio, data, mode)) {
9479 			rval = EFAULT;
9480 		}
9481 		break;
9482 	}
9483 
9484 	case FCIO_NS: {
9485 		fc_ns_cmd_t	*ns_req;
9486 		fc_ns_cmd32_t	*ns_req32;
9487 		fctl_ns_req_t	*ns_cmd;
9488 
9489 		if (use32 == B_TRUE) {
9490 			if (fcio->fcio_ilen != sizeof (*ns_req32)) {
9491 				rval = EINVAL;
9492 				break;
9493 			}
9494 
9495 			ns_req = kmem_zalloc(sizeof (*ns_req), KM_SLEEP);
9496 			ns_req32 = kmem_zalloc(sizeof (*ns_req32), KM_SLEEP);
9497 
9498 			if (ddi_copyin(fcio->fcio_ibuf, ns_req32,
9499 			    sizeof (*ns_req32), mode)) {
9500 				rval = EFAULT;
9501 				kmem_free(ns_req, sizeof (*ns_req));
9502 				kmem_free(ns_req32, sizeof (*ns_req32));
9503 				break;
9504 			}
9505 
9506 			ns_req->ns_flags = ns_req32->ns_flags;
9507 			ns_req->ns_cmd = ns_req32->ns_cmd;
9508 			ns_req->ns_req_len = ns_req32->ns_req_len;
9509 			ns_req->ns_req_payload = ns_req32->ns_req_payload;
9510 			ns_req->ns_resp_len = ns_req32->ns_resp_len;
9511 			ns_req->ns_resp_payload = ns_req32->ns_resp_payload;
9512 			ns_req->ns_fctl_private = ns_req32->ns_fctl_private;
9513 			ns_req->ns_resp_hdr = ns_req32->ns_resp_hdr;
9514 
9515 			kmem_free(ns_req32, sizeof (*ns_req32));
9516 		} else {
9517 			if (fcio->fcio_ilen != sizeof (*ns_req)) {
9518 				rval = EINVAL;
9519 				break;
9520 			}
9521 
9522 			ns_req = kmem_zalloc(sizeof (*ns_req), KM_SLEEP);
9523 
9524 			if (ddi_copyin(fcio->fcio_ibuf, ns_req,
9525 			    sizeof (fc_ns_cmd_t), mode)) {
9526 				rval = EFAULT;
9527 				kmem_free(ns_req, sizeof (*ns_req));
9528 				break;
9529 			}
9530 		}
9531 
9532 		if (ns_req->ns_req_len <= 0) {
9533 			rval = EINVAL;
9534 			kmem_free(ns_req, sizeof (*ns_req));
9535 			break;
9536 		}
9537 
9538 		job = fctl_alloc_job(JOB_NS_CMD, 0, NULL, NULL, KM_SLEEP);
9539 		ASSERT(job != NULL);
9540 
9541 		ns_cmd = fctl_alloc_ns_cmd(ns_req->ns_req_len,
9542 		    ns_req->ns_resp_len, ns_req->ns_resp_len,
9543 		    FCTL_NS_FILL_NS_MAP, KM_SLEEP);
9544 		ASSERT(ns_cmd != NULL);
9545 		ns_cmd->ns_cmd_code = ns_req->ns_cmd;
9546 
9547 		if (ns_cmd->ns_cmd_code == NS_GA_NXT) {
9548 			ns_cmd->ns_gan_max = 1;
9549 			ns_cmd->ns_gan_index = 0;
9550 			ns_cmd->ns_gan_sid = FCTL_GAN_START_ID;
9551 		}
9552 
9553 		if (ddi_copyin(ns_req->ns_req_payload,
9554 		    ns_cmd->ns_cmd_buf, ns_req->ns_req_len, mode)) {
9555 			rval = EFAULT;
9556 			fctl_free_ns_cmd(ns_cmd);
9557 			fctl_dealloc_job(job);
9558 			kmem_free(ns_req, sizeof (*ns_req));
9559 			break;
9560 		}
9561 
9562 		job->job_private = (void *)ns_cmd;
9563 		fctl_enque_job(port, job);
9564 		fctl_jobwait(job);
9565 		rval = job->job_result;
9566 
9567 		if (rval == FC_SUCCESS) {
9568 			if (ns_req->ns_resp_len) {
9569 				if (ddi_copyout(ns_cmd->ns_data_buf,
9570 				    ns_req->ns_resp_payload,
9571 				    ns_cmd->ns_data_len, mode)) {
9572 					rval = EFAULT;
9573 					fctl_free_ns_cmd(ns_cmd);
9574 					fctl_dealloc_job(job);
9575 					kmem_free(ns_req, sizeof (*ns_req));
9576 					break;
9577 				}
9578 			}
9579 		} else {
9580 			rval = EIO;
9581 		}
9582 		ns_req->ns_resp_hdr = ns_cmd->ns_resp_hdr;
9583 		fctl_free_ns_cmd(ns_cmd);
9584 		fctl_dealloc_job(job);
9585 		kmem_free(ns_req, sizeof (*ns_req));
9586 
9587 		if (fp_fcio_copyout(fcio, data, mode)) {
9588 			rval = EFAULT;
9589 		}
9590 		break;
9591 	}
9592 
9593 	default:
9594 		rval = ENOTTY;
9595 		break;
9596 	}
9597 
9598 	/*
9599 	 * If set, reset the EXCL busy bit to
9600 	 * receive other exclusive access commands
9601 	 */
9602 	mutex_enter(&port->fp_mutex);
9603 	if (port->fp_flag & FP_EXCL_BUSY) {
9604 		port->fp_flag &= ~FP_EXCL_BUSY;
9605 	}
9606 	mutex_exit(&port->fp_mutex);
9607 
9608 	return (rval);
9609 }
9610 
9611 
9612 /*
9613  * This function assumes that the response length
9614  * is same regardless of data model (LP32 or LP64)
9615  * which is true for all the ioctls currently
9616  * supported.
9617  */
9618 static int
9619 fp_copyout(void *from, void *to, size_t len, int mode)
9620 {
9621 	return (ddi_copyout(from, to, len, mode));
9622 }
9623 
9624 /*
9625  * This function does the set rnid
9626  */
9627 static int
9628 fp_set_rnid(fc_local_port_t *port, intptr_t data, int mode, fcio_t *fcio)
9629 {
9630 	int		rval = 0;
9631 	fc_rnid_t	*rnid;
9632 	fc_fca_pm_t	pm;
9633 
9634 	/* Allocate memory for node id block */
9635 	rnid = kmem_zalloc(sizeof (fc_rnid_t), KM_SLEEP);
9636 
9637 	if (ddi_copyin(fcio->fcio_ibuf, rnid, sizeof (fc_rnid_t), mode)) {
9638 		FP_TRACE(FP_NHEAD1(3, 0), "fp_set_rnid: failed = %d", EFAULT);
9639 		kmem_free(rnid, sizeof (fc_rnid_t));
9640 		return (EFAULT);
9641 	}
9642 
9643 	/* Prepare the port management structure */
9644 	bzero((caddr_t)&pm, sizeof (pm));
9645 
9646 	pm.pm_cmd_flags = FC_FCA_PM_WRITE;
9647 	pm.pm_cmd_code	= FC_PORT_SET_NODE_ID;
9648 	pm.pm_data_len	= sizeof (*rnid);
9649 	pm.pm_data_buf	= (caddr_t)rnid;
9650 
9651 	/* Get the adapter's node data */
9652 	rval = port->fp_fca_tran->fca_port_manage(
9653 	    port->fp_fca_handle, &pm);
9654 
9655 	if (rval != FC_SUCCESS) {
9656 		fcio->fcio_errno = rval;
9657 		rval = EIO;
9658 		if (fp_fcio_copyout(fcio, data, mode)) {
9659 			rval = EFAULT;
9660 		}
9661 	} else {
9662 		mutex_enter(&port->fp_mutex);
9663 		/* copy to the port structure */
9664 		bcopy(rnid, &port->fp_rnid_params,
9665 		    sizeof (port->fp_rnid_params));
9666 		mutex_exit(&port->fp_mutex);
9667 	}
9668 
9669 	kmem_free(rnid, sizeof (fc_rnid_t));
9670 
9671 	if (rval != FC_SUCCESS) {
9672 		FP_TRACE(FP_NHEAD1(3, 0), "fp_set_rnid: failed = %d", rval);
9673 	}
9674 
9675 	return (rval);
9676 }
9677 
9678 /*
9679  * This function does the local pwwn get rnid
9680  */
9681 static int
9682 fp_get_rnid(fc_local_port_t *port, intptr_t data, int mode, fcio_t *fcio)
9683 {
9684 	fc_rnid_t		*rnid;
9685 	fc_fca_pm_t		pm;
9686 	int			rval = 0;
9687 	uint32_t		ret;
9688 
9689 	/* Allocate memory for rnid data block */
9690 	rnid = kmem_zalloc(sizeof (fc_rnid_t), KM_SLEEP);
9691 
9692 	mutex_enter(&port->fp_mutex);
9693 	if (port->fp_rnid_init == 1) {
9694 		bcopy(&port->fp_rnid_params, rnid, sizeof (fc_rnid_t));
9695 		mutex_exit(&port->fp_mutex);
9696 		/* xfer node info to userland */
9697 		if (ddi_copyout((void *)rnid, (void *)fcio->fcio_obuf,
9698 		    sizeof (*rnid), mode) == 0) {
9699 			if (fp_fcio_copyout(fcio, data, mode)) {
9700 				rval = EFAULT;
9701 			}
9702 		} else {
9703 			rval = EFAULT;
9704 		}
9705 
9706 		kmem_free(rnid, sizeof (fc_rnid_t));
9707 
9708 		if (rval != FC_SUCCESS) {
9709 			FP_TRACE(FP_NHEAD1(3, 0), "fp_get_rnid: failed = %d",
9710 			    rval);
9711 		}
9712 
9713 		return (rval);
9714 	}
9715 	mutex_exit(&port->fp_mutex);
9716 
9717 	/* Prepare the port management structure */
9718 	bzero((caddr_t)&pm, sizeof (pm));
9719 
9720 	pm.pm_cmd_flags = FC_FCA_PM_READ;
9721 	pm.pm_cmd_code	= FC_PORT_GET_NODE_ID;
9722 	pm.pm_data_len	= sizeof (fc_rnid_t);
9723 	pm.pm_data_buf	= (caddr_t)rnid;
9724 
9725 	/* Get the adapter's node data */
9726 	ret = port->fp_fca_tran->fca_port_manage(
9727 	    port->fp_fca_handle,
9728 	    &pm);
9729 
9730 	if (ret == FC_SUCCESS) {
9731 		/* initialize in the port_info */
9732 		mutex_enter(&port->fp_mutex);
9733 		port->fp_rnid_init = 1;
9734 		bcopy(rnid, &port->fp_rnid_params, sizeof (*rnid));
9735 		mutex_exit(&port->fp_mutex);
9736 
9737 		/* xfer node info to userland */
9738 		if (ddi_copyout((void *)rnid,
9739 		    (void *)fcio->fcio_obuf,
9740 		    sizeof (*rnid), mode) == 0) {
9741 			if (fp_fcio_copyout(fcio, data,
9742 			    mode)) {
9743 				rval = EFAULT;
9744 			}
9745 		} else {
9746 			rval = EFAULT;
9747 		}
9748 	} else {
9749 		rval = EIO;
9750 		fcio->fcio_errno = ret;
9751 		if (fp_fcio_copyout(fcio, data, mode)) {
9752 			rval = EFAULT;
9753 		}
9754 	}
9755 
9756 	kmem_free(rnid, sizeof (fc_rnid_t));
9757 
9758 	if (rval != FC_SUCCESS) {
9759 		FP_TRACE(FP_NHEAD1(3, 0), "fp_get_rnid: failed = %d", rval);
9760 	}
9761 
9762 	return (rval);
9763 }
9764 
9765 static int
9766 fp_send_rnid(fc_local_port_t *port, intptr_t data, int mode, fcio_t *fcio,
9767     la_wwn_t *pwwn)
9768 {
9769 	int			rval = 0;
9770 	fc_remote_port_t	*pd;
9771 	fp_cmd_t		*cmd;
9772 	job_request_t		*job;
9773 	la_els_rnid_acc_t	*rnid_acc;
9774 
9775 	pd = fctl_get_remote_port_by_pwwn(port, pwwn);
9776 	if (pd == NULL) {
9777 		/*
9778 		 * We can safely assume that the destination port
9779 		 * is logged in. Either the user land will explicitly
9780 		 * login before issuing RNID ioctl or the device would
9781 		 * have been configured, meaning already logged in.
9782 		 */
9783 
9784 		FP_TRACE(FP_NHEAD1(3, 0), "fp_send_rnid: failed = %d", ENXIO);
9785 
9786 		return (ENXIO);
9787 	}
9788 	/*
9789 	 * Allocate job structure and set job_code as DUMMY,
9790 	 * because we will not go thorugh the job thread.
9791 	 * Instead fp_sendcmd() is called directly here.
9792 	 */
9793 	job = fctl_alloc_job(JOB_DUMMY, JOB_TYPE_FP_ASYNC,
9794 	    NULL, NULL, KM_SLEEP);
9795 
9796 	ASSERT(job != NULL);
9797 
9798 	job->job_counter = 1;
9799 
9800 	cmd = fp_alloc_pkt(port, sizeof (la_els_rnid_t),
9801 	    sizeof (la_els_rnid_acc_t), KM_SLEEP, pd);
9802 	if (cmd == NULL) {
9803 		fcio->fcio_errno = FC_NOMEM;
9804 		rval = ENOMEM;
9805 
9806 		fctl_dealloc_job(job);
9807 		if (fp_fcio_copyout(fcio, data, mode)) {
9808 			rval = EFAULT;
9809 		}
9810 
9811 		FP_TRACE(FP_NHEAD1(3, 0), "fp_send_rnid: failed = %d", rval);
9812 
9813 		return (rval);
9814 	}
9815 
9816 	/* Allocate memory for node id accept block */
9817 	rnid_acc = kmem_zalloc(sizeof (la_els_rnid_acc_t), KM_SLEEP);
9818 
9819 	mutex_enter(&port->fp_mutex);
9820 	mutex_enter(&pd->pd_mutex);
9821 
9822 	cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
9823 	cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
9824 	cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
9825 	cmd->cmd_retry_count = 1;
9826 	cmd->cmd_ulp_pkt = NULL;
9827 
9828 	fp_rnid_init(cmd, fcio->fcio_cmd_flags, job);
9829 
9830 	job->job_private = (void *)rnid_acc;
9831 
9832 	pd->pd_flags = PD_ELS_IN_PROGRESS;
9833 
9834 	mutex_exit(&pd->pd_mutex);
9835 	mutex_exit(&port->fp_mutex);
9836 
9837 	if (fp_sendcmd(port, cmd, port->fp_fca_handle) == FC_SUCCESS) {
9838 		fctl_jobwait(job);
9839 		fcio->fcio_errno = job->job_result;
9840 		if (job->job_result == FC_SUCCESS) {
9841 			int rnid_cnt;
9842 			ASSERT(pd != NULL);
9843 			/*
9844 			 * node id block is now available.
9845 			 * Copy it to userland
9846 			 */
9847 			ASSERT(job->job_private == (void *)rnid_acc);
9848 
9849 			/* get the response length */
9850 			rnid_cnt = sizeof (ls_code_t) + sizeof (fc_rnid_hdr_t) +
9851 			    rnid_acc->hdr.cmn_len +
9852 			    rnid_acc->hdr.specific_len;
9853 
9854 			if (fcio->fcio_olen < rnid_cnt) {
9855 				rval = EINVAL;
9856 			} else if (ddi_copyout((void *)rnid_acc,
9857 			    (void *)fcio->fcio_obuf,
9858 			    rnid_cnt, mode) == 0) {
9859 				if (fp_fcio_copyout(fcio, data,
9860 				    mode)) {
9861 					rval = EFAULT;
9862 				}
9863 			} else {
9864 				rval = EFAULT;
9865 			}
9866 		} else {
9867 			rval = EIO;
9868 		}
9869 	} else {
9870 		rval = EIO;
9871 		if (pd) {
9872 			mutex_enter(&pd->pd_mutex);
9873 			pd->pd_flags = PD_IDLE;
9874 			mutex_exit(&pd->pd_mutex);
9875 		}
9876 		fp_free_pkt(cmd);
9877 	}
9878 
9879 	fctl_dealloc_job(job);
9880 	kmem_free(rnid_acc, sizeof (la_els_rnid_acc_t));
9881 
9882 	if (fp_fcio_copyout(fcio, data, mode)) {
9883 		rval = EFAULT;
9884 	}
9885 
9886 	if (rval != FC_SUCCESS) {
9887 		FP_TRACE(FP_NHEAD1(3, 0), "fp_send_rnid: failed = %d", rval);
9888 	}
9889 
9890 	return (rval);
9891 }
9892 
9893 /*
9894  * Copy out to userland
9895  */
9896 static int
9897 fp_fcio_copyout(fcio_t *fcio, intptr_t data, int mode)
9898 {
9899 	int rval;
9900 
9901 #ifdef	_MULTI_DATAMODEL
9902 	switch (ddi_model_convert_from(mode & FMODELS)) {
9903 	case DDI_MODEL_ILP32: {
9904 		struct fcio32 fcio32;
9905 
9906 		fcio32.fcio_xfer = fcio->fcio_xfer;
9907 		fcio32.fcio_cmd = fcio->fcio_cmd;
9908 		fcio32.fcio_flags = fcio->fcio_flags;
9909 		fcio32.fcio_cmd_flags = fcio->fcio_cmd_flags;
9910 		fcio32.fcio_ilen = fcio->fcio_ilen;
9911 		fcio32.fcio_ibuf =
9912 		    (caddr32_t)(uintptr_t)fcio->fcio_ibuf;
9913 		fcio32.fcio_olen = fcio->fcio_olen;
9914 		fcio32.fcio_obuf =
9915 		    (caddr32_t)(uintptr_t)fcio->fcio_obuf;
9916 		fcio32.fcio_alen = fcio->fcio_alen;
9917 		fcio32.fcio_abuf =
9918 		    (caddr32_t)(uintptr_t)fcio->fcio_abuf;
9919 		fcio32.fcio_errno = fcio->fcio_errno;
9920 
9921 		rval = ddi_copyout((void *)&fcio32, (void *)data,
9922 		    sizeof (struct fcio32), mode);
9923 		break;
9924 	}
9925 	case DDI_MODEL_NONE:
9926 		rval = ddi_copyout((void *)fcio, (void *)data,
9927 		    sizeof (fcio_t), mode);
9928 		break;
9929 	}
9930 #else
9931 	rval = ddi_copyout((void *)fcio, (void *)data, sizeof (fcio_t), mode);
9932 #endif
9933 
9934 	return (rval);
9935 }
9936 
9937 
9938 static void
9939 fp_p2p_online(fc_local_port_t *port, job_request_t *job)
9940 {
9941 	uint32_t		listlen;
9942 	fc_portmap_t		*changelist;
9943 
9944 	ASSERT(MUTEX_HELD(&port->fp_mutex));
9945 	ASSERT(port->fp_topology == FC_TOP_PT_PT);
9946 	ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
9947 
9948 	listlen = 0;
9949 	changelist = NULL;
9950 
9951 	if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) {
9952 		if (port->fp_statec_busy > 1) {
9953 			job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION;
9954 		}
9955 	}
9956 	mutex_exit(&port->fp_mutex);
9957 
9958 	if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) {
9959 		fctl_fillout_map(port, &changelist, &listlen, 1, 0, 0);
9960 		(void) fp_ulp_statec_cb(port, FC_STATE_ONLINE, changelist,
9961 		    listlen, listlen, KM_SLEEP);
9962 
9963 		mutex_enter(&port->fp_mutex);
9964 	} else {
9965 		ASSERT(changelist == NULL && listlen == 0);
9966 		mutex_enter(&port->fp_mutex);
9967 		if (--port->fp_statec_busy == 0) {
9968 			port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
9969 		}
9970 	}
9971 }
9972 
9973 static int
9974 fp_fillout_p2pmap(fc_local_port_t *port, fcio_t *fcio, int mode)
9975 {
9976 	int			rval;
9977 	int			count;
9978 	int			index;
9979 	int			num_devices;
9980 	fc_remote_node_t	*node;
9981 	fc_port_dev_t		*devlist;
9982 	struct pwwn_hash	*head;
9983 	fc_remote_port_t	*pd;
9984 
9985 	ASSERT(MUTEX_HELD(&port->fp_mutex));
9986 
9987 	num_devices = fcio->fcio_olen / sizeof (fc_port_dev_t);
9988 
9989 	devlist = kmem_zalloc(sizeof (fc_port_dev_t) * num_devices, KM_SLEEP);
9990 
9991 	for (count = index = 0; index < pwwn_table_size; index++) {
9992 		head = &port->fp_pwwn_table[index];
9993 		pd = head->pwwn_head;
9994 		while (pd != NULL) {
9995 			mutex_enter(&pd->pd_mutex);
9996 			if (pd->pd_state == PORT_DEVICE_INVALID) {
9997 				mutex_exit(&pd->pd_mutex);
9998 				pd = pd->pd_wwn_hnext;
9999 				continue;
10000 			}
10001 
10002 			devlist[count].dev_state = pd->pd_state;
10003 			devlist[count].dev_hard_addr = pd->pd_hard_addr;
10004 			devlist[count].dev_did = pd->pd_port_id;
10005 			devlist[count].dev_did.priv_lilp_posit =
10006 			    (uint8_t)(index & 0xff);
10007 			bcopy((caddr_t)pd->pd_fc4types,
10008 			    (caddr_t)devlist[count].dev_type,
10009 			    sizeof (pd->pd_fc4types));
10010 
10011 			bcopy((caddr_t)&pd->pd_port_name,
10012 			    (caddr_t)&devlist[count].dev_pwwn,
10013 			    sizeof (la_wwn_t));
10014 
10015 			node = pd->pd_remote_nodep;
10016 			mutex_exit(&pd->pd_mutex);
10017 
10018 			if (node) {
10019 				mutex_enter(&node->fd_mutex);
10020 				bcopy((caddr_t)&node->fd_node_name,
10021 				    (caddr_t)&devlist[count].dev_nwwn,
10022 				    sizeof (la_wwn_t));
10023 				mutex_exit(&node->fd_mutex);
10024 			}
10025 			count++;
10026 			if (count >= num_devices) {
10027 				goto found;
10028 			}
10029 		}
10030 	}
10031 found:
10032 	if (fp_copyout((void *)&count, (void *)fcio->fcio_abuf,
10033 	    sizeof (count), mode)) {
10034 		rval = FC_FAILURE;
10035 	} else if (fp_copyout((void *)devlist, (void *)fcio->fcio_obuf,
10036 	    sizeof (fc_port_dev_t) * num_devices, mode)) {
10037 		rval = FC_FAILURE;
10038 	} else {
10039 		rval = FC_SUCCESS;
10040 	}
10041 
10042 	kmem_free(devlist, sizeof (fc_port_dev_t) * num_devices);
10043 
10044 	return (rval);
10045 }
10046 
10047 
10048 /*
10049  * Handle Fabric ONLINE
10050  */
10051 static void
10052 fp_fabric_online(fc_local_port_t *port, job_request_t *job)
10053 {
10054 	int			index;
10055 	int			rval;
10056 	int			dbg_count;
10057 	int			count = 0;
10058 	char			ww_name[17];
10059 	uint32_t		d_id;
10060 	uint32_t		listlen;
10061 	fctl_ns_req_t		*ns_cmd;
10062 	struct pwwn_hash	*head;
10063 	fc_remote_port_t	*pd;
10064 	fc_remote_port_t	*npd;
10065 	fc_portmap_t		*changelist;
10066 
10067 	ASSERT(MUTEX_HELD(&port->fp_mutex));
10068 	ASSERT(FC_IS_TOP_SWITCH(port->fp_topology));
10069 	ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
10070 
10071 	ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t),
10072 	    sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t),
10073 	    0, KM_SLEEP);
10074 
10075 	ASSERT(ns_cmd != NULL);
10076 
10077 	ns_cmd->ns_cmd_code = NS_GID_PN;
10078 
10079 	/*
10080 	 * Check if orphans are showing up now
10081 	 */
10082 	if (port->fp_orphan_count) {
10083 		fc_orphan_t	*orp;
10084 		fc_orphan_t	*norp = NULL;
10085 		fc_orphan_t	*prev = NULL;
10086 
10087 		for (orp = port->fp_orphan_list; orp; orp = norp) {
10088 			norp = orp->orp_next;
10089 			mutex_exit(&port->fp_mutex);
10090 			orp->orp_nscan++;
10091 
10092 			job->job_counter = 1;
10093 			job->job_result = FC_SUCCESS;
10094 
10095 			((ns_req_gid_pn_t *)
10096 			    (ns_cmd->ns_cmd_buf))->pwwn = orp->orp_pwwn;
10097 			((ns_resp_gid_pn_t *)
10098 			    ns_cmd->ns_data_buf)->pid.port_id = 0;
10099 			((ns_resp_gid_pn_t *)
10100 			    ns_cmd->ns_data_buf)->pid.priv_lilp_posit = 0;
10101 
10102 			rval = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP);
10103 			if (rval == FC_SUCCESS) {
10104 				d_id =
10105 				    BE_32(*((uint32_t *)ns_cmd->ns_data_buf));
10106 				pd = fp_create_remote_port_by_ns(port,
10107 				    d_id, KM_SLEEP);
10108 
10109 				if (pd != NULL) {
10110 					fc_wwn_to_str(&orp->orp_pwwn, ww_name);
10111 
10112 					fp_printf(port, CE_WARN, FP_LOG_ONLY,
10113 					    0, NULL, "N_x Port with D_ID=%x,"
10114 					    " PWWN=%s reappeared in fabric",
10115 					    d_id, ww_name);
10116 
10117 					mutex_enter(&port->fp_mutex);
10118 					if (prev) {
10119 						prev->orp_next = orp->orp_next;
10120 					} else {
10121 						ASSERT(orp ==
10122 						    port->fp_orphan_list);
10123 						port->fp_orphan_list =
10124 						    orp->orp_next;
10125 					}
10126 					port->fp_orphan_count--;
10127 					mutex_exit(&port->fp_mutex);
10128 					kmem_free(orp, sizeof (*orp));
10129 					count++;
10130 
10131 					mutex_enter(&pd->pd_mutex);
10132 					pd->pd_flags = PD_ELS_MARK;
10133 
10134 					mutex_exit(&pd->pd_mutex);
10135 				} else {
10136 					prev = orp;
10137 				}
10138 			} else {
10139 				if (orp->orp_nscan == FC_ORPHAN_SCAN_LIMIT) {
10140 					fc_wwn_to_str(&orp->orp_pwwn, ww_name);
10141 
10142 					fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0,
10143 					    NULL,
10144 					    " Port WWN %s removed from orphan"
10145 					    " list after %d scans", ww_name,
10146 					    orp->orp_nscan);
10147 
10148 					mutex_enter(&port->fp_mutex);
10149 					if (prev) {
10150 						prev->orp_next = orp->orp_next;
10151 					} else {
10152 						ASSERT(orp ==
10153 						    port->fp_orphan_list);
10154 						port->fp_orphan_list =
10155 						    orp->orp_next;
10156 					}
10157 					port->fp_orphan_count--;
10158 					mutex_exit(&port->fp_mutex);
10159 
10160 					kmem_free(orp, sizeof (*orp));
10161 				} else {
10162 					prev = orp;
10163 				}
10164 			}
10165 			mutex_enter(&port->fp_mutex);
10166 		}
10167 	}
10168 
10169 	/*
10170 	 * Walk the Port WWN hash table, reestablish LOGIN
10171 	 * if a LOGIN is already performed on a particular
10172 	 * device; Any failure to LOGIN should mark the
10173 	 * port device OLD.
10174 	 */
10175 	for (index = 0; index < pwwn_table_size; index++) {
10176 		head = &port->fp_pwwn_table[index];
10177 		npd = head->pwwn_head;
10178 
10179 		while ((pd = npd) != NULL) {
10180 			la_wwn_t	*pwwn;
10181 
10182 			npd = pd->pd_wwn_hnext;
10183 
10184 			/*
10185 			 * Don't count in the port devices that are new
10186 			 * unless the total number of devices visible
10187 			 * through this port is less than FP_MAX_DEVICES
10188 			 */
10189 			mutex_enter(&pd->pd_mutex);
10190 			if (port->fp_dev_count >= FP_MAX_DEVICES ||
10191 			    (port->fp_options & FP_TARGET_MODE)) {
10192 				if (pd->pd_type == PORT_DEVICE_NEW ||
10193 				    pd->pd_flags == PD_ELS_MARK ||
10194 				    pd->pd_recepient != PD_PLOGI_INITIATOR) {
10195 					mutex_exit(&pd->pd_mutex);
10196 					continue;
10197 				}
10198 			} else {
10199 				if (pd->pd_flags == PD_ELS_MARK ||
10200 				    pd->pd_recepient != PD_PLOGI_INITIATOR) {
10201 					mutex_exit(&pd->pd_mutex);
10202 					continue;
10203 				}
10204 				pd->pd_type = PORT_DEVICE_OLD;
10205 			}
10206 			count++;
10207 
10208 			/*
10209 			 * Consult with the name server about D_ID changes
10210 			 */
10211 			job->job_counter = 1;
10212 			job->job_result = FC_SUCCESS;
10213 
10214 			((ns_req_gid_pn_t *)
10215 			    (ns_cmd->ns_cmd_buf))->pwwn = pd->pd_port_name;
10216 			((ns_resp_gid_pn_t *)
10217 			    ns_cmd->ns_data_buf)->pid.port_id = 0;
10218 
10219 			((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->
10220 			    pid.priv_lilp_posit = 0;
10221 
10222 			pwwn = &pd->pd_port_name;
10223 			pd->pd_flags = PD_ELS_MARK;
10224 
10225 			mutex_exit(&pd->pd_mutex);
10226 			mutex_exit(&port->fp_mutex);
10227 
10228 			rval = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP);
10229 			if (rval != FC_SUCCESS) {
10230 				fc_wwn_to_str(pwwn, ww_name);
10231 
10232 				mutex_enter(&pd->pd_mutex);
10233 				d_id = pd->pd_port_id.port_id;
10234 				pd->pd_type = PORT_DEVICE_DELETE;
10235 				mutex_exit(&pd->pd_mutex);
10236 
10237 				FP_TRACE(FP_NHEAD1(3, 0),
10238 				    "fp_fabric_online: PD "
10239 				    "disappeared; d_id=%x, PWWN=%s",
10240 				    d_id, ww_name);
10241 
10242 				FP_TRACE(FP_NHEAD2(9, 0),
10243 				    "N_x Port with D_ID=%x, PWWN=%s"
10244 				    " disappeared from fabric", d_id,
10245 				    ww_name);
10246 
10247 				mutex_enter(&port->fp_mutex);
10248 				continue;
10249 			}
10250 
10251 			d_id = BE_32(*((uint32_t *)ns_cmd->ns_data_buf));
10252 
10253 			mutex_enter(&port->fp_mutex);
10254 			mutex_enter(&pd->pd_mutex);
10255 			if (d_id != pd->pd_port_id.port_id) {
10256 				fctl_delist_did_table(port, pd);
10257 				fc_wwn_to_str(pwwn, ww_name);
10258 
10259 				FP_TRACE(FP_NHEAD2(9, 0),
10260 				    "D_ID of a device with PWWN %s changed."
10261 				    " New D_ID = %x, OLD D_ID = %x", ww_name,
10262 				    d_id, pd->pd_port_id.port_id);
10263 
10264 				pd->pd_port_id.port_id = BE_32(d_id);
10265 				pd->pd_type = PORT_DEVICE_CHANGED;
10266 				fctl_enlist_did_table(port, pd);
10267 			}
10268 			mutex_exit(&pd->pd_mutex);
10269 
10270 		}
10271 	}
10272 
10273 	if (ns_cmd) {
10274 		fctl_free_ns_cmd(ns_cmd);
10275 	}
10276 
10277 	listlen = 0;
10278 	changelist = NULL;
10279 	if (count) {
10280 		if (port->fp_soft_state & FP_SOFT_IN_FCA_RESET) {
10281 			port->fp_soft_state &= ~FP_SOFT_IN_FCA_RESET;
10282 			mutex_exit(&port->fp_mutex);
10283 			delay(drv_usectohz(FLA_RR_TOV * 1000 * 1000));
10284 			mutex_enter(&port->fp_mutex);
10285 		}
10286 
10287 		dbg_count = 0;
10288 
10289 		job->job_counter = count;
10290 
10291 		for (index = 0; index < pwwn_table_size; index++) {
10292 			head = &port->fp_pwwn_table[index];
10293 			npd = head->pwwn_head;
10294 
10295 			while ((pd = npd) != NULL) {
10296 				npd = pd->pd_wwn_hnext;
10297 
10298 				mutex_enter(&pd->pd_mutex);
10299 				if (pd->pd_flags != PD_ELS_MARK) {
10300 					mutex_exit(&pd->pd_mutex);
10301 					continue;
10302 				}
10303 
10304 				dbg_count++;
10305 
10306 				/*
10307 				 * If it is already marked deletion, nothing
10308 				 * else to do.
10309 				 */
10310 				if (pd->pd_type == PORT_DEVICE_DELETE) {
10311 					pd->pd_type = PORT_DEVICE_OLD;
10312 
10313 					mutex_exit(&pd->pd_mutex);
10314 					mutex_exit(&port->fp_mutex);
10315 					fp_jobdone(job);
10316 					mutex_enter(&port->fp_mutex);
10317 
10318 					continue;
10319 				}
10320 
10321 				/*
10322 				 * If it is freshly discovered out of
10323 				 * the orphan list, nothing else to do
10324 				 */
10325 				if (pd->pd_type == PORT_DEVICE_NEW) {
10326 					pd->pd_flags = PD_IDLE;
10327 
10328 					mutex_exit(&pd->pd_mutex);
10329 					mutex_exit(&port->fp_mutex);
10330 					fp_jobdone(job);
10331 					mutex_enter(&port->fp_mutex);
10332 
10333 					continue;
10334 				}
10335 
10336 				pd->pd_flags = PD_IDLE;
10337 				d_id = pd->pd_port_id.port_id;
10338 
10339 				/*
10340 				 * Explicitly mark all devices OLD; successful
10341 				 * PLOGI should reset this to either NO_CHANGE
10342 				 * or CHANGED.
10343 				 */
10344 				if (pd->pd_type != PORT_DEVICE_CHANGED) {
10345 					pd->pd_type = PORT_DEVICE_OLD;
10346 				}
10347 
10348 				mutex_exit(&pd->pd_mutex);
10349 				mutex_exit(&port->fp_mutex);
10350 
10351 				rval = fp_port_login(port, d_id, job,
10352 				    FP_CMD_PLOGI_RETAIN, KM_SLEEP, pd, NULL);
10353 
10354 				if (rval != FC_SUCCESS) {
10355 					fp_jobdone(job);
10356 				}
10357 				mutex_enter(&port->fp_mutex);
10358 			}
10359 		}
10360 		mutex_exit(&port->fp_mutex);
10361 
10362 		ASSERT(dbg_count == count);
10363 		fp_jobwait(job);
10364 
10365 		mutex_enter(&port->fp_mutex);
10366 
10367 		ASSERT(port->fp_statec_busy > 0);
10368 		if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) {
10369 			if (port->fp_statec_busy > 1) {
10370 				job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION;
10371 			}
10372 		}
10373 		mutex_exit(&port->fp_mutex);
10374 	} else {
10375 		ASSERT(port->fp_statec_busy > 0);
10376 		if (port->fp_statec_busy > 1) {
10377 			job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION;
10378 		}
10379 		mutex_exit(&port->fp_mutex);
10380 	}
10381 
10382 	if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) {
10383 		fctl_fillout_map(port, &changelist, &listlen, 1, 0, 0);
10384 
10385 		(void) fp_ulp_statec_cb(port, FC_STATE_ONLINE, changelist,
10386 		    listlen, listlen, KM_SLEEP);
10387 
10388 		mutex_enter(&port->fp_mutex);
10389 	} else {
10390 		ASSERT(changelist == NULL && listlen == 0);
10391 		mutex_enter(&port->fp_mutex);
10392 		if (--port->fp_statec_busy == 0) {
10393 			port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
10394 		}
10395 	}
10396 }
10397 
10398 
10399 /*
10400  * Fill out device list for userland ioctl in private loop
10401  */
10402 static int
10403 fp_fillout_loopmap(fc_local_port_t *port, fcio_t *fcio, int mode)
10404 {
10405 	int			rval;
10406 	int			count;
10407 	int			index;
10408 	int			num_devices;
10409 	fc_remote_node_t	*node;
10410 	fc_port_dev_t		*devlist;
10411 	int			lilp_device_count;
10412 	fc_lilpmap_t		*lilp_map;
10413 	uchar_t			*alpa_list;
10414 
10415 	ASSERT(MUTEX_HELD(&port->fp_mutex));
10416 
10417 	num_devices = fcio->fcio_olen / sizeof (fc_port_dev_t);
10418 	if (port->fp_total_devices > port->fp_dev_count &&
10419 	    num_devices >= port->fp_total_devices) {
10420 		job_request_t	*job;
10421 
10422 		mutex_exit(&port->fp_mutex);
10423 		job = fctl_alloc_job(JOB_PORT_GETMAP, 0, NULL, NULL, KM_SLEEP);
10424 		job->job_counter = 1;
10425 
10426 		mutex_enter(&port->fp_mutex);
10427 		fp_get_loopmap(port, job);
10428 		mutex_exit(&port->fp_mutex);
10429 
10430 		fp_jobwait(job);
10431 		fctl_dealloc_job(job);
10432 	} else {
10433 		mutex_exit(&port->fp_mutex);
10434 	}
10435 	devlist = kmem_zalloc(sizeof (*devlist) * num_devices, KM_SLEEP);
10436 
10437 	mutex_enter(&port->fp_mutex);
10438 
10439 	/*
10440 	 * Applications are accustomed to getting the device list in
10441 	 * LILP map order. The HBA firmware usually returns the device
10442 	 * map in the LILP map order and diagnostic applications would
10443 	 * prefer to receive in the device list in that order too
10444 	 */
10445 	lilp_map = &port->fp_lilp_map;
10446 	alpa_list = &lilp_map->lilp_alpalist[0];
10447 
10448 	/*
10449 	 * the length field corresponds to the offset in the LILP frame
10450 	 * which begins with 1. The thing to note here is that the
10451 	 * lilp_device_count is 1 more than fp->fp_total_devices since
10452 	 * the host adapter's alpa also shows up in the lilp map. We
10453 	 * don't however return details of the host adapter since
10454 	 * fctl_get_remote_port_by_did fails for the host adapter's ALPA
10455 	 * and applications are required to issue the FCIO_GET_HOST_PARAMS
10456 	 * ioctl to obtain details about the host adapter port.
10457 	 */
10458 	lilp_device_count = lilp_map->lilp_length;
10459 
10460 	for (count = index = 0; index < lilp_device_count &&
10461 	    count < num_devices; index++) {
10462 		uint32_t d_id;
10463 		fc_remote_port_t *pd;
10464 
10465 		d_id = alpa_list[index];
10466 
10467 		mutex_exit(&port->fp_mutex);
10468 		pd = fctl_get_remote_port_by_did(port, d_id);
10469 		mutex_enter(&port->fp_mutex);
10470 
10471 		if (pd != NULL) {
10472 			mutex_enter(&pd->pd_mutex);
10473 
10474 			if (pd->pd_state == PORT_DEVICE_INVALID) {
10475 				mutex_exit(&pd->pd_mutex);
10476 				continue;
10477 			}
10478 
10479 			devlist[count].dev_state = pd->pd_state;
10480 			devlist[count].dev_hard_addr = pd->pd_hard_addr;
10481 			devlist[count].dev_did = pd->pd_port_id;
10482 			devlist[count].dev_did.priv_lilp_posit =
10483 			    (uint8_t)(index & 0xff);
10484 			bcopy((caddr_t)pd->pd_fc4types,
10485 			    (caddr_t)devlist[count].dev_type,
10486 			    sizeof (pd->pd_fc4types));
10487 
10488 			bcopy((caddr_t)&pd->pd_port_name,
10489 			    (caddr_t)&devlist[count].dev_pwwn,
10490 			    sizeof (la_wwn_t));
10491 
10492 			node = pd->pd_remote_nodep;
10493 			mutex_exit(&pd->pd_mutex);
10494 
10495 			if (node) {
10496 				mutex_enter(&node->fd_mutex);
10497 				bcopy((caddr_t)&node->fd_node_name,
10498 				    (caddr_t)&devlist[count].dev_nwwn,
10499 				    sizeof (la_wwn_t));
10500 				mutex_exit(&node->fd_mutex);
10501 			}
10502 			count++;
10503 		}
10504 	}
10505 
10506 	if (fp_copyout((void *)&count, (void *)fcio->fcio_abuf,
10507 	    sizeof (count), mode)) {
10508 		rval = FC_FAILURE;
10509 	}
10510 
10511 	if (fp_copyout((void *)devlist, (void *)fcio->fcio_obuf,
10512 	    sizeof (fc_port_dev_t) * num_devices, mode)) {
10513 		rval = FC_FAILURE;
10514 	} else {
10515 		rval = FC_SUCCESS;
10516 	}
10517 
10518 	kmem_free(devlist, sizeof (*devlist) * num_devices);
10519 	ASSERT(MUTEX_HELD(&port->fp_mutex));
10520 
10521 	return (rval);
10522 }
10523 
10524 
10525 /*
10526  * Completion function for responses to unsolicited commands
10527  */
10528 static void
10529 fp_unsol_intr(fc_packet_t *pkt)
10530 {
10531 	fp_cmd_t	*cmd;
10532 	fc_local_port_t *port;
10533 
10534 	cmd = pkt->pkt_ulp_private;
10535 	port = cmd->cmd_port;
10536 
10537 	mutex_enter(&port->fp_mutex);
10538 	port->fp_out_fpcmds--;
10539 	mutex_exit(&port->fp_mutex);
10540 
10541 	if (pkt->pkt_state != FC_PKT_SUCCESS) {
10542 		fp_printf(port, CE_WARN, FP_LOG_ONLY, 0, pkt,
10543 		    "couldn't post response to unsolicited request;"
10544 		    " ox_id=%x rx_id=%x", pkt->pkt_cmd_fhdr.ox_id,
10545 		    pkt->pkt_resp_fhdr.rx_id);
10546 	}
10547 
10548 	if (cmd == port->fp_els_resp_pkt) {
10549 		mutex_enter(&port->fp_mutex);
10550 		port->fp_els_resp_pkt_busy = 0;
10551 		mutex_exit(&port->fp_mutex);
10552 		return;
10553 	}
10554 
10555 	fp_free_pkt(cmd);
10556 }
10557 
10558 
10559 /*
10560  * solicited LINIT ELS completion function
10561  */
10562 static void
10563 fp_linit_intr(fc_packet_t *pkt)
10564 {
10565 	fp_cmd_t		*cmd;
10566 	job_request_t		*job;
10567 	fc_linit_resp_t		acc;
10568 	fc_local_port_t *port = ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port;
10569 
10570 	cmd = (fp_cmd_t *)pkt->pkt_ulp_private;
10571 
10572 	mutex_enter(&cmd->cmd_port->fp_mutex);
10573 	cmd->cmd_port->fp_out_fpcmds--;
10574 	mutex_exit(&cmd->cmd_port->fp_mutex);
10575 
10576 	if (FP_IS_PKT_ERROR(pkt)) {
10577 		(void) fp_common_intr(pkt, 1);
10578 		return;
10579 	}
10580 
10581 	job = cmd->cmd_job;
10582 
10583 	FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&acc,
10584 	    (uint8_t *)pkt->pkt_resp, sizeof (acc), DDI_DEV_AUTOINCR);
10585 	if (acc.status != FC_LINIT_SUCCESS) {
10586 		job->job_result = FC_FAILURE;
10587 	} else {
10588 		job->job_result = FC_SUCCESS;
10589 	}
10590 
10591 	fp_iodone(cmd);
10592 }
10593 
10594 
10595 /*
10596  * Decode the unsolicited request; For FC-4 Device and Link data frames
10597  * notify the registered ULP of this FC-4 type right here. For Unsolicited
10598  * ELS requests, submit a request to the job_handler thread to work on it.
10599  * The intent is to act quickly on the FC-4 unsolicited link and data frames
10600  * and save much of the interrupt time processing of unsolicited ELS requests
10601  * and hand it off to the job_handler thread.
10602  */
10603 static void
10604 fp_unsol_cb(opaque_t port_handle, fc_unsol_buf_t *buf, uint32_t type)
10605 {
10606 	uchar_t		r_ctl;
10607 	uchar_t		ls_code;
10608 	uint32_t	s_id;
10609 	uint32_t	rscn_count = FC_INVALID_RSCN_COUNT;
10610 	uint32_t	cb_arg;
10611 	fp_cmd_t	*cmd;
10612 	fc_local_port_t *port;
10613 	job_request_t	*job;
10614 	fc_remote_port_t	*pd;
10615 
10616 	port = port_handle;
10617 
10618 	FP_TRACE(FP_NHEAD1(1, 0), "fp_unsol_cb: s_id=%x,"
10619 	    " d_id=%x, type=%x, r_ctl=%x, f_ctl=%x"
10620 	    " seq_id=%x, df_ctl=%x, seq_cnt=%x, ox_id=%x, rx_id=%x"
10621 	    " ro=%x, buffer[0]:%x", buf->ub_frame.s_id, buf->ub_frame.d_id,
10622 	    buf->ub_frame.type, buf->ub_frame.r_ctl, buf->ub_frame.f_ctl,
10623 	    buf->ub_frame.seq_id, buf->ub_frame.df_ctl, buf->ub_frame.seq_cnt,
10624 	    buf->ub_frame.ox_id, buf->ub_frame.rx_id, buf->ub_frame.ro,
10625 	    buf->ub_buffer[0]);
10626 
10627 	if (type & 0x80000000) {
10628 		/*
10629 		 * Huh ? Nothing much can be done without
10630 		 * a valid buffer. So just exit.
10631 		 */
10632 		return;
10633 	}
10634 	/*
10635 	 * If the unsolicited interrupts arrive while it isn't
10636 	 * safe to handle unsolicited callbacks; Drop them, yes,
10637 	 * drop them on the floor
10638 	 */
10639 	mutex_enter(&port->fp_mutex);
10640 	port->fp_active_ubs++;
10641 	if ((port->fp_soft_state &
10642 	    (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN)) ||
10643 	    FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) {
10644 
10645 		FP_TRACE(FP_NHEAD1(3, 0), "fp_unsol_cb: port state is "
10646 		    "not ONLINE. s_id=%x, d_id=%x, type=%x, "
10647 		    "seq_id=%x, ox_id=%x, rx_id=%x"
10648 		    "ro=%x", buf->ub_frame.s_id, buf->ub_frame.d_id,
10649 		    buf->ub_frame.type, buf->ub_frame.seq_id,
10650 		    buf->ub_frame.ox_id, buf->ub_frame.rx_id, buf->ub_frame.ro);
10651 
10652 		ASSERT(port->fp_active_ubs > 0);
10653 		if (--(port->fp_active_ubs) == 0) {
10654 			port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB;
10655 		}
10656 
10657 		mutex_exit(&port->fp_mutex);
10658 
10659 		port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
10660 		    1, &buf->ub_token);
10661 
10662 		return;
10663 	}
10664 
10665 	r_ctl = buf->ub_frame.r_ctl;
10666 	s_id = buf->ub_frame.s_id;
10667 	if (port->fp_active_ubs == 1) {
10668 		port->fp_soft_state |= FP_SOFT_IN_UNSOL_CB;
10669 	}
10670 
10671 	if (r_ctl == R_CTL_ELS_REQ && buf->ub_buffer[0] == LA_ELS_LOGO &&
10672 	    port->fp_statec_busy) {
10673 		mutex_exit(&port->fp_mutex);
10674 		pd = fctl_get_remote_port_by_did(port, s_id);
10675 		if (pd) {
10676 			mutex_enter(&pd->pd_mutex);
10677 			if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
10678 				FP_TRACE(FP_NHEAD1(3, 0),
10679 				    "LOGO for LOGGED IN D_ID %x",
10680 				    buf->ub_frame.s_id);
10681 				pd->pd_state = PORT_DEVICE_VALID;
10682 			}
10683 			mutex_exit(&pd->pd_mutex);
10684 		}
10685 
10686 		mutex_enter(&port->fp_mutex);
10687 		ASSERT(port->fp_active_ubs > 0);
10688 		if (--(port->fp_active_ubs) == 0) {
10689 			port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB;
10690 		}
10691 		mutex_exit(&port->fp_mutex);
10692 
10693 		port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
10694 		    1, &buf->ub_token);
10695 
10696 		FP_TRACE(FP_NHEAD1(3, 0),
10697 		    "fp_unsol_cb() bailing out LOGO for D_ID %x",
10698 		    buf->ub_frame.s_id);
10699 		return;
10700 	}
10701 
10702 	if (port->fp_els_resp_pkt_busy == 0) {
10703 		if (r_ctl == R_CTL_ELS_REQ) {
10704 			ls_code = buf->ub_buffer[0];
10705 
10706 			switch (ls_code) {
10707 			case LA_ELS_PLOGI:
10708 			case LA_ELS_FLOGI:
10709 				port->fp_els_resp_pkt_busy = 1;
10710 				mutex_exit(&port->fp_mutex);
10711 				fp_i_handle_unsol_els(port, buf);
10712 
10713 				mutex_enter(&port->fp_mutex);
10714 				ASSERT(port->fp_active_ubs > 0);
10715 				if (--(port->fp_active_ubs) == 0) {
10716 					port->fp_soft_state &=
10717 					    ~FP_SOFT_IN_UNSOL_CB;
10718 				}
10719 				mutex_exit(&port->fp_mutex);
10720 				port->fp_fca_tran->fca_ub_release(
10721 				    port->fp_fca_handle, 1, &buf->ub_token);
10722 
10723 				return;
10724 			case LA_ELS_RSCN:
10725 				if (++(port)->fp_rscn_count ==
10726 				    FC_INVALID_RSCN_COUNT) {
10727 					++(port)->fp_rscn_count;
10728 				}
10729 				rscn_count = port->fp_rscn_count;
10730 				break;
10731 
10732 			default:
10733 				break;
10734 			}
10735 		}
10736 	} else if ((r_ctl == R_CTL_ELS_REQ) &&
10737 	    (buf->ub_buffer[0] == LA_ELS_RSCN)) {
10738 		if (++port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
10739 			++port->fp_rscn_count;
10740 		}
10741 		rscn_count = port->fp_rscn_count;
10742 	}
10743 
10744 	mutex_exit(&port->fp_mutex);
10745 
10746 	switch (r_ctl & R_CTL_ROUTING) {
10747 	case R_CTL_DEVICE_DATA:
10748 		/*
10749 		 * If the unsolicited buffer is a CT IU,
10750 		 * have the job_handler thread work on it.
10751 		 */
10752 		if (buf->ub_frame.type == FC_TYPE_FC_SERVICES) {
10753 			break;
10754 		}
10755 		/* FALLTHROUGH */
10756 
10757 	case R_CTL_FC4_SVC: {
10758 		int sendup = 0;
10759 
10760 		/*
10761 		 * If a LOGIN isn't performed before this request
10762 		 * shut the door on this port with a reply that a
10763 		 * LOGIN is required. We make an exception however
10764 		 * for IP broadcast packets and pass them through
10765 		 * to the IP ULP(s) to handle broadcast requests.
10766 		 * This is not a problem for private loop devices
10767 		 * but for fabric topologies we don't log into the
10768 		 * remote ports during port initialization and
10769 		 * the ULPs need to log into requesting ports on
10770 		 * demand.
10771 		 */
10772 		pd = fctl_get_remote_port_by_did(port, s_id);
10773 		if (pd) {
10774 			mutex_enter(&pd->pd_mutex);
10775 			if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
10776 				sendup++;
10777 			}
10778 			mutex_exit(&pd->pd_mutex);
10779 		} else if ((pd == NULL) &&
10780 		    (buf->ub_frame.type == FC_TYPE_IS8802_SNAP) &&
10781 		    (buf->ub_frame.d_id == 0xffffff ||
10782 		    buf->ub_frame.d_id == 0x00)) {
10783 			/* brodacst IP frame - so sendup via job thread */
10784 			break;
10785 		}
10786 
10787 		/*
10788 		 * Send all FC4 services via job thread too
10789 		 */
10790 		if ((r_ctl & R_CTL_ROUTING) == R_CTL_FC4_SVC) {
10791 			break;
10792 		}
10793 
10794 		if (sendup || !FC_IS_REAL_DEVICE(s_id)) {
10795 			fctl_ulp_unsol_cb(port, buf, buf->ub_frame.type);
10796 			return;
10797 		}
10798 
10799 		if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
10800 			cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t),
10801 			    0, KM_NOSLEEP, pd);
10802 			if (cmd != NULL) {
10803 				fp_els_rjt_init(port, cmd, buf,
10804 				    FC_ACTION_NON_RETRYABLE,
10805 				    FC_REASON_LOGIN_REQUIRED, NULL);
10806 
10807 				if (fp_sendcmd(port, cmd,
10808 				    port->fp_fca_handle) != FC_SUCCESS) {
10809 					fp_free_pkt(cmd);
10810 				}
10811 			}
10812 		}
10813 
10814 		mutex_enter(&port->fp_mutex);
10815 		ASSERT(port->fp_active_ubs > 0);
10816 		if (--(port->fp_active_ubs) == 0) {
10817 			port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB;
10818 		}
10819 		mutex_exit(&port->fp_mutex);
10820 		port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
10821 		    1, &buf->ub_token);
10822 
10823 		return;
10824 	}
10825 
10826 	default:
10827 		break;
10828 	}
10829 
10830 	/*
10831 	 * Submit a Request to the job_handler thread to work
10832 	 * on the unsolicited request. The potential side effect
10833 	 * of this is that the unsolicited buffer takes a little
10834 	 * longer to get released but we save interrupt time in
10835 	 * the bargain.
10836 	 */
10837 	cb_arg = (rscn_count == FC_INVALID_RSCN_COUNT) ? NULL : rscn_count;
10838 
10839 	/*
10840 	 * One way that the rscn_count will get used is described below :
10841 	 *
10842 	 * 1. fp_unsol_cb() gets an RSCN and updates fp_rscn_count.
10843 	 * 2. Before mutex is released, a copy of it is stored in rscn_count.
10844 	 * 3. The count is passed to job thread as JOB_UNSOL_REQUEST (below)
10845 	 *    by overloading the job_cb_arg to pass the rscn_count
10846 	 * 4. When one of the routines processing the RSCN picks it up (ex:
10847 	 *    fp_validate_rscn_page()), it passes this count in the map
10848 	 *    structure (as part of the map_rscn_info structure member) to the
10849 	 *    ULPs.
10850 	 * 5. When ULPs make calls back to the transport (example interfaces for
10851 	 *    this are fc_ulp_transport(), fc_ulp_login(), fc_issue_els()), they
10852 	 *    can now pass back this count as part of the fc_packet's
10853 	 *    pkt_ulp_rscn_count member. fcp does this currently.
10854 	 * 6. When transport gets a call to transport a command on the wire, it
10855 	 *    will check to see if there is a valid pkt_ulp_rsvd1 field in the
10856 	 *    fc_packet. If there is, it will match that info with the current
10857 	 *    rscn_count on that instance of the port. If they don't match up
10858 	 *    then there was a newer RSCN. The ULP gets back an error code which
10859 	 *    informs it about it - FC_DEVICE_BUSY_NEW_RSCN.
10860 	 * 7. At this point the ULP is free to make up its own mind as to how to
10861 	 *    handle this. Currently, fcp will reset its retry counters and keep
10862 	 *    retrying the operation it was doing in anticipation of getting a
10863 	 *    new state change call back for the new RSCN.
10864 	 */
10865 	job = fctl_alloc_job(JOB_UNSOL_REQUEST, 0, NULL,
10866 	    (opaque_t)(uintptr_t)cb_arg, KM_NOSLEEP);
10867 	if (job == NULL) {
10868 		fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, "fp_unsol_cb() "
10869 		    "couldn't submit a job to the thread, failing..");
10870 
10871 		mutex_enter(&port->fp_mutex);
10872 
10873 		if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
10874 			--port->fp_rscn_count;
10875 		}
10876 
10877 		ASSERT(port->fp_active_ubs > 0);
10878 		if (--(port->fp_active_ubs) == 0) {
10879 			port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB;
10880 		}
10881 
10882 		mutex_exit(&port->fp_mutex);
10883 		port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
10884 		    1, &buf->ub_token);
10885 
10886 		return;
10887 	}
10888 	job->job_private = (void *)buf;
10889 	fctl_enque_job(port, job);
10890 }
10891 
10892 
10893 /*
10894  * Handle unsolicited requests
10895  */
10896 static void
10897 fp_handle_unsol_buf(fc_local_port_t *port, fc_unsol_buf_t *buf,
10898     job_request_t *job)
10899 {
10900 	uchar_t			r_ctl;
10901 	uchar_t			ls_code;
10902 	uint32_t		s_id;
10903 	fp_cmd_t		*cmd;
10904 	fc_remote_port_t	*pd;
10905 	fp_unsol_spec_t		*ub_spec;
10906 
10907 	r_ctl = buf->ub_frame.r_ctl;
10908 	s_id = buf->ub_frame.s_id;
10909 
10910 	switch (r_ctl & R_CTL_ROUTING) {
10911 	case R_CTL_EXTENDED_SVC:
10912 		if (r_ctl != R_CTL_ELS_REQ) {
10913 			break;
10914 		}
10915 
10916 		ls_code = buf->ub_buffer[0];
10917 		switch (ls_code) {
10918 		case LA_ELS_LOGO:
10919 		case LA_ELS_ADISC:
10920 		case LA_ELS_PRLO:
10921 			pd = fctl_get_remote_port_by_did(port, s_id);
10922 			if (pd == NULL) {
10923 				if (!FC_IS_REAL_DEVICE(s_id)) {
10924 					break;
10925 				}
10926 				if (!FP_IS_CLASS_1_OR_2(buf->ub_class)) {
10927 					break;
10928 				}
10929 				if ((cmd = fp_alloc_pkt(port,
10930 				    sizeof (la_els_rjt_t), 0, KM_SLEEP,
10931 				    NULL)) == NULL) {
10932 					/*
10933 					 * Can this actually fail when
10934 					 * given KM_SLEEP?  (Could be used
10935 					 * this way in a number of places.)
10936 					 */
10937 					break;
10938 				}
10939 
10940 				fp_els_rjt_init(port, cmd, buf,
10941 				    FC_ACTION_NON_RETRYABLE,
10942 				    FC_REASON_INVALID_LINK_CTRL, job);
10943 
10944 				if (fp_sendcmd(port, cmd,
10945 				    port->fp_fca_handle) != FC_SUCCESS) {
10946 					fp_free_pkt(cmd);
10947 				}
10948 
10949 				break;
10950 			}
10951 			if (ls_code == LA_ELS_LOGO) {
10952 				fp_handle_unsol_logo(port, buf, pd, job);
10953 			} else if (ls_code == LA_ELS_ADISC) {
10954 				fp_handle_unsol_adisc(port, buf, pd, job);
10955 			} else {
10956 				fp_handle_unsol_prlo(port, buf, pd, job);
10957 			}
10958 			break;
10959 
10960 		case LA_ELS_PLOGI:
10961 			fp_handle_unsol_plogi(port, buf, job, KM_SLEEP);
10962 			break;
10963 
10964 		case LA_ELS_FLOGI:
10965 			fp_handle_unsol_flogi(port, buf, job, KM_SLEEP);
10966 			break;
10967 
10968 		case LA_ELS_RSCN:
10969 			fp_handle_unsol_rscn(port, buf, job, KM_SLEEP);
10970 			break;
10971 
10972 		default:
10973 			ub_spec = kmem_zalloc(sizeof (*ub_spec), KM_SLEEP);
10974 			ub_spec->port = port;
10975 			ub_spec->buf = buf;
10976 
10977 			(void) taskq_dispatch(port->fp_taskq,
10978 			    fp_ulp_unsol_cb, ub_spec, KM_SLEEP);
10979 			return;
10980 		}
10981 		break;
10982 
10983 	case R_CTL_BASIC_SVC:
10984 		/*
10985 		 * The unsolicited basic link services could be ABTS
10986 		 * and RMC (Or even a NOP). Just BA_RJT them until
10987 		 * such time there arises a need to handle them more
10988 		 * carefully.
10989 		 */
10990 		if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
10991 			cmd = fp_alloc_pkt(port, sizeof (la_ba_rjt_t),
10992 			    0, KM_SLEEP, NULL);
10993 			if (cmd != NULL) {
10994 				fp_ba_rjt_init(port, cmd, buf, job);
10995 				if (fp_sendcmd(port, cmd,
10996 				    port->fp_fca_handle) != FC_SUCCESS) {
10997 					fp_free_pkt(cmd);
10998 				}
10999 			}
11000 		}
11001 		break;
11002 
11003 	case R_CTL_DEVICE_DATA:
11004 		if (buf->ub_frame.type == FC_TYPE_FC_SERVICES) {
11005 			/*
11006 			 * Mostly this is of type FC_TYPE_FC_SERVICES.
11007 			 * As we don't like any Unsolicited FC services
11008 			 * requests, we would do well to RJT them as
11009 			 * well.
11010 			 */
11011 			if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11012 				cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t),
11013 				    0, KM_SLEEP, NULL);
11014 				if (cmd != NULL) {
11015 					fp_els_rjt_init(port, cmd, buf,
11016 					    FC_ACTION_NON_RETRYABLE,
11017 					    FC_REASON_INVALID_LINK_CTRL, job);
11018 
11019 					if (fp_sendcmd(port, cmd,
11020 					    port->fp_fca_handle) !=
11021 					    FC_SUCCESS) {
11022 						fp_free_pkt(cmd);
11023 					}
11024 				}
11025 			}
11026 			break;
11027 		}
11028 		/* FALLTHROUGH */
11029 
11030 	case R_CTL_FC4_SVC:
11031 		ub_spec = kmem_zalloc(sizeof (*ub_spec), KM_SLEEP);
11032 		ub_spec->port = port;
11033 		ub_spec->buf = buf;
11034 
11035 		(void) taskq_dispatch(port->fp_taskq,
11036 		    fp_ulp_unsol_cb, ub_spec, KM_SLEEP);
11037 		return;
11038 
11039 	case R_CTL_LINK_CTL:
11040 		/*
11041 		 * Turn deaf ear on unsolicited link control frames.
11042 		 * Typical unsolicited link control Frame is an LCR
11043 		 * (to reset End to End credit to the default login
11044 		 * value and abort current sequences for all classes)
11045 		 * An intelligent microcode/firmware should handle
11046 		 * this transparently at its level and not pass all
11047 		 * the way up here.
11048 		 *
11049 		 * Possible responses to LCR are R_RDY, F_RJT, P_RJT
11050 		 * or F_BSY. P_RJT is chosen to be the most appropriate
11051 		 * at this time.
11052 		 */
11053 		/* FALLTHROUGH */
11054 
11055 	default:
11056 		/*
11057 		 * Just reject everything else as an invalid request.
11058 		 */
11059 		if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11060 			cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t),
11061 			    0, KM_SLEEP, NULL);
11062 			if (cmd != NULL) {
11063 				fp_els_rjt_init(port, cmd, buf,
11064 				    FC_ACTION_NON_RETRYABLE,
11065 				    FC_REASON_INVALID_LINK_CTRL, job);
11066 
11067 				if (fp_sendcmd(port, cmd,
11068 				    port->fp_fca_handle) != FC_SUCCESS) {
11069 					fp_free_pkt(cmd);
11070 				}
11071 			}
11072 		}
11073 		break;
11074 	}
11075 
11076 	mutex_enter(&port->fp_mutex);
11077 	ASSERT(port->fp_active_ubs > 0);
11078 	if (--(port->fp_active_ubs) == 0) {
11079 		port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB;
11080 	}
11081 	mutex_exit(&port->fp_mutex);
11082 	port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
11083 	    1, &buf->ub_token);
11084 }
11085 
11086 
11087 /*
11088  * Prepare a BA_RJT and send it over.
11089  */
11090 static void
11091 fp_ba_rjt_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf,
11092     job_request_t *job)
11093 {
11094 	fc_packet_t	*pkt;
11095 	la_ba_rjt_t	payload;
11096 
11097 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
11098 
11099 	cmd->cmd_pkt.pkt_tran_flags = buf->ub_class;
11100 	cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND;
11101 	cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
11102 	cmd->cmd_retry_count = 1;
11103 	cmd->cmd_ulp_pkt = NULL;
11104 
11105 	cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
11106 	cmd->cmd_job = job;
11107 
11108 	pkt = &cmd->cmd_pkt;
11109 
11110 	fp_unsol_resp_init(pkt, buf, R_CTL_LS_BA_RJT, FC_TYPE_BASIC_LS);
11111 
11112 	payload.reserved = 0;
11113 	payload.reason_code = FC_REASON_CMD_UNSUPPORTED;
11114 	payload.explanation = FC_EXPLN_NONE;
11115 	payload.vendor = 0;
11116 
11117 	FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
11118 	    (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
11119 }
11120 
11121 
11122 /*
11123  * Prepare an LS_RJT and send it over
11124  */
11125 static void
11126 fp_els_rjt_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf,
11127     uchar_t action, uchar_t reason, job_request_t *job)
11128 {
11129 	fc_packet_t	*pkt;
11130 	la_els_rjt_t	payload;
11131 
11132 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
11133 
11134 	cmd->cmd_pkt.pkt_tran_flags = buf->ub_class;
11135 	cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND;
11136 	cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
11137 	cmd->cmd_retry_count = 1;
11138 	cmd->cmd_ulp_pkt = NULL;
11139 
11140 	cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
11141 	cmd->cmd_job = job;
11142 
11143 	pkt = &cmd->cmd_pkt;
11144 
11145 	fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP, FC_TYPE_EXTENDED_LS);
11146 
11147 	payload.ls_code.ls_code = LA_ELS_RJT;
11148 	payload.ls_code.mbz = 0;
11149 	payload.action = action;
11150 	payload.reason = reason;
11151 	payload.reserved = 0;
11152 	payload.vu = 0;
11153 
11154 	FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
11155 	    (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
11156 }
11157 
11158 /*
11159  *     Function: fp_prlo_acc_init
11160  *
11161  *  Description: Initializes an Link Service Accept for a PRLO.
11162  *
11163  *    Arguments: *port		Local port through which the PRLO was
11164  *				received.
11165  *		 cmd		Command that will carry the accept.
11166  *		 *buf		Unsolicited buffer containing the PRLO
11167  *				request.
11168  *		 job		Job request.
11169  *		 sleep		Allocation mode.
11170  *
11171  * Return Value: *cmd		Command containing the response.
11172  *
11173  *	Context: Depends on the parameter sleep.
11174  */
11175 fp_cmd_t *
11176 fp_prlo_acc_init(fc_local_port_t *port, fc_remote_port_t *pd,
11177     fc_unsol_buf_t *buf, job_request_t *job, int sleep)
11178 {
11179 	fp_cmd_t	*cmd;
11180 	fc_packet_t	*pkt;
11181 	la_els_prlo_t	*req;
11182 	size_t		len;
11183 	uint16_t	flags;
11184 
11185 	req = (la_els_prlo_t *)buf->ub_buffer;
11186 	len = (size_t)ntohs(req->payload_length);
11187 
11188 	/*
11189 	 * The payload of the accept to a PRLO has to be the exact match of
11190 	 * the payload of the request (at the exception of the code).
11191 	 */
11192 	cmd = fp_alloc_pkt(port, (int)len, 0, sleep, pd);
11193 
11194 	if (cmd) {
11195 		/*
11196 		 * The fp command was successfully allocated.
11197 		 */
11198 		cmd->cmd_pkt.pkt_tran_flags = buf->ub_class;
11199 		cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND;
11200 		cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
11201 		cmd->cmd_retry_count = 1;
11202 		cmd->cmd_ulp_pkt = NULL;
11203 
11204 		cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
11205 		cmd->cmd_job = job;
11206 
11207 		pkt = &cmd->cmd_pkt;
11208 
11209 		fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP,
11210 		    FC_TYPE_EXTENDED_LS);
11211 
11212 		/* The code is overwritten for the copy. */
11213 		req->ls_code = LA_ELS_ACC;
11214 		/* Response code is set. */
11215 		flags = ntohs(req->flags);
11216 		flags &= ~SP_RESP_CODE_MASK;
11217 		flags |= SP_RESP_CODE_REQ_EXECUTED;
11218 		req->flags = htons(flags);
11219 
11220 		FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)req,
11221 		    (uint8_t *)pkt->pkt_cmd, len, DDI_DEV_AUTOINCR);
11222 	}
11223 	return (cmd);
11224 }
11225 
11226 /*
11227  * Prepare an ACC response to an ELS request
11228  */
11229 static void
11230 fp_els_acc_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf,
11231     job_request_t *job)
11232 {
11233 	fc_packet_t	*pkt;
11234 	ls_code_t	payload;
11235 
11236 	cmd->cmd_pkt.pkt_tran_flags = buf->ub_class;
11237 	cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND;
11238 	cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
11239 	cmd->cmd_retry_count = 1;
11240 	cmd->cmd_ulp_pkt = NULL;
11241 
11242 	cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
11243 	cmd->cmd_job = job;
11244 
11245 	pkt = &cmd->cmd_pkt;
11246 
11247 	fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP, FC_TYPE_EXTENDED_LS);
11248 
11249 	payload.ls_code = LA_ELS_ACC;
11250 	payload.mbz = 0;
11251 
11252 	FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
11253 	    (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
11254 }
11255 
11256 /*
11257  * Unsolicited PRLO handler
11258  *
11259  * A Process Logout should be handled by the ULP that established it.  However,
11260  * some devices send a PRLO to trigger a PLOGI followed by a PRLI.  This happens
11261  * when a device implicitly logs out an initiator (for whatever reason) and
11262  * tries to get that initiator to restablish the connection (PLOGI and PRLI).
11263  * The logical thing to do for the device would be to send a LOGO in response
11264  * to any FC4 frame sent by the initiator. Some devices choose, however, to send
11265  * a PRLO instead.
11266  *
11267  * From a Fibre Channel standpoint a PRLO calls for a PRLI. There's no reason to
11268  * think that the Port Login has been lost.  If we follow the Fibre Channel
11269  * protocol to the letter a PRLI should be sent after accepting the PRLO.  If
11270  * the Port Login has also been lost, the remote port will reject the PRLI
11271  * indicating that we must PLOGI first.	 The initiator will then turn around and
11272  * send a PLOGI.  The way Leadville is layered and the way the ULP interface
11273  * is defined doesn't allow this scenario to be followed easily.  If FCP were to
11274  * handle the PRLO and attempt the PRLI, the reject indicating that a PLOGI is
11275  * needed would be received by FCP. FCP would have, then, to tell the transport
11276  * (fp) to PLOGI.  The problem is, the transport would still think the Port
11277  * Login is valid and there is no way for FCP to tell the transport: "PLOGI even
11278  * if you think it's not necessary".  To work around that difficulty, the PRLO
11279  * is treated by the transport as a LOGO.  The downside to it is a Port Login
11280  * may be disrupted (if a PLOGI wasn't actually needed) and another ULP (that
11281  * has nothing to do with the PRLO) may be impacted.  However, this is a
11282  * scenario very unlikely to happen.  As of today the only ULP in Leadville
11283  * using PRLI/PRLOs is FCP.  For a PRLO to disrupt another ULP (that would be
11284  * FCIP), a SCSI target would have to be running FCP and FCIP (which is very
11285  * unlikely).
11286  */
11287 static void
11288 fp_handle_unsol_prlo(fc_local_port_t *port, fc_unsol_buf_t *buf,
11289     fc_remote_port_t *pd, job_request_t *job)
11290 {
11291 	int		busy;
11292 	int		rval;
11293 	int		retain;
11294 	fp_cmd_t	*cmd;
11295 	fc_portmap_t	*listptr;
11296 	boolean_t	tolerance;
11297 	la_els_prlo_t	*req;
11298 
11299 	req = (la_els_prlo_t *)buf->ub_buffer;
11300 
11301 	if ((ntohs(req->payload_length) !=
11302 	    (sizeof (service_parameter_page_t) + sizeof (ls_code_t))) ||
11303 	    (req->page_length != sizeof (service_parameter_page_t))) {
11304 		/*
11305 		 * We are being very restrictive.  Only on page per
11306 		 * payload.  If it is not the case we reject the ELS although
11307 		 * we should reply indicating we handle only single page
11308 		 * per PRLO.
11309 		 */
11310 		goto fp_reject_prlo;
11311 	}
11312 
11313 	if (ntohs(req->payload_length) > buf->ub_bufsize) {
11314 		/*
11315 		 * This is in case the payload advertizes a size bigger than
11316 		 * what it really is.
11317 		 */
11318 		goto fp_reject_prlo;
11319 	}
11320 
11321 	mutex_enter(&port->fp_mutex);
11322 	busy = port->fp_statec_busy;
11323 	mutex_exit(&port->fp_mutex);
11324 
11325 	mutex_enter(&pd->pd_mutex);
11326 	tolerance = fctl_tc_increment(&pd->pd_logo_tc);
11327 	if (!busy) {
11328 		if (pd->pd_state != PORT_DEVICE_LOGGED_IN ||
11329 		    pd->pd_state == PORT_DEVICE_INVALID ||
11330 		    pd->pd_flags == PD_ELS_IN_PROGRESS ||
11331 		    pd->pd_type == PORT_DEVICE_OLD) {
11332 			busy++;
11333 		}
11334 	}
11335 
11336 	if (busy) {
11337 		mutex_exit(&pd->pd_mutex);
11338 
11339 		FP_TRACE(FP_NHEAD1(5, 0), "Logout; D_ID=%x,"
11340 		    "pd=%p - busy",
11341 		    pd->pd_port_id.port_id, pd);
11342 
11343 		if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11344 			goto fp_reject_prlo;
11345 		}
11346 	} else {
11347 		retain = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0;
11348 
11349 		if (tolerance) {
11350 			fctl_tc_reset(&pd->pd_logo_tc);
11351 			retain = 0;
11352 			pd->pd_state = PORT_DEVICE_INVALID;
11353 		}
11354 
11355 		FP_TRACE(FP_NHEAD1(5, 0), "Accepting LOGO; d_id=%x, pd=%p,"
11356 		    " tolerance=%d retain=%d", pd->pd_port_id.port_id, pd,
11357 		    tolerance, retain);
11358 
11359 		pd->pd_aux_flags |= PD_LOGGED_OUT;
11360 		mutex_exit(&pd->pd_mutex);
11361 
11362 		cmd = fp_prlo_acc_init(port, pd, buf, job, KM_SLEEP);
11363 		if (cmd == NULL) {
11364 			return;
11365 		}
11366 
11367 		rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
11368 		if (rval != FC_SUCCESS) {
11369 			fp_free_pkt(cmd);
11370 			return;
11371 		}
11372 
11373 		listptr = kmem_zalloc(sizeof (fc_portmap_t), KM_SLEEP);
11374 
11375 		if (retain) {
11376 			fp_unregister_login(pd);
11377 			fctl_copy_portmap(listptr, pd);
11378 		} else {
11379 			uint32_t	d_id;
11380 			char		ww_name[17];
11381 
11382 			mutex_enter(&pd->pd_mutex);
11383 			d_id = pd->pd_port_id.port_id;
11384 			fc_wwn_to_str(&pd->pd_port_name, ww_name);
11385 			mutex_exit(&pd->pd_mutex);
11386 
11387 			FP_TRACE(FP_NHEAD2(9, 0),
11388 			    "N_x Port with D_ID=%x, PWWN=%s logged out"
11389 			    " %d times in %d us; Giving up", d_id, ww_name,
11390 			    FC_LOGO_TOLERANCE_LIMIT,
11391 			    FC_LOGO_TOLERANCE_TIME_LIMIT);
11392 
11393 			fp_fillout_old_map(listptr, pd, 0);
11394 			listptr->map_type = PORT_DEVICE_OLD;
11395 		}
11396 
11397 		(void) fp_ulp_devc_cb(port, listptr, 1, 1, KM_SLEEP, 0);
11398 		return;
11399 	}
11400 
11401 fp_reject_prlo:
11402 
11403 	cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t), 0, KM_SLEEP, pd);
11404 	if (cmd != NULL) {
11405 		fp_els_rjt_init(port, cmd, buf, FC_ACTION_NON_RETRYABLE,
11406 		    FC_REASON_INVALID_LINK_CTRL, job);
11407 
11408 		if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
11409 			fp_free_pkt(cmd);
11410 		}
11411 	}
11412 }
11413 
11414 /*
11415  * Unsolicited LOGO handler
11416  */
11417 static void
11418 fp_handle_unsol_logo(fc_local_port_t *port, fc_unsol_buf_t *buf,
11419     fc_remote_port_t *pd, job_request_t *job)
11420 {
11421 	int		busy;
11422 	int		rval;
11423 	int		retain;
11424 	fp_cmd_t	*cmd;
11425 	fc_portmap_t	*listptr;
11426 	boolean_t	tolerance;
11427 
11428 	mutex_enter(&port->fp_mutex);
11429 	busy = port->fp_statec_busy;
11430 	mutex_exit(&port->fp_mutex);
11431 
11432 	mutex_enter(&pd->pd_mutex);
11433 	tolerance = fctl_tc_increment(&pd->pd_logo_tc);
11434 	if (!busy) {
11435 		if (pd->pd_state != PORT_DEVICE_LOGGED_IN ||
11436 		    pd->pd_state == PORT_DEVICE_INVALID ||
11437 		    pd->pd_flags == PD_ELS_IN_PROGRESS ||
11438 		    pd->pd_type == PORT_DEVICE_OLD) {
11439 			busy++;
11440 		}
11441 	}
11442 
11443 	if (busy) {
11444 		mutex_exit(&pd->pd_mutex);
11445 
11446 		FP_TRACE(FP_NHEAD1(5, 0), "Logout; D_ID=%x,"
11447 		    "pd=%p - busy",
11448 		    pd->pd_port_id.port_id, pd);
11449 
11450 		if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11451 			cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t),
11452 			    0, KM_SLEEP, pd);
11453 			if (cmd != NULL) {
11454 				fp_els_rjt_init(port, cmd, buf,
11455 				    FC_ACTION_NON_RETRYABLE,
11456 				    FC_REASON_INVALID_LINK_CTRL, job);
11457 
11458 				if (fp_sendcmd(port, cmd,
11459 				    port->fp_fca_handle) != FC_SUCCESS) {
11460 					fp_free_pkt(cmd);
11461 				}
11462 			}
11463 		}
11464 	} else {
11465 		retain = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0;
11466 
11467 		if (tolerance) {
11468 			fctl_tc_reset(&pd->pd_logo_tc);
11469 			retain = 0;
11470 			pd->pd_state = PORT_DEVICE_INVALID;
11471 		}
11472 
11473 		FP_TRACE(FP_NHEAD1(5, 0), "Accepting LOGO; d_id=%x, pd=%p,"
11474 		    " tolerance=%d retain=%d", pd->pd_port_id.port_id, pd,
11475 		    tolerance, retain);
11476 
11477 		pd->pd_aux_flags |= PD_LOGGED_OUT;
11478 		mutex_exit(&pd->pd_mutex);
11479 
11480 		cmd = fp_alloc_pkt(port, FP_PORT_IDENTIFIER_LEN, 0,
11481 		    KM_SLEEP, pd);
11482 		if (cmd == NULL) {
11483 			return;
11484 		}
11485 
11486 		fp_els_acc_init(port, cmd, buf, job);
11487 
11488 		rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
11489 		if (rval != FC_SUCCESS) {
11490 			fp_free_pkt(cmd);
11491 			return;
11492 		}
11493 
11494 		listptr = kmem_zalloc(sizeof (fc_portmap_t), KM_SLEEP);
11495 
11496 		if (retain) {
11497 			job_request_t	*job;
11498 			fctl_ns_req_t	*ns_cmd;
11499 
11500 			/*
11501 			 * when get LOGO, first try to get PID from nameserver
11502 			 * if failed, then we do not need
11503 			 * send PLOGI to that remote port
11504 			 */
11505 			job = fctl_alloc_job(
11506 			    JOB_NS_CMD, 0, NULL, (opaque_t)port, KM_SLEEP);
11507 
11508 			if (job != NULL) {
11509 				ns_cmd = fctl_alloc_ns_cmd(
11510 				    sizeof (ns_req_gid_pn_t),
11511 				    sizeof (ns_resp_gid_pn_t),
11512 				    sizeof (ns_resp_gid_pn_t),
11513 				    0, KM_SLEEP);
11514 				if (ns_cmd != NULL) {
11515 					int ret;
11516 					job->job_result = FC_SUCCESS;
11517 					ns_cmd->ns_cmd_code = NS_GID_PN;
11518 					((ns_req_gid_pn_t *)
11519 					    (ns_cmd->ns_cmd_buf))->pwwn =
11520 					    pd->pd_port_name;
11521 					ret = fp_ns_query(
11522 					    port, ns_cmd, job, 1, KM_SLEEP);
11523 					if ((ret != FC_SUCCESS) ||
11524 					    (job->job_result != FC_SUCCESS)) {
11525 						fctl_free_ns_cmd(ns_cmd);
11526 						fctl_dealloc_job(job);
11527 						FP_TRACE(FP_NHEAD2(9, 0),
11528 						    "NS query failed,",
11529 						    " delete pd");
11530 						goto delete_pd;
11531 					}
11532 					fctl_free_ns_cmd(ns_cmd);
11533 				}
11534 				fctl_dealloc_job(job);
11535 			}
11536 			fp_unregister_login(pd);
11537 			fctl_copy_portmap(listptr, pd);
11538 		} else {
11539 			uint32_t	d_id;
11540 			char		ww_name[17];
11541 
11542 		delete_pd:
11543 			mutex_enter(&pd->pd_mutex);
11544 			d_id = pd->pd_port_id.port_id;
11545 			fc_wwn_to_str(&pd->pd_port_name, ww_name);
11546 			mutex_exit(&pd->pd_mutex);
11547 
11548 			FP_TRACE(FP_NHEAD2(9, 0),
11549 			    "N_x Port with D_ID=%x, PWWN=%s logged out"
11550 			    " %d times in %d us; Giving up", d_id, ww_name,
11551 			    FC_LOGO_TOLERANCE_LIMIT,
11552 			    FC_LOGO_TOLERANCE_TIME_LIMIT);
11553 
11554 			fp_fillout_old_map(listptr, pd, 0);
11555 			listptr->map_type = PORT_DEVICE_OLD;
11556 		}
11557 
11558 		(void) fp_ulp_devc_cb(port, listptr, 1, 1, KM_SLEEP, 0);
11559 	}
11560 }
11561 
11562 
11563 /*
11564  * Perform general purpose preparation of a response to an unsolicited request
11565  */
11566 static void
11567 fp_unsol_resp_init(fc_packet_t *pkt, fc_unsol_buf_t *buf,
11568     uchar_t r_ctl, uchar_t type)
11569 {
11570 	pkt->pkt_cmd_fhdr.r_ctl = r_ctl;
11571 	pkt->pkt_cmd_fhdr.d_id = buf->ub_frame.s_id;
11572 	pkt->pkt_cmd_fhdr.s_id = buf->ub_frame.d_id;
11573 	pkt->pkt_cmd_fhdr.type = type;
11574 	pkt->pkt_cmd_fhdr.f_ctl = F_CTL_LAST_SEQ | F_CTL_XCHG_CONTEXT;
11575 	pkt->pkt_cmd_fhdr.seq_id = buf->ub_frame.seq_id;
11576 	pkt->pkt_cmd_fhdr.df_ctl  = buf->ub_frame.df_ctl;
11577 	pkt->pkt_cmd_fhdr.seq_cnt = buf->ub_frame.seq_cnt;
11578 	pkt->pkt_cmd_fhdr.ox_id = buf->ub_frame.ox_id;
11579 	pkt->pkt_cmd_fhdr.rx_id = buf->ub_frame.rx_id;
11580 	pkt->pkt_cmd_fhdr.ro = 0;
11581 	pkt->pkt_cmd_fhdr.rsvd = 0;
11582 	pkt->pkt_comp = fp_unsol_intr;
11583 	pkt->pkt_timeout = FP_ELS_TIMEOUT;
11584 	pkt->pkt_ub_resp_token = (opaque_t)buf;
11585 }
11586 
11587 /*
11588  * Immediate handling of unsolicited FLOGI and PLOGI requests. In the
11589  * early development days of public loop soc+ firmware, numerous problems
11590  * were encountered (the details are undocumented and history now) which
11591  * led to the birth of this function.
11592  *
11593  * If a pre-allocated unsolicited response packet is free, send out an
11594  * immediate response, otherwise submit the request to the port thread
11595  * to do the deferred processing.
11596  */
11597 static void
11598 fp_i_handle_unsol_els(fc_local_port_t *port, fc_unsol_buf_t *buf)
11599 {
11600 	int			sent;
11601 	int			f_port;
11602 	int			do_acc;
11603 	fp_cmd_t		*cmd;
11604 	la_els_logi_t		*payload;
11605 	fc_remote_port_t	*pd;
11606 	char			dww_name[17];
11607 
11608 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
11609 
11610 	cmd = port->fp_els_resp_pkt;
11611 
11612 	mutex_enter(&port->fp_mutex);
11613 	do_acc = (port->fp_statec_busy == 0) ? 1 : 0;
11614 	mutex_exit(&port->fp_mutex);
11615 
11616 	switch (buf->ub_buffer[0]) {
11617 	case LA_ELS_PLOGI: {
11618 		int small;
11619 
11620 		payload = (la_els_logi_t *)buf->ub_buffer;
11621 
11622 		f_port = FP_IS_F_PORT(payload->
11623 		    common_service.cmn_features) ? 1 : 0;
11624 
11625 		small = fctl_wwn_cmp(&port->fp_service_params.nport_ww_name,
11626 		    &payload->nport_ww_name);
11627 		pd = fctl_get_remote_port_by_pwwn(port,
11628 		    &payload->nport_ww_name);
11629 		if (pd) {
11630 			mutex_enter(&pd->pd_mutex);
11631 			sent = (pd->pd_flags == PD_ELS_IN_PROGRESS) ? 1 : 0;
11632 			/*
11633 			 * Most likely this means a cross login is in
11634 			 * progress or a device about to be yanked out.
11635 			 * Only accept the plogi if my wwn is smaller.
11636 			 */
11637 			if (pd->pd_type == PORT_DEVICE_OLD) {
11638 				sent = 1;
11639 			}
11640 			/*
11641 			 * Stop plogi request (if any)
11642 			 * attempt from local side to speedup
11643 			 * the discovery progress.
11644 			 * Mark the pd as PD_PLOGI_RECEPIENT.
11645 			 */
11646 			if (f_port == 0 && small < 0) {
11647 				pd->pd_recepient = PD_PLOGI_RECEPIENT;
11648 			}
11649 			fc_wwn_to_str(&pd->pd_port_name, dww_name);
11650 
11651 			mutex_exit(&pd->pd_mutex);
11652 
11653 			FP_TRACE(FP_NHEAD1(3, 0), "fp_i_handle_unsol_els: "
11654 			    "Unsol PLOGI received. PD still exists in the "
11655 			    "PWWN list. pd=%p PWWN=%s, sent=%x",
11656 			    pd, dww_name, sent);
11657 
11658 			if (f_port == 0 && small < 0) {
11659 				FP_TRACE(FP_NHEAD1(3, 0),
11660 				    "fp_i_handle_unsol_els: Mark the pd"
11661 				    " as plogi recipient, pd=%p, PWWN=%s"
11662 				    ", sent=%x",
11663 				    pd, dww_name, sent);
11664 			}
11665 		} else {
11666 			sent = 0;
11667 		}
11668 
11669 		/*
11670 		 * To avoid Login collisions, accept only if my WWN
11671 		 * is smaller than the requester (A curious side note
11672 		 * would be that this rule may not satisfy the PLOGIs
11673 		 * initiated by the switch from not-so-well known
11674 		 * ports such as 0xFFFC41)
11675 		 */
11676 		if ((f_port == 0 && small < 0) ||
11677 		    (((small > 0 && do_acc) ||
11678 		    FC_MUST_ACCEPT_D_ID(buf->ub_frame.s_id)) && sent == 0)) {
11679 			if (fp_is_class_supported(port->fp_cos,
11680 			    buf->ub_class) == FC_FAILURE) {
11681 				if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11682 					cmd->cmd_pkt.pkt_cmdlen =
11683 					    sizeof (la_els_rjt_t);
11684 					cmd->cmd_pkt.pkt_rsplen = 0;
11685 					fp_els_rjt_init(port, cmd, buf,
11686 					    FC_ACTION_NON_RETRYABLE,
11687 					    FC_REASON_CLASS_NOT_SUPP, NULL);
11688 					FP_TRACE(FP_NHEAD1(3, 0),
11689 					    "fp_i_handle_unsol_els: "
11690 					    "Unsupported class. "
11691 					    "Rejecting PLOGI");
11692 
11693 				} else {
11694 					mutex_enter(&port->fp_mutex);
11695 					port->fp_els_resp_pkt_busy = 0;
11696 					mutex_exit(&port->fp_mutex);
11697 					return;
11698 				}
11699 			} else {
11700 				cmd->cmd_pkt.pkt_cmdlen =
11701 				    sizeof (la_els_logi_t);
11702 				cmd->cmd_pkt.pkt_rsplen = 0;
11703 
11704 				/*
11705 				 * If fp_port_id is zero and topology is
11706 				 * Point-to-Point, get the local port id from
11707 				 * the d_id in the PLOGI request.
11708 				 * If the outgoing FLOGI hasn't been accepted,
11709 				 * the topology will be unknown here. But it's
11710 				 * still safe to save the d_id to fp_port_id,
11711 				 * just because it will be overwritten later
11712 				 * if the topology is not Point-to-Point.
11713 				 */
11714 				mutex_enter(&port->fp_mutex);
11715 				if ((port->fp_port_id.port_id == 0) &&
11716 				    (port->fp_topology == FC_TOP_PT_PT ||
11717 				    port->fp_topology == FC_TOP_UNKNOWN)) {
11718 					port->fp_port_id.port_id =
11719 					    buf->ub_frame.d_id;
11720 				}
11721 				mutex_exit(&port->fp_mutex);
11722 
11723 				/*
11724 				 * Sometime later, we should validate
11725 				 * the service parameters instead of
11726 				 * just accepting it.
11727 				 */
11728 				fp_login_acc_init(port, cmd, buf, NULL,
11729 				    KM_NOSLEEP);
11730 				FP_TRACE(FP_NHEAD1(3, 0),
11731 				    "fp_i_handle_unsol_els: Accepting PLOGI,"
11732 				    " f_port=%d, small=%d, do_acc=%d,"
11733 				    " sent=%d.", f_port, small, do_acc,
11734 				    sent);
11735 			}
11736 		} else {
11737 			if (FP_IS_CLASS_1_OR_2(buf->ub_class) ||
11738 			    port->fp_options & FP_SEND_RJT) {
11739 				cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_rjt_t);
11740 				cmd->cmd_pkt.pkt_rsplen = 0;
11741 				fp_els_rjt_init(port, cmd, buf,
11742 				    FC_ACTION_NON_RETRYABLE,
11743 				    FC_REASON_LOGICAL_BSY, NULL);
11744 				FP_TRACE(FP_NHEAD1(3, 0),
11745 				    "fp_i_handle_unsol_els: "
11746 				    "Rejecting PLOGI with Logical Busy."
11747 				    "Possible Login collision.");
11748 			} else {
11749 				mutex_enter(&port->fp_mutex);
11750 				port->fp_els_resp_pkt_busy = 0;
11751 				mutex_exit(&port->fp_mutex);
11752 				return;
11753 			}
11754 		}
11755 		break;
11756 	}
11757 
11758 	case LA_ELS_FLOGI:
11759 		if (fp_is_class_supported(port->fp_cos,
11760 		    buf->ub_class) == FC_FAILURE) {
11761 			if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11762 				cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_rjt_t);
11763 				cmd->cmd_pkt.pkt_rsplen = 0;
11764 				fp_els_rjt_init(port, cmd, buf,
11765 				    FC_ACTION_NON_RETRYABLE,
11766 				    FC_REASON_CLASS_NOT_SUPP, NULL);
11767 				FP_TRACE(FP_NHEAD1(3, 0),
11768 				    "fp_i_handle_unsol_els: "
11769 				    "Unsupported Class. Rejecting FLOGI.");
11770 			} else {
11771 				mutex_enter(&port->fp_mutex);
11772 				port->fp_els_resp_pkt_busy = 0;
11773 				mutex_exit(&port->fp_mutex);
11774 				return;
11775 			}
11776 		} else {
11777 			mutex_enter(&port->fp_mutex);
11778 			if (FC_PORT_STATE_MASK(port->fp_state) !=
11779 			    FC_STATE_ONLINE || (port->fp_port_id.port_id &&
11780 			    buf->ub_frame.s_id == port->fp_port_id.port_id)) {
11781 				mutex_exit(&port->fp_mutex);
11782 				if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11783 					cmd->cmd_pkt.pkt_cmdlen =
11784 					    sizeof (la_els_rjt_t);
11785 					cmd->cmd_pkt.pkt_rsplen = 0;
11786 					fp_els_rjt_init(port, cmd, buf,
11787 					    FC_ACTION_NON_RETRYABLE,
11788 					    FC_REASON_INVALID_LINK_CTRL,
11789 					    NULL);
11790 					FP_TRACE(FP_NHEAD1(3, 0),
11791 					    "fp_i_handle_unsol_els: "
11792 					    "Invalid Link Ctrl. "
11793 					    "Rejecting FLOGI.");
11794 				} else {
11795 					mutex_enter(&port->fp_mutex);
11796 					port->fp_els_resp_pkt_busy = 0;
11797 					mutex_exit(&port->fp_mutex);
11798 					return;
11799 				}
11800 			} else {
11801 				mutex_exit(&port->fp_mutex);
11802 				cmd->cmd_pkt.pkt_cmdlen =
11803 				    sizeof (la_els_logi_t);
11804 				cmd->cmd_pkt.pkt_rsplen = 0;
11805 				/*
11806 				 * Let's not aggressively validate the N_Port's
11807 				 * service parameters until PLOGI. Suffice it
11808 				 * to give a hint that we are an N_Port and we
11809 				 * are game to some serious stuff here.
11810 				 */
11811 				fp_login_acc_init(port, cmd, buf,
11812 				    NULL, KM_NOSLEEP);
11813 				FP_TRACE(FP_NHEAD1(3, 0),
11814 				    "fp_i_handle_unsol_els: "
11815 				    "Accepting FLOGI.");
11816 			}
11817 		}
11818 		break;
11819 
11820 	default:
11821 		return;
11822 	}
11823 
11824 	if ((fp_sendcmd(port, cmd, port->fp_fca_handle)) != FC_SUCCESS) {
11825 		mutex_enter(&port->fp_mutex);
11826 		port->fp_els_resp_pkt_busy = 0;
11827 		mutex_exit(&port->fp_mutex);
11828 	}
11829 }
11830 
11831 
11832 /*
11833  * Handle unsolicited PLOGI request
11834  */
11835 static void
11836 fp_handle_unsol_plogi(fc_local_port_t *port, fc_unsol_buf_t *buf,
11837     job_request_t *job, int sleep)
11838 {
11839 	int			sent;
11840 	int			small;
11841 	int			f_port;
11842 	int			do_acc;
11843 	fp_cmd_t		*cmd;
11844 	la_wwn_t		*swwn;
11845 	la_wwn_t		*dwwn;
11846 	la_els_logi_t		*payload;
11847 	fc_remote_port_t	*pd;
11848 	char			dww_name[17];
11849 
11850 	payload = (la_els_logi_t *)buf->ub_buffer;
11851 	f_port = FP_IS_F_PORT(payload->common_service.cmn_features) ? 1 : 0;
11852 
11853 	mutex_enter(&port->fp_mutex);
11854 	do_acc = (port->fp_statec_busy == 0) ? 1 : 0;
11855 	mutex_exit(&port->fp_mutex);
11856 
11857 	FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_plogi: s_id=%x, d_id=%x,"
11858 	    "type=%x, f_ctl=%x"
11859 	    " seq_id=%x, ox_id=%x, rx_id=%x"
11860 	    " ro=%x", buf->ub_frame.s_id, buf->ub_frame.d_id,
11861 	    buf->ub_frame.type, buf->ub_frame.f_ctl, buf->ub_frame.seq_id,
11862 	    buf->ub_frame.ox_id, buf->ub_frame.rx_id, buf->ub_frame.ro);
11863 
11864 	swwn = &port->fp_service_params.nport_ww_name;
11865 	dwwn = &payload->nport_ww_name;
11866 	small = fctl_wwn_cmp(swwn, dwwn);
11867 	pd = fctl_get_remote_port_by_pwwn(port, dwwn);
11868 	if (pd) {
11869 		mutex_enter(&pd->pd_mutex);
11870 		sent = (pd->pd_flags == PD_ELS_IN_PROGRESS) ? 1 : 0;
11871 		/*
11872 		 * Most likely this means a cross login is in
11873 		 * progress or a device about to be yanked out.
11874 		 * Only accept the plogi if my wwn is smaller.
11875 		 */
11876 
11877 		if (pd->pd_type == PORT_DEVICE_OLD) {
11878 			sent = 1;
11879 		}
11880 		/*
11881 		 * Stop plogi request (if any)
11882 		 * attempt from local side to speedup
11883 		 * the discovery progress.
11884 		 * Mark the pd as PD_PLOGI_RECEPIENT.
11885 		 */
11886 		if (f_port == 0 && small < 0) {
11887 			pd->pd_recepient = PD_PLOGI_RECEPIENT;
11888 		}
11889 		fc_wwn_to_str(&pd->pd_port_name, dww_name);
11890 
11891 		mutex_exit(&pd->pd_mutex);
11892 
11893 		FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_plogi: Unsol PLOGI"
11894 		    " received. PD still exists in the PWWN list. pd=%p "
11895 		    "PWWN=%s, sent=%x", pd, dww_name, sent);
11896 
11897 		if (f_port == 0 && small < 0) {
11898 			FP_TRACE(FP_NHEAD1(3, 0),
11899 			    "fp_handle_unsol_plogi: Mark the pd"
11900 			    " as plogi recipient, pd=%p, PWWN=%s"
11901 			    ", sent=%x",
11902 			    pd, dww_name, sent);
11903 		}
11904 	} else {
11905 		sent = 0;
11906 	}
11907 
11908 	/*
11909 	 * Avoid Login collisions by accepting only if my WWN is smaller.
11910 	 *
11911 	 * A side note: There is no need to start a PLOGI from this end in
11912 	 *	this context if login isn't going to be accepted for the
11913 	 *	above reason as either a LIP (in private loop), RSCN (in
11914 	 *	fabric topology), or an FLOGI (in point to point - Huh ?
11915 	 *	check FC-PH) would normally drive the PLOGI from this end.
11916 	 *	At this point of time there is no need for an inbound PLOGI
11917 	 *	to kick an outbound PLOGI when it is going to be rejected
11918 	 *	for the reason of WWN being smaller. However it isn't hard
11919 	 *	to do that either (when such a need arises, start a timer
11920 	 *	for a duration that extends beyond a normal device discovery
11921 	 *	time and check if an outbound PLOGI did go before that, if
11922 	 *	none fire one)
11923 	 *
11924 	 *	Unfortunately, as it turned out, during booting, it is possible
11925 	 *	to miss another initiator in the same loop as port driver
11926 	 *	instances are serially attached. While preserving the above
11927 	 *	comments for belly laughs, please kick an outbound PLOGI in
11928 	 *	a non-switch environment (which is a pt pt between N_Ports or
11929 	 *	a private loop)
11930 	 *
11931 	 *	While preserving the above comments for amusement, send an
11932 	 *	ACC if the PLOGI is going to be rejected for WWN being smaller
11933 	 *	when no discovery is in progress at this end. Turn around
11934 	 *	and make the port device as the PLOGI initiator, so that
11935 	 *	during subsequent link/loop initialization, this end drives
11936 	 *	the PLOGI (In fact both ends do in this particular case, but
11937 	 *	only one wins)
11938 	 *
11939 	 * Make sure the PLOGIs initiated by the switch from not-so-well-known
11940 	 * ports (such as 0xFFFC41) are accepted too.
11941 	 */
11942 	if ((f_port == 0 && small < 0) || (((small > 0 && do_acc) ||
11943 	    FC_MUST_ACCEPT_D_ID(buf->ub_frame.s_id)) && sent == 0)) {
11944 		if (fp_is_class_supported(port->fp_cos,
11945 		    buf->ub_class) == FC_FAILURE) {
11946 			if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11947 				cmd = fp_alloc_pkt(port,
11948 				    sizeof (la_els_logi_t), 0, sleep, pd);
11949 				if (cmd == NULL) {
11950 					return;
11951 				}
11952 				cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_rjt_t);
11953 				cmd->cmd_pkt.pkt_rsplen = 0;
11954 				fp_els_rjt_init(port, cmd, buf,
11955 				    FC_ACTION_NON_RETRYABLE,
11956 				    FC_REASON_CLASS_NOT_SUPP, job);
11957 				FP_TRACE(FP_NHEAD1(3, 0),
11958 				    "fp_handle_unsol_plogi: "
11959 				    "Unsupported class. rejecting PLOGI");
11960 			}
11961 		} else {
11962 			cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t),
11963 			    0, sleep, pd);
11964 			if (cmd == NULL) {
11965 				return;
11966 			}
11967 			cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_logi_t);
11968 			cmd->cmd_pkt.pkt_rsplen = 0;
11969 
11970 			/*
11971 			 * Sometime later, we should validate the service
11972 			 * parameters instead of just accepting it.
11973 			 */
11974 			fp_login_acc_init(port, cmd, buf, job, KM_SLEEP);
11975 			FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_plogi: "
11976 			    "Accepting PLOGI, f_port=%d, small=%d, "
11977 			    "do_acc=%d, sent=%d.", f_port, small, do_acc,
11978 			    sent);
11979 
11980 			/*
11981 			 * If fp_port_id is zero and topology is
11982 			 * Point-to-Point, get the local port id from
11983 			 * the d_id in the PLOGI request.
11984 			 * If the outgoing FLOGI hasn't been accepted,
11985 			 * the topology will be unknown here. But it's
11986 			 * still safe to save the d_id to fp_port_id,
11987 			 * just because it will be overwritten later
11988 			 * if the topology is not Point-to-Point.
11989 			 */
11990 			mutex_enter(&port->fp_mutex);
11991 			if ((port->fp_port_id.port_id == 0) &&
11992 			    (port->fp_topology == FC_TOP_PT_PT ||
11993 			    port->fp_topology == FC_TOP_UNKNOWN)) {
11994 				port->fp_port_id.port_id =
11995 				    buf->ub_frame.d_id;
11996 			}
11997 			mutex_exit(&port->fp_mutex);
11998 		}
11999 	} else {
12000 		if (FP_IS_CLASS_1_OR_2(buf->ub_class) ||
12001 		    port->fp_options & FP_SEND_RJT) {
12002 			cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t),
12003 			    0, sleep, pd);
12004 			if (cmd == NULL) {
12005 				return;
12006 			}
12007 			cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_rjt_t);
12008 			cmd->cmd_pkt.pkt_rsplen = 0;
12009 			/*
12010 			 * Send out Logical busy to indicate
12011 			 * the detection of PLOGI collision
12012 			 */
12013 			fp_els_rjt_init(port, cmd, buf,
12014 			    FC_ACTION_NON_RETRYABLE,
12015 			    FC_REASON_LOGICAL_BSY, job);
12016 
12017 			fc_wwn_to_str(dwwn, dww_name);
12018 			FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_plogi: "
12019 			    "Rejecting Unsol PLOGI with Logical Busy."
12020 			    "possible PLOGI collision. PWWN=%s, sent=%x",
12021 			    dww_name, sent);
12022 		} else {
12023 			return;
12024 		}
12025 	}
12026 
12027 	if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
12028 		fp_free_pkt(cmd);
12029 	}
12030 }
12031 
12032 
12033 /*
12034  * Handle mischievous turning over of our own FLOGI requests back to
12035  * us by the SOC+ microcode. In other words, look at the class of such
12036  * bone headed requests, if 1 or 2, bluntly P_RJT them, if 3 drop them
12037  * on the floor
12038  */
12039 static void
12040 fp_handle_unsol_flogi(fc_local_port_t *port, fc_unsol_buf_t *buf,
12041     job_request_t *job, int sleep)
12042 {
12043 	uint32_t	state;
12044 	uint32_t	s_id;
12045 	fp_cmd_t	*cmd;
12046 
12047 	if (fp_is_class_supported(port->fp_cos, buf->ub_class) == FC_FAILURE) {
12048 		if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
12049 			cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t),
12050 			    0, sleep, NULL);
12051 			if (cmd == NULL) {
12052 				return;
12053 			}
12054 			fp_els_rjt_init(port, cmd, buf,
12055 			    FC_ACTION_NON_RETRYABLE,
12056 			    FC_REASON_CLASS_NOT_SUPP, job);
12057 		} else {
12058 			return;
12059 		}
12060 	} else {
12061 
12062 		FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_flogi:"
12063 		    " s_id=%x, d_id=%x, type=%x, f_ctl=%x"
12064 		    " seq_id=%x, ox_id=%x, rx_id=%x, ro=%x",
12065 		    buf->ub_frame.s_id, buf->ub_frame.d_id,
12066 		    buf->ub_frame.type, buf->ub_frame.f_ctl,
12067 		    buf->ub_frame.seq_id, buf->ub_frame.ox_id,
12068 		    buf->ub_frame.rx_id, buf->ub_frame.ro);
12069 
12070 		mutex_enter(&port->fp_mutex);
12071 		state = FC_PORT_STATE_MASK(port->fp_state);
12072 		s_id = port->fp_port_id.port_id;
12073 		mutex_exit(&port->fp_mutex);
12074 
12075 		if (state != FC_STATE_ONLINE ||
12076 		    (s_id && buf->ub_frame.s_id == s_id)) {
12077 			if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
12078 				cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t),
12079 				    0, sleep, NULL);
12080 				if (cmd == NULL) {
12081 					return;
12082 				}
12083 				fp_els_rjt_init(port, cmd, buf,
12084 				    FC_ACTION_NON_RETRYABLE,
12085 				    FC_REASON_INVALID_LINK_CTRL, job);
12086 				FP_TRACE(FP_NHEAD1(3, 0),
12087 				    "fp_handle_unsol_flogi: "
12088 				    "Rejecting PLOGI. Invalid Link CTRL");
12089 			} else {
12090 				return;
12091 			}
12092 		} else {
12093 			cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t),
12094 			    0, sleep, NULL);
12095 			if (cmd == NULL) {
12096 				return;
12097 			}
12098 			/*
12099 			 * Let's not aggressively validate the N_Port's
12100 			 * service parameters until PLOGI. Suffice it
12101 			 * to give a hint that we are an N_Port and we
12102 			 * are game to some serious stuff here.
12103 			 */
12104 			fp_login_acc_init(port, cmd, buf, job, KM_SLEEP);
12105 			FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_flogi: "
12106 			    "Accepting PLOGI");
12107 		}
12108 	}
12109 
12110 	if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
12111 		fp_free_pkt(cmd);
12112 	}
12113 }
12114 
12115 
12116 /*
12117  * Perform PLOGI accept
12118  */
12119 static void
12120 fp_login_acc_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf,
12121     job_request_t *job, int sleep)
12122 {
12123 	fc_packet_t	*pkt;
12124 	fc_portmap_t	*listptr;
12125 	la_els_logi_t	payload;
12126 
12127 	ASSERT(buf != NULL);
12128 
12129 	/*
12130 	 * If we are sending ACC to PLOGI and we haven't already
12131 	 * create port and node device handles, let's create them
12132 	 * here.
12133 	 */
12134 	if (buf->ub_buffer[0] == LA_ELS_PLOGI &&
12135 	    FC_IS_REAL_DEVICE(buf->ub_frame.s_id)) {
12136 		int			small;
12137 		int			do_acc;
12138 		fc_remote_port_t	*pd;
12139 		la_els_logi_t		*req;
12140 
12141 		req = (la_els_logi_t *)buf->ub_buffer;
12142 		small = fctl_wwn_cmp(&port->fp_service_params.nport_ww_name,
12143 		    &req->nport_ww_name);
12144 
12145 		mutex_enter(&port->fp_mutex);
12146 		do_acc = (port->fp_statec_busy == 0) ? 1 : 0;
12147 		mutex_exit(&port->fp_mutex);
12148 
12149 		FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_acc_init fp %x, pd %x",
12150 		    port->fp_port_id.port_id, buf->ub_frame.s_id);
12151 		pd = fctl_create_remote_port(port, &req->node_ww_name,
12152 		    &req->nport_ww_name, buf->ub_frame.s_id,
12153 		    PD_PLOGI_RECEPIENT, sleep);
12154 		if (pd == NULL) {
12155 			FP_TRACE(FP_NHEAD1(3, 0), "login_acc_init: "
12156 			    "Couldn't create port device for d_id:0x%x",
12157 			    buf->ub_frame.s_id);
12158 
12159 			fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
12160 			    "couldn't create port device d_id=%x",
12161 			    buf->ub_frame.s_id);
12162 		} else {
12163 			/*
12164 			 * usoc currently returns PLOGIs inline and
12165 			 * the maximum buffer size is 60 bytes or so.
12166 			 * So attempt not to look beyond what is in
12167 			 * the unsolicited buffer
12168 			 *
12169 			 * JNI also traverses this path sometimes
12170 			 */
12171 			if (buf->ub_bufsize >= sizeof (la_els_logi_t)) {
12172 				fp_register_login(NULL, pd, req, buf->ub_class);
12173 			} else {
12174 				mutex_enter(&pd->pd_mutex);
12175 				if (pd->pd_login_count == 0) {
12176 					pd->pd_login_count++;
12177 				}
12178 				pd->pd_state = PORT_DEVICE_LOGGED_IN;
12179 				pd->pd_login_class = buf->ub_class;
12180 				mutex_exit(&pd->pd_mutex);
12181 			}
12182 
12183 			listptr = kmem_zalloc(sizeof (fc_portmap_t), sleep);
12184 			if (listptr != NULL) {
12185 				fctl_copy_portmap(listptr, pd);
12186 				(void) fp_ulp_devc_cb(port, listptr,
12187 				    1, 1, sleep, 0);
12188 			}
12189 
12190 			if (small > 0 && do_acc) {
12191 				mutex_enter(&pd->pd_mutex);
12192 				pd->pd_recepient = PD_PLOGI_INITIATOR;
12193 				mutex_exit(&pd->pd_mutex);
12194 			}
12195 		}
12196 	}
12197 
12198 	cmd->cmd_pkt.pkt_tran_flags = buf->ub_class;
12199 	cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND;
12200 	cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
12201 	cmd->cmd_retry_count = 1;
12202 	cmd->cmd_ulp_pkt = NULL;
12203 
12204 	cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
12205 	cmd->cmd_job = job;
12206 
12207 	pkt = &cmd->cmd_pkt;
12208 
12209 	fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP, FC_TYPE_EXTENDED_LS);
12210 
12211 	payload = port->fp_service_params;
12212 	payload.ls_code.ls_code = LA_ELS_ACC;
12213 
12214 	FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
12215 	    (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
12216 
12217 	FP_TRACE(FP_NHEAD1(3, 0), "login_acc_init: ELS:0x%x d_id:0x%x "
12218 	    "bufsize:0x%x sizeof (la_els_logi):0x%x "
12219 	    "port's wwn:0x%01x%03x%04x%08x requestor's wwn:0x%01x%03x%04x%08x "
12220 	    "statec_busy:0x%x", buf->ub_buffer[0], buf->ub_frame.s_id,
12221 	    buf->ub_bufsize, sizeof (la_els_logi_t),
12222 	    port->fp_service_params.nport_ww_name.w.naa_id,
12223 	    port->fp_service_params.nport_ww_name.w.nport_id,
12224 	    port->fp_service_params.nport_ww_name.w.wwn_hi,
12225 	    port->fp_service_params.nport_ww_name.w.wwn_lo,
12226 	    ((la_els_logi_t *)buf->ub_buffer)->nport_ww_name.w.naa_id,
12227 	    ((la_els_logi_t *)buf->ub_buffer)->nport_ww_name.w.nport_id,
12228 	    ((la_els_logi_t *)buf->ub_buffer)->nport_ww_name.w.wwn_hi,
12229 	    ((la_els_logi_t *)buf->ub_buffer)->nport_ww_name.w.wwn_lo,
12230 	    port->fp_statec_busy);
12231 }
12232 
12233 
12234 #define	RSCN_EVENT_NAME_LEN	256
12235 
12236 /*
12237  * Handle RSCNs
12238  */
12239 static void
12240 fp_handle_unsol_rscn(fc_local_port_t *port, fc_unsol_buf_t *buf,
12241     job_request_t *job, int sleep)
12242 {
12243 	uint32_t		mask;
12244 	fp_cmd_t		*cmd;
12245 	uint32_t		count;
12246 	int			listindex;
12247 	int16_t			len;
12248 	fc_rscn_t		*payload;
12249 	fc_portmap_t		*listptr;
12250 	fctl_ns_req_t		*ns_cmd;
12251 	fc_affected_id_t	*page;
12252 	caddr_t			nvname;
12253 	nvlist_t		*attr_list = NULL;
12254 
12255 	mutex_enter(&port->fp_mutex);
12256 	if (!FC_IS_TOP_SWITCH(port->fp_topology)) {
12257 		if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
12258 			--port->fp_rscn_count;
12259 		}
12260 		mutex_exit(&port->fp_mutex);
12261 		return;
12262 	}
12263 	mutex_exit(&port->fp_mutex);
12264 
12265 	cmd = fp_alloc_pkt(port, FP_PORT_IDENTIFIER_LEN, 0, sleep, NULL);
12266 	if (cmd != NULL) {
12267 		fp_els_acc_init(port, cmd, buf, job);
12268 		if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
12269 			fp_free_pkt(cmd);
12270 		}
12271 	}
12272 
12273 	payload = (fc_rscn_t *)buf->ub_buffer;
12274 	ASSERT(payload->rscn_code == LA_ELS_RSCN);
12275 	ASSERT(payload->rscn_len == FP_PORT_IDENTIFIER_LEN);
12276 
12277 	len = payload->rscn_payload_len - FP_PORT_IDENTIFIER_LEN;
12278 
12279 	if (len <= 0) {
12280 		mutex_enter(&port->fp_mutex);
12281 		if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
12282 			--port->fp_rscn_count;
12283 		}
12284 		mutex_exit(&port->fp_mutex);
12285 
12286 		return;
12287 	}
12288 
12289 	ASSERT((len & 0x3) == 0);	/* Must be power of 4 */
12290 	count = (len >> 2) << 1;	/* number of pages multiplied by 2 */
12291 
12292 	listptr = kmem_zalloc(sizeof (fc_portmap_t) * count, sleep);
12293 	page = (fc_affected_id_t *)(buf->ub_buffer + sizeof (fc_rscn_t));
12294 
12295 	ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
12296 
12297 	ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gpn_id_t),
12298 	    sizeof (ns_resp_gpn_id_t), sizeof (ns_resp_gpn_id_t),
12299 	    0, sleep);
12300 	if (ns_cmd == NULL) {
12301 		kmem_free(listptr, sizeof (fc_portmap_t) * count);
12302 
12303 		mutex_enter(&port->fp_mutex);
12304 		if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
12305 			--port->fp_rscn_count;
12306 		}
12307 		mutex_exit(&port->fp_mutex);
12308 
12309 		return;
12310 	}
12311 
12312 	ns_cmd->ns_cmd_code = NS_GPN_ID;
12313 
12314 	FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_rscn: s_id=%x, d_id=%x,"
12315 	    "type=%x, f_ctl=%x seq_id=%x, ox_id=%x, rx_id=%x"
12316 	    " ro=%x", buf->ub_frame.s_id, buf->ub_frame.d_id,
12317 	    buf->ub_frame.type, buf->ub_frame.f_ctl, buf->ub_frame.seq_id,
12318 	    buf->ub_frame.ox_id, buf->ub_frame.rx_id, buf->ub_frame.ro);
12319 
12320 	/* Only proceed if we can allocate nvname and the nvlist */
12321 	if ((nvname = kmem_zalloc(RSCN_EVENT_NAME_LEN, KM_NOSLEEP)) != NULL &&
12322 	    nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE,
12323 	    KM_NOSLEEP) == DDI_SUCCESS) {
12324 		if (!(attr_list && nvlist_add_uint32(attr_list, "instance",
12325 		    port->fp_instance) == DDI_SUCCESS &&
12326 		    nvlist_add_byte_array(attr_list, "port-wwn",
12327 		    port->fp_service_params.nport_ww_name.raw_wwn,
12328 		    sizeof (la_wwn_t)) == DDI_SUCCESS)) {
12329 			nvlist_free(attr_list);
12330 			attr_list = NULL;
12331 		}
12332 	}
12333 
12334 	for (listindex = 0; len; len -= FP_PORT_IDENTIFIER_LEN, page++) {
12335 		/* Add affected page to the event payload */
12336 		if (attr_list != NULL) {
12337 			(void) snprintf(nvname, RSCN_EVENT_NAME_LEN,
12338 			    "affected_page_%d", listindex);
12339 			if (attr_list && nvlist_add_uint32(attr_list, nvname,
12340 			    ntohl(*(uint32_t *)page)) != DDI_SUCCESS) {
12341 				/* We don't send a partial event, so dump it */
12342 				nvlist_free(attr_list);
12343 				attr_list = NULL;
12344 			}
12345 		}
12346 		/*
12347 		 * Query the NS to get the Port WWN for this
12348 		 * affected D_ID.
12349 		 */
12350 		mask = 0;
12351 		switch (page->aff_format & FC_RSCN_ADDRESS_MASK) {
12352 		case FC_RSCN_PORT_ADDRESS:
12353 			fp_validate_rscn_page(port, page, job, ns_cmd,
12354 			    listptr, &listindex, sleep);
12355 
12356 			if (listindex == 0) {
12357 				/*
12358 				 * We essentially did not process this RSCN. So,
12359 				 * ULPs are not going to be called and so we
12360 				 * decrement the rscn_count
12361 				 */
12362 				mutex_enter(&port->fp_mutex);
12363 				if (--port->fp_rscn_count ==
12364 				    FC_INVALID_RSCN_COUNT) {
12365 					--port->fp_rscn_count;
12366 				}
12367 				mutex_exit(&port->fp_mutex);
12368 			}
12369 			break;
12370 
12371 		case FC_RSCN_AREA_ADDRESS:
12372 			mask = 0xFFFF00;
12373 			/* FALLTHROUGH */
12374 
12375 		case FC_RSCN_DOMAIN_ADDRESS:
12376 			if (!mask) {
12377 				mask = 0xFF0000;
12378 			}
12379 			fp_validate_area_domain(port, page->aff_d_id, mask,
12380 			    job, sleep);
12381 			break;
12382 
12383 		case FC_RSCN_FABRIC_ADDRESS:
12384 			/*
12385 			 * We need to discover all the devices on this
12386 			 * port.
12387 			 */
12388 			fp_validate_area_domain(port, 0, 0, job, sleep);
12389 			break;
12390 
12391 		default:
12392 			break;
12393 		}
12394 	}
12395 	if (attr_list != NULL) {
12396 		(void) ddi_log_sysevent(port->fp_port_dip, DDI_VENDOR_SUNW,
12397 		    EC_SUNFC, ESC_SUNFC_PORT_RSCN, attr_list,
12398 		    NULL, DDI_SLEEP);
12399 		nvlist_free(attr_list);
12400 	} else {
12401 		FP_TRACE(FP_NHEAD1(9, 0),
12402 		    "RSCN handled, but event not sent to userland");
12403 	}
12404 	if (nvname != NULL) {
12405 		kmem_free(nvname, RSCN_EVENT_NAME_LEN);
12406 	}
12407 
12408 	if (ns_cmd) {
12409 		fctl_free_ns_cmd(ns_cmd);
12410 	}
12411 
12412 	if (listindex) {
12413 #ifdef	DEBUG
12414 		page = (fc_affected_id_t *)(buf->ub_buffer +
12415 		    sizeof (fc_rscn_t));
12416 
12417 		if (listptr->map_did.port_id != page->aff_d_id) {
12418 			FP_TRACE(FP_NHEAD1(9, 0),
12419 			    "PORT RSCN: processed=%x, reporting=%x",
12420 			    listptr->map_did.port_id, page->aff_d_id);
12421 		}
12422 #endif
12423 
12424 		(void) fp_ulp_devc_cb(port, listptr, listindex, count,
12425 		    sleep, 0);
12426 	} else {
12427 		kmem_free(listptr, sizeof (fc_portmap_t) * count);
12428 	}
12429 }
12430 
12431 
12432 /*
12433  * Fill out old map for ULPs with fp_mutex, fd_mutex and pd_mutex held
12434  */
12435 static void
12436 fp_fillout_old_map_held(fc_portmap_t *map, fc_remote_port_t *pd, uchar_t flag)
12437 {
12438 	int		is_switch;
12439 	int		initiator;
12440 	fc_local_port_t	*port;
12441 
12442 	port = pd->pd_port;
12443 
12444 	/* This function has the following bunch of assumptions */
12445 	ASSERT(port != NULL);
12446 	ASSERT(MUTEX_HELD(&port->fp_mutex));
12447 	ASSERT(MUTEX_HELD(&pd->pd_remote_nodep->fd_mutex));
12448 	ASSERT(MUTEX_HELD(&pd->pd_mutex));
12449 
12450 	pd->pd_state = PORT_DEVICE_INVALID;
12451 	pd->pd_type = PORT_DEVICE_OLD;
12452 	initiator = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0;
12453 	is_switch = FC_IS_TOP_SWITCH(port->fp_topology);
12454 
12455 	fctl_delist_did_table(port, pd);
12456 	fctl_delist_pwwn_table(port, pd);
12457 
12458 	FP_TRACE(FP_NHEAD1(6, 0), "fp_fillout_old_map_held: port=%p, d_id=%x"
12459 	    " removed the PD=%p from DID and PWWN tables",
12460 	    port, pd->pd_port_id.port_id, pd);
12461 
12462 	if ((!flag) && port && initiator && is_switch) {
12463 		(void) fctl_add_orphan_held(port, pd);
12464 	}
12465 	fctl_copy_portmap_held(map, pd);
12466 	map->map_pd = pd;
12467 }
12468 
12469 /*
12470  * Fill out old map for ULPs
12471  */
12472 static void
12473 fp_fillout_old_map(fc_portmap_t *map, fc_remote_port_t *pd, uchar_t flag)
12474 {
12475 	int		is_switch;
12476 	int		initiator;
12477 	fc_local_port_t	*port;
12478 
12479 	mutex_enter(&pd->pd_mutex);
12480 	port = pd->pd_port;
12481 	mutex_exit(&pd->pd_mutex);
12482 
12483 	mutex_enter(&port->fp_mutex);
12484 	mutex_enter(&pd->pd_mutex);
12485 
12486 	pd->pd_state = PORT_DEVICE_INVALID;
12487 	pd->pd_type = PORT_DEVICE_OLD;
12488 	initiator = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0;
12489 	is_switch = FC_IS_TOP_SWITCH(port->fp_topology);
12490 
12491 	fctl_delist_did_table(port, pd);
12492 	fctl_delist_pwwn_table(port, pd);
12493 
12494 	FP_TRACE(FP_NHEAD1(6, 0), "fp_fillout_old_map: port=%p, d_id=%x"
12495 	    " removed the PD=%p from DID and PWWN tables",
12496 	    port, pd->pd_port_id.port_id, pd);
12497 
12498 	mutex_exit(&pd->pd_mutex);
12499 	mutex_exit(&port->fp_mutex);
12500 
12501 	ASSERT(port != NULL);
12502 	if ((!flag) && port && initiator && is_switch) {
12503 		(void) fctl_add_orphan(port, pd, KM_NOSLEEP);
12504 	}
12505 	fctl_copy_portmap(map, pd);
12506 	map->map_pd = pd;
12507 }
12508 
12509 
12510 /*
12511  * Fillout Changed Map for ULPs
12512  */
12513 static void
12514 fp_fillout_changed_map(fc_portmap_t *map, fc_remote_port_t *pd,
12515     uint32_t *new_did, la_wwn_t *new_pwwn)
12516 {
12517 	ASSERT(MUTEX_HELD(&pd->pd_mutex));
12518 
12519 	pd->pd_type = PORT_DEVICE_CHANGED;
12520 	if (new_did) {
12521 		pd->pd_port_id.port_id = *new_did;
12522 	}
12523 	if (new_pwwn) {
12524 		pd->pd_port_name = *new_pwwn;
12525 	}
12526 	mutex_exit(&pd->pd_mutex);
12527 
12528 	fctl_copy_portmap(map, pd);
12529 
12530 	mutex_enter(&pd->pd_mutex);
12531 	pd->pd_type = PORT_DEVICE_NOCHANGE;
12532 }
12533 
12534 
12535 /*
12536  * Fillout New Name Server map
12537  */
12538 static void
12539 fp_fillout_new_nsmap(fc_local_port_t *port, ddi_acc_handle_t *handle,
12540     fc_portmap_t *port_map, ns_resp_gan_t *gan_resp, uint32_t d_id)
12541 {
12542 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
12543 
12544 	if (handle) {
12545 		FC_GET_RSP(port, *handle, (uint8_t *)&port_map->map_pwwn,
12546 		    (uint8_t *)&gan_resp->gan_pwwn, sizeof (gan_resp->gan_pwwn),
12547 		    DDI_DEV_AUTOINCR);
12548 		FC_GET_RSP(port, *handle, (uint8_t *)&port_map->map_nwwn,
12549 		    (uint8_t *)&gan_resp->gan_nwwn, sizeof (gan_resp->gan_nwwn),
12550 		    DDI_DEV_AUTOINCR);
12551 		FC_GET_RSP(port, *handle, (uint8_t *)port_map->map_fc4_types,
12552 		    (uint8_t *)gan_resp->gan_fc4types,
12553 		    sizeof (gan_resp->gan_fc4types), DDI_DEV_AUTOINCR);
12554 	} else {
12555 		bcopy(&gan_resp->gan_pwwn, &port_map->map_pwwn,
12556 		    sizeof (gan_resp->gan_pwwn));
12557 		bcopy(&gan_resp->gan_nwwn, &port_map->map_nwwn,
12558 		    sizeof (gan_resp->gan_nwwn));
12559 		bcopy(gan_resp->gan_fc4types, port_map->map_fc4_types,
12560 		    sizeof (gan_resp->gan_fc4types));
12561 	}
12562 	port_map->map_did.port_id = d_id;
12563 	port_map->map_did.priv_lilp_posit = 0;
12564 	port_map->map_hard_addr.hard_addr = 0;
12565 	port_map->map_hard_addr.rsvd = 0;
12566 	port_map->map_state = PORT_DEVICE_INVALID;
12567 	port_map->map_type = PORT_DEVICE_NEW;
12568 	port_map->map_flags = 0;
12569 	port_map->map_pd = NULL;
12570 
12571 	(void) fctl_remove_if_orphan(port, &port_map->map_pwwn);
12572 
12573 	ASSERT(port != NULL);
12574 }
12575 
12576 
12577 /*
12578  * Perform LINIT ELS
12579  */
12580 static int
12581 fp_remote_lip(fc_local_port_t *port, la_wwn_t *pwwn, int sleep,
12582     job_request_t *job)
12583 {
12584 	int			rval;
12585 	uint32_t		d_id;
12586 	uint32_t		s_id;
12587 	uint32_t		lfa;
12588 	uchar_t			class;
12589 	uint32_t		ret;
12590 	fp_cmd_t		*cmd;
12591 	fc_porttype_t		ptype;
12592 	fc_packet_t		*pkt;
12593 	fc_linit_req_t		payload;
12594 	fc_remote_port_t	*pd;
12595 
12596 	rval = 0;
12597 
12598 	ASSERT(job != NULL);
12599 	ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
12600 
12601 	pd = fctl_get_remote_port_by_pwwn(port, pwwn);
12602 	if (pd == NULL) {
12603 		fctl_ns_req_t *ns_cmd;
12604 
12605 		ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t),
12606 		    sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t),
12607 		    0, sleep);
12608 
12609 		if (ns_cmd == NULL) {
12610 			return (FC_NOMEM);
12611 		}
12612 		job->job_result = FC_SUCCESS;
12613 		ns_cmd->ns_cmd_code = NS_GID_PN;
12614 		((ns_req_gid_pn_t *)(ns_cmd->ns_cmd_buf))->pwwn = *pwwn;
12615 
12616 		ret = fp_ns_query(port, ns_cmd, job, 1, sleep);
12617 		if (ret != FC_SUCCESS || job->job_result != FC_SUCCESS) {
12618 			fctl_free_ns_cmd(ns_cmd);
12619 			return (FC_FAILURE);
12620 		}
12621 		bcopy(ns_cmd->ns_data_buf, (caddr_t)&d_id, sizeof (d_id));
12622 		d_id = BE_32(*((uint32_t *)ns_cmd->ns_data_buf));
12623 
12624 		fctl_free_ns_cmd(ns_cmd);
12625 		lfa = d_id & 0xFFFF00;
12626 
12627 		/*
12628 		 * Given this D_ID, get the port type to see if
12629 		 * we can do LINIT on the LFA
12630 		 */
12631 		ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gpt_id_t),
12632 		    sizeof (ns_resp_gpt_id_t), sizeof (ns_resp_gpt_id_t),
12633 		    0, sleep);
12634 
12635 		if (ns_cmd == NULL) {
12636 			return (FC_NOMEM);
12637 		}
12638 
12639 		job->job_result = FC_SUCCESS;
12640 		ns_cmd->ns_cmd_code = NS_GPT_ID;
12641 
12642 		((ns_req_gpt_id_t *)(ns_cmd->ns_cmd_buf))->pid.port_id = d_id;
12643 		((ns_req_gpt_id_t *)
12644 		    (ns_cmd->ns_cmd_buf))->pid.priv_lilp_posit = 0;
12645 
12646 		ret = fp_ns_query(port, ns_cmd, job, 1, sleep);
12647 		if (ret != FC_SUCCESS || job->job_result != FC_SUCCESS) {
12648 			fctl_free_ns_cmd(ns_cmd);
12649 			return (FC_FAILURE);
12650 		}
12651 		bcopy(ns_cmd->ns_data_buf, (caddr_t)&ptype, sizeof (ptype));
12652 
12653 		fctl_free_ns_cmd(ns_cmd);
12654 
12655 		switch (ptype.port_type) {
12656 		case FC_NS_PORT_NL:
12657 		case FC_NS_PORT_F_NL:
12658 		case FC_NS_PORT_FL:
12659 			break;
12660 
12661 		default:
12662 			return (FC_FAILURE);
12663 		}
12664 	} else {
12665 		mutex_enter(&pd->pd_mutex);
12666 		ptype = pd->pd_porttype;
12667 
12668 		switch (pd->pd_porttype.port_type) {
12669 		case FC_NS_PORT_NL:
12670 		case FC_NS_PORT_F_NL:
12671 		case FC_NS_PORT_FL:
12672 			lfa = pd->pd_port_id.port_id & 0xFFFF00;
12673 			break;
12674 
12675 		default:
12676 			mutex_exit(&pd->pd_mutex);
12677 			return (FC_FAILURE);
12678 		}
12679 		mutex_exit(&pd->pd_mutex);
12680 	}
12681 
12682 	mutex_enter(&port->fp_mutex);
12683 	s_id = port->fp_port_id.port_id;
12684 	class = port->fp_ns_login_class;
12685 	mutex_exit(&port->fp_mutex);
12686 
12687 	cmd = fp_alloc_pkt(port, sizeof (fc_linit_req_t),
12688 	    sizeof (fc_linit_resp_t), sleep, pd);
12689 	if (cmd == NULL) {
12690 		return (FC_NOMEM);
12691 	}
12692 
12693 	cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class;
12694 	cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
12695 	cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
12696 	cmd->cmd_retry_count = fp_retry_count;
12697 	cmd->cmd_ulp_pkt = NULL;
12698 
12699 	pkt = &cmd->cmd_pkt;
12700 	cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
12701 
12702 	fp_els_init(cmd, s_id, lfa, fp_linit_intr, job);
12703 
12704 	/*
12705 	 * How does LIP work by the way ?
12706 	 *	If the L_Port receives three consecutive identical ordered
12707 	 *	sets whose first two characters (fully decoded) are equal to
12708 	 *	the values shown in Table 3 of FC-AL-2 then the L_Port shall
12709 	 *	recognize a Loop Initialization Primitive sequence. The
12710 	 *	character 3 determines the type of lip:
12711 	 *		LIP(F7)		Normal LIP
12712 	 *		LIP(F8)		Loop Failure LIP
12713 	 *
12714 	 * The possible combination for the 3rd and 4th bytes are:
12715 	 *	F7,	F7	Normal Lip	- No valid AL_PA
12716 	 *	F8,	F8	Loop Failure	- No valid AL_PA
12717 	 *	F7,	AL_PS	Normal Lip	- Valid source AL_PA
12718 	 *	F8,	AL_PS	Loop Failure	- Valid source AL_PA
12719 	 *	AL_PD	AL_PS	Loop reset of AL_PD originated by AL_PS
12720 	 *			And Normal Lip for all other loop members
12721 	 *	0xFF	AL_PS	Vendor specific reset of all loop members
12722 	 *
12723 	 * Now, it may not always be that we, at the source, may have an
12724 	 * AL_PS (AL_PA of source) for 4th character slot, so we decide
12725 	 * to do (Normal Lip, No Valid AL_PA), that means, in the LINIT
12726 	 * payload we are going to set:
12727 	 *	lip_b3 = 0xF7;		Normal LIP
12728 	 *	lip_b4 = 0xF7;		No valid source AL_PA
12729 	 */
12730 	payload.ls_code.ls_code = LA_ELS_LINIT;
12731 	payload.ls_code.mbz = 0;
12732 	payload.rsvd = 0;
12733 	payload.func = 0;		/* Let Fabric determine the best way */
12734 	payload.lip_b3 = 0xF7;		/* Normal LIP */
12735 	payload.lip_b4 = 0xF7;		/* No valid source AL_PA */
12736 
12737 	FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
12738 	    (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
12739 
12740 	job->job_counter = 1;
12741 
12742 	ret = fp_sendcmd(port, cmd, port->fp_fca_handle);
12743 	if (ret == FC_SUCCESS) {
12744 		fp_jobwait(job);
12745 		rval = job->job_result;
12746 	} else {
12747 		rval = FC_FAILURE;
12748 		fp_free_pkt(cmd);
12749 	}
12750 
12751 	return (rval);
12752 }
12753 
12754 
12755 /*
12756  * Fill out the device handles with GAN response
12757  */
12758 static void
12759 fp_stuff_device_with_gan(ddi_acc_handle_t *handle, fc_remote_port_t *pd,
12760     ns_resp_gan_t *gan_resp)
12761 {
12762 	fc_remote_node_t	*node;
12763 	fc_porttype_t		type;
12764 	fc_local_port_t		*port;
12765 
12766 	ASSERT(pd != NULL);
12767 	ASSERT(handle != NULL);
12768 
12769 	port = pd->pd_port;
12770 
12771 	FP_TRACE(FP_NHEAD1(1, 0), "GAN PD stuffing; pd=%p,"
12772 	    " port_id=%x, sym_len=%d fc4-type=%x",
12773 	    pd, gan_resp->gan_type_id.rsvd,
12774 	    gan_resp->gan_spnlen, gan_resp->gan_fc4types[0]);
12775 
12776 	mutex_enter(&pd->pd_mutex);
12777 
12778 	FC_GET_RSP(port, *handle, (uint8_t *)&type,
12779 	    (uint8_t *)&gan_resp->gan_type_id, sizeof (type), DDI_DEV_AUTOINCR);
12780 
12781 	pd->pd_porttype.port_type = type.port_type;
12782 	pd->pd_porttype.rsvd = 0;
12783 
12784 	pd->pd_spn_len = gan_resp->gan_spnlen;
12785 	if (pd->pd_spn_len) {
12786 		FC_GET_RSP(port, *handle, (uint8_t *)pd->pd_spn,
12787 		    (uint8_t *)gan_resp->gan_spname, pd->pd_spn_len,
12788 		    DDI_DEV_AUTOINCR);
12789 	}
12790 
12791 	FC_GET_RSP(port, *handle, (uint8_t *)pd->pd_ip_addr,
12792 	    (uint8_t *)gan_resp->gan_ip, sizeof (pd->pd_ip_addr),
12793 	    DDI_DEV_AUTOINCR);
12794 	FC_GET_RSP(port, *handle, (uint8_t *)&pd->pd_cos,
12795 	    (uint8_t *)&gan_resp->gan_cos, sizeof (pd->pd_cos),
12796 	    DDI_DEV_AUTOINCR);
12797 	FC_GET_RSP(port, *handle, (uint8_t *)pd->pd_fc4types,
12798 	    (uint8_t *)gan_resp->gan_fc4types, sizeof (pd->pd_fc4types),
12799 	    DDI_DEV_AUTOINCR);
12800 
12801 	node = pd->pd_remote_nodep;
12802 	mutex_exit(&pd->pd_mutex);
12803 
12804 	mutex_enter(&node->fd_mutex);
12805 
12806 	FC_GET_RSP(port, *handle, (uint8_t *)node->fd_ipa,
12807 	    (uint8_t *)gan_resp->gan_ipa, sizeof (node->fd_ipa),
12808 	    DDI_DEV_AUTOINCR);
12809 
12810 	node->fd_snn_len = gan_resp->gan_snnlen;
12811 	if (node->fd_snn_len) {
12812 		FC_GET_RSP(port, *handle, (uint8_t *)node->fd_snn,
12813 		    (uint8_t *)gan_resp->gan_snname, node->fd_snn_len,
12814 		    DDI_DEV_AUTOINCR);
12815 	}
12816 
12817 	mutex_exit(&node->fd_mutex);
12818 }
12819 
12820 
12821 /*
12822  * Handles all NS Queries (also means that this function
12823  * doesn't handle NS object registration)
12824  */
12825 static int
12826 fp_ns_query(fc_local_port_t *port, fctl_ns_req_t *ns_cmd, job_request_t *job,
12827     int polled, int sleep)
12828 {
12829 	int		rval;
12830 	fp_cmd_t	*cmd;
12831 
12832 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
12833 
12834 	if (ns_cmd->ns_cmd_code == NS_GA_NXT) {
12835 		FP_TRACE(FP_NHEAD1(1, 0), "fp_ns_query GA_NXT fp %x pd %x",
12836 		    port->fp_port_id.port_id, ns_cmd->ns_gan_sid);
12837 	}
12838 
12839 	if (ns_cmd->ns_cmd_size == 0) {
12840 		return (FC_FAILURE);
12841 	}
12842 
12843 	cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
12844 	    ns_cmd->ns_cmd_size, sizeof (fc_ct_header_t) +
12845 	    ns_cmd->ns_resp_size, sleep, NULL);
12846 	if (cmd == NULL) {
12847 		return (FC_NOMEM);
12848 	}
12849 
12850 	fp_ct_init(port, cmd, ns_cmd, ns_cmd->ns_cmd_code, ns_cmd->ns_cmd_buf,
12851 	    ns_cmd->ns_cmd_size, ns_cmd->ns_resp_size, job);
12852 
12853 	if (polled) {
12854 		job->job_counter = 1;
12855 		ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
12856 	}
12857 	rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
12858 	if (rval != FC_SUCCESS) {
12859 		job->job_result = rval;
12860 		fp_iodone(cmd);
12861 		if (polled == 0) {
12862 			/*
12863 			 * Return FC_SUCCESS to indicate that
12864 			 * fp_iodone is performed already.
12865 			 */
12866 			rval = FC_SUCCESS;
12867 		}
12868 	}
12869 
12870 	if (polled) {
12871 		fp_jobwait(job);
12872 		rval = job->job_result;
12873 	}
12874 
12875 	return (rval);
12876 }
12877 
12878 
12879 /*
12880  * Initialize Common Transport request
12881  */
12882 static void
12883 fp_ct_init(fc_local_port_t *port, fp_cmd_t *cmd, fctl_ns_req_t *ns_cmd,
12884     uint16_t cmd_code, caddr_t cmd_buf, uint16_t cmd_len,
12885     uint16_t resp_len, job_request_t *job)
12886 {
12887 	uint32_t	s_id;
12888 	uchar_t		class;
12889 	fc_packet_t	*pkt;
12890 	fc_ct_header_t	ct;
12891 
12892 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
12893 
12894 	mutex_enter(&port->fp_mutex);
12895 	s_id = port->fp_port_id.port_id;
12896 	class = port->fp_ns_login_class;
12897 	mutex_exit(&port->fp_mutex);
12898 
12899 	cmd->cmd_job = job;
12900 	cmd->cmd_private = ns_cmd;
12901 	pkt = &cmd->cmd_pkt;
12902 
12903 	ct.ct_rev = CT_REV;
12904 	ct.ct_inid = 0;
12905 	ct.ct_fcstype = FCSTYPE_DIRECTORY;
12906 	ct.ct_fcssubtype = FCSSUB_DS_NAME_SERVER;
12907 	ct.ct_options = 0;
12908 	ct.ct_reserved1 = 0;
12909 	ct.ct_cmdrsp = cmd_code;
12910 	ct.ct_aiusize = resp_len >> 2;
12911 	ct.ct_reserved2 = 0;
12912 	ct.ct_reason = 0;
12913 	ct.ct_expln = 0;
12914 	ct.ct_vendor = 0;
12915 
12916 	FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&ct,
12917 	    (uint8_t *)pkt->pkt_cmd, sizeof (ct), DDI_DEV_AUTOINCR);
12918 
12919 	pkt->pkt_cmd_fhdr.r_ctl = R_CTL_UNSOL_CONTROL;
12920 	pkt->pkt_cmd_fhdr.d_id = 0xFFFFFC;
12921 	pkt->pkt_cmd_fhdr.s_id = s_id;
12922 	pkt->pkt_cmd_fhdr.type = FC_TYPE_FC_SERVICES;
12923 	pkt->pkt_cmd_fhdr.f_ctl = F_CTL_SEQ_INITIATIVE |
12924 	    F_CTL_FIRST_SEQ | F_CTL_END_SEQ;
12925 	pkt->pkt_cmd_fhdr.seq_id = 0;
12926 	pkt->pkt_cmd_fhdr.df_ctl  = 0;
12927 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
12928 	pkt->pkt_cmd_fhdr.ox_id = 0xffff;
12929 	pkt->pkt_cmd_fhdr.rx_id = 0xffff;
12930 	pkt->pkt_cmd_fhdr.ro = 0;
12931 	pkt->pkt_cmd_fhdr.rsvd = 0;
12932 
12933 	pkt->pkt_comp = fp_ns_intr;
12934 	pkt->pkt_ulp_private = (opaque_t)cmd;
12935 	pkt->pkt_timeout = FP_NS_TIMEOUT;
12936 
12937 	if (cmd_buf) {
12938 		FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)cmd_buf,
12939 		    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
12940 		    cmd_len, DDI_DEV_AUTOINCR);
12941 	}
12942 
12943 	cmd->cmd_transport = port->fp_fca_tran->fca_transport;
12944 
12945 	cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class;
12946 	cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
12947 	cmd->cmd_flags = FP_CMD_PLOGI_DONT_CARE;
12948 	cmd->cmd_retry_count = fp_retry_count;
12949 	cmd->cmd_ulp_pkt = NULL;
12950 }
12951 
12952 
12953 /*
12954  * Name Server request interrupt routine
12955  */
12956 static void
12957 fp_ns_intr(fc_packet_t *pkt)
12958 {
12959 	fp_cmd_t	*cmd;
12960 	fc_local_port_t	*port;
12961 	fc_ct_header_t	resp_hdr;
12962 	fc_ct_header_t	cmd_hdr;
12963 	fctl_ns_req_t	*ns_cmd;
12964 
12965 	cmd = pkt->pkt_ulp_private;
12966 	port = cmd->cmd_port;
12967 
12968 	mutex_enter(&port->fp_mutex);
12969 	port->fp_out_fpcmds--;
12970 	mutex_exit(&port->fp_mutex);
12971 
12972 	FC_GET_RSP(port, pkt->pkt_cmd_acc, (uint8_t *)&cmd_hdr,
12973 	    (uint8_t *)pkt->pkt_cmd, sizeof (cmd_hdr), DDI_DEV_AUTOINCR);
12974 	ns_cmd = (fctl_ns_req_t *)
12975 	    (((fp_cmd_t *)(pkt->pkt_ulp_private))->cmd_private);
12976 	if (!FP_IS_PKT_ERROR(pkt)) {
12977 		FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp_hdr,
12978 		    (uint8_t *)pkt->pkt_resp, sizeof (resp_hdr),
12979 		    DDI_DEV_AUTOINCR);
12980 
12981 		/*
12982 		 * On x86 architectures, make sure the resp_hdr is big endian.
12983 		 * This macro is a NOP on sparc architectures mainly because
12984 		 * we don't want to end up wasting time since the end result
12985 		 * is going to be the same.
12986 		 */
12987 		MAKE_BE_32(&resp_hdr);
12988 
12989 		if (ns_cmd) {
12990 			/*
12991 			 * Always copy out the response CT_HDR
12992 			 */
12993 			bcopy(&resp_hdr, &ns_cmd->ns_resp_hdr,
12994 			    sizeof (resp_hdr));
12995 		}
12996 
12997 		if (resp_hdr.ct_cmdrsp == FS_RJT_IU) {
12998 			pkt->pkt_state = FC_PKT_FS_RJT;
12999 			pkt->pkt_reason = resp_hdr.ct_reason;
13000 			pkt->pkt_expln = resp_hdr.ct_expln;
13001 		}
13002 	}
13003 
13004 	if (FP_IS_PKT_ERROR(pkt)) {
13005 		if (ns_cmd) {
13006 			if (ns_cmd->ns_flags & FCTL_NS_VALIDATE_PD) {
13007 				ASSERT(ns_cmd->ns_pd != NULL);
13008 
13009 				/* Mark it OLD if not already done */
13010 				mutex_enter(&ns_cmd->ns_pd->pd_mutex);
13011 				ns_cmd->ns_pd->pd_type = PORT_DEVICE_OLD;
13012 				mutex_exit(&ns_cmd->ns_pd->pd_mutex);
13013 			}
13014 
13015 			if (ns_cmd->ns_flags & FCTL_NS_ASYNC_REQUEST) {
13016 				fctl_free_ns_cmd(ns_cmd);
13017 				((fp_cmd_t *)
13018 				    (pkt->pkt_ulp_private))->cmd_private = NULL;
13019 			}
13020 
13021 		}
13022 
13023 		FP_TRACE(FP_NHEAD2(9, 0), "%x NS failure pkt state=%x"
13024 		    "reason=%x, expln=%x, NSCMD=%04X, NSRSP=%04X",
13025 		    port->fp_port_id.port_id, pkt->pkt_state,
13026 		    pkt->pkt_reason, pkt->pkt_expln,
13027 		    cmd_hdr.ct_cmdrsp,  resp_hdr.ct_cmdrsp);
13028 
13029 		(void) fp_common_intr(pkt, 1);
13030 
13031 		return;
13032 	}
13033 
13034 	if (resp_hdr.ct_cmdrsp != FS_ACC_IU) {
13035 		uint32_t	d_id;
13036 		fc_local_port_t	*port;
13037 		fp_cmd_t	*cmd;
13038 
13039 		d_id = pkt->pkt_cmd_fhdr.d_id;
13040 		cmd = pkt->pkt_ulp_private;
13041 		port = cmd->cmd_port;
13042 		FP_TRACE(FP_NHEAD2(9, 0),
13043 		    "Bogus NS response received for D_ID=%x", d_id);
13044 	}
13045 
13046 	if (cmd_hdr.ct_cmdrsp == NS_GA_NXT) {
13047 		fp_gan_handler(pkt, ns_cmd);
13048 		return;
13049 	}
13050 
13051 	if (cmd_hdr.ct_cmdrsp >= NS_GPN_ID &&
13052 	    cmd_hdr.ct_cmdrsp <= NS_GID_PT) {
13053 		if (ns_cmd) {
13054 			if ((ns_cmd->ns_flags & FCTL_NS_NO_DATA_BUF) == 0) {
13055 				fp_ns_query_handler(pkt, ns_cmd);
13056 				return;
13057 			}
13058 		}
13059 	}
13060 
13061 	fp_iodone(pkt->pkt_ulp_private);
13062 }
13063 
13064 
13065 /*
13066  * Process NS_GAN response
13067  */
13068 static void
13069 fp_gan_handler(fc_packet_t *pkt, fctl_ns_req_t *ns_cmd)
13070 {
13071 	int			my_did;
13072 	fc_portid_t		d_id;
13073 	fp_cmd_t		*cmd;
13074 	fc_local_port_t		*port;
13075 	fc_remote_port_t	*pd;
13076 	ns_req_gan_t		gan_req;
13077 	ns_resp_gan_t		*gan_resp;
13078 
13079 	ASSERT(ns_cmd != NULL);
13080 
13081 	cmd = pkt->pkt_ulp_private;
13082 	port = cmd->cmd_port;
13083 
13084 	gan_resp = (ns_resp_gan_t *)(pkt->pkt_resp + sizeof (fc_ct_header_t));
13085 
13086 	FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&d_id,
13087 	    (uint8_t *)&gan_resp->gan_type_id, sizeof (d_id), DDI_DEV_AUTOINCR);
13088 
13089 	*(uint32_t *)&d_id = BE_32(*(uint32_t *)&d_id);
13090 
13091 	/*
13092 	 * In this case the priv_lilp_posit field  in reality
13093 	 * is actually represents the relative position on a private loop.
13094 	 * So zero it while dealing with Port Identifiers.
13095 	 */
13096 	d_id.priv_lilp_posit = 0;
13097 	pd = fctl_get_remote_port_by_did(port, d_id.port_id);
13098 	if (ns_cmd->ns_gan_sid == d_id.port_id) {
13099 		/*
13100 		 * We've come a full circle; time to get out.
13101 		 */
13102 		fp_iodone(cmd);
13103 		return;
13104 	}
13105 
13106 	if (ns_cmd->ns_gan_sid == FCTL_GAN_START_ID) {
13107 		ns_cmd->ns_gan_sid = d_id.port_id;
13108 	}
13109 
13110 	mutex_enter(&port->fp_mutex);
13111 	my_did = (d_id.port_id == port->fp_port_id.port_id) ? 1 : 0;
13112 	mutex_exit(&port->fp_mutex);
13113 
13114 	FP_TRACE(FP_NHEAD1(1, 0), "GAN response; port=%p, fp %x pd %x", port,
13115 	    port->fp_port_id.port_id, d_id.port_id);
13116 	if (my_did == 0) {
13117 		la_wwn_t pwwn;
13118 		la_wwn_t nwwn;
13119 
13120 		FP_TRACE(FP_NHEAD1(1, 0), "GAN response details; "
13121 		    "port=%p, d_id=%x, type_id=%x, "
13122 		    "pwwn=%x %x %x %x %x %x %x %x, "
13123 		    "nwwn=%x %x %x %x %x %x %x %x",
13124 		    port, d_id.port_id, gan_resp->gan_type_id,
13125 
13126 		    gan_resp->gan_pwwn.raw_wwn[0],
13127 		    gan_resp->gan_pwwn.raw_wwn[1],
13128 		    gan_resp->gan_pwwn.raw_wwn[2],
13129 		    gan_resp->gan_pwwn.raw_wwn[3],
13130 		    gan_resp->gan_pwwn.raw_wwn[4],
13131 		    gan_resp->gan_pwwn.raw_wwn[5],
13132 		    gan_resp->gan_pwwn.raw_wwn[6],
13133 		    gan_resp->gan_pwwn.raw_wwn[7],
13134 
13135 		    gan_resp->gan_nwwn.raw_wwn[0],
13136 		    gan_resp->gan_nwwn.raw_wwn[1],
13137 		    gan_resp->gan_nwwn.raw_wwn[2],
13138 		    gan_resp->gan_nwwn.raw_wwn[3],
13139 		    gan_resp->gan_nwwn.raw_wwn[4],
13140 		    gan_resp->gan_nwwn.raw_wwn[5],
13141 		    gan_resp->gan_nwwn.raw_wwn[6],
13142 		    gan_resp->gan_nwwn.raw_wwn[7]);
13143 
13144 		FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&nwwn,
13145 		    (uint8_t *)&gan_resp->gan_nwwn, sizeof (nwwn),
13146 		    DDI_DEV_AUTOINCR);
13147 
13148 		FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&pwwn,
13149 		    (uint8_t *)&gan_resp->gan_pwwn, sizeof (pwwn),
13150 		    DDI_DEV_AUTOINCR);
13151 
13152 		if (ns_cmd->ns_flags & FCTL_NS_CREATE_DEVICE && pd == NULL) {
13153 			FP_TRACE(FP_NHEAD1(1, 0), "fp %x gan_hander create"
13154 			    "pd %x", port->fp_port_id.port_id, d_id.port_id);
13155 			pd = fctl_create_remote_port(port, &nwwn, &pwwn,
13156 			    d_id.port_id, PD_PLOGI_INITIATOR, KM_NOSLEEP);
13157 		}
13158 		if (pd != NULL) {
13159 			fp_stuff_device_with_gan(&pkt->pkt_resp_acc,
13160 			    pd, gan_resp);
13161 		}
13162 
13163 		if (ns_cmd->ns_flags & FCTL_NS_GET_DEV_COUNT) {
13164 			*((int *)ns_cmd->ns_data_buf) += 1;
13165 		}
13166 
13167 		if (ns_cmd->ns_flags & FCTL_NS_FILL_NS_MAP) {
13168 			ASSERT((ns_cmd->ns_flags & FCTL_NS_NO_DATA_BUF) == 0);
13169 
13170 			if (ns_cmd->ns_flags & FCTL_NS_BUF_IS_USERLAND) {
13171 				fc_port_dev_t *userbuf;
13172 
13173 				userbuf = ((fc_port_dev_t *)
13174 				    ns_cmd->ns_data_buf) +
13175 				    ns_cmd->ns_gan_index++;
13176 
13177 				userbuf->dev_did = d_id;
13178 
13179 				FC_GET_RSP(port, pkt->pkt_resp_acc,
13180 				    (uint8_t *)userbuf->dev_type,
13181 				    (uint8_t *)gan_resp->gan_fc4types,
13182 				    sizeof (userbuf->dev_type),
13183 				    DDI_DEV_AUTOINCR);
13184 
13185 				userbuf->dev_nwwn = nwwn;
13186 				userbuf->dev_pwwn = pwwn;
13187 
13188 				if (pd != NULL) {
13189 					mutex_enter(&pd->pd_mutex);
13190 					userbuf->dev_state = pd->pd_state;
13191 					userbuf->dev_hard_addr =
13192 					    pd->pd_hard_addr;
13193 					mutex_exit(&pd->pd_mutex);
13194 				} else {
13195 					userbuf->dev_state =
13196 					    PORT_DEVICE_INVALID;
13197 				}
13198 			} else if (ns_cmd->ns_flags &
13199 			    FCTL_NS_BUF_IS_FC_PORTMAP) {
13200 				fc_portmap_t *map;
13201 
13202 				map = ((fc_portmap_t *)
13203 				    ns_cmd->ns_data_buf) +
13204 				    ns_cmd->ns_gan_index++;
13205 
13206 				/*
13207 				 * First fill it like any new map
13208 				 * and update the port device info
13209 				 * below.
13210 				 */
13211 				fp_fillout_new_nsmap(port, &pkt->pkt_resp_acc,
13212 				    map, gan_resp, d_id.port_id);
13213 				if (pd != NULL) {
13214 					fctl_copy_portmap(map, pd);
13215 				} else {
13216 					map->map_state = PORT_DEVICE_INVALID;
13217 					map->map_type = PORT_DEVICE_NOCHANGE;
13218 				}
13219 			} else {
13220 				caddr_t dst_ptr;
13221 
13222 				dst_ptr = ns_cmd->ns_data_buf +
13223 				    (NS_GAN_RESP_LEN) * ns_cmd->ns_gan_index++;
13224 
13225 				FC_GET_RSP(port, pkt->pkt_resp_acc,
13226 				    (uint8_t *)dst_ptr, (uint8_t *)gan_resp,
13227 				    NS_GAN_RESP_LEN, DDI_DEV_AUTOINCR);
13228 			}
13229 		} else {
13230 			ns_cmd->ns_gan_index++;
13231 		}
13232 		if (ns_cmd->ns_gan_index >= ns_cmd->ns_gan_max) {
13233 			fp_iodone(cmd);
13234 			return;
13235 		}
13236 	}
13237 
13238 	gan_req.pid = d_id;
13239 
13240 	FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&gan_req,
13241 	    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
13242 	    sizeof (gan_req), DDI_DEV_AUTOINCR);
13243 
13244 	if (cmd->cmd_transport(port->fp_fca_handle, pkt) != FC_SUCCESS) {
13245 		pkt->pkt_state = FC_PKT_TRAN_ERROR;
13246 		fp_iodone(cmd);
13247 	} else {
13248 		mutex_enter(&port->fp_mutex);
13249 		port->fp_out_fpcmds++;
13250 		mutex_exit(&port->fp_mutex);
13251 	}
13252 }
13253 
13254 
13255 /*
13256  * Handle NS Query interrupt
13257  */
13258 static void
13259 fp_ns_query_handler(fc_packet_t *pkt, fctl_ns_req_t *ns_cmd)
13260 {
13261 	fp_cmd_t	*cmd;
13262 	fc_local_port_t	*port;
13263 	caddr_t		src_ptr;
13264 	uint32_t	xfer_len;
13265 
13266 	cmd = pkt->pkt_ulp_private;
13267 	port = cmd->cmd_port;
13268 
13269 	xfer_len = ns_cmd->ns_resp_size;
13270 
13271 	FP_TRACE(FP_NHEAD1(1, 0), "NS Query response, cmd_code=%x, xfer_len=%x",
13272 	    ns_cmd->ns_cmd_code, xfer_len);
13273 
13274 	if (ns_cmd->ns_cmd_code == NS_GPN_ID) {
13275 		src_ptr = (caddr_t)pkt->pkt_resp + sizeof (fc_ct_header_t);
13276 
13277 		FP_TRACE(FP_NHEAD1(6, 0), "GPN_ID results; %x %x %x %x %x",
13278 		    src_ptr[0], src_ptr[1], src_ptr[2], src_ptr[3], src_ptr[4]);
13279 	}
13280 
13281 	if (xfer_len <= ns_cmd->ns_data_len) {
13282 		src_ptr = (caddr_t)pkt->pkt_resp + sizeof (fc_ct_header_t);
13283 		FC_GET_RSP(port, pkt->pkt_resp_acc,
13284 		    (uint8_t *)ns_cmd->ns_data_buf,
13285 		    (uint8_t *)src_ptr, xfer_len, DDI_DEV_AUTOINCR);
13286 	}
13287 
13288 	if (ns_cmd->ns_flags & FCTL_NS_VALIDATE_PD) {
13289 		ASSERT(ns_cmd->ns_pd != NULL);
13290 
13291 		mutex_enter(&ns_cmd->ns_pd->pd_mutex);
13292 		if (ns_cmd->ns_pd->pd_type == PORT_DEVICE_OLD) {
13293 			ns_cmd->ns_pd->pd_type = PORT_DEVICE_NOCHANGE;
13294 		}
13295 		mutex_exit(&ns_cmd->ns_pd->pd_mutex);
13296 	}
13297 
13298 	if (ns_cmd->ns_flags & FCTL_NS_ASYNC_REQUEST) {
13299 		fctl_free_ns_cmd(ns_cmd);
13300 		((fp_cmd_t *)(pkt->pkt_ulp_private))->cmd_private = NULL;
13301 	}
13302 	fp_iodone(cmd);
13303 }
13304 
13305 
13306 /*
13307  * Handle unsolicited ADISC ELS request
13308  */
13309 static void
13310 fp_handle_unsol_adisc(fc_local_port_t *port, fc_unsol_buf_t *buf,
13311     fc_remote_port_t *pd, job_request_t *job)
13312 {
13313 	int		rval;
13314 	fp_cmd_t	*cmd;
13315 
13316 	FP_TRACE(FP_NHEAD1(5, 0), "ADISC; port=%p, D_ID=%x state=%x, pd=%p",
13317 	    port, pd->pd_port_id.port_id, pd->pd_state, pd);
13318 	mutex_enter(&pd->pd_mutex);
13319 	if (pd->pd_state != PORT_DEVICE_LOGGED_IN) {
13320 		mutex_exit(&pd->pd_mutex);
13321 		if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
13322 			cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t),
13323 			    0, KM_SLEEP, pd);
13324 			if (cmd != NULL) {
13325 				fp_els_rjt_init(port, cmd, buf,
13326 				    FC_ACTION_NON_RETRYABLE,
13327 				    FC_REASON_INVALID_LINK_CTRL, job);
13328 
13329 				if (fp_sendcmd(port, cmd,
13330 				    port->fp_fca_handle) != FC_SUCCESS) {
13331 					fp_free_pkt(cmd);
13332 				}
13333 			}
13334 		}
13335 	} else {
13336 		mutex_exit(&pd->pd_mutex);
13337 		/*
13338 		 * Yes, yes, we don't have a hard address. But we
13339 		 * we should still respond. Huh ? Visit 21.19.2
13340 		 * of FC-PH-2 which essentially says that if an
13341 		 * NL_Port doesn't have a hard address, or if a port
13342 		 * does not have FC-AL capability, it shall report
13343 		 * zeroes in this field.
13344 		 */
13345 		cmd = fp_alloc_pkt(port, sizeof (la_els_adisc_t),
13346 		    0, KM_SLEEP, pd);
13347 		if (cmd == NULL) {
13348 			return;
13349 		}
13350 		fp_adisc_acc_init(port, cmd, buf, job);
13351 		rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
13352 		if (rval != FC_SUCCESS) {
13353 			fp_free_pkt(cmd);
13354 		}
13355 	}
13356 }
13357 
13358 
13359 /*
13360  * Initialize ADISC response.
13361  */
13362 static void
13363 fp_adisc_acc_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf,
13364     job_request_t *job)
13365 {
13366 	fc_packet_t	*pkt;
13367 	la_els_adisc_t	payload;
13368 
13369 	cmd->cmd_pkt.pkt_tran_flags = buf->ub_class;
13370 	cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND;
13371 	cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
13372 	cmd->cmd_retry_count = 1;
13373 	cmd->cmd_ulp_pkt = NULL;
13374 
13375 	cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
13376 	cmd->cmd_job = job;
13377 
13378 	pkt = &cmd->cmd_pkt;
13379 
13380 	fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP, FC_TYPE_EXTENDED_LS);
13381 
13382 	payload.ls_code.ls_code = LA_ELS_ACC;
13383 	payload.ls_code.mbz = 0;
13384 
13385 	mutex_enter(&port->fp_mutex);
13386 	payload.nport_id = port->fp_port_id;
13387 	payload.hard_addr = port->fp_hard_addr;
13388 	mutex_exit(&port->fp_mutex);
13389 
13390 	payload.port_wwn = port->fp_service_params.nport_ww_name;
13391 	payload.node_wwn = port->fp_service_params.node_ww_name;
13392 
13393 	FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
13394 	    (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
13395 }
13396 
13397 
13398 /*
13399  * Hold and Install the requested ULP drivers
13400  */
13401 static void
13402 fp_load_ulp_modules(dev_info_t *dip, fc_local_port_t *port)
13403 {
13404 	int		len;
13405 	int		count;
13406 	int		data_len;
13407 	major_t		ulp_major;
13408 	caddr_t		ulp_name;
13409 	caddr_t		data_ptr;
13410 	caddr_t		data_buf;
13411 
13412 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
13413 
13414 	data_buf = NULL;
13415 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
13416 	    DDI_PROP_DONTPASS, "load-ulp-list",
13417 	    (caddr_t)&data_buf, &data_len) != DDI_PROP_SUCCESS) {
13418 		return;
13419 	}
13420 
13421 	len = strlen(data_buf);
13422 	port->fp_ulp_nload = fctl_atoi(data_buf, 10);
13423 
13424 	data_ptr = data_buf + len + 1;
13425 	for (count = 0; count < port->fp_ulp_nload; count++) {
13426 		len = strlen(data_ptr) + 1;
13427 		ulp_name = kmem_zalloc(len, KM_SLEEP);
13428 		bcopy(data_ptr, ulp_name, len);
13429 
13430 		ulp_major = ddi_name_to_major(ulp_name);
13431 
13432 		if (ulp_major != (major_t)-1) {
13433 			if (modload("drv", ulp_name) < 0) {
13434 				fp_printf(port, CE_NOTE, FP_LOG_ONLY,
13435 				    0, NULL, "failed to load %s",
13436 				    ulp_name);
13437 			}
13438 		} else {
13439 			fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
13440 			    "%s isn't a valid driver", ulp_name);
13441 		}
13442 
13443 		kmem_free(ulp_name, len);
13444 		data_ptr += len;	/* Skip to next field */
13445 	}
13446 
13447 	/*
13448 	 * Free the memory allocated by DDI
13449 	 */
13450 	if (data_buf != NULL) {
13451 		kmem_free(data_buf, data_len);
13452 	}
13453 }
13454 
13455 
13456 /*
13457  * Perform LOGO operation
13458  */
13459 static int
13460 fp_logout(fc_local_port_t *port, fc_remote_port_t *pd, job_request_t *job)
13461 {
13462 	int		rval;
13463 	fp_cmd_t	*cmd;
13464 
13465 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
13466 	ASSERT(!MUTEX_HELD(&pd->pd_mutex));
13467 
13468 	cmd = fp_alloc_pkt(port, sizeof (la_els_logo_t),
13469 	    FP_PORT_IDENTIFIER_LEN, KM_SLEEP, pd);
13470 
13471 	mutex_enter(&port->fp_mutex);
13472 	mutex_enter(&pd->pd_mutex);
13473 
13474 	ASSERT(pd->pd_state == PORT_DEVICE_LOGGED_IN);
13475 	ASSERT(pd->pd_login_count == 1);
13476 
13477 	cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
13478 	cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
13479 	cmd->cmd_flags = 0;
13480 	cmd->cmd_retry_count = 1;
13481 	cmd->cmd_ulp_pkt = NULL;
13482 
13483 	fp_logo_init(pd, cmd, job);
13484 
13485 	mutex_exit(&pd->pd_mutex);
13486 	mutex_exit(&port->fp_mutex);
13487 
13488 	rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
13489 	if (rval != FC_SUCCESS) {
13490 		fp_iodone(cmd);
13491 	}
13492 
13493 	return (rval);
13494 }
13495 
13496 
13497 /*
13498  * Perform Port attach callbacks to registered ULPs
13499  */
13500 static void
13501 fp_attach_ulps(fc_local_port_t *port, fc_attach_cmd_t cmd)
13502 {
13503 	fp_soft_attach_t *att;
13504 
13505 	att = kmem_zalloc(sizeof (*att), KM_SLEEP);
13506 	att->att_cmd = cmd;
13507 	att->att_port = port;
13508 
13509 	/*
13510 	 * We need to remember whether or not fctl_busy_port
13511 	 * succeeded so we know whether or not to call
13512 	 * fctl_idle_port when the task is complete.
13513 	 */
13514 
13515 	if (fctl_busy_port(port) == 0) {
13516 		att->att_need_pm_idle = B_TRUE;
13517 	} else {
13518 		att->att_need_pm_idle = B_FALSE;
13519 	}
13520 
13521 	(void) taskq_dispatch(port->fp_taskq, fp_ulp_port_attach,
13522 	    att, KM_SLEEP);
13523 }
13524 
13525 
13526 /*
13527  * Forward state change notifications on to interested ULPs.
13528  * Spawns a call to fctl_ulp_statec_cb() in a taskq thread to do all the
13529  * real work.
13530  */
13531 static int
13532 fp_ulp_notify(fc_local_port_t *port, uint32_t statec, int sleep)
13533 {
13534 	fc_port_clist_t *clist;
13535 
13536 	clist = kmem_zalloc(sizeof (*clist), sleep);
13537 	if (clist == NULL) {
13538 		return (FC_NOMEM);
13539 	}
13540 
13541 	clist->clist_state = statec;
13542 
13543 	mutex_enter(&port->fp_mutex);
13544 	clist->clist_flags = port->fp_topology;
13545 	mutex_exit(&port->fp_mutex);
13546 
13547 	clist->clist_port = (opaque_t)port;
13548 	clist->clist_len = 0;
13549 	clist->clist_size = 0;
13550 	clist->clist_map = NULL;
13551 
13552 	(void) taskq_dispatch(port->fp_taskq, fctl_ulp_statec_cb,
13553 	    clist, KM_SLEEP);
13554 
13555 	return (FC_SUCCESS);
13556 }
13557 
13558 
13559 /*
13560  * Get name server map
13561  */
13562 static int
13563 fp_ns_getmap(fc_local_port_t *port, job_request_t *job, fc_portmap_t **map,
13564     uint32_t *len, uint32_t sid)
13565 {
13566 	int ret;
13567 	fctl_ns_req_t *ns_cmd;
13568 
13569 	/*
13570 	 * Don't let the allocator do anything for response;
13571 	 * we have have buffer ready to fillout.
13572 	 */
13573 	ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t),
13574 	    sizeof (ns_resp_gan_t), 0, (FCTL_NS_FILL_NS_MAP |
13575 	    FCTL_NS_BUF_IS_FC_PORTMAP), KM_SLEEP);
13576 
13577 	ns_cmd->ns_data_len = sizeof (**map) * (*len);
13578 	ns_cmd->ns_data_buf = (caddr_t)*map;
13579 
13580 	ASSERT(ns_cmd != NULL);
13581 
13582 	ns_cmd->ns_gan_index = 0;
13583 	ns_cmd->ns_gan_sid = sid;
13584 	ns_cmd->ns_cmd_code = NS_GA_NXT;
13585 	ns_cmd->ns_gan_max = *len;
13586 
13587 	ret = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP);
13588 
13589 	if (ns_cmd->ns_gan_index != *len) {
13590 		*len = ns_cmd->ns_gan_index;
13591 	}
13592 	ns_cmd->ns_data_len = 0;
13593 	ns_cmd->ns_data_buf = NULL;
13594 	fctl_free_ns_cmd(ns_cmd);
13595 
13596 	return (ret);
13597 }
13598 
13599 
13600 /*
13601  * Create a remote port in Fabric topology by using NS services
13602  */
13603 static fc_remote_port_t *
13604 fp_create_remote_port_by_ns(fc_local_port_t *port, uint32_t d_id, int sleep)
13605 {
13606 	int			rval;
13607 	job_request_t		*job;
13608 	fctl_ns_req_t		*ns_cmd;
13609 	fc_remote_port_t	*pd;
13610 
13611 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
13612 
13613 	FP_TRACE(FP_NHEAD1(1, 0), "PD creation begin; port=%p, d_id=%x",
13614 	    port, d_id);
13615 
13616 #ifdef	DEBUG
13617 	mutex_enter(&port->fp_mutex);
13618 	ASSERT(FC_IS_TOP_SWITCH(port->fp_topology));
13619 	mutex_exit(&port->fp_mutex);
13620 #endif
13621 
13622 	job = fctl_alloc_job(JOB_NS_CMD, 0, NULL, (opaque_t)port, sleep);
13623 	if (job == NULL) {
13624 		return (NULL);
13625 	}
13626 
13627 	ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t),
13628 	    sizeof (ns_resp_gan_t), 0, (FCTL_NS_CREATE_DEVICE |
13629 	    FCTL_NS_NO_DATA_BUF), sleep);
13630 	if (ns_cmd == NULL) {
13631 		return (NULL);
13632 	}
13633 
13634 	job->job_result = FC_SUCCESS;
13635 	ns_cmd->ns_gan_max = 1;
13636 	ns_cmd->ns_cmd_code = NS_GA_NXT;
13637 	ns_cmd->ns_gan_sid = FCTL_GAN_START_ID;
13638 	((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.port_id = d_id - 1;
13639 	((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.priv_lilp_posit = 0;
13640 
13641 	ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
13642 	rval = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP);
13643 	fctl_free_ns_cmd(ns_cmd);
13644 
13645 	if (rval != FC_SUCCESS || job->job_result != FC_SUCCESS) {
13646 		fctl_dealloc_job(job);
13647 		return (NULL);
13648 	}
13649 	fctl_dealloc_job(job);
13650 
13651 	pd = fctl_get_remote_port_by_did(port, d_id);
13652 
13653 	FP_TRACE(FP_NHEAD1(1, 0), "PD creation end; port=%p, d_id=%x, pd=%p",
13654 	    port, d_id, pd);
13655 
13656 	return (pd);
13657 }
13658 
13659 
13660 /*
13661  * Check for the permissions on an ioctl command. If it is required to have an
13662  * EXCLUSIVE open performed, return a FAILURE to just shut the door on it. If
13663  * the ioctl command isn't in one of the list built, shut the door on that too.
13664  *
13665  *	Certain ioctls perform hardware accesses in FCA drivers, and it needs
13666  *	to be made sure that users open the port for an exclusive access while
13667  *	performing those operations.
13668  *
13669  *	This can prevent a casual user from inflicting damage on the port by
13670  *	sending these ioctls from multiple processes/threads (there is no good
13671  *	reason why one would need to do that) without actually realizing how
13672  *	expensive such commands could turn out to be.
13673  *
13674  *	It is also important to note that, even with an exclusive access,
13675  *	multiple threads can share the same file descriptor and fire down
13676  *	commands in parallel. To prevent that the driver needs to make sure
13677  *	that such commands aren't in progress already. This is taken care of
13678  *	in the FP_EXCL_BUSY bit of fp_flag.
13679  */
13680 static int
13681 fp_check_perms(uchar_t open_flag, uint16_t ioctl_cmd)
13682 {
13683 	int ret = FC_FAILURE;
13684 	int count;
13685 
13686 	for (count = 0;
13687 	    count < sizeof (fp_perm_list) / sizeof (fp_perm_list[0]);
13688 	    count++) {
13689 		if (fp_perm_list[count].fp_ioctl_cmd == ioctl_cmd) {
13690 			if (fp_perm_list[count].fp_open_flag & open_flag) {
13691 				ret = FC_SUCCESS;
13692 			}
13693 			break;
13694 		}
13695 	}
13696 
13697 	return (ret);
13698 }
13699 
13700 
13701 /*
13702  * Bind Port driver's unsolicited, state change callbacks
13703  */
13704 static int
13705 fp_bind_callbacks(fc_local_port_t *port)
13706 {
13707 	fc_fca_bind_info_t	bind_info = {0};
13708 	fc_fca_port_info_t	*port_info;
13709 	int		rval =	DDI_SUCCESS;
13710 	uint16_t	class;
13711 	int		node_namelen, port_namelen;
13712 	char		*nname = NULL, *pname = NULL;
13713 
13714 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
13715 
13716 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, port->fp_port_dip,
13717 	    DDI_PROP_NOTPROM | DDI_PROP_DONTPASS,
13718 	    "node-name", &nname) != DDI_PROP_SUCCESS) {
13719 		FP_TRACE(FP_NHEAD1(1, 0),
13720 		    "fp_bind_callback fail to get node-name");
13721 	}
13722 	if (nname) {
13723 		fc_str_to_wwn(nname, &(bind_info.port_nwwn));
13724 	}
13725 
13726 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, port->fp_port_dip,
13727 	    DDI_PROP_NOTPROM | DDI_PROP_DONTPASS,
13728 	    "port-name", &pname) != DDI_PROP_SUCCESS) {
13729 		FP_TRACE(FP_NHEAD1(1, 0),
13730 		    "fp_bind_callback fail to get port-name");
13731 	}
13732 	if (pname) {
13733 		fc_str_to_wwn(pname, &(bind_info.port_pwwn));
13734 	}
13735 
13736 	if (port->fp_npiv_type == FC_NPIV_PORT) {
13737 		bind_info.port_npiv = 1;
13738 	}
13739 
13740 	/*
13741 	 * fca_bind_port returns the FCA driver's handle for the local
13742 	 * port instance. If the port number isn't supported it returns NULL.
13743 	 * It also sets up callback in the FCA for various
13744 	 * things like state change, ELS etc..
13745 	 */
13746 	bind_info.port_statec_cb = fp_statec_cb;
13747 	bind_info.port_unsol_cb = fp_unsol_cb;
13748 	bind_info.port_num = port->fp_port_num;
13749 	bind_info.port_handle = (opaque_t)port;
13750 
13751 	port_info = kmem_zalloc(sizeof (*port_info), KM_SLEEP);
13752 
13753 	/*
13754 	 * Hold the port driver mutex as the callbacks are bound until the
13755 	 * service parameters are properly filled in (in order to be able to
13756 	 * properly respond to unsolicited ELS requests)
13757 	 */
13758 	mutex_enter(&port->fp_mutex);
13759 
13760 	port->fp_fca_handle = port->fp_fca_tran->fca_bind_port(
13761 	    port->fp_fca_dip, port_info, &bind_info);
13762 
13763 	if (port->fp_fca_handle == NULL) {
13764 		rval = DDI_FAILURE;
13765 		goto exit;
13766 	}
13767 
13768 	/*
13769 	 * Only fcoei will set this bit
13770 	 */
13771 	if (port_info->pi_port_state & FC_STATE_FCA_IS_NODMA) {
13772 		port->fp_soft_state |= FP_SOFT_FCA_IS_NODMA;
13773 		port_info->pi_port_state &= ~(FC_STATE_FCA_IS_NODMA);
13774 	}
13775 
13776 	port->fp_bind_state = port->fp_state = port_info->pi_port_state;
13777 	port->fp_service_params = port_info->pi_login_params;
13778 	port->fp_hard_addr = port_info->pi_hard_addr;
13779 
13780 	/* Copy from the FCA structure to the FP structure */
13781 	port->fp_hba_port_attrs = port_info->pi_attrs;
13782 
13783 	if (port_info->pi_rnid_params.status == FC_SUCCESS) {
13784 		port->fp_rnid_init = 1;
13785 		bcopy(&port_info->pi_rnid_params.params,
13786 		    &port->fp_rnid_params,
13787 		    sizeof (port->fp_rnid_params));
13788 	} else {
13789 		port->fp_rnid_init = 0;
13790 	}
13791 
13792 	node_namelen = strlen((char *)&port_info->pi_attrs.sym_node_name);
13793 	if (node_namelen) {
13794 		bcopy(&port_info->pi_attrs.sym_node_name,
13795 		    &port->fp_sym_node_name,
13796 		    node_namelen);
13797 		port->fp_sym_node_namelen = node_namelen;
13798 	}
13799 	port_namelen = strlen((char *)&port_info->pi_attrs.sym_port_name);
13800 	if (port_namelen) {
13801 		bcopy(&port_info->pi_attrs.sym_port_name,
13802 		    &port->fp_sym_port_name,
13803 		    port_namelen);
13804 		port->fp_sym_port_namelen = port_namelen;
13805 	}
13806 
13807 	/* zero out the normally unused fields right away */
13808 	port->fp_service_params.ls_code.mbz = 0;
13809 	port->fp_service_params.ls_code.ls_code = 0;
13810 	bzero(&port->fp_service_params.reserved,
13811 	    sizeof (port->fp_service_params.reserved));
13812 
13813 	class = port_info->pi_login_params.class_1.class_opt;
13814 	port->fp_cos |= (class & 0x8000) ? FC_NS_CLASS1 : 0;
13815 
13816 	class = port_info->pi_login_params.class_2.class_opt;
13817 	port->fp_cos |= (class & 0x8000) ? FC_NS_CLASS2 : 0;
13818 
13819 	class = port_info->pi_login_params.class_3.class_opt;
13820 	port->fp_cos |= (class & 0x8000) ? FC_NS_CLASS3 : 0;
13821 
13822 exit:
13823 	if (nname) {
13824 		ddi_prop_free(nname);
13825 	}
13826 	if (pname) {
13827 		ddi_prop_free(pname);
13828 	}
13829 	mutex_exit(&port->fp_mutex);
13830 	kmem_free(port_info, sizeof (*port_info));
13831 
13832 	return (rval);
13833 }
13834 
13835 
13836 /*
13837  * Retrieve FCA capabilities
13838  */
13839 static void
13840 fp_retrieve_caps(fc_local_port_t *port)
13841 {
13842 	int			rval;
13843 	int			ub_count;
13844 	fc_fcp_dma_t		fcp_dma;
13845 	fc_reset_action_t	action;
13846 	fc_dma_behavior_t	dma_behavior;
13847 
13848 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
13849 
13850 	rval = port->fp_fca_tran->fca_get_cap(port->fp_fca_handle,
13851 	    FC_CAP_UNSOL_BUF, &ub_count);
13852 
13853 	switch (rval) {
13854 	case FC_CAP_FOUND:
13855 	case FC_CAP_SETTABLE:
13856 		switch (ub_count) {
13857 		case 0:
13858 			break;
13859 
13860 		case -1:
13861 			ub_count = fp_unsol_buf_count;
13862 			break;
13863 
13864 		default:
13865 			/* 1/4th of total buffers is my share */
13866 			ub_count =
13867 			    (ub_count / port->fp_fca_tran->fca_numports) >> 2;
13868 			break;
13869 		}
13870 		break;
13871 
13872 	default:
13873 		ub_count = 0;
13874 		break;
13875 	}
13876 
13877 	mutex_enter(&port->fp_mutex);
13878 	port->fp_ub_count = ub_count;
13879 	mutex_exit(&port->fp_mutex);
13880 
13881 	rval = port->fp_fca_tran->fca_get_cap(port->fp_fca_handle,
13882 	    FC_CAP_POST_RESET_BEHAVIOR, &action);
13883 
13884 	switch (rval) {
13885 	case FC_CAP_FOUND:
13886 	case FC_CAP_SETTABLE:
13887 		switch (action) {
13888 		case FC_RESET_RETURN_NONE:
13889 		case FC_RESET_RETURN_ALL:
13890 		case FC_RESET_RETURN_OUTSTANDING:
13891 			break;
13892 
13893 		default:
13894 			action = FC_RESET_RETURN_NONE;
13895 			break;
13896 		}
13897 		break;
13898 
13899 	default:
13900 		action = FC_RESET_RETURN_NONE;
13901 		break;
13902 	}
13903 	mutex_enter(&port->fp_mutex);
13904 	port->fp_reset_action = action;
13905 	mutex_exit(&port->fp_mutex);
13906 
13907 	rval = port->fp_fca_tran->fca_get_cap(port->fp_fca_handle,
13908 	    FC_CAP_NOSTREAM_ON_UNALIGN_BUF, &dma_behavior);
13909 
13910 	switch (rval) {
13911 	case FC_CAP_FOUND:
13912 		switch (dma_behavior) {
13913 		case FC_ALLOW_STREAMING:
13914 			/* FALLTHROUGH */
13915 		case FC_NO_STREAMING:
13916 			break;
13917 
13918 		default:
13919 			/*
13920 			 * If capability was found and the value
13921 			 * was incorrect assume the worst
13922 			 */
13923 			dma_behavior = FC_NO_STREAMING;
13924 			break;
13925 		}
13926 		break;
13927 
13928 	default:
13929 		/*
13930 		 * If capability was not defined - allow streaming; existing
13931 		 * FCAs should not be affected.
13932 		 */
13933 		dma_behavior = FC_ALLOW_STREAMING;
13934 		break;
13935 	}
13936 	mutex_enter(&port->fp_mutex);
13937 	port->fp_dma_behavior = dma_behavior;
13938 	mutex_exit(&port->fp_mutex);
13939 
13940 	rval = port->fp_fca_tran->fca_get_cap(port->fp_fca_handle,
13941 	    FC_CAP_FCP_DMA, &fcp_dma);
13942 
13943 	if (rval != FC_CAP_FOUND || (fcp_dma != FC_NO_DVMA_SPACE &&
13944 	    fcp_dma != FC_DVMA_SPACE)) {
13945 		fcp_dma = FC_DVMA_SPACE;
13946 	}
13947 
13948 	mutex_enter(&port->fp_mutex);
13949 	port->fp_fcp_dma = fcp_dma;
13950 	mutex_exit(&port->fp_mutex);
13951 }
13952 
13953 
13954 /*
13955  * Handle Domain, Area changes in the Fabric.
13956  */
13957 static void
13958 fp_validate_area_domain(fc_local_port_t *port, uint32_t id, uint32_t mask,
13959     job_request_t *job, int sleep)
13960 {
13961 #ifdef	DEBUG
13962 	uint32_t		dcnt;
13963 #endif
13964 	int			rval;
13965 	int			send;
13966 	int			index;
13967 	int			listindex;
13968 	int			login;
13969 	int			job_flags;
13970 	char			ww_name[17];
13971 	uint32_t		d_id;
13972 	uint32_t		count;
13973 	fctl_ns_req_t		*ns_cmd;
13974 	fc_portmap_t		*list;
13975 	fc_orphan_t		*orp;
13976 	fc_orphan_t		*norp;
13977 	fc_orphan_t		*prev;
13978 	fc_remote_port_t	*pd;
13979 	fc_remote_port_t	*npd;
13980 	struct pwwn_hash	*head;
13981 
13982 	ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t),
13983 	    sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t),
13984 	    0, sleep);
13985 	if (ns_cmd == NULL) {
13986 		mutex_enter(&port->fp_mutex);
13987 		if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
13988 			--port->fp_rscn_count;
13989 		}
13990 		mutex_exit(&port->fp_mutex);
13991 
13992 		return;
13993 	}
13994 	ns_cmd->ns_cmd_code = NS_GID_PN;
13995 
13996 	/*
13997 	 * We need to get a new count of devices from the
13998 	 * name server, which will also create any new devices
13999 	 * as needed.
14000 	 */
14001 
14002 	(void) fp_ns_get_devcount(port, job, 1, sleep);
14003 
14004 	FP_TRACE(FP_NHEAD1(3, 0),
14005 	    "fp_validate_area_domain: get_devcount found %d devices",
14006 	    port->fp_total_devices);
14007 
14008 	mutex_enter(&port->fp_mutex);
14009 
14010 	for (count = index = 0; index < pwwn_table_size; index++) {
14011 		head = &port->fp_pwwn_table[index];
14012 		pd = head->pwwn_head;
14013 		while (pd != NULL) {
14014 			mutex_enter(&pd->pd_mutex);
14015 			if (pd->pd_flags != PD_ELS_IN_PROGRESS) {
14016 				if ((pd->pd_port_id.port_id & mask) == id &&
14017 				    pd->pd_recepient == PD_PLOGI_INITIATOR) {
14018 					count++;
14019 					pd->pd_type = PORT_DEVICE_OLD;
14020 					pd->pd_flags = PD_ELS_MARK;
14021 				}
14022 			}
14023 			mutex_exit(&pd->pd_mutex);
14024 			pd = pd->pd_wwn_hnext;
14025 		}
14026 	}
14027 
14028 #ifdef	DEBUG
14029 	dcnt = count;
14030 #endif /* DEBUG */
14031 
14032 	/*
14033 	 * Since port->fp_orphan_count is declared an 'int' it is
14034 	 * theoretically possible that the count could go negative.
14035 	 *
14036 	 * This would be bad and if that happens we really do want
14037 	 * to know.
14038 	 */
14039 
14040 	ASSERT(port->fp_orphan_count >= 0);
14041 
14042 	count += port->fp_orphan_count;
14043 
14044 	/*
14045 	 * We add the port->fp_total_devices value to the count
14046 	 * in the case where our port is newly attached. This is
14047 	 * because we haven't done any discovery and we don't have
14048 	 * any orphans in the port's orphan list. If we do not do
14049 	 * this addition to count then we won't alloc enough kmem
14050 	 * to do discovery with.
14051 	 */
14052 
14053 	if (count == 0) {
14054 		count += port->fp_total_devices;
14055 		FP_TRACE(FP_NHEAD1(3, 0), "fp_validate_area_domain: "
14056 		    "0x%x orphans found, using 0x%x",
14057 		    port->fp_orphan_count, count);
14058 	}
14059 
14060 	mutex_exit(&port->fp_mutex);
14061 
14062 	/*
14063 	 * Allocate the change list
14064 	 */
14065 
14066 	list = kmem_zalloc(sizeof (fc_portmap_t) * count, sleep);
14067 	if (list == NULL) {
14068 		fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
14069 		    " Not enough memory to service RSCNs"
14070 		    " for %d ports, continuing...", count);
14071 
14072 		fctl_free_ns_cmd(ns_cmd);
14073 
14074 		mutex_enter(&port->fp_mutex);
14075 		if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
14076 			--port->fp_rscn_count;
14077 		}
14078 		mutex_exit(&port->fp_mutex);
14079 
14080 		return;
14081 	}
14082 
14083 	/*
14084 	 * Attempt to validate or invalidate the devices that were
14085 	 * already in the pwwn hash table.
14086 	 */
14087 
14088 	mutex_enter(&port->fp_mutex);
14089 	for (listindex = 0, index = 0; index < pwwn_table_size; index++) {
14090 		head = &port->fp_pwwn_table[index];
14091 		npd = head->pwwn_head;
14092 
14093 		while ((pd = npd) != NULL) {
14094 			npd = pd->pd_wwn_hnext;
14095 
14096 			mutex_enter(&pd->pd_mutex);
14097 			if ((pd->pd_port_id.port_id & mask) == id &&
14098 			    pd->pd_flags == PD_ELS_MARK) {
14099 				la_wwn_t *pwwn;
14100 
14101 				job->job_result = FC_SUCCESS;
14102 
14103 				((ns_req_gid_pn_t *)
14104 				    (ns_cmd->ns_cmd_buf))->pwwn =
14105 				    pd->pd_port_name;
14106 
14107 				pwwn = &pd->pd_port_name;
14108 				d_id = pd->pd_port_id.port_id;
14109 
14110 				mutex_exit(&pd->pd_mutex);
14111 				mutex_exit(&port->fp_mutex);
14112 
14113 				rval = fp_ns_query(port, ns_cmd, job, 1,
14114 				    sleep);
14115 				if (rval != FC_SUCCESS) {
14116 					fc_wwn_to_str(pwwn, ww_name);
14117 
14118 					FP_TRACE(FP_NHEAD1(3, 0),
14119 					    "AREA RSCN: PD disappeared; "
14120 					    "d_id=%x, PWWN=%s", d_id, ww_name);
14121 
14122 					FP_TRACE(FP_NHEAD2(9, 0),
14123 					    "N_x Port with D_ID=%x,"
14124 					    " PWWN=%s disappeared from fabric",
14125 					    d_id, ww_name);
14126 
14127 					fp_fillout_old_map(list + listindex++,
14128 					    pd, 1);
14129 				} else {
14130 					fctl_copy_portmap(list + listindex++,
14131 					    pd);
14132 
14133 					mutex_enter(&pd->pd_mutex);
14134 					pd->pd_flags = PD_ELS_IN_PROGRESS;
14135 					mutex_exit(&pd->pd_mutex);
14136 				}
14137 
14138 				mutex_enter(&port->fp_mutex);
14139 			} else {
14140 				mutex_exit(&pd->pd_mutex);
14141 			}
14142 		}
14143 	}
14144 
14145 	mutex_exit(&port->fp_mutex);
14146 
14147 	ASSERT(listindex == dcnt);
14148 
14149 	job->job_counter = listindex;
14150 	job_flags = job->job_flags;
14151 	job->job_flags |= JOB_TYPE_FP_ASYNC;
14152 
14153 	/*
14154 	 * Login (if we were the initiator) or validate devices in the
14155 	 * port map.
14156 	 */
14157 
14158 	for (index = 0; index < listindex; index++) {
14159 		pd = list[index].map_pd;
14160 
14161 		mutex_enter(&pd->pd_mutex);
14162 		ASSERT((pd->pd_port_id.port_id & mask) == id);
14163 
14164 		if (pd->pd_flags != PD_ELS_IN_PROGRESS) {
14165 			ASSERT(pd->pd_type == PORT_DEVICE_OLD);
14166 			mutex_exit(&pd->pd_mutex);
14167 			fp_jobdone(job);
14168 			continue;
14169 		}
14170 
14171 		login = (pd->pd_state == PORT_DEVICE_LOGGED_IN) ? 1 : 0;
14172 		send = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0;
14173 		d_id = pd->pd_port_id.port_id;
14174 		mutex_exit(&pd->pd_mutex);
14175 
14176 		if ((d_id & mask) == id && send) {
14177 			if (login) {
14178 				FP_TRACE(FP_NHEAD1(6, 0),
14179 				    "RSCN and PLOGI request;"
14180 				    " pd=%p, job=%p d_id=%x, index=%d", pd,
14181 				    job, d_id, index);
14182 
14183 				rval = fp_port_login(port, d_id, job,
14184 				    FP_CMD_PLOGI_RETAIN, sleep, pd, NULL);
14185 				if (rval != FC_SUCCESS) {
14186 					mutex_enter(&pd->pd_mutex);
14187 					pd->pd_flags = PD_IDLE;
14188 					mutex_exit(&pd->pd_mutex);
14189 
14190 					job->job_result = rval;
14191 					fp_jobdone(job);
14192 				}
14193 				FP_TRACE(FP_NHEAD2(4, 0),
14194 				    "PLOGI succeeded:no skip(1) for "
14195 				    "D_ID %x", d_id);
14196 				list[index].map_flags |=
14197 				    PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY;
14198 			} else {
14199 				FP_TRACE(FP_NHEAD1(6, 0), "RSCN and NS request;"
14200 				    " pd=%p, job=%p d_id=%x, index=%d", pd,
14201 				    job, d_id, index);
14202 
14203 				rval = fp_ns_validate_device(port, pd, job,
14204 				    0, sleep);
14205 				if (rval != FC_SUCCESS) {
14206 					fp_jobdone(job);
14207 				}
14208 				mutex_enter(&pd->pd_mutex);
14209 				pd->pd_flags = PD_IDLE;
14210 				mutex_exit(&pd->pd_mutex);
14211 			}
14212 		} else {
14213 			FP_TRACE(FP_NHEAD1(6, 0),
14214 			    "RSCN and NO request sent; pd=%p,"
14215 			    " d_id=%x, index=%d", pd, d_id, index);
14216 
14217 			mutex_enter(&pd->pd_mutex);
14218 			pd->pd_flags = PD_IDLE;
14219 			mutex_exit(&pd->pd_mutex);
14220 
14221 			fp_jobdone(job);
14222 		}
14223 	}
14224 
14225 	if (listindex) {
14226 		fctl_jobwait(job);
14227 	}
14228 	job->job_flags = job_flags;
14229 
14230 	/*
14231 	 * Orphan list validation.
14232 	 */
14233 	mutex_enter(&port->fp_mutex);
14234 	for (prev = NULL, orp = port->fp_orphan_list; port->fp_orphan_count &&
14235 	    orp != NULL; orp = norp) {
14236 		norp = orp->orp_next;
14237 		mutex_exit(&port->fp_mutex);
14238 
14239 		job->job_counter = 1;
14240 		job->job_result = FC_SUCCESS;
14241 		ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
14242 
14243 		((ns_req_gid_pn_t *)ns_cmd->ns_cmd_buf)->pwwn = orp->orp_pwwn;
14244 
14245 		((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->pid.port_id = 0;
14246 		((ns_resp_gid_pn_t *)
14247 		    ns_cmd->ns_data_buf)->pid.priv_lilp_posit = 0;
14248 
14249 		rval = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP);
14250 		if (rval == FC_SUCCESS) {
14251 			d_id = BE_32(*((uint32_t *)ns_cmd->ns_data_buf));
14252 			pd = fp_create_remote_port_by_ns(port, d_id, KM_SLEEP);
14253 			if (pd != NULL) {
14254 				fc_wwn_to_str(&orp->orp_pwwn, ww_name);
14255 
14256 				FP_TRACE(FP_NHEAD1(6, 0),
14257 				    "RSCN and ORPHAN list "
14258 				    "success; d_id=%x, PWWN=%s", d_id, ww_name);
14259 
14260 				FP_TRACE(FP_NHEAD2(6, 0),
14261 				    "N_x Port with D_ID=%x, PWWN=%s reappeared"
14262 				    " in fabric", d_id, ww_name);
14263 
14264 				mutex_enter(&port->fp_mutex);
14265 				if (prev) {
14266 					prev->orp_next = orp->orp_next;
14267 				} else {
14268 					ASSERT(orp == port->fp_orphan_list);
14269 					port->fp_orphan_list = orp->orp_next;
14270 				}
14271 				port->fp_orphan_count--;
14272 				mutex_exit(&port->fp_mutex);
14273 
14274 				kmem_free(orp, sizeof (*orp));
14275 				fctl_copy_portmap(list + listindex++, pd);
14276 			} else {
14277 				prev = orp;
14278 			}
14279 		} else {
14280 			prev = orp;
14281 		}
14282 		mutex_enter(&port->fp_mutex);
14283 	}
14284 	mutex_exit(&port->fp_mutex);
14285 
14286 	/*
14287 	 * One more pass through the list to delist old devices from
14288 	 * the d_id and pwwn tables and possibly add to the orphan list.
14289 	 */
14290 
14291 	for (index = 0; index < listindex; index++) {
14292 		pd = list[index].map_pd;
14293 		ASSERT(pd != NULL);
14294 
14295 		/*
14296 		 * Update PLOGI results; For NS validation
14297 		 * of orphan list, it is redundant
14298 		 *
14299 		 * Take care to preserve PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY if
14300 		 * appropriate as fctl_copy_portmap() will clear map_flags.
14301 		 */
14302 		if (list[index].map_flags &
14303 		    PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY) {
14304 			fctl_copy_portmap(list + index, pd);
14305 			list[index].map_flags |=
14306 			    PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY;
14307 		} else {
14308 			fctl_copy_portmap(list + index, pd);
14309 		}
14310 
14311 		FP_TRACE(FP_NHEAD1(6, 0), "RSCN with Area DOMAIN "
14312 		    "results; pd=%p, d_id=%x pwwn=%x %x %x %x %x %x %x %x",
14313 		    pd, pd->pd_port_id.port_id,
14314 		    pd->pd_port_name.raw_wwn[0],
14315 		    pd->pd_port_name.raw_wwn[1],
14316 		    pd->pd_port_name.raw_wwn[2],
14317 		    pd->pd_port_name.raw_wwn[3],
14318 		    pd->pd_port_name.raw_wwn[4],
14319 		    pd->pd_port_name.raw_wwn[5],
14320 		    pd->pd_port_name.raw_wwn[6],
14321 		    pd->pd_port_name.raw_wwn[7]);
14322 
14323 		FP_TRACE(FP_NHEAD1(6, 0), "RSCN with Area DOMAIN "
14324 		    "results continued, pd=%p type=%x, flags=%x, state=%x",
14325 		    pd, pd->pd_type, pd->pd_flags, pd->pd_state);
14326 
14327 		mutex_enter(&pd->pd_mutex);
14328 		if (pd->pd_type == PORT_DEVICE_OLD) {
14329 			int initiator;
14330 
14331 			pd->pd_flags = PD_IDLE;
14332 			initiator = (pd->pd_recepient ==
14333 			    PD_PLOGI_INITIATOR) ? 1 : 0;
14334 
14335 			mutex_exit(&pd->pd_mutex);
14336 
14337 			mutex_enter(&port->fp_mutex);
14338 			mutex_enter(&pd->pd_mutex);
14339 
14340 			pd->pd_state = PORT_DEVICE_INVALID;
14341 			fctl_delist_did_table(port, pd);
14342 			fctl_delist_pwwn_table(port, pd);
14343 
14344 			mutex_exit(&pd->pd_mutex);
14345 			mutex_exit(&port->fp_mutex);
14346 
14347 			if (initiator) {
14348 				(void) fctl_add_orphan(port, pd, sleep);
14349 			}
14350 			list[index].map_pd = pd;
14351 		} else {
14352 			ASSERT(pd->pd_flags == PD_IDLE);
14353 			if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
14354 				/*
14355 				 * Reset LOGO tolerance to zero
14356 				 */
14357 				fctl_tc_reset(&pd->pd_logo_tc);
14358 			}
14359 			mutex_exit(&pd->pd_mutex);
14360 		}
14361 	}
14362 
14363 	if (ns_cmd) {
14364 		fctl_free_ns_cmd(ns_cmd);
14365 	}
14366 	if (listindex) {
14367 		(void) fp_ulp_devc_cb(port, list, listindex, count,
14368 		    sleep, 0);
14369 	} else {
14370 		kmem_free(list, sizeof (*list) * count);
14371 
14372 		mutex_enter(&port->fp_mutex);
14373 		if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
14374 			--port->fp_rscn_count;
14375 		}
14376 		mutex_exit(&port->fp_mutex);
14377 	}
14378 }
14379 
14380 
14381 /*
14382  * Work hard to make sense out of an RSCN page.
14383  */
14384 static void
14385 fp_validate_rscn_page(fc_local_port_t *port, fc_affected_id_t *page,
14386     job_request_t *job, fctl_ns_req_t *ns_cmd, fc_portmap_t *listptr,
14387     int *listindex, int sleep)
14388 {
14389 	int			rval;
14390 	char			ww_name[17];
14391 	la_wwn_t		*pwwn;
14392 	fc_remote_port_t	*pwwn_pd;
14393 	fc_remote_port_t	*did_pd;
14394 
14395 	did_pd = fctl_get_remote_port_by_did(port, page->aff_d_id);
14396 
14397 	FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page; "
14398 	    "port=%p, d_id=%x, pd=%p, rscn_count:0x%x", port, page->aff_d_id,
14399 	    did_pd, (uint32_t)(uintptr_t)job->job_cb_arg);
14400 
14401 	if (did_pd != NULL) {
14402 		mutex_enter(&did_pd->pd_mutex);
14403 		if (did_pd->pd_flags != PD_IDLE) {
14404 			mutex_exit(&did_pd->pd_mutex);
14405 			FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page: "
14406 			    "PD is BUSY; port=%p, d_id=%x, pd=%p",
14407 			    port, page->aff_d_id, did_pd);
14408 			return;
14409 		}
14410 		did_pd->pd_flags = PD_ELS_IN_PROGRESS;
14411 		mutex_exit(&did_pd->pd_mutex);
14412 	}
14413 
14414 	job->job_counter = 1;
14415 
14416 	pwwn = &((ns_resp_gpn_id_t *)ns_cmd->ns_data_buf)->pwwn;
14417 
14418 	((ns_req_gpn_id_t *)ns_cmd->ns_cmd_buf)->pid.port_id = page->aff_d_id;
14419 	((ns_req_gpn_id_t *)ns_cmd->ns_cmd_buf)->pid.priv_lilp_posit = 0;
14420 
14421 	bzero(ns_cmd->ns_data_buf, sizeof (la_wwn_t));
14422 	rval = fp_ns_query(port, ns_cmd, job, 1, sleep);
14423 
14424 	FP_TRACE(FP_NHEAD1(1, 0), "NS Query Response for D_ID page; rev=%x,"
14425 	    " in_id=%x, cmdrsp=%x, reason=%x, expln=%x",
14426 	    ns_cmd->ns_resp_hdr.ct_rev, ns_cmd->ns_resp_hdr.ct_inid,
14427 	    ns_cmd->ns_resp_hdr.ct_cmdrsp, ns_cmd->ns_resp_hdr.ct_reason,
14428 	    ns_cmd->ns_resp_hdr.ct_expln);
14429 
14430 	job->job_counter = 1;
14431 
14432 	if (rval != FC_SUCCESS || fctl_is_wwn_zero(pwwn) == FC_SUCCESS) {
14433 		/*
14434 		 * What this means is that the D_ID
14435 		 * disappeared from the Fabric.
14436 		 */
14437 		if (did_pd == NULL) {
14438 			FP_TRACE(FP_NHEAD1(1, 0), "RSCN with D_ID page;"
14439 			    " NULL PD disappeared, rval=%x", rval);
14440 			return;
14441 		}
14442 
14443 		fc_wwn_to_str(&did_pd->pd_port_name, ww_name);
14444 
14445 		(listptr + *listindex)->map_rscn_info.ulp_rscn_count =
14446 		    (uint32_t)(uintptr_t)job->job_cb_arg;
14447 
14448 		fp_fillout_old_map(listptr + (*listindex)++, did_pd, 0);
14449 
14450 		FP_TRACE(FP_NHEAD1(3, 0), "RSCN: PD disappeared; "
14451 		    "d_id=%x, PWWN=%s", page->aff_d_id, ww_name);
14452 
14453 		FP_TRACE(FP_NHEAD2(9, 0),
14454 		    "GPN_ID for D_ID=%x failed", page->aff_d_id);
14455 
14456 		FP_TRACE(FP_NHEAD2(9, 0),
14457 		    "N_x Port with D_ID=%x, PWWN=%s disappeared from"
14458 		    " fabric", page->aff_d_id, ww_name);
14459 
14460 		mutex_enter(&did_pd->pd_mutex);
14461 		did_pd->pd_flags = PD_IDLE;
14462 		mutex_exit(&did_pd->pd_mutex);
14463 
14464 		FP_TRACE(FP_NHEAD1(3, 0), "RSCN with D_ID (%x) page; "
14465 		    "PD disappeared, pd=%p", page->aff_d_id, did_pd);
14466 
14467 		return;
14468 	}
14469 
14470 	pwwn_pd = fctl_get_remote_port_by_pwwn(port, pwwn);
14471 
14472 	if (did_pd != NULL && pwwn_pd != NULL && did_pd == pwwn_pd) {
14473 		/*
14474 		 * There is no change. Do PLOGI again and add it to
14475 		 * ULP portmap baggage and return. Note: When RSCNs
14476 		 * arrive with per page states, the need for PLOGI
14477 		 * can be determined correctly.
14478 		 */
14479 		mutex_enter(&pwwn_pd->pd_mutex);
14480 		pwwn_pd->pd_type = PORT_DEVICE_NOCHANGE;
14481 		mutex_exit(&pwwn_pd->pd_mutex);
14482 
14483 		(listptr + *listindex)->map_rscn_info.ulp_rscn_count =
14484 		    (uint32_t)(uintptr_t)job->job_cb_arg;
14485 
14486 		fctl_copy_portmap(listptr + (*listindex)++, pwwn_pd);
14487 
14488 		mutex_enter(&pwwn_pd->pd_mutex);
14489 		if ((pwwn_pd->pd_state == PORT_DEVICE_LOGGED_IN) ||
14490 		    (pwwn_pd->pd_aux_flags & PD_LOGGED_OUT)) {
14491 			fc_wwn_to_str(&pwwn_pd->pd_port_name, ww_name);
14492 			mutex_exit(&pwwn_pd->pd_mutex);
14493 
14494 			rval = fp_port_login(port, page->aff_d_id, job,
14495 			    FP_CMD_PLOGI_RETAIN, sleep, pwwn_pd, NULL);
14496 			if (rval == FC_SUCCESS) {
14497 				fp_jobwait(job);
14498 				rval = job->job_result;
14499 
14500 				/*
14501 				 * Reset LOGO tolerance to zero
14502 				 * Also we are the PLOGI initiator now.
14503 				 */
14504 				mutex_enter(&pwwn_pd->pd_mutex);
14505 				fctl_tc_reset(&pwwn_pd->pd_logo_tc);
14506 				pwwn_pd->pd_recepient = PD_PLOGI_INITIATOR;
14507 				mutex_exit(&pwwn_pd->pd_mutex);
14508 			}
14509 
14510 			if (rval == FC_SUCCESS) {
14511 				struct fc_portmap *map =
14512 				    listptr + *listindex - 1;
14513 
14514 				FP_TRACE(FP_NHEAD2(4, 0),
14515 				    "PLOGI succeeded: no skip(2)"
14516 				    " for D_ID %x", page->aff_d_id);
14517 				map->map_flags |=
14518 				    PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY;
14519 			} else {
14520 				FP_TRACE(FP_NHEAD2(9, rval),
14521 				    "PLOGI to D_ID=%x failed", page->aff_d_id);
14522 
14523 				FP_TRACE(FP_NHEAD2(9, 0),
14524 				    "N_x Port with D_ID=%x, PWWN=%s"
14525 				    " disappeared from fabric",
14526 				    page->aff_d_id, ww_name);
14527 
14528 				fp_fillout_old_map(listptr +
14529 				    *listindex - 1, pwwn_pd, 0);
14530 			}
14531 		} else {
14532 			mutex_exit(&pwwn_pd->pd_mutex);
14533 		}
14534 
14535 		mutex_enter(&did_pd->pd_mutex);
14536 		did_pd->pd_flags = PD_IDLE;
14537 		mutex_exit(&did_pd->pd_mutex);
14538 
14539 		FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID (0x%x) page; "
14540 		    "Case ONE, rval=%x, result=%x pd=%p", page->aff_d_id, rval,
14541 		    job->job_result, pwwn_pd);
14542 
14543 		return;
14544 	}
14545 
14546 	if (did_pd == NULL && pwwn_pd == NULL) {
14547 
14548 		fc_orphan_t	*orp  = NULL;
14549 		fc_orphan_t	*norp = NULL;
14550 		fc_orphan_t	*prev = NULL;
14551 
14552 		/*
14553 		 * Hunt down the orphan list before giving up.
14554 		 */
14555 
14556 		mutex_enter(&port->fp_mutex);
14557 		if (port->fp_orphan_count) {
14558 
14559 			for (orp = port->fp_orphan_list; orp; orp = norp) {
14560 				norp = orp->orp_next;
14561 
14562 				if (fctl_wwn_cmp(&orp->orp_pwwn, pwwn) != 0) {
14563 					prev = orp;
14564 					continue;
14565 				}
14566 
14567 				if (prev) {
14568 					prev->orp_next = orp->orp_next;
14569 				} else {
14570 					ASSERT(orp ==
14571 					    port->fp_orphan_list);
14572 					port->fp_orphan_list =
14573 					    orp->orp_next;
14574 				}
14575 				port->fp_orphan_count--;
14576 				break;
14577 			}
14578 		}
14579 
14580 		mutex_exit(&port->fp_mutex);
14581 		pwwn_pd = fp_create_remote_port_by_ns(port,
14582 		    page->aff_d_id, sleep);
14583 
14584 		if (pwwn_pd != NULL) {
14585 
14586 			if (orp) {
14587 				fc_wwn_to_str(&orp->orp_pwwn,
14588 				    ww_name);
14589 
14590 				FP_TRACE(FP_NHEAD2(9, 0),
14591 				    "N_x Port with D_ID=%x,"
14592 				    " PWWN=%s reappeared in fabric",
14593 				    page->aff_d_id, ww_name);
14594 
14595 				kmem_free(orp, sizeof (*orp));
14596 			}
14597 
14598 			(listptr + *listindex)->
14599 			    map_rscn_info.ulp_rscn_count =
14600 			    (uint32_t)(uintptr_t)job->job_cb_arg;
14601 
14602 			fctl_copy_portmap(listptr +
14603 			    (*listindex)++, pwwn_pd);
14604 		}
14605 
14606 		FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID (0x%x) page; "
14607 		    "Case TWO", page->aff_d_id);
14608 
14609 		return;
14610 	}
14611 
14612 	if (pwwn_pd != NULL && did_pd == NULL) {
14613 		uint32_t old_d_id;
14614 		uint32_t d_id = page->aff_d_id;
14615 
14616 		/*
14617 		 * What this means is there is a new D_ID for this
14618 		 * Port WWN. Take out the port device off D_ID
14619 		 * list and put it back with a new D_ID. Perform
14620 		 * PLOGI if already logged in.
14621 		 */
14622 		mutex_enter(&port->fp_mutex);
14623 		mutex_enter(&pwwn_pd->pd_mutex);
14624 
14625 		old_d_id = pwwn_pd->pd_port_id.port_id;
14626 
14627 		fctl_delist_did_table(port, pwwn_pd);
14628 
14629 		(listptr + *listindex)->map_rscn_info.ulp_rscn_count =
14630 		    (uint32_t)(uintptr_t)job->job_cb_arg;
14631 
14632 		fp_fillout_changed_map(listptr + (*listindex)++, pwwn_pd,
14633 		    &d_id, NULL);
14634 		fctl_enlist_did_table(port, pwwn_pd);
14635 
14636 		FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page;"
14637 		    " Case THREE, pd=%p,"
14638 		    " state=%x", pwwn_pd, pwwn_pd->pd_state);
14639 
14640 		if ((pwwn_pd->pd_state == PORT_DEVICE_LOGGED_IN) ||
14641 		    (pwwn_pd->pd_aux_flags & PD_LOGGED_OUT)) {
14642 			fc_wwn_to_str(&pwwn_pd->pd_port_name, ww_name);
14643 
14644 			mutex_exit(&pwwn_pd->pd_mutex);
14645 			mutex_exit(&port->fp_mutex);
14646 
14647 			FP_TRACE(FP_NHEAD2(9, 0),
14648 			    "N_x Port with D_ID=%x, PWWN=%s has a new"
14649 			    " D_ID=%x now", old_d_id, ww_name, d_id);
14650 
14651 			rval = fp_port_login(port, page->aff_d_id, job,
14652 			    FP_CMD_PLOGI_RETAIN, sleep, pwwn_pd, NULL);
14653 			if (rval == FC_SUCCESS) {
14654 				fp_jobwait(job);
14655 				rval = job->job_result;
14656 			}
14657 
14658 			if (rval != FC_SUCCESS) {
14659 				fp_fillout_old_map(listptr +
14660 				    *listindex - 1, pwwn_pd, 0);
14661 			}
14662 		} else {
14663 			mutex_exit(&pwwn_pd->pd_mutex);
14664 			mutex_exit(&port->fp_mutex);
14665 		}
14666 
14667 		return;
14668 	}
14669 
14670 	if (pwwn_pd == NULL && did_pd != NULL) {
14671 		fc_portmap_t	*ptr;
14672 		uint32_t	len = 1;
14673 		char		old_ww_name[17];
14674 
14675 		mutex_enter(&did_pd->pd_mutex);
14676 		fc_wwn_to_str(&did_pd->pd_port_name, old_ww_name);
14677 		mutex_exit(&did_pd->pd_mutex);
14678 
14679 		fc_wwn_to_str(pwwn, ww_name);
14680 
14681 		(listptr + *listindex)->map_rscn_info.ulp_rscn_count =
14682 		    (uint32_t)(uintptr_t)job->job_cb_arg;
14683 
14684 		/*
14685 		 * What this means is that there is a new Port WWN for
14686 		 * this D_ID; Mark the Port device as old and provide
14687 		 * the new PWWN and D_ID combination as new.
14688 		 */
14689 		fp_fillout_old_map(listptr + (*listindex)++, did_pd, 0);
14690 
14691 		FP_TRACE(FP_NHEAD2(9, 0),
14692 		    "N_x Port with D_ID=%x, PWWN=%s has a new PWWN=%s now",
14693 		    page->aff_d_id, old_ww_name, ww_name);
14694 
14695 		(listptr + *listindex)->map_rscn_info.ulp_rscn_count =
14696 		    (uint32_t)(uintptr_t)job->job_cb_arg;
14697 
14698 		ptr = listptr + (*listindex)++;
14699 
14700 		job->job_counter = 1;
14701 
14702 		if (fp_ns_getmap(port, job, &ptr, &len,
14703 		    page->aff_d_id - 1) != FC_SUCCESS) {
14704 			(*listindex)--;
14705 		}
14706 
14707 		mutex_enter(&did_pd->pd_mutex);
14708 		did_pd->pd_flags = PD_IDLE;
14709 		mutex_exit(&did_pd->pd_mutex);
14710 
14711 		return;
14712 	}
14713 
14714 	/*
14715 	 * A weird case of Port WWN and D_ID existence but not matching up
14716 	 * between them. Trust your instincts - Take the port device handle
14717 	 * off Port WWN list, fix it with new Port WWN and put it back, In
14718 	 * the mean time mark the port device corresponding to the old port
14719 	 * WWN as OLD.
14720 	 */
14721 	FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page; Case WEIRD, pwwn_pd=%p,"
14722 	    " did_pd=%p", pwwn_pd, did_pd);
14723 
14724 	mutex_enter(&port->fp_mutex);
14725 	mutex_enter(&pwwn_pd->pd_mutex);
14726 
14727 	pwwn_pd->pd_type = PORT_DEVICE_OLD;
14728 	pwwn_pd->pd_state = PORT_DEVICE_INVALID;
14729 	fctl_delist_did_table(port, pwwn_pd);
14730 	fctl_delist_pwwn_table(port, pwwn_pd);
14731 
14732 	FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page; case WEIRD continued,"
14733 	    " pwwn-d_id=%x pwwn-wwn=%x %x %x %x %x %x %x %x",
14734 	    pwwn_pd->pd_port_id.port_id,
14735 
14736 	    pwwn_pd->pd_port_name.raw_wwn[0],
14737 	    pwwn_pd->pd_port_name.raw_wwn[1],
14738 	    pwwn_pd->pd_port_name.raw_wwn[2],
14739 	    pwwn_pd->pd_port_name.raw_wwn[3],
14740 	    pwwn_pd->pd_port_name.raw_wwn[4],
14741 	    pwwn_pd->pd_port_name.raw_wwn[5],
14742 	    pwwn_pd->pd_port_name.raw_wwn[6],
14743 	    pwwn_pd->pd_port_name.raw_wwn[7]);
14744 
14745 	mutex_exit(&pwwn_pd->pd_mutex);
14746 	mutex_exit(&port->fp_mutex);
14747 
14748 	(listptr + *listindex)->map_rscn_info.ulp_rscn_count =
14749 	    (uint32_t)(uintptr_t)job->job_cb_arg;
14750 
14751 	fctl_copy_portmap(listptr + (*listindex)++, pwwn_pd);
14752 
14753 	mutex_enter(&port->fp_mutex);
14754 	mutex_enter(&did_pd->pd_mutex);
14755 
14756 	fctl_delist_pwwn_table(port, did_pd);
14757 
14758 	(listptr + *listindex)->map_rscn_info.ulp_rscn_count =
14759 	    (uint32_t)(uintptr_t)job->job_cb_arg;
14760 
14761 	fp_fillout_changed_map(listptr + (*listindex)++, did_pd, NULL, pwwn);
14762 	fctl_enlist_pwwn_table(port, did_pd);
14763 
14764 	FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page; case WEIRD continued,"
14765 	    " d_id=%x, state=%x, did-wwn=%x %x %x %x %x %x %x %x",
14766 	    did_pd->pd_port_id.port_id, did_pd->pd_state,
14767 
14768 	    did_pd->pd_port_name.raw_wwn[0],
14769 	    did_pd->pd_port_name.raw_wwn[1],
14770 	    did_pd->pd_port_name.raw_wwn[2],
14771 	    did_pd->pd_port_name.raw_wwn[3],
14772 	    did_pd->pd_port_name.raw_wwn[4],
14773 	    did_pd->pd_port_name.raw_wwn[5],
14774 	    did_pd->pd_port_name.raw_wwn[6],
14775 	    did_pd->pd_port_name.raw_wwn[7]);
14776 
14777 	if ((did_pd->pd_state == PORT_DEVICE_LOGGED_IN) ||
14778 	    (did_pd->pd_aux_flags & PD_LOGGED_OUT)) {
14779 		mutex_exit(&did_pd->pd_mutex);
14780 		mutex_exit(&port->fp_mutex);
14781 
14782 		rval = fp_port_login(port, page->aff_d_id, job,
14783 		    FP_CMD_PLOGI_RETAIN, sleep, did_pd, NULL);
14784 		if (rval == FC_SUCCESS) {
14785 			fp_jobwait(job);
14786 			if (job->job_result != FC_SUCCESS) {
14787 				fp_fillout_old_map(listptr +
14788 				    *listindex - 1, did_pd, 0);
14789 			}
14790 		} else {
14791 			fp_fillout_old_map(listptr + *listindex - 1, did_pd, 0);
14792 		}
14793 	} else {
14794 		mutex_exit(&did_pd->pd_mutex);
14795 		mutex_exit(&port->fp_mutex);
14796 	}
14797 
14798 	mutex_enter(&did_pd->pd_mutex);
14799 	did_pd->pd_flags = PD_IDLE;
14800 	mutex_exit(&did_pd->pd_mutex);
14801 }
14802 
14803 
14804 /*
14805  * Check with NS for the presence of this port WWN
14806  */
14807 static int
14808 fp_ns_validate_device(fc_local_port_t *port, fc_remote_port_t *pd,
14809     job_request_t *job, int polled, int sleep)
14810 {
14811 	la_wwn_t	pwwn;
14812 	uint32_t	flags;
14813 	fctl_ns_req_t	*ns_cmd;
14814 
14815 	flags = FCTL_NS_VALIDATE_PD | ((polled) ? 0: FCTL_NS_ASYNC_REQUEST);
14816 	ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t),
14817 	    sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t),
14818 	    flags, sleep);
14819 	if (ns_cmd == NULL) {
14820 		return (FC_NOMEM);
14821 	}
14822 
14823 	mutex_enter(&pd->pd_mutex);
14824 	pwwn = pd->pd_port_name;
14825 	mutex_exit(&pd->pd_mutex);
14826 
14827 	ns_cmd->ns_cmd_code = NS_GID_PN;
14828 	ns_cmd->ns_pd = pd;
14829 	((ns_req_gid_pn_t *)ns_cmd->ns_cmd_buf)->pwwn = pwwn;
14830 	((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->pid.port_id = 0;
14831 	((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->pid.priv_lilp_posit = 0;
14832 
14833 	return (fp_ns_query(port, ns_cmd, job, polled, sleep));
14834 }
14835 
14836 
14837 /*
14838  * Sanity check the LILP map returned by FCA
14839  */
14840 static int
14841 fp_validate_lilp_map(fc_lilpmap_t *lilp_map)
14842 {
14843 	int	count;
14844 
14845 	if (lilp_map->lilp_length == 0) {
14846 		return (FC_FAILURE);
14847 	}
14848 
14849 	for (count = 0; count < lilp_map->lilp_length; count++) {
14850 		if (fp_is_valid_alpa(lilp_map->lilp_alpalist[count]) !=
14851 		    FC_SUCCESS) {
14852 			return (FC_FAILURE);
14853 		}
14854 	}
14855 
14856 	return (FC_SUCCESS);
14857 }
14858 
14859 
14860 /*
14861  * Sanity check if the AL_PA is a valid address
14862  */
14863 static int
14864 fp_is_valid_alpa(uchar_t al_pa)
14865 {
14866 	int	count;
14867 
14868 	for (count = 0; count < sizeof (fp_valid_alpas); count++) {
14869 		if (al_pa == fp_valid_alpas[count] || al_pa == 0) {
14870 			return (FC_SUCCESS);
14871 		}
14872 	}
14873 
14874 	return (FC_FAILURE);
14875 }
14876 
14877 
14878 /*
14879  * Post unsolicited callbacks to ULPs
14880  */
14881 static void
14882 fp_ulp_unsol_cb(void *arg)
14883 {
14884 	fp_unsol_spec_t	*ub_spec = (fp_unsol_spec_t *)arg;
14885 
14886 	fctl_ulp_unsol_cb(ub_spec->port, ub_spec->buf,
14887 	    ub_spec->buf->ub_frame.type);
14888 	kmem_free(ub_spec, sizeof (*ub_spec));
14889 }
14890 
14891 
14892 /*
14893  * Perform message reporting in a consistent manner. Unless there is
14894  * a strong reason NOT to use this function (which is very very rare)
14895  * all message reporting should go through this.
14896  */
14897 static void
14898 fp_printf(fc_local_port_t *port, int level, fp_mesg_dest_t dest, int fc_errno,
14899     fc_packet_t *pkt, const char *fmt, ...)
14900 {
14901 	caddr_t		buf;
14902 	va_list		ap;
14903 
14904 	switch (level) {
14905 	case CE_NOTE:
14906 		if ((port->fp_verbose & FP_WARNING_MESSAGES) == 0) {
14907 			return;
14908 		}
14909 		break;
14910 
14911 	case CE_WARN:
14912 		if ((port->fp_verbose & FP_FATAL_MESSAGES) == 0) {
14913 			return;
14914 		}
14915 		break;
14916 	}
14917 
14918 	buf = kmem_zalloc(256, KM_NOSLEEP);
14919 	if (buf == NULL) {
14920 		return;
14921 	}
14922 
14923 	(void) sprintf(buf, "fp(%d): ", port->fp_instance);
14924 
14925 	va_start(ap, fmt);
14926 	(void) vsprintf(buf + strlen(buf), fmt, ap);
14927 	va_end(ap);
14928 
14929 	if (fc_errno) {
14930 		char *errmsg;
14931 
14932 		(void) fc_ulp_error(fc_errno, &errmsg);
14933 		(void) sprintf(buf + strlen(buf), " FC Error=%s", errmsg);
14934 	} else {
14935 		if (pkt) {
14936 			caddr_t	state, reason, action, expln;
14937 
14938 			(void) fc_ulp_pkt_error(pkt, &state, &reason,
14939 			    &action, &expln);
14940 
14941 			(void) sprintf(buf + strlen(buf),
14942 			    " state=%s, reason=%s", state, reason);
14943 
14944 			if (pkt->pkt_resp_resid) {
14945 				(void) sprintf(buf + strlen(buf),
14946 				    " resp resid=%x\n", pkt->pkt_resp_resid);
14947 			}
14948 		}
14949 	}
14950 
14951 	switch (dest) {
14952 	case FP_CONSOLE_ONLY:
14953 		cmn_err(level, "^%s", buf);
14954 		break;
14955 
14956 	case FP_LOG_ONLY:
14957 		cmn_err(level, "!%s", buf);
14958 		break;
14959 
14960 	default:
14961 		cmn_err(level, "%s", buf);
14962 		break;
14963 	}
14964 
14965 	kmem_free(buf, 256);
14966 }
14967 
14968 static int
14969 fp_fcio_login(fc_local_port_t *port, fcio_t *fcio, job_request_t *job)
14970 {
14971 	int			ret;
14972 	uint32_t		d_id;
14973 	la_wwn_t		pwwn;
14974 	fc_remote_port_t	*pd = NULL;
14975 	fc_remote_port_t	*held_pd = NULL;
14976 	fctl_ns_req_t		*ns_cmd;
14977 	fc_portmap_t		*changelist;
14978 
14979 	bcopy(fcio->fcio_ibuf, &pwwn, sizeof (pwwn));
14980 
14981 	mutex_enter(&port->fp_mutex);
14982 	if (FC_IS_TOP_SWITCH(port->fp_topology)) {
14983 		mutex_exit(&port->fp_mutex);
14984 		job->job_counter = 1;
14985 
14986 		job->job_result = FC_SUCCESS;
14987 
14988 		ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t),
14989 		    sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t),
14990 		    FCTL_NS_BUF_IS_USERLAND, KM_SLEEP);
14991 
14992 		ASSERT(ns_cmd != NULL);
14993 
14994 		ns_cmd->ns_cmd_code = NS_GID_PN;
14995 		((ns_req_gid_pn_t *)(ns_cmd->ns_cmd_buf))->pwwn = pwwn;
14996 
14997 		ret = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP);
14998 
14999 		if (ret != FC_SUCCESS || job->job_result != FC_SUCCESS) {
15000 			if (ret != FC_SUCCESS) {
15001 				fcio->fcio_errno = ret;
15002 			} else {
15003 				fcio->fcio_errno = job->job_result;
15004 			}
15005 			fctl_free_ns_cmd(ns_cmd);
15006 			return (EIO);
15007 		}
15008 		d_id = BE_32(*((uint32_t *)ns_cmd->ns_data_buf));
15009 		fctl_free_ns_cmd(ns_cmd);
15010 	} else {
15011 		mutex_exit(&port->fp_mutex);
15012 
15013 		held_pd = fctl_hold_remote_port_by_pwwn(port, &pwwn);
15014 		if (held_pd == NULL) {
15015 			fcio->fcio_errno = FC_BADWWN;
15016 			return (EIO);
15017 		}
15018 		pd = held_pd;
15019 
15020 		mutex_enter(&pd->pd_mutex);
15021 		d_id = pd->pd_port_id.port_id;
15022 		mutex_exit(&pd->pd_mutex);
15023 	}
15024 
15025 	job->job_counter = 1;
15026 
15027 	pd = fctl_get_remote_port_by_did(port, d_id);
15028 
15029 	if (pd) {
15030 		mutex_enter(&pd->pd_mutex);
15031 		if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
15032 			pd->pd_login_count++;
15033 			mutex_exit(&pd->pd_mutex);
15034 
15035 			fcio->fcio_errno = FC_SUCCESS;
15036 			if (held_pd) {
15037 				fctl_release_remote_port(held_pd);
15038 			}
15039 
15040 			return (0);
15041 		}
15042 		mutex_exit(&pd->pd_mutex);
15043 	} else {
15044 		mutex_enter(&port->fp_mutex);
15045 		if (FC_IS_TOP_SWITCH(port->fp_topology)) {
15046 			mutex_exit(&port->fp_mutex);
15047 			pd = fp_create_remote_port_by_ns(port, d_id, KM_SLEEP);
15048 			if (pd == NULL) {
15049 				fcio->fcio_errno = FC_FAILURE;
15050 				if (held_pd) {
15051 					fctl_release_remote_port(held_pd);
15052 				}
15053 				return (EIO);
15054 			}
15055 		} else {
15056 			mutex_exit(&port->fp_mutex);
15057 		}
15058 	}
15059 
15060 	job->job_flags &= ~JOB_TYPE_FP_ASYNC;
15061 	job->job_counter = 1;
15062 
15063 	ret = fp_port_login(port, d_id, job, FP_CMD_PLOGI_RETAIN,
15064 	    KM_SLEEP, pd, NULL);
15065 
15066 	if (ret != FC_SUCCESS) {
15067 		fcio->fcio_errno = ret;
15068 		if (held_pd) {
15069 			fctl_release_remote_port(held_pd);
15070 		}
15071 		return (EIO);
15072 	}
15073 	fp_jobwait(job);
15074 
15075 	fcio->fcio_errno = job->job_result;
15076 
15077 	if (held_pd) {
15078 		fctl_release_remote_port(held_pd);
15079 	}
15080 
15081 	if (job->job_result != FC_SUCCESS) {
15082 		return (EIO);
15083 	}
15084 
15085 	pd = fctl_hold_remote_port_by_pwwn(port, &pwwn);
15086 	if (pd == NULL) {
15087 		fcio->fcio_errno = FC_BADDEV;
15088 		return (ENODEV);
15089 	}
15090 
15091 	changelist = kmem_zalloc(sizeof (*changelist), KM_SLEEP);
15092 
15093 	fctl_copy_portmap(changelist, pd);
15094 	changelist->map_type = PORT_DEVICE_USER_LOGIN;
15095 
15096 	(void) fp_ulp_devc_cb(port, changelist, 1, 1, KM_SLEEP, 1);
15097 
15098 	mutex_enter(&pd->pd_mutex);
15099 	pd->pd_type = PORT_DEVICE_NOCHANGE;
15100 	mutex_exit(&pd->pd_mutex);
15101 
15102 	fctl_release_remote_port(pd);
15103 
15104 	return (0);
15105 }
15106 
15107 
15108 static int
15109 fp_fcio_logout(fc_local_port_t *port, fcio_t *fcio, job_request_t *job)
15110 {
15111 	la_wwn_t		pwwn;
15112 	fp_cmd_t		*cmd;
15113 	fc_portmap_t		*changelist;
15114 	fc_remote_port_t	*pd;
15115 
15116 	bcopy(fcio->fcio_ibuf, &pwwn, sizeof (pwwn));
15117 
15118 	pd = fctl_hold_remote_port_by_pwwn(port, &pwwn);
15119 	if (pd == NULL) {
15120 		fcio->fcio_errno = FC_BADWWN;
15121 		return (ENXIO);
15122 	}
15123 
15124 	mutex_enter(&pd->pd_mutex);
15125 	if (pd->pd_state != PORT_DEVICE_LOGGED_IN) {
15126 		fcio->fcio_errno = FC_LOGINREQ;
15127 		mutex_exit(&pd->pd_mutex);
15128 
15129 		fctl_release_remote_port(pd);
15130 
15131 		return (EINVAL);
15132 	}
15133 
15134 	ASSERT(pd->pd_login_count >= 1);
15135 
15136 	if (pd->pd_flags == PD_ELS_IN_PROGRESS) {
15137 		fcio->fcio_errno = FC_FAILURE;
15138 		mutex_exit(&pd->pd_mutex);
15139 
15140 		fctl_release_remote_port(pd);
15141 
15142 		return (EBUSY);
15143 	}
15144 
15145 	if (pd->pd_login_count > 1) {
15146 		pd->pd_login_count--;
15147 		fcio->fcio_errno = FC_SUCCESS;
15148 		mutex_exit(&pd->pd_mutex);
15149 
15150 		changelist = kmem_zalloc(sizeof (*changelist), KM_SLEEP);
15151 
15152 		fctl_copy_portmap(changelist, pd);
15153 		changelist->map_type = PORT_DEVICE_USER_LOGOUT;
15154 
15155 		fctl_release_remote_port(pd);
15156 
15157 		(void) fp_ulp_devc_cb(port, changelist, 1, 1, KM_SLEEP, 1);
15158 
15159 		return (0);
15160 	}
15161 
15162 	pd->pd_flags = PD_ELS_IN_PROGRESS;
15163 	mutex_exit(&pd->pd_mutex);
15164 
15165 	job->job_counter = 1;
15166 
15167 	cmd = fp_alloc_pkt(port, sizeof (la_els_logo_t),
15168 	    FP_PORT_IDENTIFIER_LEN, KM_SLEEP, pd);
15169 	if (cmd == NULL) {
15170 		fcio->fcio_errno = FC_NOMEM;
15171 		fctl_release_remote_port(pd);
15172 
15173 		mutex_enter(&pd->pd_mutex);
15174 		pd->pd_flags = PD_IDLE;
15175 		mutex_exit(&pd->pd_mutex);
15176 
15177 		return (ENOMEM);
15178 	}
15179 
15180 	mutex_enter(&port->fp_mutex);
15181 	mutex_enter(&pd->pd_mutex);
15182 
15183 	cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
15184 	cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
15185 	cmd->cmd_flags = FP_CMD_PLOGI_DONT_CARE;
15186 	cmd->cmd_retry_count = 1;
15187 	cmd->cmd_ulp_pkt = NULL;
15188 
15189 	fp_logo_init(pd, cmd, job);
15190 
15191 	mutex_exit(&pd->pd_mutex);
15192 	mutex_exit(&port->fp_mutex);
15193 
15194 	if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
15195 		mutex_enter(&pd->pd_mutex);
15196 		pd->pd_flags = PD_IDLE;
15197 		mutex_exit(&pd->pd_mutex);
15198 
15199 		fp_free_pkt(cmd);
15200 		fctl_release_remote_port(pd);
15201 
15202 		return (EIO);
15203 	}
15204 
15205 	fp_jobwait(job);
15206 
15207 	fcio->fcio_errno = job->job_result;
15208 	if (job->job_result != FC_SUCCESS) {
15209 		mutex_enter(&pd->pd_mutex);
15210 		pd->pd_flags = PD_IDLE;
15211 		mutex_exit(&pd->pd_mutex);
15212 
15213 		fctl_release_remote_port(pd);
15214 
15215 		return (EIO);
15216 	}
15217 
15218 	ASSERT(pd != NULL);
15219 
15220 	changelist = kmem_zalloc(sizeof (*changelist), KM_SLEEP);
15221 
15222 	fctl_copy_portmap(changelist, pd);
15223 	changelist->map_type = PORT_DEVICE_USER_LOGOUT;
15224 	changelist->map_state = PORT_DEVICE_INVALID;
15225 
15226 	mutex_enter(&port->fp_mutex);
15227 	mutex_enter(&pd->pd_mutex);
15228 
15229 	fctl_delist_did_table(port, pd);
15230 	fctl_delist_pwwn_table(port, pd);
15231 	pd->pd_flags = PD_IDLE;
15232 
15233 	mutex_exit(&pd->pd_mutex);
15234 	mutex_exit(&port->fp_mutex);
15235 
15236 	(void) fp_ulp_devc_cb(port, changelist, 1, 1, KM_SLEEP, 1);
15237 
15238 	fctl_release_remote_port(pd);
15239 
15240 	return (0);
15241 }
15242 
15243 
15244 
15245 /*
15246  * Send a syslog event for adapter port level events.
15247  */
15248 static void
15249 fp_log_port_event(fc_local_port_t *port, char *subclass)
15250 {
15251 	nvlist_t *attr_list;
15252 
15253 	if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE,
15254 	    KM_SLEEP) != DDI_SUCCESS) {
15255 		goto alloc_failed;
15256 	}
15257 
15258 	if (nvlist_add_uint32(attr_list, "instance",
15259 	    port->fp_instance) != DDI_SUCCESS) {
15260 		goto error;
15261 	}
15262 
15263 	if (nvlist_add_byte_array(attr_list, "port-wwn",
15264 	    port->fp_service_params.nport_ww_name.raw_wwn,
15265 	    sizeof (la_wwn_t)) != DDI_SUCCESS) {
15266 		goto error;
15267 	}
15268 
15269 	(void) ddi_log_sysevent(port->fp_port_dip, DDI_VENDOR_SUNW, EC_SUNFC,
15270 	    subclass, attr_list, NULL, DDI_SLEEP);
15271 
15272 	nvlist_free(attr_list);
15273 	return;
15274 
15275 error:
15276 	nvlist_free(attr_list);
15277 alloc_failed:
15278 	FP_TRACE(FP_NHEAD1(9, 0), "Unable to send %s event", subclass);
15279 }
15280 
15281 
15282 static void
15283 fp_log_target_event(fc_local_port_t *port, char *subclass, la_wwn_t tgt_pwwn,
15284     uint32_t port_id)
15285 {
15286 	nvlist_t *attr_list;
15287 
15288 	if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE,
15289 	    KM_SLEEP) != DDI_SUCCESS) {
15290 		goto alloc_failed;
15291 	}
15292 
15293 	if (nvlist_add_uint32(attr_list, "instance",
15294 	    port->fp_instance) != DDI_SUCCESS) {
15295 		goto error;
15296 	}
15297 
15298 	if (nvlist_add_byte_array(attr_list, "port-wwn",
15299 	    port->fp_service_params.nport_ww_name.raw_wwn,
15300 	    sizeof (la_wwn_t)) != DDI_SUCCESS) {
15301 		goto error;
15302 	}
15303 
15304 	if (nvlist_add_byte_array(attr_list, "target-port-wwn",
15305 	    tgt_pwwn.raw_wwn, sizeof (la_wwn_t)) != DDI_SUCCESS) {
15306 		goto error;
15307 	}
15308 
15309 	if (nvlist_add_uint32(attr_list, "target-port-id",
15310 	    port_id) != DDI_SUCCESS) {
15311 		goto error;
15312 	}
15313 
15314 	(void) ddi_log_sysevent(port->fp_port_dip, DDI_VENDOR_SUNW, EC_SUNFC,
15315 	    subclass, attr_list, NULL, DDI_SLEEP);
15316 
15317 	nvlist_free(attr_list);
15318 	return;
15319 
15320 error:
15321 	nvlist_free(attr_list);
15322 alloc_failed:
15323 	FP_TRACE(FP_NHEAD1(9, 0), "Unable to send %s event", subclass);
15324 }
15325 
15326 static uint32_t
15327 fp_map_remote_port_state(uint32_t rm_state)
15328 {
15329 	switch (rm_state) {
15330 	case PORT_DEVICE_LOGGED_IN:
15331 		return (FC_HBA_PORTSTATE_ONLINE);
15332 	case PORT_DEVICE_VALID:
15333 	case PORT_DEVICE_INVALID:
15334 	default:
15335 		return (FC_HBA_PORTSTATE_UNKNOWN);
15336 	}
15337 }
15338