xref: /titanic_41/usr/src/uts/common/io/fibre-channel/impl/fp.c (revision 7a17cfad7ff3427e1ce7ecdbf566e442a7025ec9)
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		"20091123-1.101"
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 	fcio->fcio_errno = FC_SUCCESS;
7228 
7229 	switch (fcio->fcio_cmd) {
7230 	case FCIO_GET_HOST_PARAMS: {
7231 		fc_port_dev_t	*val;
7232 		fc_port_dev32_t	*val32;
7233 		int		index;
7234 		int		lilp_device_count;
7235 		fc_lilpmap_t	*lilp_map;
7236 		uchar_t		*alpa_list;
7237 
7238 		if (use32 == B_TRUE) {
7239 			if (fcio->fcio_olen != sizeof (*val32) ||
7240 			    fcio->fcio_xfer != FCIO_XFER_READ) {
7241 				rval = EINVAL;
7242 				break;
7243 			}
7244 		} else {
7245 			if (fcio->fcio_olen != sizeof (*val) ||
7246 			    fcio->fcio_xfer != FCIO_XFER_READ) {
7247 				rval = EINVAL;
7248 				break;
7249 			}
7250 		}
7251 
7252 		val = kmem_zalloc(sizeof (*val), KM_SLEEP);
7253 
7254 		mutex_enter(&port->fp_mutex);
7255 		val->dev_did = port->fp_port_id;
7256 		val->dev_hard_addr = port->fp_hard_addr;
7257 		val->dev_pwwn = port->fp_service_params.nport_ww_name;
7258 		val->dev_nwwn = port->fp_service_params.node_ww_name;
7259 		val->dev_state = port->fp_state;
7260 
7261 		lilp_map = &port->fp_lilp_map;
7262 		alpa_list = &lilp_map->lilp_alpalist[0];
7263 		lilp_device_count = lilp_map->lilp_length;
7264 		for (index = 0; index < lilp_device_count; index++) {
7265 			uint32_t d_id;
7266 
7267 			d_id = alpa_list[index];
7268 			if (d_id == port->fp_port_id.port_id) {
7269 				break;
7270 			}
7271 		}
7272 		val->dev_did.priv_lilp_posit = (uint8_t)(index & 0xff);
7273 
7274 		bcopy(port->fp_fc4_types, val->dev_type,
7275 		    sizeof (port->fp_fc4_types));
7276 		mutex_exit(&port->fp_mutex);
7277 
7278 		if (use32 == B_TRUE) {
7279 			val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP);
7280 
7281 			val32->dev_did = val->dev_did;
7282 			val32->dev_hard_addr = val->dev_hard_addr;
7283 			val32->dev_pwwn = val->dev_pwwn;
7284 			val32->dev_nwwn = val->dev_nwwn;
7285 			val32->dev_state = val->dev_state;
7286 			val32->dev_did.priv_lilp_posit =
7287 			    val->dev_did.priv_lilp_posit;
7288 
7289 			bcopy(val->dev_type, val32->dev_type,
7290 			    sizeof (port->fp_fc4_types));
7291 
7292 			if (fp_copyout((void *)val32, (void *)fcio->fcio_obuf,
7293 			    fcio->fcio_olen, mode) == 0) {
7294 				if (fp_fcio_copyout(fcio, data, mode)) {
7295 					rval = EFAULT;
7296 				}
7297 			} else {
7298 				rval = EFAULT;
7299 			}
7300 
7301 			kmem_free(val32, sizeof (*val32));
7302 		} else {
7303 			if (fp_copyout((void *)val, (void *)fcio->fcio_obuf,
7304 			    fcio->fcio_olen, mode) == 0) {
7305 				if (fp_fcio_copyout(fcio, data, mode)) {
7306 					rval = EFAULT;
7307 				}
7308 			} else {
7309 				rval = EFAULT;
7310 			}
7311 		}
7312 
7313 		/* need to free "val" here */
7314 		kmem_free(val, sizeof (*val));
7315 		break;
7316 	}
7317 
7318 	case FCIO_GET_OTHER_ADAPTER_PORTS: {
7319 		uint32_t    index;
7320 		char	    *tmpPath;
7321 		fc_local_port_t	  *tmpPort;
7322 
7323 		if (fcio->fcio_olen < MAXPATHLEN ||
7324 		    fcio->fcio_ilen != sizeof (uint32_t)) {
7325 			rval = EINVAL;
7326 			break;
7327 		}
7328 		if (ddi_copyin(fcio->fcio_ibuf, &index, sizeof (index), mode)) {
7329 			rval = EFAULT;
7330 			break;
7331 		}
7332 
7333 		tmpPort = fctl_get_adapter_port_by_index(port, index);
7334 		if (tmpPort == NULL) {
7335 			FP_TRACE(FP_NHEAD1(9, 0),
7336 			    "User supplied index out of range");
7337 			fcio->fcio_errno = FC_BADPORT;
7338 			rval = EFAULT;
7339 			if (fp_fcio_copyout(fcio, data, mode)) {
7340 				rval = EFAULT;
7341 			}
7342 			break;
7343 		}
7344 
7345 		tmpPath = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
7346 		(void) ddi_pathname(tmpPort->fp_port_dip, tmpPath);
7347 		if (fp_copyout((void *)tmpPath, (void *)fcio->fcio_obuf,
7348 		    MAXPATHLEN, mode) == 0) {
7349 			if (fp_fcio_copyout(fcio, data, mode)) {
7350 				rval = EFAULT;
7351 			}
7352 		} else {
7353 			rval = EFAULT;
7354 		}
7355 		kmem_free(tmpPath, MAXPATHLEN);
7356 		break;
7357 	}
7358 
7359 	case FCIO_NPIV_GET_ADAPTER_ATTRIBUTES:
7360 	case FCIO_GET_ADAPTER_ATTRIBUTES: {
7361 		fc_hba_adapter_attributes_t	*val;
7362 		fc_hba_adapter_attributes32_t	*val32;
7363 
7364 		if (use32 == B_TRUE) {
7365 			if (fcio->fcio_olen < sizeof (*val32) ||
7366 			    fcio->fcio_xfer != FCIO_XFER_READ) {
7367 				rval = EINVAL;
7368 				break;
7369 			}
7370 		} else {
7371 			if (fcio->fcio_olen < sizeof (*val) ||
7372 			    fcio->fcio_xfer != FCIO_XFER_READ) {
7373 				rval = EINVAL;
7374 				break;
7375 			}
7376 		}
7377 
7378 		val = kmem_zalloc(sizeof (*val), KM_SLEEP);
7379 		val->version = FC_HBA_ADAPTER_ATTRIBUTES_VERSION;
7380 		mutex_enter(&port->fp_mutex);
7381 		bcopy(port->fp_hba_port_attrs.manufacturer,
7382 		    val->Manufacturer,
7383 		    sizeof (val->Manufacturer));
7384 		bcopy(port->fp_hba_port_attrs.serial_number,
7385 		    val->SerialNumber,
7386 		    sizeof (val->SerialNumber));
7387 		bcopy(port->fp_hba_port_attrs.model,
7388 		    val->Model,
7389 		    sizeof (val->Model));
7390 		bcopy(port->fp_hba_port_attrs.model_description,
7391 		    val->ModelDescription,
7392 		    sizeof (val->ModelDescription));
7393 		bcopy(port->fp_sym_node_name, val->NodeSymbolicName,
7394 		    port->fp_sym_node_namelen);
7395 		bcopy(port->fp_hba_port_attrs.hardware_version,
7396 		    val->HardwareVersion,
7397 		    sizeof (val->HardwareVersion));
7398 		bcopy(port->fp_hba_port_attrs.option_rom_version,
7399 		    val->OptionROMVersion,
7400 		    sizeof (val->OptionROMVersion));
7401 		bcopy(port->fp_hba_port_attrs.firmware_version,
7402 		    val->FirmwareVersion,
7403 		    sizeof (val->FirmwareVersion));
7404 		val->VendorSpecificID =
7405 		    port->fp_hba_port_attrs.vendor_specific_id;
7406 		bcopy(&port->fp_service_params.node_ww_name.raw_wwn,
7407 		    &val->NodeWWN.raw_wwn,
7408 		    sizeof (val->NodeWWN.raw_wwn));
7409 
7410 
7411 		bcopy(port->fp_hba_port_attrs.driver_name,
7412 		    val->DriverName,
7413 		    sizeof (val->DriverName));
7414 		bcopy(port->fp_hba_port_attrs.driver_version,
7415 		    val->DriverVersion,
7416 		    sizeof (val->DriverVersion));
7417 		mutex_exit(&port->fp_mutex);
7418 
7419 		if (fcio->fcio_cmd == FCIO_GET_ADAPTER_ATTRIBUTES) {
7420 			val->NumberOfPorts = fctl_count_fru_ports(port, 0);
7421 		} else {
7422 			val->NumberOfPorts = fctl_count_fru_ports(port, 1);
7423 		}
7424 
7425 		if (use32 == B_TRUE) {
7426 			val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP);
7427 			val32->version = val->version;
7428 			bcopy(val->Manufacturer, val32->Manufacturer,
7429 			    sizeof (val->Manufacturer));
7430 			bcopy(val->SerialNumber, val32->SerialNumber,
7431 			    sizeof (val->SerialNumber));
7432 			bcopy(val->Model, val32->Model,
7433 			    sizeof (val->Model));
7434 			bcopy(val->ModelDescription, val32->ModelDescription,
7435 			    sizeof (val->ModelDescription));
7436 			bcopy(val->NodeSymbolicName, val32->NodeSymbolicName,
7437 			    sizeof (val->NodeSymbolicName));
7438 			bcopy(val->HardwareVersion, val32->HardwareVersion,
7439 			    sizeof (val->HardwareVersion));
7440 			bcopy(val->OptionROMVersion, val32->OptionROMVersion,
7441 			    sizeof (val->OptionROMVersion));
7442 			bcopy(val->FirmwareVersion, val32->FirmwareVersion,
7443 			    sizeof (val->FirmwareVersion));
7444 			val32->VendorSpecificID = val->VendorSpecificID;
7445 			bcopy(&val->NodeWWN.raw_wwn, &val32->NodeWWN.raw_wwn,
7446 			    sizeof (val->NodeWWN.raw_wwn));
7447 			bcopy(val->DriverName, val32->DriverName,
7448 			    sizeof (val->DriverName));
7449 			bcopy(val->DriverVersion, val32->DriverVersion,
7450 			    sizeof (val->DriverVersion));
7451 
7452 			val32->NumberOfPorts = val->NumberOfPorts;
7453 
7454 			if (fp_copyout((void *)val32, (void *)fcio->fcio_obuf,
7455 			    fcio->fcio_olen, mode) == 0) {
7456 				if (fp_fcio_copyout(fcio, data, mode)) {
7457 					rval = EFAULT;
7458 				}
7459 			} else {
7460 				rval = EFAULT;
7461 			}
7462 
7463 			kmem_free(val32, sizeof (*val32));
7464 		} else {
7465 			if (fp_copyout((void *)val, (void *)fcio->fcio_obuf,
7466 			    fcio->fcio_olen, mode) == 0) {
7467 				if (fp_fcio_copyout(fcio, data, mode)) {
7468 					rval = EFAULT;
7469 				}
7470 			} else {
7471 				rval = EFAULT;
7472 			}
7473 		}
7474 
7475 		kmem_free(val, sizeof (*val));
7476 		break;
7477 	}
7478 
7479 	case FCIO_GET_NPIV_ATTRIBUTES: {
7480 		fc_hba_npiv_attributes_t *attrs;
7481 
7482 		attrs = kmem_zalloc(sizeof (*attrs), KM_SLEEP);
7483 		mutex_enter(&port->fp_mutex);
7484 		bcopy(&port->fp_service_params.node_ww_name.raw_wwn,
7485 		    &attrs->NodeWWN.raw_wwn,
7486 		    sizeof (attrs->NodeWWN.raw_wwn));
7487 		bcopy(&port->fp_service_params.nport_ww_name.raw_wwn,
7488 		    &attrs->PortWWN.raw_wwn,
7489 		    sizeof (attrs->PortWWN.raw_wwn));
7490 		mutex_exit(&port->fp_mutex);
7491 		if (fp_copyout((void *)attrs, (void *)fcio->fcio_obuf,
7492 		    fcio->fcio_olen, mode) == 0) {
7493 			if (fp_fcio_copyout(fcio, data, mode)) {
7494 				rval = EFAULT;
7495 			}
7496 		} else {
7497 			rval = EFAULT;
7498 		}
7499 		kmem_free(attrs, sizeof (*attrs));
7500 		break;
7501 	}
7502 
7503 	case FCIO_DELETE_NPIV_PORT: {
7504 		fc_local_port_t *tmpport;
7505 		char	ww_pname[17];
7506 		la_wwn_t	vwwn[1];
7507 
7508 		FP_TRACE(FP_NHEAD1(1, 0), "Delete NPIV Port");
7509 		if (ddi_copyin(fcio->fcio_ibuf,
7510 		    &vwwn, sizeof (la_wwn_t), mode)) {
7511 			rval = EFAULT;
7512 			break;
7513 		}
7514 
7515 		fc_wwn_to_str(&vwwn[0], ww_pname);
7516 		FP_TRACE(FP_NHEAD1(3, 0),
7517 		    "Delete NPIV Port %s", ww_pname);
7518 		tmpport = fc_delete_npiv_port(port, &vwwn[0]);
7519 		if (tmpport == NULL) {
7520 			FP_TRACE(FP_NHEAD1(3, 0),
7521 			    "Delete NPIV Port : no found");
7522 			rval = EFAULT;
7523 		} else {
7524 			fc_local_port_t *nextport = tmpport->fp_port_next;
7525 			fc_local_port_t *prevport = tmpport->fp_port_prev;
7526 			int portlen, portindex, ret;
7527 
7528 			portlen = sizeof (portindex);
7529 			ret = ddi_prop_op(DDI_DEV_T_ANY,
7530 			    tmpport->fp_port_dip, PROP_LEN_AND_VAL_BUF,
7531 			    DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "port",
7532 			    (caddr_t)&portindex, &portlen);
7533 			if (ret != DDI_SUCCESS) {
7534 				rval = EFAULT;
7535 				break;
7536 			}
7537 			if (ndi_devi_offline(tmpport->fp_port_dip,
7538 			    NDI_DEVI_REMOVE) != DDI_SUCCESS) {
7539 				FP_TRACE(FP_NHEAD1(1, 0),
7540 				    "Delete NPIV Port failed");
7541 				mutex_enter(&port->fp_mutex);
7542 				tmpport->fp_npiv_state = 0;
7543 				mutex_exit(&port->fp_mutex);
7544 				rval = EFAULT;
7545 			} else {
7546 				mutex_enter(&port->fp_mutex);
7547 				nextport->fp_port_prev = prevport;
7548 				prevport->fp_port_next = nextport;
7549 				if (port == port->fp_port_next) {
7550 					port->fp_port_next =
7551 					    port->fp_port_prev = NULL;
7552 				}
7553 				port->fp_npiv_portnum--;
7554 				FP_TRACE(FP_NHEAD1(3, 0),
7555 				    "Delete NPIV Port %d", portindex);
7556 				port->fp_npiv_portindex[portindex-1] = 0;
7557 				mutex_exit(&port->fp_mutex);
7558 			}
7559 		}
7560 		break;
7561 	}
7562 
7563 	case FCIO_CREATE_NPIV_PORT: {
7564 		char ww_nname[17], ww_pname[17];
7565 		la_npiv_create_entry_t entrybuf;
7566 		uint32_t vportindex = 0;
7567 		int npiv_ret = 0;
7568 		char *portname, *fcaname;
7569 
7570 		portname = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
7571 		(void) ddi_pathname(port->fp_port_dip, portname);
7572 		fcaname = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
7573 		(void) ddi_pathname(port->fp_fca_dip, fcaname);
7574 		FP_TRACE(FP_NHEAD1(1, 0),
7575 		    "Create NPIV port %s %s %s", portname, fcaname,
7576 		    ddi_driver_name(port->fp_fca_dip));
7577 		kmem_free(portname, MAXPATHLEN);
7578 		kmem_free(fcaname, MAXPATHLEN);
7579 		if (ddi_copyin(fcio->fcio_ibuf,
7580 		    &entrybuf, sizeof (la_npiv_create_entry_t), mode)) {
7581 			rval = EFAULT;
7582 			break;
7583 		}
7584 
7585 		fc_wwn_to_str(&entrybuf.VNodeWWN, ww_nname);
7586 		fc_wwn_to_str(&entrybuf.VPortWWN, ww_pname);
7587 		vportindex = entrybuf.vindex;
7588 		FP_TRACE(FP_NHEAD1(3, 0),
7589 		    "Create NPIV Port %s %s %d",
7590 		    ww_nname, ww_pname, vportindex);
7591 
7592 		if (fc_get_npiv_port(port, &entrybuf.VPortWWN)) {
7593 			rval = EFAULT;
7594 			break;
7595 		}
7596 		npiv_ret = fctl_fca_create_npivport(port->fp_fca_dip,
7597 		    port->fp_port_dip, ww_nname, ww_pname, &vportindex);
7598 		if (npiv_ret == NDI_SUCCESS) {
7599 			mutex_enter(&port->fp_mutex);
7600 			port->fp_npiv_portnum++;
7601 			mutex_exit(&port->fp_mutex);
7602 			if (fp_copyout((void *)&vportindex,
7603 			    (void *)fcio->fcio_obuf,
7604 			    fcio->fcio_olen, mode) == 0) {
7605 				if (fp_fcio_copyout(fcio, data, mode)) {
7606 					rval = EFAULT;
7607 				}
7608 			} else {
7609 				rval = EFAULT;
7610 			}
7611 		} else {
7612 			rval = EFAULT;
7613 		}
7614 		FP_TRACE(FP_NHEAD1(3, 0),
7615 		    "Create NPIV Port %d %d", npiv_ret, vportindex);
7616 		break;
7617 	}
7618 
7619 	case FCIO_GET_NPIV_PORT_LIST: {
7620 		fc_hba_npiv_port_list_t *list;
7621 		int count;
7622 
7623 		if ((fcio->fcio_xfer != FCIO_XFER_READ) ||
7624 		    (fcio->fcio_olen == 0) || (fcio->fcio_obuf == 0)) {
7625 			rval = EINVAL;
7626 			break;
7627 		}
7628 
7629 		list = kmem_zalloc(fcio->fcio_olen, KM_SLEEP);
7630 		list->version = FC_HBA_LIST_VERSION;
7631 		/* build npiv port list */
7632 		count = fc_ulp_get_npiv_port_list(port, (char *)list->hbaPaths);
7633 		if (count < 0) {
7634 			rval = ENXIO;
7635 			FP_TRACE(FP_NHEAD1(1, 0), "Build NPIV Port List error");
7636 			kmem_free(list, fcio->fcio_olen);
7637 			break;
7638 		}
7639 		list->numAdapters = count;
7640 
7641 		if (fp_copyout((void *)list, (void *)fcio->fcio_obuf,
7642 		    fcio->fcio_olen, mode) == 0) {
7643 			if (fp_fcio_copyout(fcio, data, mode)) {
7644 				FP_TRACE(FP_NHEAD1(1, 0),
7645 				    "Copy NPIV Port data error");
7646 				rval = EFAULT;
7647 			}
7648 		} else {
7649 			FP_TRACE(FP_NHEAD1(1, 0), "Copy NPIV Port List error");
7650 			rval = EFAULT;
7651 		}
7652 		kmem_free(list, fcio->fcio_olen);
7653 		break;
7654 	}
7655 
7656 	case FCIO_GET_ADAPTER_PORT_NPIV_ATTRIBUTES: {
7657 		fc_hba_port_npiv_attributes_t	*val;
7658 
7659 		val = kmem_zalloc(sizeof (*val), KM_SLEEP);
7660 		val->version = FC_HBA_PORT_NPIV_ATTRIBUTES_VERSION;
7661 
7662 		mutex_enter(&port->fp_mutex);
7663 		val->npivflag = port->fp_npiv_flag;
7664 		val->lastChange = port->fp_last_change;
7665 		bcopy(&port->fp_service_params.nport_ww_name.raw_wwn,
7666 		    &val->PortWWN.raw_wwn,
7667 		    sizeof (val->PortWWN.raw_wwn));
7668 		bcopy(&port->fp_service_params.node_ww_name.raw_wwn,
7669 		    &val->NodeWWN.raw_wwn,
7670 		    sizeof (val->NodeWWN.raw_wwn));
7671 		mutex_exit(&port->fp_mutex);
7672 
7673 		val->NumberOfNPIVPorts = fc_ulp_get_npiv_port_num(port);
7674 		if (port->fp_npiv_type != FC_NPIV_PORT) {
7675 			val->MaxNumberOfNPIVPorts =
7676 			    port->fp_fca_tran->fca_num_npivports;
7677 		} else {
7678 			val->MaxNumberOfNPIVPorts = 0;
7679 		}
7680 
7681 		if (fp_copyout((void *)val, (void *)fcio->fcio_obuf,
7682 		    fcio->fcio_olen, mode) == 0) {
7683 			if (fp_fcio_copyout(fcio, data, mode)) {
7684 				rval = EFAULT;
7685 			}
7686 		} else {
7687 			rval = EFAULT;
7688 		}
7689 		kmem_free(val, sizeof (*val));
7690 		break;
7691 	}
7692 
7693 	case FCIO_GET_ADAPTER_PORT_ATTRIBUTES: {
7694 		fc_hba_port_attributes_t	*val;
7695 		fc_hba_port_attributes32_t	*val32;
7696 
7697 		if (use32 == B_TRUE) {
7698 			if (fcio->fcio_olen < sizeof (*val32) ||
7699 			    fcio->fcio_xfer != FCIO_XFER_READ) {
7700 				rval = EINVAL;
7701 				break;
7702 			}
7703 		} else {
7704 			if (fcio->fcio_olen < sizeof (*val) ||
7705 			    fcio->fcio_xfer != FCIO_XFER_READ) {
7706 				rval = EINVAL;
7707 				break;
7708 			}
7709 		}
7710 
7711 		val = kmem_zalloc(sizeof (*val), KM_SLEEP);
7712 		val->version = FC_HBA_PORT_ATTRIBUTES_VERSION;
7713 		mutex_enter(&port->fp_mutex);
7714 		val->lastChange = port->fp_last_change;
7715 		val->fp_minor = port->fp_instance;
7716 
7717 		bcopy(&port->fp_service_params.nport_ww_name.raw_wwn,
7718 		    &val->PortWWN.raw_wwn,
7719 		    sizeof (val->PortWWN.raw_wwn));
7720 		bcopy(&port->fp_service_params.node_ww_name.raw_wwn,
7721 		    &val->NodeWWN.raw_wwn,
7722 		    sizeof (val->NodeWWN.raw_wwn));
7723 		bcopy(&port->fp_fabric_name, &val->FabricName.raw_wwn,
7724 		    sizeof (val->FabricName.raw_wwn));
7725 
7726 		val->PortFcId = port->fp_port_id.port_id;
7727 
7728 		switch (FC_PORT_STATE_MASK(port->fp_state)) {
7729 		case FC_STATE_OFFLINE:
7730 			val->PortState = FC_HBA_PORTSTATE_OFFLINE;
7731 			break;
7732 		case FC_STATE_ONLINE:
7733 		case FC_STATE_LOOP:
7734 		case FC_STATE_NAMESERVICE:
7735 			val->PortState = FC_HBA_PORTSTATE_ONLINE;
7736 			break;
7737 		default:
7738 			val->PortState = FC_HBA_PORTSTATE_UNKNOWN;
7739 			break;
7740 		}
7741 
7742 		/* Translate from LV to FC-HBA port type codes */
7743 		switch (port->fp_port_type.port_type) {
7744 		case FC_NS_PORT_N:
7745 			val->PortType = FC_HBA_PORTTYPE_NPORT;
7746 			break;
7747 		case FC_NS_PORT_NL:
7748 			/* Actually means loop for us */
7749 			val->PortType = FC_HBA_PORTTYPE_LPORT;
7750 			break;
7751 		case FC_NS_PORT_F:
7752 			val->PortType = FC_HBA_PORTTYPE_FPORT;
7753 			break;
7754 		case FC_NS_PORT_FL:
7755 			val->PortType = FC_HBA_PORTTYPE_FLPORT;
7756 			break;
7757 		case FC_NS_PORT_E:
7758 			val->PortType = FC_HBA_PORTTYPE_EPORT;
7759 			break;
7760 		default:
7761 			val->PortType = FC_HBA_PORTTYPE_OTHER;
7762 			break;
7763 		}
7764 
7765 
7766 		/*
7767 		 * If fp has decided that the topology is public loop,
7768 		 * we will indicate that using the appropriate
7769 		 * FC HBA API constant.
7770 		 */
7771 		switch (port->fp_topology) {
7772 		case FC_TOP_PUBLIC_LOOP:
7773 			val->PortType = FC_HBA_PORTTYPE_NLPORT;
7774 			break;
7775 
7776 		case FC_TOP_PT_PT:
7777 			val->PortType = FC_HBA_PORTTYPE_PTP;
7778 			break;
7779 
7780 		case FC_TOP_UNKNOWN:
7781 			/*
7782 			 * This should cover the case where nothing is connected
7783 			 * to the port. Crystal+ is p'bly an exception here.
7784 			 * For Crystal+, port 0 will come up as private loop
7785 			 * (i.e fp_bind_state will be FC_STATE_LOOP) even when
7786 			 * nothing is connected to it.
7787 			 * Current plan is to let userland handle this.
7788 			 */
7789 			if (port->fp_bind_state == FC_STATE_OFFLINE) {
7790 				val->PortType = FC_HBA_PORTTYPE_UNKNOWN;
7791 			}
7792 			break;
7793 
7794 		default:
7795 			/*
7796 			 * Do Nothing.
7797 			 * Unused:
7798 			 *   val->PortType = FC_HBA_PORTTYPE_GPORT;
7799 			 */
7800 			break;
7801 		}
7802 
7803 		val->PortSupportedClassofService =
7804 		    port->fp_hba_port_attrs.supported_cos;
7805 		val->PortSupportedFc4Types[0] = 0;
7806 		bcopy(port->fp_fc4_types, val->PortActiveFc4Types,
7807 		    sizeof (val->PortActiveFc4Types));
7808 		bcopy(port->fp_sym_port_name, val->PortSymbolicName,
7809 		    port->fp_sym_port_namelen);
7810 		val->PortSupportedSpeed =
7811 		    port->fp_hba_port_attrs.supported_speed;
7812 
7813 		switch (FC_PORT_SPEED_MASK(port->fp_state)) {
7814 		case FC_STATE_1GBIT_SPEED:
7815 			val->PortSpeed = FC_HBA_PORTSPEED_1GBIT;
7816 			break;
7817 		case FC_STATE_2GBIT_SPEED:
7818 			val->PortSpeed = FC_HBA_PORTSPEED_2GBIT;
7819 			break;
7820 		case FC_STATE_4GBIT_SPEED:
7821 			val->PortSpeed = FC_HBA_PORTSPEED_4GBIT;
7822 			break;
7823 		case FC_STATE_8GBIT_SPEED:
7824 			val->PortSpeed = FC_HBA_PORTSPEED_8GBIT;
7825 			break;
7826 		case FC_STATE_10GBIT_SPEED:
7827 			val->PortSpeed = FC_HBA_PORTSPEED_10GBIT;
7828 			break;
7829 		case FC_STATE_16GBIT_SPEED:
7830 			val->PortSpeed = FC_HBA_PORTSPEED_16GBIT;
7831 			break;
7832 		default:
7833 			val->PortSpeed = FC_HBA_PORTSPEED_UNKNOWN;
7834 			break;
7835 		}
7836 		val->PortMaxFrameSize = port->fp_hba_port_attrs.max_frame_size;
7837 		val->NumberofDiscoveredPorts = port->fp_dev_count;
7838 		mutex_exit(&port->fp_mutex);
7839 
7840 		if (use32 == B_TRUE) {
7841 			val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP);
7842 			val32->version = val->version;
7843 			val32->lastChange = val->lastChange;
7844 			val32->fp_minor = val->fp_minor;
7845 
7846 			bcopy(&val->PortWWN.raw_wwn, &val32->PortWWN.raw_wwn,
7847 			    sizeof (val->PortWWN.raw_wwn));
7848 			bcopy(&val->NodeWWN.raw_wwn, &val32->NodeWWN.raw_wwn,
7849 			    sizeof (val->NodeWWN.raw_wwn));
7850 			val32->PortFcId = val->PortFcId;
7851 			val32->PortState = val->PortState;
7852 			val32->PortType = val->PortType;
7853 
7854 			val32->PortSupportedClassofService =
7855 			    val->PortSupportedClassofService;
7856 			bcopy(val->PortActiveFc4Types,
7857 			    val32->PortActiveFc4Types,
7858 			    sizeof (val->PortActiveFc4Types));
7859 			bcopy(val->PortSymbolicName, val32->PortSymbolicName,
7860 			    sizeof (val->PortSymbolicName));
7861 			bcopy(&val->FabricName, &val32->FabricName,
7862 			    sizeof (val->FabricName.raw_wwn));
7863 			val32->PortSupportedSpeed = val->PortSupportedSpeed;
7864 			val32->PortSpeed = val->PortSpeed;
7865 
7866 			val32->PortMaxFrameSize = val->PortMaxFrameSize;
7867 			val32->NumberofDiscoveredPorts =
7868 			    val->NumberofDiscoveredPorts;
7869 
7870 			if (fp_copyout((void *)val32, (void *)fcio->fcio_obuf,
7871 			    fcio->fcio_olen, mode) == 0) {
7872 				if (fp_fcio_copyout(fcio, data, mode)) {
7873 					rval = EFAULT;
7874 				}
7875 			} else {
7876 				rval = EFAULT;
7877 			}
7878 
7879 			kmem_free(val32, sizeof (*val32));
7880 		} else {
7881 			if (fp_copyout((void *)val, (void *)fcio->fcio_obuf,
7882 			    fcio->fcio_olen, mode) == 0) {
7883 				if (fp_fcio_copyout(fcio, data, mode)) {
7884 					rval = EFAULT;
7885 				}
7886 			} else {
7887 				rval = EFAULT;
7888 			}
7889 		}
7890 
7891 		kmem_free(val, sizeof (*val));
7892 		break;
7893 	}
7894 
7895 	case FCIO_GET_DISCOVERED_PORT_ATTRIBUTES: {
7896 		fc_hba_port_attributes_t	*val;
7897 		fc_hba_port_attributes32_t	*val32;
7898 		uint32_t	index = 0;
7899 		fc_remote_port_t *tmp_pd;
7900 
7901 		if (use32 == B_TRUE) {
7902 			if (fcio->fcio_olen < sizeof (*val32) ||
7903 			    fcio->fcio_xfer != FCIO_XFER_READ) {
7904 				rval = EINVAL;
7905 				break;
7906 			}
7907 		} else {
7908 			if (fcio->fcio_olen < sizeof (*val) ||
7909 			    fcio->fcio_xfer != FCIO_XFER_READ) {
7910 				rval = EINVAL;
7911 				break;
7912 			}
7913 		}
7914 
7915 		if (ddi_copyin(fcio->fcio_ibuf, &index, sizeof (index), mode)) {
7916 			rval = EFAULT;
7917 			break;
7918 		}
7919 
7920 		if (index >= port->fp_dev_count) {
7921 			FP_TRACE(FP_NHEAD1(9, 0),
7922 			    "User supplied index out of range");
7923 			fcio->fcio_errno = FC_OUTOFBOUNDS;
7924 			rval = EINVAL;
7925 			if (fp_fcio_copyout(fcio, data, mode)) {
7926 				rval = EFAULT;
7927 			}
7928 			break;
7929 		}
7930 
7931 		val = kmem_zalloc(sizeof (*val), KM_SLEEP);
7932 		val->version = FC_HBA_PORT_ATTRIBUTES_VERSION;
7933 
7934 		mutex_enter(&port->fp_mutex);
7935 		tmp_pd = fctl_lookup_pd_by_index(port, index);
7936 
7937 		if (tmp_pd == NULL) {
7938 			fcio->fcio_errno = FC_BADPORT;
7939 			rval = EINVAL;
7940 		} else {
7941 			val->lastChange = port->fp_last_change;
7942 			val->fp_minor = port->fp_instance;
7943 
7944 			mutex_enter(&tmp_pd->pd_mutex);
7945 			bcopy(&tmp_pd->pd_port_name.raw_wwn,
7946 			    &val->PortWWN.raw_wwn,
7947 			    sizeof (val->PortWWN.raw_wwn));
7948 			bcopy(&tmp_pd->pd_remote_nodep->fd_node_name.raw_wwn,
7949 			    &val->NodeWWN.raw_wwn,
7950 			    sizeof (val->NodeWWN.raw_wwn));
7951 			val->PortFcId = tmp_pd->pd_port_id.port_id;
7952 			bcopy(tmp_pd->pd_spn, val->PortSymbolicName,
7953 			    tmp_pd->pd_spn_len);
7954 			val->PortSupportedClassofService = tmp_pd->pd_cos;
7955 			/*
7956 			 * we will assume the sizeof these pd_fc4types and
7957 			 * portActiveFc4Types will remain the same.  we could
7958 			 * add in a check for it, but we decided it was unneeded
7959 			 */
7960 			bcopy((caddr_t)tmp_pd->pd_fc4types,
7961 			    val->PortActiveFc4Types,
7962 			    sizeof (tmp_pd->pd_fc4types));
7963 			val->PortState =
7964 			    fp_map_remote_port_state(tmp_pd->pd_state);
7965 			mutex_exit(&tmp_pd->pd_mutex);
7966 
7967 			val->PortType = FC_HBA_PORTTYPE_UNKNOWN;
7968 			val->PortSupportedFc4Types[0] = 0;
7969 			val->PortSupportedSpeed = FC_HBA_PORTSPEED_UNKNOWN;
7970 			val->PortSpeed = FC_HBA_PORTSPEED_UNKNOWN;
7971 			val->PortMaxFrameSize = 0;
7972 			val->NumberofDiscoveredPorts = 0;
7973 
7974 			if (use32 == B_TRUE) {
7975 				val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP);
7976 				val32->version = val->version;
7977 				val32->lastChange = val->lastChange;
7978 				val32->fp_minor = val->fp_minor;
7979 
7980 				bcopy(&val->PortWWN.raw_wwn,
7981 				    &val32->PortWWN.raw_wwn,
7982 				    sizeof (val->PortWWN.raw_wwn));
7983 				bcopy(&val->NodeWWN.raw_wwn,
7984 				    &val32->NodeWWN.raw_wwn,
7985 				    sizeof (val->NodeWWN.raw_wwn));
7986 				val32->PortFcId = val->PortFcId;
7987 				bcopy(val->PortSymbolicName,
7988 				    val32->PortSymbolicName,
7989 				    sizeof (val->PortSymbolicName));
7990 				val32->PortSupportedClassofService =
7991 				    val->PortSupportedClassofService;
7992 				bcopy(val->PortActiveFc4Types,
7993 				    val32->PortActiveFc4Types,
7994 				    sizeof (tmp_pd->pd_fc4types));
7995 
7996 				val32->PortType = val->PortType;
7997 				val32->PortState = val->PortState;
7998 				val32->PortSupportedFc4Types[0] =
7999 				    val->PortSupportedFc4Types[0];
8000 				val32->PortSupportedSpeed =
8001 				    val->PortSupportedSpeed;
8002 				val32->PortSpeed = val->PortSpeed;
8003 				val32->PortMaxFrameSize =
8004 				    val->PortMaxFrameSize;
8005 				val32->NumberofDiscoveredPorts =
8006 				    val->NumberofDiscoveredPorts;
8007 
8008 				if (fp_copyout((void *)val32,
8009 				    (void *)fcio->fcio_obuf,
8010 				    fcio->fcio_olen, mode) == 0) {
8011 					if (fp_fcio_copyout(fcio,
8012 					    data, mode)) {
8013 						rval = EFAULT;
8014 					}
8015 				} else {
8016 					rval = EFAULT;
8017 				}
8018 
8019 				kmem_free(val32, sizeof (*val32));
8020 			} else {
8021 				if (fp_copyout((void *)val,
8022 				    (void *)fcio->fcio_obuf,
8023 				    fcio->fcio_olen, mode) == 0) {
8024 					if (fp_fcio_copyout(fcio, data, mode)) {
8025 						rval = EFAULT;
8026 					}
8027 				} else {
8028 					rval = EFAULT;
8029 				}
8030 			}
8031 		}
8032 
8033 		mutex_exit(&port->fp_mutex);
8034 		kmem_free(val, sizeof (*val));
8035 		break;
8036 	}
8037 
8038 	case FCIO_GET_PORT_ATTRIBUTES: {
8039 		fc_hba_port_attributes_t    *val;
8040 		fc_hba_port_attributes32_t  *val32;
8041 		la_wwn_t		    wwn;
8042 		fc_remote_port_t	    *tmp_pd;
8043 
8044 		if (use32 == B_TRUE) {
8045 			if (fcio->fcio_olen < sizeof (*val32) ||
8046 			    fcio->fcio_xfer != FCIO_XFER_READ) {
8047 				rval = EINVAL;
8048 				break;
8049 			}
8050 		} else {
8051 			if (fcio->fcio_olen < sizeof (*val) ||
8052 			    fcio->fcio_xfer != FCIO_XFER_READ) {
8053 				rval = EINVAL;
8054 				break;
8055 			}
8056 		}
8057 
8058 		if (ddi_copyin(fcio->fcio_ibuf, &wwn, sizeof (wwn), mode)) {
8059 			rval = EFAULT;
8060 			break;
8061 		}
8062 
8063 		val = kmem_zalloc(sizeof (*val), KM_SLEEP);
8064 		val->version = FC_HBA_PORT_ATTRIBUTES_VERSION;
8065 
8066 		mutex_enter(&port->fp_mutex);
8067 		tmp_pd = fctl_lookup_pd_by_wwn(port, wwn);
8068 		val->lastChange = port->fp_last_change;
8069 		val->fp_minor = port->fp_instance;
8070 		mutex_exit(&port->fp_mutex);
8071 
8072 		if (tmp_pd == NULL) {
8073 			fcio->fcio_errno = FC_BADWWN;
8074 			rval = EINVAL;
8075 		} else {
8076 			mutex_enter(&tmp_pd->pd_mutex);
8077 			bcopy(&tmp_pd->pd_port_name.raw_wwn,
8078 			    &val->PortWWN.raw_wwn,
8079 			    sizeof (val->PortWWN.raw_wwn));
8080 			bcopy(&tmp_pd->pd_remote_nodep->fd_node_name.raw_wwn,
8081 			    &val->NodeWWN.raw_wwn,
8082 			    sizeof (val->NodeWWN.raw_wwn));
8083 			val->PortFcId = tmp_pd->pd_port_id.port_id;
8084 			bcopy(tmp_pd->pd_spn, val->PortSymbolicName,
8085 			    tmp_pd->pd_spn_len);
8086 			val->PortSupportedClassofService = tmp_pd->pd_cos;
8087 			val->PortType = FC_HBA_PORTTYPE_UNKNOWN;
8088 			val->PortState =
8089 			    fp_map_remote_port_state(tmp_pd->pd_state);
8090 			val->PortSupportedFc4Types[0] = 0;
8091 			/*
8092 			 * we will assume the sizeof these pd_fc4types and
8093 			 * portActiveFc4Types will remain the same.  we could
8094 			 * add in a check for it, but we decided it was unneeded
8095 			 */
8096 			bcopy((caddr_t)tmp_pd->pd_fc4types,
8097 			    val->PortActiveFc4Types,
8098 			    sizeof (tmp_pd->pd_fc4types));
8099 			val->PortSupportedSpeed = FC_HBA_PORTSPEED_UNKNOWN;
8100 			val->PortSpeed = FC_HBA_PORTSPEED_UNKNOWN;
8101 			val->PortMaxFrameSize = 0;
8102 			val->NumberofDiscoveredPorts = 0;
8103 			mutex_exit(&tmp_pd->pd_mutex);
8104 
8105 			if (use32 == B_TRUE) {
8106 				val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP);
8107 				val32->version = val->version;
8108 				val32->lastChange = val->lastChange;
8109 				val32->fp_minor = val->fp_minor;
8110 				bcopy(&val->PortWWN.raw_wwn,
8111 				    &val32->PortWWN.raw_wwn,
8112 				    sizeof (val->PortWWN.raw_wwn));
8113 				bcopy(&val->NodeWWN.raw_wwn,
8114 				    &val32->NodeWWN.raw_wwn,
8115 				    sizeof (val->NodeWWN.raw_wwn));
8116 				val32->PortFcId = val->PortFcId;
8117 				bcopy(val->PortSymbolicName,
8118 				    val32->PortSymbolicName,
8119 				    sizeof (val->PortSymbolicName));
8120 				val32->PortSupportedClassofService =
8121 				    val->PortSupportedClassofService;
8122 				val32->PortType = val->PortType;
8123 				val32->PortState = val->PortState;
8124 				val32->PortSupportedFc4Types[0] =
8125 				    val->PortSupportedFc4Types[0];
8126 				bcopy(val->PortActiveFc4Types,
8127 				    val32->PortActiveFc4Types,
8128 				    sizeof (tmp_pd->pd_fc4types));
8129 				val32->PortSupportedSpeed =
8130 				    val->PortSupportedSpeed;
8131 				val32->PortSpeed = val->PortSpeed;
8132 				val32->PortMaxFrameSize = val->PortMaxFrameSize;
8133 				val32->NumberofDiscoveredPorts =
8134 				    val->NumberofDiscoveredPorts;
8135 
8136 				if (fp_copyout((void *)val32,
8137 				    (void *)fcio->fcio_obuf,
8138 				    fcio->fcio_olen, mode) == 0) {
8139 					if (fp_fcio_copyout(fcio, data, mode)) {
8140 						rval = EFAULT;
8141 					}
8142 				} else {
8143 					rval = EFAULT;
8144 				}
8145 
8146 				kmem_free(val32, sizeof (*val32));
8147 			} else {
8148 				if (fp_copyout((void *)val,
8149 				    (void *)fcio->fcio_obuf,
8150 				    fcio->fcio_olen, mode) == 0) {
8151 					if (fp_fcio_copyout(fcio, data, mode)) {
8152 						rval = EFAULT;
8153 					}
8154 				} else {
8155 					rval = EFAULT;
8156 				}
8157 			}
8158 		}
8159 		kmem_free(val, sizeof (*val));
8160 		break;
8161 	}
8162 
8163 	case FCIO_GET_NUM_DEVS: {
8164 		int num_devices;
8165 
8166 		if (fcio->fcio_olen != sizeof (num_devices) ||
8167 		    fcio->fcio_xfer != FCIO_XFER_READ) {
8168 			rval = EINVAL;
8169 			break;
8170 		}
8171 
8172 		mutex_enter(&port->fp_mutex);
8173 		switch (port->fp_topology) {
8174 		case FC_TOP_PRIVATE_LOOP:
8175 		case FC_TOP_PT_PT:
8176 			num_devices = port->fp_total_devices;
8177 			fcio->fcio_errno = FC_SUCCESS;
8178 			break;
8179 
8180 		case FC_TOP_PUBLIC_LOOP:
8181 		case FC_TOP_FABRIC:
8182 			mutex_exit(&port->fp_mutex);
8183 			job = fctl_alloc_job(JOB_NS_CMD, 0, NULL,
8184 			    NULL, KM_SLEEP);
8185 			ASSERT(job != NULL);
8186 
8187 			/*
8188 			 * In FC-GS-2 the Name Server doesn't send out
8189 			 * RSCNs for any Name Server Database updates
8190 			 * When it is finally fixed there is no need
8191 			 * to probe as below and should be removed.
8192 			 */
8193 			(void) fp_ns_get_devcount(port, job, 0, KM_SLEEP);
8194 			fctl_dealloc_job(job);
8195 
8196 			mutex_enter(&port->fp_mutex);
8197 			num_devices = port->fp_total_devices;
8198 			fcio->fcio_errno = FC_SUCCESS;
8199 			break;
8200 
8201 		case FC_TOP_NO_NS:
8202 			/* FALLTHROUGH */
8203 		case FC_TOP_UNKNOWN:
8204 			/* FALLTHROUGH */
8205 		default:
8206 			num_devices = 0;
8207 			fcio->fcio_errno = FC_SUCCESS;
8208 			break;
8209 		}
8210 		mutex_exit(&port->fp_mutex);
8211 
8212 		if (fp_copyout((void *)&num_devices,
8213 		    (void *)fcio->fcio_obuf, fcio->fcio_olen,
8214 		    mode) == 0) {
8215 			if (fp_fcio_copyout(fcio, data, mode)) {
8216 				rval = EFAULT;
8217 			}
8218 		} else {
8219 			rval = EFAULT;
8220 		}
8221 		break;
8222 	}
8223 
8224 	case FCIO_GET_DEV_LIST: {
8225 		int num_devices;
8226 		int new_count;
8227 		int map_size;
8228 
8229 		if (fcio->fcio_xfer != FCIO_XFER_READ ||
8230 		    fcio->fcio_alen != sizeof (new_count)) {
8231 			rval = EINVAL;
8232 			break;
8233 		}
8234 
8235 		num_devices = fcio->fcio_olen / sizeof (fc_port_dev_t);
8236 
8237 		mutex_enter(&port->fp_mutex);
8238 		if (num_devices < port->fp_total_devices) {
8239 			fcio->fcio_errno = FC_TOOMANY;
8240 			new_count = port->fp_total_devices;
8241 			mutex_exit(&port->fp_mutex);
8242 
8243 			if (fp_copyout((void *)&new_count,
8244 			    (void *)fcio->fcio_abuf,
8245 			    sizeof (new_count), mode)) {
8246 				rval = EFAULT;
8247 				break;
8248 			}
8249 
8250 			if (fp_fcio_copyout(fcio, data, mode)) {
8251 				rval = EFAULT;
8252 				break;
8253 			}
8254 			rval = EINVAL;
8255 			break;
8256 		}
8257 
8258 		if (port->fp_total_devices <= 0) {
8259 			fcio->fcio_errno = FC_NO_MAP;
8260 			new_count = port->fp_total_devices;
8261 			mutex_exit(&port->fp_mutex);
8262 
8263 			if (fp_copyout((void *)&new_count,
8264 			    (void *)fcio->fcio_abuf,
8265 			    sizeof (new_count), mode)) {
8266 				rval = EFAULT;
8267 				break;
8268 			}
8269 
8270 			if (fp_fcio_copyout(fcio, data, mode)) {
8271 				rval = EFAULT;
8272 				break;
8273 			}
8274 			rval = EINVAL;
8275 			break;
8276 		}
8277 
8278 		switch (port->fp_topology) {
8279 		case FC_TOP_PRIVATE_LOOP:
8280 			if (fp_fillout_loopmap(port, fcio,
8281 			    mode) != FC_SUCCESS) {
8282 				rval = EFAULT;
8283 				break;
8284 			}
8285 			if (fp_fcio_copyout(fcio, data, mode)) {
8286 				rval = EFAULT;
8287 			}
8288 			break;
8289 
8290 		case FC_TOP_PT_PT:
8291 			if (fp_fillout_p2pmap(port, fcio,
8292 			    mode) != FC_SUCCESS) {
8293 				rval = EFAULT;
8294 				break;
8295 			}
8296 			if (fp_fcio_copyout(fcio, data, mode)) {
8297 				rval = EFAULT;
8298 			}
8299 			break;
8300 
8301 		case FC_TOP_PUBLIC_LOOP:
8302 		case FC_TOP_FABRIC: {
8303 			fctl_ns_req_t *ns_cmd;
8304 
8305 			map_size =
8306 			    sizeof (fc_port_dev_t) * port->fp_total_devices;
8307 
8308 			mutex_exit(&port->fp_mutex);
8309 
8310 			ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t),
8311 			    sizeof (ns_resp_gan_t), map_size,
8312 			    (FCTL_NS_FILL_NS_MAP | FCTL_NS_BUF_IS_USERLAND),
8313 			    KM_SLEEP);
8314 			ASSERT(ns_cmd != NULL);
8315 
8316 			ns_cmd->ns_gan_index = 0;
8317 			ns_cmd->ns_gan_sid = FCTL_GAN_START_ID;
8318 			ns_cmd->ns_cmd_code = NS_GA_NXT;
8319 			ns_cmd->ns_gan_max = map_size / sizeof (fc_port_dev_t);
8320 
8321 			job = fctl_alloc_job(JOB_PORT_GETMAP, 0, NULL,
8322 			    NULL, KM_SLEEP);
8323 			ASSERT(job != NULL);
8324 
8325 			ret = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP);
8326 
8327 			if (ret != FC_SUCCESS ||
8328 			    job->job_result != FC_SUCCESS) {
8329 				fctl_free_ns_cmd(ns_cmd);
8330 
8331 				fcio->fcio_errno = job->job_result;
8332 				new_count = 0;
8333 				if (fp_copyout((void *)&new_count,
8334 				    (void *)fcio->fcio_abuf,
8335 				    sizeof (new_count), mode)) {
8336 					fctl_dealloc_job(job);
8337 					mutex_enter(&port->fp_mutex);
8338 					rval = EFAULT;
8339 					break;
8340 				}
8341 
8342 				if (fp_fcio_copyout(fcio, data, mode)) {
8343 					fctl_dealloc_job(job);
8344 					mutex_enter(&port->fp_mutex);
8345 					rval = EFAULT;
8346 					break;
8347 				}
8348 				rval = EIO;
8349 				mutex_enter(&port->fp_mutex);
8350 				break;
8351 			}
8352 			fctl_dealloc_job(job);
8353 
8354 			new_count = ns_cmd->ns_gan_index;
8355 			if (fp_copyout((void *)&new_count,
8356 			    (void *)fcio->fcio_abuf, sizeof (new_count),
8357 			    mode)) {
8358 				rval = EFAULT;
8359 				fctl_free_ns_cmd(ns_cmd);
8360 				mutex_enter(&port->fp_mutex);
8361 				break;
8362 			}
8363 
8364 			if (fp_copyout((void *)ns_cmd->ns_data_buf,
8365 			    (void *)fcio->fcio_obuf, sizeof (fc_port_dev_t) *
8366 			    ns_cmd->ns_gan_index, mode)) {
8367 				rval = EFAULT;
8368 				fctl_free_ns_cmd(ns_cmd);
8369 				mutex_enter(&port->fp_mutex);
8370 				break;
8371 			}
8372 			fctl_free_ns_cmd(ns_cmd);
8373 
8374 			if (fp_fcio_copyout(fcio, data, mode)) {
8375 				rval = EFAULT;
8376 			}
8377 			mutex_enter(&port->fp_mutex);
8378 			break;
8379 		}
8380 
8381 		case FC_TOP_NO_NS:
8382 			/* FALLTHROUGH */
8383 		case FC_TOP_UNKNOWN:
8384 			/* FALLTHROUGH */
8385 		default:
8386 			fcio->fcio_errno = FC_NO_MAP;
8387 			num_devices = port->fp_total_devices;
8388 
8389 			if (fp_copyout((void *)&new_count,
8390 			    (void *)fcio->fcio_abuf,
8391 			    sizeof (new_count), mode)) {
8392 				rval = EFAULT;
8393 				break;
8394 			}
8395 
8396 			if (fp_fcio_copyout(fcio, data, mode)) {
8397 				rval = EFAULT;
8398 				break;
8399 			}
8400 			rval = EINVAL;
8401 			break;
8402 		}
8403 		mutex_exit(&port->fp_mutex);
8404 		break;
8405 	}
8406 
8407 	case FCIO_GET_SYM_PNAME: {
8408 		rval = ENOTSUP;
8409 		break;
8410 	}
8411 
8412 	case FCIO_GET_SYM_NNAME: {
8413 		rval = ENOTSUP;
8414 		break;
8415 	}
8416 
8417 	case FCIO_SET_SYM_PNAME: {
8418 		rval = ENOTSUP;
8419 		break;
8420 	}
8421 
8422 	case FCIO_SET_SYM_NNAME: {
8423 		rval = ENOTSUP;
8424 		break;
8425 	}
8426 
8427 	case FCIO_GET_LOGI_PARAMS: {
8428 		la_wwn_t		pwwn;
8429 		la_wwn_t		*my_pwwn;
8430 		la_els_logi_t		*params;
8431 		la_els_logi32_t		*params32;
8432 		fc_remote_node_t	*node;
8433 		fc_remote_port_t	*pd;
8434 
8435 		if (fcio->fcio_ilen != sizeof (la_wwn_t) ||
8436 		    (fcio->fcio_xfer & FCIO_XFER_READ) == 0 ||
8437 		    (fcio->fcio_xfer & FCIO_XFER_WRITE) == 0) {
8438 			rval = EINVAL;
8439 			break;
8440 		}
8441 
8442 		if (use32 == B_TRUE) {
8443 			if (fcio->fcio_olen != sizeof (la_els_logi32_t)) {
8444 				rval = EINVAL;
8445 				break;
8446 			}
8447 		} else {
8448 			if (fcio->fcio_olen != sizeof (la_els_logi_t)) {
8449 				rval = EINVAL;
8450 				break;
8451 			}
8452 		}
8453 
8454 		if (ddi_copyin(fcio->fcio_ibuf, &pwwn, sizeof (pwwn), mode)) {
8455 			rval = EFAULT;
8456 			break;
8457 		}
8458 
8459 		pd = fctl_hold_remote_port_by_pwwn(port, &pwwn);
8460 		if (pd == NULL) {
8461 			mutex_enter(&port->fp_mutex);
8462 			my_pwwn = &port->fp_service_params.nport_ww_name;
8463 			mutex_exit(&port->fp_mutex);
8464 
8465 			if (fctl_wwn_cmp(&pwwn, my_pwwn) != 0) {
8466 				rval = ENXIO;
8467 				break;
8468 			}
8469 
8470 			params = kmem_zalloc(sizeof (*params), KM_SLEEP);
8471 			mutex_enter(&port->fp_mutex);
8472 			*params = port->fp_service_params;
8473 			mutex_exit(&port->fp_mutex);
8474 		} else {
8475 			params = kmem_zalloc(sizeof (*params), KM_SLEEP);
8476 
8477 			mutex_enter(&pd->pd_mutex);
8478 			params->ls_code.mbz = params->ls_code.ls_code = 0;
8479 			params->common_service = pd->pd_csp;
8480 			params->nport_ww_name = pd->pd_port_name;
8481 			params->class_1 = pd->pd_clsp1;
8482 			params->class_2 = pd->pd_clsp2;
8483 			params->class_3 = pd->pd_clsp3;
8484 			node = pd->pd_remote_nodep;
8485 			mutex_exit(&pd->pd_mutex);
8486 
8487 			bzero(params->reserved, sizeof (params->reserved));
8488 
8489 			mutex_enter(&node->fd_mutex);
8490 			bcopy(node->fd_vv, params->vendor_version,
8491 			    sizeof (node->fd_vv));
8492 			params->node_ww_name = node->fd_node_name;
8493 			mutex_exit(&node->fd_mutex);
8494 
8495 			fctl_release_remote_port(pd);
8496 		}
8497 
8498 		if (use32 == B_TRUE) {
8499 			params32 = kmem_zalloc(sizeof (*params32), KM_SLEEP);
8500 
8501 			params32->ls_code.mbz = params->ls_code.mbz;
8502 			params32->common_service = params->common_service;
8503 			params32->nport_ww_name = params->nport_ww_name;
8504 			params32->class_1 = params->class_1;
8505 			params32->class_2 = params->class_2;
8506 			params32->class_3 = params->class_3;
8507 			bzero(params32->reserved, sizeof (params32->reserved));
8508 			bcopy(params->vendor_version, params32->vendor_version,
8509 			    sizeof (node->fd_vv));
8510 			params32->node_ww_name = params->node_ww_name;
8511 
8512 			if (ddi_copyout((void *)params32,
8513 			    (void *)fcio->fcio_obuf,
8514 			    sizeof (*params32), mode)) {
8515 				rval = EFAULT;
8516 			}
8517 
8518 			kmem_free(params32, sizeof (*params32));
8519 		} else {
8520 			if (ddi_copyout((void *)params, (void *)fcio->fcio_obuf,
8521 			    sizeof (*params), mode)) {
8522 				rval = EFAULT;
8523 			}
8524 		}
8525 
8526 		kmem_free(params, sizeof (*params));
8527 		if (fp_fcio_copyout(fcio, data, mode)) {
8528 			rval = EFAULT;
8529 		}
8530 		break;
8531 	}
8532 
8533 	case FCIO_DEV_LOGOUT:
8534 	case FCIO_DEV_LOGIN:
8535 		if (fcio->fcio_ilen != sizeof (la_wwn_t) ||
8536 		    fcio->fcio_xfer != FCIO_XFER_WRITE) {
8537 			rval = EINVAL;
8538 
8539 			if (fp_fcio_copyout(fcio, data, mode)) {
8540 				rval = EFAULT;
8541 			}
8542 			break;
8543 		}
8544 
8545 		if (fcio->fcio_cmd == FCIO_DEV_LOGIN) {
8546 			jcode = JOB_FCIO_LOGIN;
8547 		} else {
8548 			jcode = JOB_FCIO_LOGOUT;
8549 		}
8550 
8551 		kfcio = kmem_zalloc(sizeof (*kfcio), KM_SLEEP);
8552 		bcopy(fcio, kfcio, sizeof (*fcio));
8553 
8554 		if (kfcio->fcio_ilen) {
8555 			kfcio->fcio_ibuf = kmem_zalloc(kfcio->fcio_ilen,
8556 			    KM_SLEEP);
8557 
8558 			if (ddi_copyin((void *)fcio->fcio_ibuf,
8559 			    (void *)kfcio->fcio_ibuf, kfcio->fcio_ilen,
8560 			    mode)) {
8561 				rval = EFAULT;
8562 
8563 				kmem_free(kfcio->fcio_ibuf, kfcio->fcio_ilen);
8564 				kmem_free(kfcio, sizeof (*kfcio));
8565 				fcio->fcio_errno = job->job_result;
8566 				if (fp_fcio_copyout(fcio, data, mode)) {
8567 					rval = EFAULT;
8568 				}
8569 				break;
8570 			}
8571 		}
8572 
8573 		job = fctl_alloc_job(jcode, 0, NULL, NULL, KM_SLEEP);
8574 		job->job_private = kfcio;
8575 
8576 		fctl_enque_job(port, job);
8577 		fctl_jobwait(job);
8578 
8579 		rval = job->job_result;
8580 
8581 		fcio->fcio_errno = kfcio->fcio_errno;
8582 		if (fp_fcio_copyout(fcio, data, mode)) {
8583 			rval = EFAULT;
8584 		}
8585 
8586 		kmem_free(kfcio->fcio_ibuf, kfcio->fcio_ilen);
8587 		kmem_free(kfcio, sizeof (*kfcio));
8588 		fctl_dealloc_job(job);
8589 		break;
8590 
8591 	case FCIO_GET_STATE: {
8592 		la_wwn_t		pwwn;
8593 		uint32_t		state;
8594 		fc_remote_port_t	*pd;
8595 		fctl_ns_req_t		*ns_cmd;
8596 
8597 		if (fcio->fcio_ilen != sizeof (la_wwn_t) ||
8598 		    fcio->fcio_olen != sizeof (state) ||
8599 		    (fcio->fcio_xfer & FCIO_XFER_WRITE) == 0 ||
8600 		    (fcio->fcio_xfer & FCIO_XFER_READ) == 0) {
8601 			rval = EINVAL;
8602 			break;
8603 		}
8604 
8605 		if (ddi_copyin(fcio->fcio_ibuf, &pwwn, sizeof (pwwn), mode)) {
8606 			rval = EFAULT;
8607 			break;
8608 		}
8609 		fcio->fcio_errno = 0;
8610 
8611 		pd = fctl_hold_remote_port_by_pwwn(port, &pwwn);
8612 		if (pd == NULL) {
8613 			mutex_enter(&port->fp_mutex);
8614 			if (FC_IS_TOP_SWITCH(port->fp_topology)) {
8615 				mutex_exit(&port->fp_mutex);
8616 				job = fctl_alloc_job(JOB_PLOGI_ONE, 0,
8617 				    NULL, NULL, KM_SLEEP);
8618 
8619 				job->job_counter = 1;
8620 				job->job_result = FC_SUCCESS;
8621 
8622 				ns_cmd = fctl_alloc_ns_cmd(
8623 				    sizeof (ns_req_gid_pn_t),
8624 				    sizeof (ns_resp_gid_pn_t),
8625 				    sizeof (ns_resp_gid_pn_t),
8626 				    FCTL_NS_BUF_IS_USERLAND, KM_SLEEP);
8627 				ASSERT(ns_cmd != NULL);
8628 
8629 				ns_cmd->ns_cmd_code = NS_GID_PN;
8630 				((ns_req_gid_pn_t *)
8631 				    (ns_cmd->ns_cmd_buf))->pwwn = pwwn;
8632 
8633 				ret = fp_ns_query(port, ns_cmd, job,
8634 				    1, KM_SLEEP);
8635 
8636 				if (ret != FC_SUCCESS || job->job_result !=
8637 				    FC_SUCCESS) {
8638 					if (ret != FC_SUCCESS) {
8639 						fcio->fcio_errno = ret;
8640 					} else {
8641 						fcio->fcio_errno =
8642 						    job->job_result;
8643 					}
8644 					rval = EIO;
8645 				} else {
8646 					state = PORT_DEVICE_INVALID;
8647 				}
8648 				fctl_free_ns_cmd(ns_cmd);
8649 				fctl_dealloc_job(job);
8650 			} else {
8651 				mutex_exit(&port->fp_mutex);
8652 				fcio->fcio_errno = FC_BADWWN;
8653 				rval = ENXIO;
8654 			}
8655 		} else {
8656 			mutex_enter(&pd->pd_mutex);
8657 			state = pd->pd_state;
8658 			mutex_exit(&pd->pd_mutex);
8659 
8660 			fctl_release_remote_port(pd);
8661 		}
8662 
8663 		if (!rval) {
8664 			if (ddi_copyout((void *)&state,
8665 			    (void *)fcio->fcio_obuf, sizeof (state),
8666 			    mode)) {
8667 				rval = EFAULT;
8668 			}
8669 		}
8670 		if (fp_fcio_copyout(fcio, data, mode)) {
8671 			rval = EFAULT;
8672 		}
8673 		break;
8674 	}
8675 
8676 	case FCIO_DEV_REMOVE: {
8677 		la_wwn_t	pwwn;
8678 		fc_portmap_t	*changelist;
8679 		fc_remote_port_t *pd;
8680 
8681 		if (fcio->fcio_ilen != sizeof (la_wwn_t) ||
8682 		    fcio->fcio_xfer != FCIO_XFER_WRITE) {
8683 			rval = EINVAL;
8684 			break;
8685 		}
8686 
8687 		if (ddi_copyin(fcio->fcio_ibuf, &pwwn, sizeof (pwwn), mode)) {
8688 			rval = EFAULT;
8689 			break;
8690 		}
8691 
8692 		pd = fctl_hold_remote_port_by_pwwn(port, &pwwn);
8693 		if (pd == NULL) {
8694 			rval = ENXIO;
8695 			fcio->fcio_errno = FC_BADWWN;
8696 			if (fp_fcio_copyout(fcio, data, mode)) {
8697 				rval = EFAULT;
8698 			}
8699 			break;
8700 		}
8701 
8702 		mutex_enter(&pd->pd_mutex);
8703 		if (pd->pd_ref_count > 1) {
8704 			mutex_exit(&pd->pd_mutex);
8705 
8706 			rval = EBUSY;
8707 			fcio->fcio_errno = FC_FAILURE;
8708 			fctl_release_remote_port(pd);
8709 
8710 			if (fp_fcio_copyout(fcio, data, mode)) {
8711 				rval = EFAULT;
8712 			}
8713 			break;
8714 		}
8715 		mutex_exit(&pd->pd_mutex);
8716 
8717 		changelist = kmem_zalloc(sizeof (*changelist), KM_SLEEP);
8718 
8719 		fctl_copy_portmap(changelist, pd);
8720 		changelist->map_type = PORT_DEVICE_USER_LOGOUT;
8721 		(void) fp_ulp_devc_cb(port, changelist, 1, 1, KM_SLEEP, 1);
8722 
8723 		fctl_release_remote_port(pd);
8724 		break;
8725 	}
8726 
8727 	case FCIO_GET_FCODE_REV: {
8728 		caddr_t		fcode_rev;
8729 		fc_fca_pm_t	pm;
8730 
8731 		if (fcio->fcio_olen < FC_FCODE_REV_SIZE ||
8732 		    fcio->fcio_xfer != FCIO_XFER_READ) {
8733 			rval = EINVAL;
8734 			break;
8735 		}
8736 		bzero((caddr_t)&pm, sizeof (pm));
8737 
8738 		fcode_rev = kmem_zalloc(fcio->fcio_olen, KM_SLEEP);
8739 
8740 		pm.pm_cmd_flags = FC_FCA_PM_READ;
8741 		pm.pm_cmd_code = FC_PORT_GET_FCODE_REV;
8742 		pm.pm_data_len = fcio->fcio_olen;
8743 		pm.pm_data_buf = fcode_rev;
8744 
8745 		ret = port->fp_fca_tran->fca_port_manage(
8746 		    port->fp_fca_handle, &pm);
8747 
8748 		if (ret == FC_SUCCESS) {
8749 			if (ddi_copyout((void *)fcode_rev,
8750 			    (void *)fcio->fcio_obuf,
8751 			    fcio->fcio_olen, mode) == 0) {
8752 				if (fp_fcio_copyout(fcio, data, mode)) {
8753 					rval = EFAULT;
8754 				}
8755 			} else {
8756 				rval = EFAULT;
8757 			}
8758 		} else {
8759 			/*
8760 			 * check if buffer was not large enough to obtain
8761 			 * FCODE version.
8762 			 */
8763 			if (pm.pm_data_len > fcio->fcio_olen) {
8764 				rval = ENOMEM;
8765 			} else {
8766 				rval = EIO;
8767 			}
8768 			fcio->fcio_errno = ret;
8769 			if (fp_fcio_copyout(fcio, data, mode)) {
8770 				rval = EFAULT;
8771 			}
8772 		}
8773 		kmem_free(fcode_rev, fcio->fcio_olen);
8774 		break;
8775 	}
8776 
8777 	case FCIO_GET_FW_REV: {
8778 		caddr_t		fw_rev;
8779 		fc_fca_pm_t	pm;
8780 
8781 		if (fcio->fcio_olen < FC_FW_REV_SIZE ||
8782 		    fcio->fcio_xfer != FCIO_XFER_READ) {
8783 			rval = EINVAL;
8784 			break;
8785 		}
8786 		bzero((caddr_t)&pm, sizeof (pm));
8787 
8788 		fw_rev = kmem_zalloc(fcio->fcio_olen, KM_SLEEP);
8789 
8790 		pm.pm_cmd_flags = FC_FCA_PM_READ;
8791 		pm.pm_cmd_code = FC_PORT_GET_FW_REV;
8792 		pm.pm_data_len = fcio->fcio_olen;
8793 		pm.pm_data_buf = fw_rev;
8794 
8795 		ret = port->fp_fca_tran->fca_port_manage(
8796 		    port->fp_fca_handle, &pm);
8797 
8798 		if (ret == FC_SUCCESS) {
8799 			if (ddi_copyout((void *)fw_rev,
8800 			    (void *)fcio->fcio_obuf,
8801 			    fcio->fcio_olen, mode) == 0) {
8802 				if (fp_fcio_copyout(fcio, data, mode)) {
8803 					rval = EFAULT;
8804 				}
8805 			} else {
8806 				rval = EFAULT;
8807 			}
8808 		} else {
8809 			if (fp_fcio_copyout(fcio, data, mode)) {
8810 				rval = EFAULT;
8811 			}
8812 			rval = EIO;
8813 		}
8814 		kmem_free(fw_rev, fcio->fcio_olen);
8815 		break;
8816 	}
8817 
8818 	case FCIO_GET_DUMP_SIZE: {
8819 		uint32_t	dump_size;
8820 		fc_fca_pm_t	pm;
8821 
8822 		if (fcio->fcio_olen != sizeof (dump_size) ||
8823 		    fcio->fcio_xfer != FCIO_XFER_READ) {
8824 			rval = EINVAL;
8825 			break;
8826 		}
8827 		bzero((caddr_t)&pm, sizeof (pm));
8828 		pm.pm_cmd_flags = FC_FCA_PM_READ;
8829 		pm.pm_cmd_code = FC_PORT_GET_DUMP_SIZE;
8830 		pm.pm_data_len = sizeof (dump_size);
8831 		pm.pm_data_buf = (caddr_t)&dump_size;
8832 
8833 		ret = port->fp_fca_tran->fca_port_manage(
8834 		    port->fp_fca_handle, &pm);
8835 
8836 		if (ret == FC_SUCCESS) {
8837 			if (ddi_copyout((void *)&dump_size,
8838 			    (void *)fcio->fcio_obuf, sizeof (dump_size),
8839 			    mode) == 0) {
8840 				if (fp_fcio_copyout(fcio, data, mode)) {
8841 					rval = EFAULT;
8842 				}
8843 			} else {
8844 				rval = EFAULT;
8845 			}
8846 		} else {
8847 			fcio->fcio_errno = ret;
8848 			rval = EIO;
8849 			if (fp_fcio_copyout(fcio, data, mode)) {
8850 				rval = EFAULT;
8851 			}
8852 		}
8853 		break;
8854 	}
8855 
8856 	case FCIO_DOWNLOAD_FW: {
8857 		caddr_t		firmware;
8858 		fc_fca_pm_t	pm;
8859 
8860 		if (fcio->fcio_ilen <= 0 ||
8861 		    fcio->fcio_xfer != FCIO_XFER_WRITE) {
8862 			rval = EINVAL;
8863 			break;
8864 		}
8865 
8866 		firmware = kmem_zalloc(fcio->fcio_ilen, KM_SLEEP);
8867 		if (ddi_copyin(fcio->fcio_ibuf, firmware,
8868 		    fcio->fcio_ilen, mode)) {
8869 			rval = EFAULT;
8870 			kmem_free(firmware, fcio->fcio_ilen);
8871 			break;
8872 		}
8873 
8874 		bzero((caddr_t)&pm, sizeof (pm));
8875 		pm.pm_cmd_flags = FC_FCA_PM_WRITE;
8876 		pm.pm_cmd_code = FC_PORT_DOWNLOAD_FW;
8877 		pm.pm_data_len = fcio->fcio_ilen;
8878 		pm.pm_data_buf = firmware;
8879 
8880 		ret = port->fp_fca_tran->fca_port_manage(
8881 		    port->fp_fca_handle, &pm);
8882 
8883 		kmem_free(firmware, fcio->fcio_ilen);
8884 
8885 		if (ret != FC_SUCCESS) {
8886 			fcio->fcio_errno = ret;
8887 			rval = EIO;
8888 			if (fp_fcio_copyout(fcio, data, mode)) {
8889 				rval = EFAULT;
8890 			}
8891 		}
8892 		break;
8893 	}
8894 
8895 	case FCIO_DOWNLOAD_FCODE: {
8896 		caddr_t		fcode;
8897 		fc_fca_pm_t	pm;
8898 
8899 		if (fcio->fcio_ilen <= 0 ||
8900 		    fcio->fcio_xfer != FCIO_XFER_WRITE) {
8901 			rval = EINVAL;
8902 			break;
8903 		}
8904 
8905 		fcode = kmem_zalloc(fcio->fcio_ilen, KM_SLEEP);
8906 		if (ddi_copyin(fcio->fcio_ibuf, fcode,
8907 		    fcio->fcio_ilen, mode)) {
8908 			rval = EFAULT;
8909 			kmem_free(fcode, fcio->fcio_ilen);
8910 			break;
8911 		}
8912 
8913 		bzero((caddr_t)&pm, sizeof (pm));
8914 		pm.pm_cmd_flags = FC_FCA_PM_WRITE;
8915 		pm.pm_cmd_code = FC_PORT_DOWNLOAD_FCODE;
8916 		pm.pm_data_len = fcio->fcio_ilen;
8917 		pm.pm_data_buf = fcode;
8918 
8919 		ret = port->fp_fca_tran->fca_port_manage(
8920 		    port->fp_fca_handle, &pm);
8921 
8922 		kmem_free(fcode, fcio->fcio_ilen);
8923 
8924 		if (ret != FC_SUCCESS) {
8925 			fcio->fcio_errno = ret;
8926 			rval = EIO;
8927 			if (fp_fcio_copyout(fcio, data, mode)) {
8928 				rval = EFAULT;
8929 			}
8930 		}
8931 		break;
8932 	}
8933 
8934 	case FCIO_FORCE_DUMP:
8935 		ret = port->fp_fca_tran->fca_reset(
8936 		    port->fp_fca_handle, FC_FCA_CORE);
8937 
8938 		if (ret != FC_SUCCESS) {
8939 			fcio->fcio_errno = ret;
8940 			rval = EIO;
8941 			if (fp_fcio_copyout(fcio, data, mode)) {
8942 				rval = EFAULT;
8943 			}
8944 		}
8945 		break;
8946 
8947 	case FCIO_GET_DUMP: {
8948 		caddr_t		dump;
8949 		uint32_t	dump_size;
8950 		fc_fca_pm_t	pm;
8951 
8952 		if (fcio->fcio_xfer != FCIO_XFER_READ) {
8953 			rval = EINVAL;
8954 			break;
8955 		}
8956 		bzero((caddr_t)&pm, sizeof (pm));
8957 
8958 		pm.pm_cmd_flags = FC_FCA_PM_READ;
8959 		pm.pm_cmd_code = FC_PORT_GET_DUMP_SIZE;
8960 		pm.pm_data_len = sizeof (dump_size);
8961 		pm.pm_data_buf = (caddr_t)&dump_size;
8962 
8963 		ret = port->fp_fca_tran->fca_port_manage(
8964 		    port->fp_fca_handle, &pm);
8965 
8966 		if (ret != FC_SUCCESS) {
8967 			fcio->fcio_errno = ret;
8968 			rval = EIO;
8969 			if (fp_fcio_copyout(fcio, data, mode)) {
8970 				rval = EFAULT;
8971 			}
8972 			break;
8973 		}
8974 		if (fcio->fcio_olen != dump_size) {
8975 			fcio->fcio_errno = FC_NOMEM;
8976 			rval = EINVAL;
8977 			if (fp_fcio_copyout(fcio, data, mode)) {
8978 				rval = EFAULT;
8979 			}
8980 			break;
8981 		}
8982 
8983 		dump = kmem_zalloc(dump_size, KM_SLEEP);
8984 
8985 		bzero((caddr_t)&pm, sizeof (pm));
8986 		pm.pm_cmd_flags = FC_FCA_PM_READ;
8987 		pm.pm_cmd_code = FC_PORT_GET_DUMP;
8988 		pm.pm_data_len = dump_size;
8989 		pm.pm_data_buf = dump;
8990 
8991 		ret = port->fp_fca_tran->fca_port_manage(
8992 		    port->fp_fca_handle, &pm);
8993 
8994 		if (ret == FC_SUCCESS) {
8995 			if (ddi_copyout((void *)dump, (void *)fcio->fcio_obuf,
8996 			    dump_size, mode) == 0) {
8997 				if (fp_fcio_copyout(fcio, data, mode)) {
8998 					rval = EFAULT;
8999 				}
9000 			} else {
9001 				rval = EFAULT;
9002 			}
9003 		} else {
9004 			fcio->fcio_errno = ret;
9005 			rval = EIO;
9006 			if (fp_fcio_copyout(fcio, data, mode)) {
9007 				rval = EFAULT;
9008 			}
9009 		}
9010 		kmem_free(dump, dump_size);
9011 		break;
9012 	}
9013 
9014 	case FCIO_GET_TOPOLOGY: {
9015 		uint32_t user_topology;
9016 
9017 		if (fcio->fcio_xfer != FCIO_XFER_READ ||
9018 		    fcio->fcio_olen != sizeof (user_topology)) {
9019 			rval = EINVAL;
9020 			break;
9021 		}
9022 
9023 		mutex_enter(&port->fp_mutex);
9024 		if (FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) {
9025 			user_topology = FC_TOP_UNKNOWN;
9026 		} else {
9027 			user_topology = port->fp_topology;
9028 		}
9029 		mutex_exit(&port->fp_mutex);
9030 
9031 		if (ddi_copyout((void *)&user_topology,
9032 		    (void *)fcio->fcio_obuf, sizeof (user_topology),
9033 		    mode)) {
9034 			rval = EFAULT;
9035 		}
9036 		break;
9037 	}
9038 
9039 	case FCIO_RESET_LINK: {
9040 		la_wwn_t pwwn;
9041 
9042 		/*
9043 		 * Look at the output buffer field; if this field has zero
9044 		 * bytes then attempt to reset the local link/loop. If the
9045 		 * fcio_ibuf field points to a WWN, see if it's an NL_Port,
9046 		 * and if yes, determine the LFA and reset the remote LIP
9047 		 * by LINIT ELS.
9048 		 */
9049 
9050 		if (fcio->fcio_xfer != FCIO_XFER_WRITE ||
9051 		    fcio->fcio_ilen != sizeof (pwwn)) {
9052 			rval = EINVAL;
9053 			break;
9054 		}
9055 
9056 		if (ddi_copyin(fcio->fcio_ibuf, &pwwn,
9057 		    sizeof (pwwn), mode)) {
9058 			rval = EFAULT;
9059 			break;
9060 		}
9061 
9062 		mutex_enter(&port->fp_mutex);
9063 		if (port->fp_soft_state & FP_SOFT_IN_LINK_RESET) {
9064 			mutex_exit(&port->fp_mutex);
9065 			break;
9066 		}
9067 		port->fp_soft_state |= FP_SOFT_IN_LINK_RESET;
9068 		mutex_exit(&port->fp_mutex);
9069 
9070 		job = fctl_alloc_job(JOB_LINK_RESET, 0, NULL, NULL, KM_SLEEP);
9071 		if (job == NULL) {
9072 			rval = ENOMEM;
9073 			break;
9074 		}
9075 		job->job_counter = 1;
9076 		job->job_private = (void *)&pwwn;
9077 
9078 		fctl_enque_job(port, job);
9079 		fctl_jobwait(job);
9080 
9081 		mutex_enter(&port->fp_mutex);
9082 		port->fp_soft_state &= ~FP_SOFT_IN_LINK_RESET;
9083 		mutex_exit(&port->fp_mutex);
9084 
9085 		if (job->job_result != FC_SUCCESS) {
9086 			fcio->fcio_errno = job->job_result;
9087 			rval = EIO;
9088 			if (fp_fcio_copyout(fcio, data, mode)) {
9089 				rval = EFAULT;
9090 			}
9091 		}
9092 		fctl_dealloc_job(job);
9093 		break;
9094 	}
9095 
9096 	case FCIO_RESET_HARD:
9097 		ret = port->fp_fca_tran->fca_reset(
9098 		    port->fp_fca_handle, FC_FCA_RESET);
9099 		if (ret != FC_SUCCESS) {
9100 			fcio->fcio_errno = ret;
9101 			rval = EIO;
9102 			if (fp_fcio_copyout(fcio, data, mode)) {
9103 				rval = EFAULT;
9104 			}
9105 		}
9106 		break;
9107 
9108 	case FCIO_RESET_HARD_CORE:
9109 		ret = port->fp_fca_tran->fca_reset(
9110 		    port->fp_fca_handle, FC_FCA_RESET_CORE);
9111 		if (ret != FC_SUCCESS) {
9112 			rval = EIO;
9113 			fcio->fcio_errno = ret;
9114 			if (fp_fcio_copyout(fcio, data, mode)) {
9115 				rval = EFAULT;
9116 			}
9117 		}
9118 		break;
9119 
9120 	case FCIO_DIAG: {
9121 		fc_fca_pm_t pm;
9122 
9123 		bzero((caddr_t)&pm, sizeof (fc_fca_pm_t));
9124 
9125 		/* Validate user buffer from ioctl call. */
9126 		if (((fcio->fcio_ilen > 0) && (fcio->fcio_ibuf == NULL)) ||
9127 		    ((fcio->fcio_ilen <= 0) && (fcio->fcio_ibuf != NULL)) ||
9128 		    ((fcio->fcio_alen > 0) && (fcio->fcio_abuf == NULL)) ||
9129 		    ((fcio->fcio_alen <= 0) && (fcio->fcio_abuf != NULL)) ||
9130 		    ((fcio->fcio_olen > 0) && (fcio->fcio_obuf == NULL)) ||
9131 		    ((fcio->fcio_olen <= 0) && (fcio->fcio_obuf != NULL))) {
9132 			rval = EFAULT;
9133 			break;
9134 		}
9135 
9136 		if ((pm.pm_cmd_len = fcio->fcio_ilen) > 0) {
9137 			pm.pm_cmd_buf = kmem_zalloc(fcio->fcio_ilen, KM_SLEEP);
9138 			if (ddi_copyin(fcio->fcio_ibuf, pm.pm_cmd_buf,
9139 			    fcio->fcio_ilen, mode)) {
9140 				rval = EFAULT;
9141 				goto fp_fcio_diag_cleanup;
9142 			}
9143 		}
9144 
9145 		if ((pm.pm_data_len = fcio->fcio_alen) > 0) {
9146 			pm.pm_data_buf = kmem_zalloc(fcio->fcio_alen, KM_SLEEP);
9147 			if (ddi_copyin(fcio->fcio_abuf, pm.pm_data_buf,
9148 			    fcio->fcio_alen, mode)) {
9149 				rval = EFAULT;
9150 				goto fp_fcio_diag_cleanup;
9151 			}
9152 		}
9153 
9154 		if ((pm.pm_stat_len = fcio->fcio_olen) > 0) {
9155 			pm.pm_stat_buf = kmem_zalloc(fcio->fcio_olen, KM_SLEEP);
9156 		}
9157 
9158 		pm.pm_cmd_code = FC_PORT_DIAG;
9159 		pm.pm_cmd_flags = fcio->fcio_cmd_flags;
9160 
9161 		ret = port->fp_fca_tran->fca_port_manage(
9162 		    port->fp_fca_handle, &pm);
9163 
9164 		if (ret != FC_SUCCESS) {
9165 			if (ret == FC_INVALID_REQUEST) {
9166 				rval = ENOTTY;
9167 			} else {
9168 				rval = EIO;
9169 			}
9170 
9171 			fcio->fcio_errno = ret;
9172 			if (fp_fcio_copyout(fcio, data, mode)) {
9173 				rval = EFAULT;
9174 			}
9175 			goto fp_fcio_diag_cleanup;
9176 		}
9177 
9178 		/*
9179 		 * pm_stat_len will contain the number of status bytes
9180 		 * an FCA driver requires to return the complete status
9181 		 * of the requested diag operation. If the user buffer
9182 		 * is not large enough to hold the entire status, We
9183 		 * copy only the portion of data the fits in the buffer and
9184 		 * return a ENOMEM to the user application.
9185 		 */
9186 		if (pm.pm_stat_len > fcio->fcio_olen) {
9187 			fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
9188 			    "fp:FCIO_DIAG:status buffer too small\n");
9189 
9190 			rval = ENOMEM;
9191 			if (ddi_copyout(pm.pm_stat_buf, fcio->fcio_obuf,
9192 			    fcio->fcio_olen, mode)) {
9193 				rval = EFAULT;
9194 				goto fp_fcio_diag_cleanup;
9195 			}
9196 		} else {
9197 			/*
9198 			 * Copy only data pm_stat_len bytes of data
9199 			 */
9200 			if (ddi_copyout(pm.pm_stat_buf, fcio->fcio_obuf,
9201 			    pm.pm_stat_len, mode)) {
9202 				rval = EFAULT;
9203 				goto fp_fcio_diag_cleanup;
9204 			}
9205 		}
9206 
9207 		if (fp_fcio_copyout(fcio, data, mode)) {
9208 			rval = EFAULT;
9209 		}
9210 
9211 		fp_fcio_diag_cleanup:
9212 		if (pm.pm_cmd_buf != NULL) {
9213 			kmem_free(pm.pm_cmd_buf, fcio->fcio_ilen);
9214 		}
9215 		if (pm.pm_data_buf != NULL) {
9216 			kmem_free(pm.pm_data_buf, fcio->fcio_alen);
9217 		}
9218 		if (pm.pm_stat_buf != NULL) {
9219 			kmem_free(pm.pm_stat_buf, fcio->fcio_olen);
9220 		}
9221 
9222 		break;
9223 	}
9224 
9225 	case FCIO_GET_NODE_ID: {
9226 		/* validate parameters */
9227 		if (fcio->fcio_xfer != FCIO_XFER_READ ||
9228 		    fcio->fcio_olen < sizeof (fc_rnid_t)) {
9229 			rval = EINVAL;
9230 			break;
9231 		}
9232 
9233 		rval = fp_get_rnid(port, data, mode, fcio);
9234 
9235 		/* ioctl handling is over */
9236 		break;
9237 	}
9238 
9239 	case FCIO_SEND_NODE_ID: {
9240 		la_wwn_t		pwwn;
9241 
9242 		/* validate parameters */
9243 		if (fcio->fcio_ilen != sizeof (la_wwn_t) ||
9244 		    fcio->fcio_xfer != FCIO_XFER_READ) {
9245 			rval = EINVAL;
9246 			break;
9247 		}
9248 
9249 		if (ddi_copyin(fcio->fcio_ibuf, &pwwn,
9250 		    sizeof (la_wwn_t), mode)) {
9251 			rval = EFAULT;
9252 			break;
9253 		}
9254 
9255 		rval = fp_send_rnid(port, data, mode, fcio, &pwwn);
9256 
9257 		/* ioctl handling is over */
9258 		break;
9259 	}
9260 
9261 	case FCIO_SET_NODE_ID: {
9262 		if (fcio->fcio_ilen != sizeof (fc_rnid_t) ||
9263 		    (fcio->fcio_xfer != FCIO_XFER_WRITE)) {
9264 			rval = EINVAL;
9265 			break;
9266 		}
9267 
9268 		rval = fp_set_rnid(port, data, mode, fcio);
9269 		break;
9270 	}
9271 
9272 	case FCIO_LINK_STATUS: {
9273 		fc_portid_t		rls_req;
9274 		fc_rls_acc_t		*rls_acc;
9275 		fc_fca_pm_t		pm;
9276 		uint32_t		dest, src_id;
9277 		fp_cmd_t		*cmd;
9278 		fc_remote_port_t	*pd;
9279 		uchar_t			pd_flags;
9280 
9281 		/* validate parameters */
9282 		if (fcio->fcio_ilen != sizeof (fc_portid_t) ||
9283 		    fcio->fcio_olen != sizeof (fc_rls_acc_t) ||
9284 		    fcio->fcio_xfer != FCIO_XFER_RW) {
9285 			rval = EINVAL;
9286 			break;
9287 		}
9288 
9289 		if ((fcio->fcio_cmd_flags != FCIO_CFLAGS_RLS_DEST_FPORT) &&
9290 		    (fcio->fcio_cmd_flags != FCIO_CFLAGS_RLS_DEST_NPORT)) {
9291 			rval = EINVAL;
9292 			break;
9293 		}
9294 
9295 		if (ddi_copyin((void *)fcio->fcio_ibuf, (void *)&rls_req,
9296 		    sizeof (fc_portid_t), mode)) {
9297 			rval = EFAULT;
9298 			break;
9299 		}
9300 
9301 
9302 		/* Determine the destination of the RLS frame */
9303 		if (fcio->fcio_cmd_flags == FCIO_CFLAGS_RLS_DEST_FPORT) {
9304 			dest = FS_FABRIC_F_PORT;
9305 		} else {
9306 			dest = rls_req.port_id;
9307 		}
9308 
9309 		mutex_enter(&port->fp_mutex);
9310 		src_id = port->fp_port_id.port_id;
9311 		mutex_exit(&port->fp_mutex);
9312 
9313 		/* If dest is zero OR same as FCA ID, then use port_manage() */
9314 		if (dest == 0 || dest == src_id) {
9315 
9316 			/* Allocate memory for link error status block */
9317 			rls_acc = kmem_zalloc(sizeof (*rls_acc), KM_SLEEP);
9318 			ASSERT(rls_acc != NULL);
9319 
9320 			/* Prepare the port management structure */
9321 			bzero((caddr_t)&pm, sizeof (pm));
9322 
9323 			pm.pm_cmd_flags = FC_FCA_PM_READ;
9324 			pm.pm_cmd_code	= FC_PORT_RLS;
9325 			pm.pm_data_len	= sizeof (*rls_acc);
9326 			pm.pm_data_buf	= (caddr_t)rls_acc;
9327 
9328 			/* Get the adapter's link error status block */
9329 			ret = port->fp_fca_tran->fca_port_manage(
9330 			    port->fp_fca_handle, &pm);
9331 
9332 			if (ret == FC_SUCCESS) {
9333 				/* xfer link status block to userland */
9334 				if (ddi_copyout((void *)rls_acc,
9335 				    (void *)fcio->fcio_obuf,
9336 				    sizeof (*rls_acc), mode) == 0) {
9337 					if (fp_fcio_copyout(fcio, data,
9338 					    mode)) {
9339 						rval = EFAULT;
9340 					}
9341 				} else {
9342 					rval = EFAULT;
9343 				}
9344 			} else {
9345 				rval = EIO;
9346 				fcio->fcio_errno = ret;
9347 				if (fp_fcio_copyout(fcio, data, mode)) {
9348 					rval = EFAULT;
9349 				}
9350 			}
9351 
9352 			kmem_free(rls_acc, sizeof (*rls_acc));
9353 
9354 			/* ioctl handling is over */
9355 			break;
9356 		}
9357 
9358 		/*
9359 		 * Send RLS to the destination port.
9360 		 * Having RLS frame destination is as FPORT is not yet
9361 		 * supported and will be implemented in future, if needed.
9362 		 * Following call to get "pd" will fail if dest is FPORT
9363 		 */
9364 		pd = fctl_hold_remote_port_by_did(port, dest);
9365 		if (pd == NULL) {
9366 			fcio->fcio_errno = FC_BADOBJECT;
9367 			rval = ENXIO;
9368 			if (fp_fcio_copyout(fcio, data, mode)) {
9369 				rval = EFAULT;
9370 			}
9371 			break;
9372 		}
9373 
9374 		mutex_enter(&pd->pd_mutex);
9375 		if (pd->pd_state != PORT_DEVICE_LOGGED_IN) {
9376 			mutex_exit(&pd->pd_mutex);
9377 			fctl_release_remote_port(pd);
9378 
9379 			fcio->fcio_errno = FC_LOGINREQ;
9380 			rval = EINVAL;
9381 			if (fp_fcio_copyout(fcio, data, mode)) {
9382 				rval = EFAULT;
9383 			}
9384 			break;
9385 		}
9386 		ASSERT(pd->pd_login_count >= 1);
9387 		mutex_exit(&pd->pd_mutex);
9388 
9389 		/*
9390 		 * Allocate job structure and set job_code as DUMMY,
9391 		 * because we will not go through the job thread.
9392 		 * Instead fp_sendcmd() is called directly here.
9393 		 */
9394 		job = fctl_alloc_job(JOB_DUMMY, JOB_TYPE_FP_ASYNC,
9395 		    NULL, NULL, KM_SLEEP);
9396 		ASSERT(job != NULL);
9397 
9398 		job->job_counter = 1;
9399 
9400 		cmd = fp_alloc_pkt(port, sizeof (la_els_rls_t),
9401 		    sizeof (la_els_rls_acc_t), KM_SLEEP, pd);
9402 		if (cmd == NULL) {
9403 			fcio->fcio_errno = FC_NOMEM;
9404 			rval = ENOMEM;
9405 
9406 			fctl_release_remote_port(pd);
9407 
9408 			fctl_dealloc_job(job);
9409 			if (fp_fcio_copyout(fcio, data, mode)) {
9410 				rval = EFAULT;
9411 			}
9412 			break;
9413 		}
9414 
9415 		/* Allocate memory for link error status block */
9416 		rls_acc = kmem_zalloc(sizeof (*rls_acc), KM_SLEEP);
9417 
9418 		mutex_enter(&port->fp_mutex);
9419 		mutex_enter(&pd->pd_mutex);
9420 
9421 		cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
9422 		cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
9423 		cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
9424 		cmd->cmd_retry_count = 1;
9425 		cmd->cmd_ulp_pkt = NULL;
9426 
9427 		fp_rls_init(cmd, job);
9428 
9429 		job->job_private = (void *)rls_acc;
9430 
9431 		pd_flags = pd->pd_flags;
9432 		pd->pd_flags = PD_ELS_IN_PROGRESS;
9433 
9434 		mutex_exit(&pd->pd_mutex);
9435 		mutex_exit(&port->fp_mutex);
9436 
9437 		if (fp_sendcmd(port, cmd, port->fp_fca_handle) == FC_SUCCESS) {
9438 			fctl_jobwait(job);
9439 
9440 			fcio->fcio_errno = job->job_result;
9441 			if (job->job_result == FC_SUCCESS) {
9442 				ASSERT(pd != NULL);
9443 				/*
9444 				 * link error status block is now available.
9445 				 * Copy it to userland
9446 				 */
9447 				ASSERT(job->job_private == (void *)rls_acc);
9448 				if (ddi_copyout((void *)rls_acc,
9449 				    (void *)fcio->fcio_obuf,
9450 				    sizeof (*rls_acc), mode) == 0) {
9451 					if (fp_fcio_copyout(fcio, data,
9452 					    mode)) {
9453 						rval = EFAULT;
9454 					}
9455 				} else {
9456 					rval = EFAULT;
9457 				}
9458 			} else {
9459 				rval = EIO;
9460 			}
9461 		} else {
9462 			rval = EIO;
9463 			fp_free_pkt(cmd);
9464 		}
9465 
9466 		if (rval) {
9467 			mutex_enter(&port->fp_mutex);
9468 			mutex_enter(&pd->pd_mutex);
9469 			if (pd->pd_flags == PD_ELS_IN_PROGRESS) {
9470 				pd->pd_flags = pd_flags;
9471 			}
9472 			mutex_exit(&pd->pd_mutex);
9473 			mutex_exit(&port->fp_mutex);
9474 		}
9475 
9476 		fctl_release_remote_port(pd);
9477 		fctl_dealloc_job(job);
9478 		kmem_free(rls_acc, sizeof (*rls_acc));
9479 
9480 		if (fp_fcio_copyout(fcio, data, mode)) {
9481 			rval = EFAULT;
9482 		}
9483 		break;
9484 	}
9485 
9486 	case FCIO_NS: {
9487 		fc_ns_cmd_t	*ns_req;
9488 		fc_ns_cmd32_t	*ns_req32;
9489 		fctl_ns_req_t	*ns_cmd;
9490 
9491 		if (use32 == B_TRUE) {
9492 			if (fcio->fcio_ilen != sizeof (*ns_req32)) {
9493 				rval = EINVAL;
9494 				break;
9495 			}
9496 
9497 			ns_req = kmem_zalloc(sizeof (*ns_req), KM_SLEEP);
9498 			ns_req32 = kmem_zalloc(sizeof (*ns_req32), KM_SLEEP);
9499 
9500 			if (ddi_copyin(fcio->fcio_ibuf, ns_req32,
9501 			    sizeof (*ns_req32), mode)) {
9502 				rval = EFAULT;
9503 				kmem_free(ns_req, sizeof (*ns_req));
9504 				kmem_free(ns_req32, sizeof (*ns_req32));
9505 				break;
9506 			}
9507 
9508 			ns_req->ns_flags = ns_req32->ns_flags;
9509 			ns_req->ns_cmd = ns_req32->ns_cmd;
9510 			ns_req->ns_req_len = ns_req32->ns_req_len;
9511 			ns_req->ns_req_payload = ns_req32->ns_req_payload;
9512 			ns_req->ns_resp_len = ns_req32->ns_resp_len;
9513 			ns_req->ns_resp_payload = ns_req32->ns_resp_payload;
9514 			ns_req->ns_fctl_private = ns_req32->ns_fctl_private;
9515 			ns_req->ns_resp_hdr = ns_req32->ns_resp_hdr;
9516 
9517 			kmem_free(ns_req32, sizeof (*ns_req32));
9518 		} else {
9519 			if (fcio->fcio_ilen != sizeof (*ns_req)) {
9520 				rval = EINVAL;
9521 				break;
9522 			}
9523 
9524 			ns_req = kmem_zalloc(sizeof (*ns_req), KM_SLEEP);
9525 
9526 			if (ddi_copyin(fcio->fcio_ibuf, ns_req,
9527 			    sizeof (fc_ns_cmd_t), mode)) {
9528 				rval = EFAULT;
9529 				kmem_free(ns_req, sizeof (*ns_req));
9530 				break;
9531 			}
9532 		}
9533 
9534 		if (ns_req->ns_req_len <= 0) {
9535 			rval = EINVAL;
9536 			kmem_free(ns_req, sizeof (*ns_req));
9537 			break;
9538 		}
9539 
9540 		job = fctl_alloc_job(JOB_NS_CMD, 0, NULL, NULL, KM_SLEEP);
9541 		ASSERT(job != NULL);
9542 
9543 		ns_cmd = fctl_alloc_ns_cmd(ns_req->ns_req_len,
9544 		    ns_req->ns_resp_len, ns_req->ns_resp_len,
9545 		    FCTL_NS_FILL_NS_MAP, KM_SLEEP);
9546 		ASSERT(ns_cmd != NULL);
9547 		ns_cmd->ns_cmd_code = ns_req->ns_cmd;
9548 
9549 		if (ns_cmd->ns_cmd_code == NS_GA_NXT) {
9550 			ns_cmd->ns_gan_max = 1;
9551 			ns_cmd->ns_gan_index = 0;
9552 			ns_cmd->ns_gan_sid = FCTL_GAN_START_ID;
9553 		}
9554 
9555 		if (ddi_copyin(ns_req->ns_req_payload,
9556 		    ns_cmd->ns_cmd_buf, ns_req->ns_req_len, mode)) {
9557 			rval = EFAULT;
9558 			fctl_free_ns_cmd(ns_cmd);
9559 			fctl_dealloc_job(job);
9560 			kmem_free(ns_req, sizeof (*ns_req));
9561 			break;
9562 		}
9563 
9564 		job->job_private = (void *)ns_cmd;
9565 		fctl_enque_job(port, job);
9566 		fctl_jobwait(job);
9567 		rval = job->job_result;
9568 
9569 		if (rval == FC_SUCCESS) {
9570 			if (ns_req->ns_resp_len) {
9571 				if (ddi_copyout(ns_cmd->ns_data_buf,
9572 				    ns_req->ns_resp_payload,
9573 				    ns_cmd->ns_data_len, mode)) {
9574 					rval = EFAULT;
9575 					fctl_free_ns_cmd(ns_cmd);
9576 					fctl_dealloc_job(job);
9577 					kmem_free(ns_req, sizeof (*ns_req));
9578 					break;
9579 				}
9580 			}
9581 		} else {
9582 			rval = EIO;
9583 		}
9584 		ns_req->ns_resp_hdr = ns_cmd->ns_resp_hdr;
9585 		fctl_free_ns_cmd(ns_cmd);
9586 		fctl_dealloc_job(job);
9587 		kmem_free(ns_req, sizeof (*ns_req));
9588 
9589 		if (fp_fcio_copyout(fcio, data, mode)) {
9590 			rval = EFAULT;
9591 		}
9592 		break;
9593 	}
9594 
9595 	default:
9596 		rval = ENOTTY;
9597 		break;
9598 	}
9599 
9600 	/*
9601 	 * If set, reset the EXCL busy bit to
9602 	 * receive other exclusive access commands
9603 	 */
9604 	mutex_enter(&port->fp_mutex);
9605 	if (port->fp_flag & FP_EXCL_BUSY) {
9606 		port->fp_flag &= ~FP_EXCL_BUSY;
9607 	}
9608 	mutex_exit(&port->fp_mutex);
9609 
9610 	return (rval);
9611 }
9612 
9613 
9614 /*
9615  * This function assumes that the response length
9616  * is same regardless of data model (LP32 or LP64)
9617  * which is true for all the ioctls currently
9618  * supported.
9619  */
9620 static int
9621 fp_copyout(void *from, void *to, size_t len, int mode)
9622 {
9623 	return (ddi_copyout(from, to, len, mode));
9624 }
9625 
9626 /*
9627  * This function does the set rnid
9628  */
9629 static int
9630 fp_set_rnid(fc_local_port_t *port, intptr_t data, int mode, fcio_t *fcio)
9631 {
9632 	int		rval = 0;
9633 	fc_rnid_t	*rnid;
9634 	fc_fca_pm_t	pm;
9635 
9636 	/* Allocate memory for node id block */
9637 	rnid = kmem_zalloc(sizeof (fc_rnid_t), KM_SLEEP);
9638 
9639 	if (ddi_copyin(fcio->fcio_ibuf, rnid, sizeof (fc_rnid_t), mode)) {
9640 		FP_TRACE(FP_NHEAD1(3, 0), "fp_set_rnid: failed = %d", EFAULT);
9641 		kmem_free(rnid, sizeof (fc_rnid_t));
9642 		return (EFAULT);
9643 	}
9644 
9645 	/* Prepare the port management structure */
9646 	bzero((caddr_t)&pm, sizeof (pm));
9647 
9648 	pm.pm_cmd_flags = FC_FCA_PM_WRITE;
9649 	pm.pm_cmd_code	= FC_PORT_SET_NODE_ID;
9650 	pm.pm_data_len	= sizeof (*rnid);
9651 	pm.pm_data_buf	= (caddr_t)rnid;
9652 
9653 	/* Get the adapter's node data */
9654 	rval = port->fp_fca_tran->fca_port_manage(
9655 	    port->fp_fca_handle, &pm);
9656 
9657 	if (rval != FC_SUCCESS) {
9658 		fcio->fcio_errno = rval;
9659 		rval = EIO;
9660 		if (fp_fcio_copyout(fcio, data, mode)) {
9661 			rval = EFAULT;
9662 		}
9663 	} else {
9664 		mutex_enter(&port->fp_mutex);
9665 		/* copy to the port structure */
9666 		bcopy(rnid, &port->fp_rnid_params,
9667 		    sizeof (port->fp_rnid_params));
9668 		mutex_exit(&port->fp_mutex);
9669 	}
9670 
9671 	kmem_free(rnid, sizeof (fc_rnid_t));
9672 
9673 	if (rval != FC_SUCCESS) {
9674 		FP_TRACE(FP_NHEAD1(3, 0), "fp_set_rnid: failed = %d", rval);
9675 	}
9676 
9677 	return (rval);
9678 }
9679 
9680 /*
9681  * This function does the local pwwn get rnid
9682  */
9683 static int
9684 fp_get_rnid(fc_local_port_t *port, intptr_t data, int mode, fcio_t *fcio)
9685 {
9686 	fc_rnid_t		*rnid;
9687 	fc_fca_pm_t		pm;
9688 	int			rval = 0;
9689 	uint32_t		ret;
9690 
9691 	/* Allocate memory for rnid data block */
9692 	rnid = kmem_zalloc(sizeof (fc_rnid_t), KM_SLEEP);
9693 
9694 	mutex_enter(&port->fp_mutex);
9695 	if (port->fp_rnid_init == 1) {
9696 		bcopy(&port->fp_rnid_params, rnid, sizeof (fc_rnid_t));
9697 		mutex_exit(&port->fp_mutex);
9698 		/* xfer node info to userland */
9699 		if (ddi_copyout((void *)rnid, (void *)fcio->fcio_obuf,
9700 		    sizeof (*rnid), mode) == 0) {
9701 			if (fp_fcio_copyout(fcio, data, mode)) {
9702 				rval = EFAULT;
9703 			}
9704 		} else {
9705 			rval = EFAULT;
9706 		}
9707 
9708 		kmem_free(rnid, sizeof (fc_rnid_t));
9709 
9710 		if (rval != FC_SUCCESS) {
9711 			FP_TRACE(FP_NHEAD1(3, 0), "fp_get_rnid: failed = %d",
9712 			    rval);
9713 		}
9714 
9715 		return (rval);
9716 	}
9717 	mutex_exit(&port->fp_mutex);
9718 
9719 	/* Prepare the port management structure */
9720 	bzero((caddr_t)&pm, sizeof (pm));
9721 
9722 	pm.pm_cmd_flags = FC_FCA_PM_READ;
9723 	pm.pm_cmd_code	= FC_PORT_GET_NODE_ID;
9724 	pm.pm_data_len	= sizeof (fc_rnid_t);
9725 	pm.pm_data_buf	= (caddr_t)rnid;
9726 
9727 	/* Get the adapter's node data */
9728 	ret = port->fp_fca_tran->fca_port_manage(
9729 	    port->fp_fca_handle,
9730 	    &pm);
9731 
9732 	if (ret == FC_SUCCESS) {
9733 		/* initialize in the port_info */
9734 		mutex_enter(&port->fp_mutex);
9735 		port->fp_rnid_init = 1;
9736 		bcopy(rnid, &port->fp_rnid_params, sizeof (*rnid));
9737 		mutex_exit(&port->fp_mutex);
9738 
9739 		/* xfer node info to userland */
9740 		if (ddi_copyout((void *)rnid,
9741 		    (void *)fcio->fcio_obuf,
9742 		    sizeof (*rnid), mode) == 0) {
9743 			if (fp_fcio_copyout(fcio, data,
9744 			    mode)) {
9745 				rval = EFAULT;
9746 			}
9747 		} else {
9748 			rval = EFAULT;
9749 		}
9750 	} else {
9751 		rval = EIO;
9752 		fcio->fcio_errno = ret;
9753 		if (fp_fcio_copyout(fcio, data, mode)) {
9754 			rval = EFAULT;
9755 		}
9756 	}
9757 
9758 	kmem_free(rnid, sizeof (fc_rnid_t));
9759 
9760 	if (rval != FC_SUCCESS) {
9761 		FP_TRACE(FP_NHEAD1(3, 0), "fp_get_rnid: failed = %d", rval);
9762 	}
9763 
9764 	return (rval);
9765 }
9766 
9767 static int
9768 fp_send_rnid(fc_local_port_t *port, intptr_t data, int mode, fcio_t *fcio,
9769     la_wwn_t *pwwn)
9770 {
9771 	int			rval = 0;
9772 	fc_remote_port_t	*pd;
9773 	fp_cmd_t		*cmd;
9774 	job_request_t		*job;
9775 	la_els_rnid_acc_t	*rnid_acc;
9776 
9777 	pd = fctl_get_remote_port_by_pwwn(port, pwwn);
9778 	if (pd == NULL) {
9779 		/*
9780 		 * We can safely assume that the destination port
9781 		 * is logged in. Either the user land will explicitly
9782 		 * login before issuing RNID ioctl or the device would
9783 		 * have been configured, meaning already logged in.
9784 		 */
9785 
9786 		FP_TRACE(FP_NHEAD1(3, 0), "fp_send_rnid: failed = %d", ENXIO);
9787 
9788 		return (ENXIO);
9789 	}
9790 	/*
9791 	 * Allocate job structure and set job_code as DUMMY,
9792 	 * because we will not go thorugh the job thread.
9793 	 * Instead fp_sendcmd() is called directly here.
9794 	 */
9795 	job = fctl_alloc_job(JOB_DUMMY, JOB_TYPE_FP_ASYNC,
9796 	    NULL, NULL, KM_SLEEP);
9797 
9798 	ASSERT(job != NULL);
9799 
9800 	job->job_counter = 1;
9801 
9802 	cmd = fp_alloc_pkt(port, sizeof (la_els_rnid_t),
9803 	    sizeof (la_els_rnid_acc_t), KM_SLEEP, pd);
9804 	if (cmd == NULL) {
9805 		fcio->fcio_errno = FC_NOMEM;
9806 		rval = ENOMEM;
9807 
9808 		fctl_dealloc_job(job);
9809 		if (fp_fcio_copyout(fcio, data, mode)) {
9810 			rval = EFAULT;
9811 		}
9812 
9813 		FP_TRACE(FP_NHEAD1(3, 0), "fp_send_rnid: failed = %d", rval);
9814 
9815 		return (rval);
9816 	}
9817 
9818 	/* Allocate memory for node id accept block */
9819 	rnid_acc = kmem_zalloc(sizeof (la_els_rnid_acc_t), KM_SLEEP);
9820 
9821 	mutex_enter(&port->fp_mutex);
9822 	mutex_enter(&pd->pd_mutex);
9823 
9824 	cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
9825 	cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
9826 	cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
9827 	cmd->cmd_retry_count = 1;
9828 	cmd->cmd_ulp_pkt = NULL;
9829 
9830 	fp_rnid_init(cmd, fcio->fcio_cmd_flags, job);
9831 
9832 	job->job_private = (void *)rnid_acc;
9833 
9834 	pd->pd_flags = PD_ELS_IN_PROGRESS;
9835 
9836 	mutex_exit(&pd->pd_mutex);
9837 	mutex_exit(&port->fp_mutex);
9838 
9839 	if (fp_sendcmd(port, cmd, port->fp_fca_handle) == FC_SUCCESS) {
9840 		fctl_jobwait(job);
9841 		fcio->fcio_errno = job->job_result;
9842 		if (job->job_result == FC_SUCCESS) {
9843 			int rnid_cnt;
9844 			ASSERT(pd != NULL);
9845 			/*
9846 			 * node id block is now available.
9847 			 * Copy it to userland
9848 			 */
9849 			ASSERT(job->job_private == (void *)rnid_acc);
9850 
9851 			/* get the response length */
9852 			rnid_cnt = sizeof (ls_code_t) + sizeof (fc_rnid_hdr_t) +
9853 			    rnid_acc->hdr.cmn_len +
9854 			    rnid_acc->hdr.specific_len;
9855 
9856 			if (fcio->fcio_olen < rnid_cnt) {
9857 				rval = EINVAL;
9858 			} else if (ddi_copyout((void *)rnid_acc,
9859 			    (void *)fcio->fcio_obuf,
9860 			    rnid_cnt, mode) == 0) {
9861 				if (fp_fcio_copyout(fcio, data,
9862 				    mode)) {
9863 					rval = EFAULT;
9864 				}
9865 			} else {
9866 				rval = EFAULT;
9867 			}
9868 		} else {
9869 			rval = EIO;
9870 		}
9871 	} else {
9872 		rval = EIO;
9873 		if (pd) {
9874 			mutex_enter(&pd->pd_mutex);
9875 			pd->pd_flags = PD_IDLE;
9876 			mutex_exit(&pd->pd_mutex);
9877 		}
9878 		fp_free_pkt(cmd);
9879 	}
9880 
9881 	fctl_dealloc_job(job);
9882 	kmem_free(rnid_acc, sizeof (la_els_rnid_acc_t));
9883 
9884 	if (fp_fcio_copyout(fcio, data, mode)) {
9885 		rval = EFAULT;
9886 	}
9887 
9888 	if (rval != FC_SUCCESS) {
9889 		FP_TRACE(FP_NHEAD1(3, 0), "fp_send_rnid: failed = %d", rval);
9890 	}
9891 
9892 	return (rval);
9893 }
9894 
9895 /*
9896  * Copy out to userland
9897  */
9898 static int
9899 fp_fcio_copyout(fcio_t *fcio, intptr_t data, int mode)
9900 {
9901 	int rval;
9902 
9903 #ifdef	_MULTI_DATAMODEL
9904 	switch (ddi_model_convert_from(mode & FMODELS)) {
9905 	case DDI_MODEL_ILP32: {
9906 		struct fcio32 fcio32;
9907 
9908 		fcio32.fcio_xfer = fcio->fcio_xfer;
9909 		fcio32.fcio_cmd = fcio->fcio_cmd;
9910 		fcio32.fcio_flags = fcio->fcio_flags;
9911 		fcio32.fcio_cmd_flags = fcio->fcio_cmd_flags;
9912 		fcio32.fcio_ilen = fcio->fcio_ilen;
9913 		fcio32.fcio_ibuf =
9914 		    (caddr32_t)(uintptr_t)fcio->fcio_ibuf;
9915 		fcio32.fcio_olen = fcio->fcio_olen;
9916 		fcio32.fcio_obuf =
9917 		    (caddr32_t)(uintptr_t)fcio->fcio_obuf;
9918 		fcio32.fcio_alen = fcio->fcio_alen;
9919 		fcio32.fcio_abuf =
9920 		    (caddr32_t)(uintptr_t)fcio->fcio_abuf;
9921 		fcio32.fcio_errno = fcio->fcio_errno;
9922 
9923 		rval = ddi_copyout((void *)&fcio32, (void *)data,
9924 		    sizeof (struct fcio32), mode);
9925 		break;
9926 	}
9927 	case DDI_MODEL_NONE:
9928 		rval = ddi_copyout((void *)fcio, (void *)data,
9929 		    sizeof (fcio_t), mode);
9930 		break;
9931 	}
9932 #else
9933 	rval = ddi_copyout((void *)fcio, (void *)data, sizeof (fcio_t), mode);
9934 #endif
9935 
9936 	return (rval);
9937 }
9938 
9939 
9940 static void
9941 fp_p2p_online(fc_local_port_t *port, job_request_t *job)
9942 {
9943 	uint32_t		listlen;
9944 	fc_portmap_t		*changelist;
9945 
9946 	ASSERT(MUTEX_HELD(&port->fp_mutex));
9947 	ASSERT(port->fp_topology == FC_TOP_PT_PT);
9948 	ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
9949 
9950 	listlen = 0;
9951 	changelist = NULL;
9952 
9953 	if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) {
9954 		if (port->fp_statec_busy > 1) {
9955 			job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION;
9956 		}
9957 	}
9958 	mutex_exit(&port->fp_mutex);
9959 
9960 	if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) {
9961 		fctl_fillout_map(port, &changelist, &listlen, 1, 0, 0);
9962 		(void) fp_ulp_statec_cb(port, FC_STATE_ONLINE, changelist,
9963 		    listlen, listlen, KM_SLEEP);
9964 
9965 		mutex_enter(&port->fp_mutex);
9966 	} else {
9967 		ASSERT(changelist == NULL && listlen == 0);
9968 		mutex_enter(&port->fp_mutex);
9969 		if (--port->fp_statec_busy == 0) {
9970 			port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
9971 		}
9972 	}
9973 }
9974 
9975 static int
9976 fp_fillout_p2pmap(fc_local_port_t *port, fcio_t *fcio, int mode)
9977 {
9978 	int			rval;
9979 	int			count;
9980 	int			index;
9981 	int			num_devices;
9982 	fc_remote_node_t	*node;
9983 	fc_port_dev_t		*devlist;
9984 	struct pwwn_hash	*head;
9985 	fc_remote_port_t	*pd;
9986 
9987 	ASSERT(MUTEX_HELD(&port->fp_mutex));
9988 
9989 	num_devices = fcio->fcio_olen / sizeof (fc_port_dev_t);
9990 
9991 	devlist = kmem_zalloc(sizeof (fc_port_dev_t) * num_devices, KM_SLEEP);
9992 
9993 	for (count = index = 0; index < pwwn_table_size; index++) {
9994 		head = &port->fp_pwwn_table[index];
9995 		pd = head->pwwn_head;
9996 		while (pd != NULL) {
9997 			mutex_enter(&pd->pd_mutex);
9998 			if (pd->pd_state == PORT_DEVICE_INVALID) {
9999 				mutex_exit(&pd->pd_mutex);
10000 				pd = pd->pd_wwn_hnext;
10001 				continue;
10002 			}
10003 
10004 			devlist[count].dev_state = pd->pd_state;
10005 			devlist[count].dev_hard_addr = pd->pd_hard_addr;
10006 			devlist[count].dev_did = pd->pd_port_id;
10007 			devlist[count].dev_did.priv_lilp_posit =
10008 			    (uint8_t)(index & 0xff);
10009 			bcopy((caddr_t)pd->pd_fc4types,
10010 			    (caddr_t)devlist[count].dev_type,
10011 			    sizeof (pd->pd_fc4types));
10012 
10013 			bcopy((caddr_t)&pd->pd_port_name,
10014 			    (caddr_t)&devlist[count].dev_pwwn,
10015 			    sizeof (la_wwn_t));
10016 
10017 			node = pd->pd_remote_nodep;
10018 			mutex_exit(&pd->pd_mutex);
10019 
10020 			if (node) {
10021 				mutex_enter(&node->fd_mutex);
10022 				bcopy((caddr_t)&node->fd_node_name,
10023 				    (caddr_t)&devlist[count].dev_nwwn,
10024 				    sizeof (la_wwn_t));
10025 				mutex_exit(&node->fd_mutex);
10026 			}
10027 			count++;
10028 			if (count >= num_devices) {
10029 				goto found;
10030 			}
10031 		}
10032 	}
10033 found:
10034 	if (fp_copyout((void *)&count, (void *)fcio->fcio_abuf,
10035 	    sizeof (count), mode)) {
10036 		rval = FC_FAILURE;
10037 	} else if (fp_copyout((void *)devlist, (void *)fcio->fcio_obuf,
10038 	    sizeof (fc_port_dev_t) * num_devices, mode)) {
10039 		rval = FC_FAILURE;
10040 	} else {
10041 		rval = FC_SUCCESS;
10042 	}
10043 
10044 	kmem_free(devlist, sizeof (fc_port_dev_t) * num_devices);
10045 
10046 	return (rval);
10047 }
10048 
10049 
10050 /*
10051  * Handle Fabric ONLINE
10052  */
10053 static void
10054 fp_fabric_online(fc_local_port_t *port, job_request_t *job)
10055 {
10056 	int			index;
10057 	int			rval;
10058 	int			dbg_count;
10059 	int			count = 0;
10060 	char			ww_name[17];
10061 	uint32_t		d_id;
10062 	uint32_t		listlen;
10063 	fctl_ns_req_t		*ns_cmd;
10064 	struct pwwn_hash	*head;
10065 	fc_remote_port_t	*pd;
10066 	fc_remote_port_t	*npd;
10067 	fc_portmap_t		*changelist;
10068 
10069 	ASSERT(MUTEX_HELD(&port->fp_mutex));
10070 	ASSERT(FC_IS_TOP_SWITCH(port->fp_topology));
10071 	ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
10072 
10073 	ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t),
10074 	    sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t),
10075 	    0, KM_SLEEP);
10076 
10077 	ASSERT(ns_cmd != NULL);
10078 
10079 	ns_cmd->ns_cmd_code = NS_GID_PN;
10080 
10081 	/*
10082 	 * Check if orphans are showing up now
10083 	 */
10084 	if (port->fp_orphan_count) {
10085 		fc_orphan_t	*orp;
10086 		fc_orphan_t	*norp = NULL;
10087 		fc_orphan_t	*prev = NULL;
10088 
10089 		for (orp = port->fp_orphan_list; orp; orp = norp) {
10090 			norp = orp->orp_next;
10091 			mutex_exit(&port->fp_mutex);
10092 			orp->orp_nscan++;
10093 
10094 			job->job_counter = 1;
10095 			job->job_result = FC_SUCCESS;
10096 
10097 			((ns_req_gid_pn_t *)
10098 			    (ns_cmd->ns_cmd_buf))->pwwn = orp->orp_pwwn;
10099 			((ns_resp_gid_pn_t *)
10100 			    ns_cmd->ns_data_buf)->pid.port_id = 0;
10101 			((ns_resp_gid_pn_t *)
10102 			    ns_cmd->ns_data_buf)->pid.priv_lilp_posit = 0;
10103 
10104 			rval = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP);
10105 			if (rval == FC_SUCCESS) {
10106 				d_id =
10107 				    BE_32(*((uint32_t *)ns_cmd->ns_data_buf));
10108 				pd = fp_create_remote_port_by_ns(port,
10109 				    d_id, KM_SLEEP);
10110 
10111 				if (pd != NULL) {
10112 					fc_wwn_to_str(&orp->orp_pwwn, ww_name);
10113 
10114 					fp_printf(port, CE_WARN, FP_LOG_ONLY,
10115 					    0, NULL, "N_x Port with D_ID=%x,"
10116 					    " PWWN=%s reappeared in fabric",
10117 					    d_id, ww_name);
10118 
10119 					mutex_enter(&port->fp_mutex);
10120 					if (prev) {
10121 						prev->orp_next = orp->orp_next;
10122 					} else {
10123 						ASSERT(orp ==
10124 						    port->fp_orphan_list);
10125 						port->fp_orphan_list =
10126 						    orp->orp_next;
10127 					}
10128 					port->fp_orphan_count--;
10129 					mutex_exit(&port->fp_mutex);
10130 					kmem_free(orp, sizeof (*orp));
10131 					count++;
10132 
10133 					mutex_enter(&pd->pd_mutex);
10134 					pd->pd_flags = PD_ELS_MARK;
10135 
10136 					mutex_exit(&pd->pd_mutex);
10137 				} else {
10138 					prev = orp;
10139 				}
10140 			} else {
10141 				if (orp->orp_nscan == FC_ORPHAN_SCAN_LIMIT) {
10142 					fc_wwn_to_str(&orp->orp_pwwn, ww_name);
10143 
10144 					fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0,
10145 					    NULL,
10146 					    " Port WWN %s removed from orphan"
10147 					    " list after %d scans", ww_name,
10148 					    orp->orp_nscan);
10149 
10150 					mutex_enter(&port->fp_mutex);
10151 					if (prev) {
10152 						prev->orp_next = orp->orp_next;
10153 					} else {
10154 						ASSERT(orp ==
10155 						    port->fp_orphan_list);
10156 						port->fp_orphan_list =
10157 						    orp->orp_next;
10158 					}
10159 					port->fp_orphan_count--;
10160 					mutex_exit(&port->fp_mutex);
10161 
10162 					kmem_free(orp, sizeof (*orp));
10163 				} else {
10164 					prev = orp;
10165 				}
10166 			}
10167 			mutex_enter(&port->fp_mutex);
10168 		}
10169 	}
10170 
10171 	/*
10172 	 * Walk the Port WWN hash table, reestablish LOGIN
10173 	 * if a LOGIN is already performed on a particular
10174 	 * device; Any failure to LOGIN should mark the
10175 	 * port device OLD.
10176 	 */
10177 	for (index = 0; index < pwwn_table_size; index++) {
10178 		head = &port->fp_pwwn_table[index];
10179 		npd = head->pwwn_head;
10180 
10181 		while ((pd = npd) != NULL) {
10182 			la_wwn_t	*pwwn;
10183 
10184 			npd = pd->pd_wwn_hnext;
10185 
10186 			/*
10187 			 * Don't count in the port devices that are new
10188 			 * unless the total number of devices visible
10189 			 * through this port is less than FP_MAX_DEVICES
10190 			 */
10191 			mutex_enter(&pd->pd_mutex);
10192 			if (port->fp_dev_count >= FP_MAX_DEVICES ||
10193 			    (port->fp_options & FP_TARGET_MODE)) {
10194 				if (pd->pd_type == PORT_DEVICE_NEW ||
10195 				    pd->pd_flags == PD_ELS_MARK ||
10196 				    pd->pd_recepient != PD_PLOGI_INITIATOR) {
10197 					mutex_exit(&pd->pd_mutex);
10198 					continue;
10199 				}
10200 			} else {
10201 				if (pd->pd_flags == PD_ELS_MARK ||
10202 				    pd->pd_recepient != PD_PLOGI_INITIATOR) {
10203 					mutex_exit(&pd->pd_mutex);
10204 					continue;
10205 				}
10206 				pd->pd_type = PORT_DEVICE_OLD;
10207 			}
10208 			count++;
10209 
10210 			/*
10211 			 * Consult with the name server about D_ID changes
10212 			 */
10213 			job->job_counter = 1;
10214 			job->job_result = FC_SUCCESS;
10215 
10216 			((ns_req_gid_pn_t *)
10217 			    (ns_cmd->ns_cmd_buf))->pwwn = pd->pd_port_name;
10218 			((ns_resp_gid_pn_t *)
10219 			    ns_cmd->ns_data_buf)->pid.port_id = 0;
10220 
10221 			((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->
10222 			    pid.priv_lilp_posit = 0;
10223 
10224 			pwwn = &pd->pd_port_name;
10225 			pd->pd_flags = PD_ELS_MARK;
10226 
10227 			mutex_exit(&pd->pd_mutex);
10228 			mutex_exit(&port->fp_mutex);
10229 
10230 			rval = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP);
10231 			if (rval != FC_SUCCESS) {
10232 				fc_wwn_to_str(pwwn, ww_name);
10233 
10234 				mutex_enter(&pd->pd_mutex);
10235 				d_id = pd->pd_port_id.port_id;
10236 				pd->pd_type = PORT_DEVICE_DELETE;
10237 				mutex_exit(&pd->pd_mutex);
10238 
10239 				FP_TRACE(FP_NHEAD1(3, 0),
10240 				    "fp_fabric_online: PD "
10241 				    "disappeared; d_id=%x, PWWN=%s",
10242 				    d_id, ww_name);
10243 
10244 				FP_TRACE(FP_NHEAD2(9, 0),
10245 				    "N_x Port with D_ID=%x, PWWN=%s"
10246 				    " disappeared from fabric", d_id,
10247 				    ww_name);
10248 
10249 				mutex_enter(&port->fp_mutex);
10250 				continue;
10251 			}
10252 
10253 			d_id = BE_32(*((uint32_t *)ns_cmd->ns_data_buf));
10254 
10255 			mutex_enter(&port->fp_mutex);
10256 			mutex_enter(&pd->pd_mutex);
10257 			if (d_id != pd->pd_port_id.port_id) {
10258 				fctl_delist_did_table(port, pd);
10259 				fc_wwn_to_str(pwwn, ww_name);
10260 
10261 				FP_TRACE(FP_NHEAD2(9, 0),
10262 				    "D_ID of a device with PWWN %s changed."
10263 				    " New D_ID = %x, OLD D_ID = %x", ww_name,
10264 				    d_id, pd->pd_port_id.port_id);
10265 
10266 				pd->pd_port_id.port_id = BE_32(d_id);
10267 				pd->pd_type = PORT_DEVICE_CHANGED;
10268 				fctl_enlist_did_table(port, pd);
10269 			}
10270 			mutex_exit(&pd->pd_mutex);
10271 
10272 		}
10273 	}
10274 
10275 	if (ns_cmd) {
10276 		fctl_free_ns_cmd(ns_cmd);
10277 	}
10278 
10279 	listlen = 0;
10280 	changelist = NULL;
10281 	if (count) {
10282 		if (port->fp_soft_state & FP_SOFT_IN_FCA_RESET) {
10283 			port->fp_soft_state &= ~FP_SOFT_IN_FCA_RESET;
10284 			mutex_exit(&port->fp_mutex);
10285 			delay(drv_usectohz(FLA_RR_TOV * 1000 * 1000));
10286 			mutex_enter(&port->fp_mutex);
10287 		}
10288 
10289 		dbg_count = 0;
10290 
10291 		job->job_counter = count;
10292 
10293 		for (index = 0; index < pwwn_table_size; index++) {
10294 			head = &port->fp_pwwn_table[index];
10295 			npd = head->pwwn_head;
10296 
10297 			while ((pd = npd) != NULL) {
10298 				npd = pd->pd_wwn_hnext;
10299 
10300 				mutex_enter(&pd->pd_mutex);
10301 				if (pd->pd_flags != PD_ELS_MARK) {
10302 					mutex_exit(&pd->pd_mutex);
10303 					continue;
10304 				}
10305 
10306 				dbg_count++;
10307 
10308 				/*
10309 				 * If it is already marked deletion, nothing
10310 				 * else to do.
10311 				 */
10312 				if (pd->pd_type == PORT_DEVICE_DELETE) {
10313 					pd->pd_type = PORT_DEVICE_OLD;
10314 
10315 					mutex_exit(&pd->pd_mutex);
10316 					mutex_exit(&port->fp_mutex);
10317 					fp_jobdone(job);
10318 					mutex_enter(&port->fp_mutex);
10319 
10320 					continue;
10321 				}
10322 
10323 				/*
10324 				 * If it is freshly discovered out of
10325 				 * the orphan list, nothing else to do
10326 				 */
10327 				if (pd->pd_type == PORT_DEVICE_NEW) {
10328 					pd->pd_flags = PD_IDLE;
10329 
10330 					mutex_exit(&pd->pd_mutex);
10331 					mutex_exit(&port->fp_mutex);
10332 					fp_jobdone(job);
10333 					mutex_enter(&port->fp_mutex);
10334 
10335 					continue;
10336 				}
10337 
10338 				pd->pd_flags = PD_IDLE;
10339 				d_id = pd->pd_port_id.port_id;
10340 
10341 				/*
10342 				 * Explicitly mark all devices OLD; successful
10343 				 * PLOGI should reset this to either NO_CHANGE
10344 				 * or CHANGED.
10345 				 */
10346 				if (pd->pd_type != PORT_DEVICE_CHANGED) {
10347 					pd->pd_type = PORT_DEVICE_OLD;
10348 				}
10349 
10350 				mutex_exit(&pd->pd_mutex);
10351 				mutex_exit(&port->fp_mutex);
10352 
10353 				rval = fp_port_login(port, d_id, job,
10354 				    FP_CMD_PLOGI_RETAIN, KM_SLEEP, pd, NULL);
10355 
10356 				if (rval != FC_SUCCESS) {
10357 					fp_jobdone(job);
10358 				}
10359 				mutex_enter(&port->fp_mutex);
10360 			}
10361 		}
10362 		mutex_exit(&port->fp_mutex);
10363 
10364 		ASSERT(dbg_count == count);
10365 		fp_jobwait(job);
10366 
10367 		mutex_enter(&port->fp_mutex);
10368 
10369 		ASSERT(port->fp_statec_busy > 0);
10370 		if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) {
10371 			if (port->fp_statec_busy > 1) {
10372 				job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION;
10373 			}
10374 		}
10375 		mutex_exit(&port->fp_mutex);
10376 	} else {
10377 		ASSERT(port->fp_statec_busy > 0);
10378 		if (port->fp_statec_busy > 1) {
10379 			job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION;
10380 		}
10381 		mutex_exit(&port->fp_mutex);
10382 	}
10383 
10384 	if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) {
10385 		fctl_fillout_map(port, &changelist, &listlen, 1, 0, 0);
10386 
10387 		(void) fp_ulp_statec_cb(port, FC_STATE_ONLINE, changelist,
10388 		    listlen, listlen, KM_SLEEP);
10389 
10390 		mutex_enter(&port->fp_mutex);
10391 	} else {
10392 		ASSERT(changelist == NULL && listlen == 0);
10393 		mutex_enter(&port->fp_mutex);
10394 		if (--port->fp_statec_busy == 0) {
10395 			port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
10396 		}
10397 	}
10398 }
10399 
10400 
10401 /*
10402  * Fill out device list for userland ioctl in private loop
10403  */
10404 static int
10405 fp_fillout_loopmap(fc_local_port_t *port, fcio_t *fcio, int mode)
10406 {
10407 	int			rval;
10408 	int			count;
10409 	int			index;
10410 	int			num_devices;
10411 	fc_remote_node_t	*node;
10412 	fc_port_dev_t		*devlist;
10413 	int			lilp_device_count;
10414 	fc_lilpmap_t		*lilp_map;
10415 	uchar_t			*alpa_list;
10416 
10417 	ASSERT(MUTEX_HELD(&port->fp_mutex));
10418 
10419 	num_devices = fcio->fcio_olen / sizeof (fc_port_dev_t);
10420 	if (port->fp_total_devices > port->fp_dev_count &&
10421 	    num_devices >= port->fp_total_devices) {
10422 		job_request_t	*job;
10423 
10424 		mutex_exit(&port->fp_mutex);
10425 		job = fctl_alloc_job(JOB_PORT_GETMAP, 0, NULL, NULL, KM_SLEEP);
10426 		job->job_counter = 1;
10427 
10428 		mutex_enter(&port->fp_mutex);
10429 		fp_get_loopmap(port, job);
10430 		mutex_exit(&port->fp_mutex);
10431 
10432 		fp_jobwait(job);
10433 		fctl_dealloc_job(job);
10434 	} else {
10435 		mutex_exit(&port->fp_mutex);
10436 	}
10437 	devlist = kmem_zalloc(sizeof (*devlist) * num_devices, KM_SLEEP);
10438 
10439 	mutex_enter(&port->fp_mutex);
10440 
10441 	/*
10442 	 * Applications are accustomed to getting the device list in
10443 	 * LILP map order. The HBA firmware usually returns the device
10444 	 * map in the LILP map order and diagnostic applications would
10445 	 * prefer to receive in the device list in that order too
10446 	 */
10447 	lilp_map = &port->fp_lilp_map;
10448 	alpa_list = &lilp_map->lilp_alpalist[0];
10449 
10450 	/*
10451 	 * the length field corresponds to the offset in the LILP frame
10452 	 * which begins with 1. The thing to note here is that the
10453 	 * lilp_device_count is 1 more than fp->fp_total_devices since
10454 	 * the host adapter's alpa also shows up in the lilp map. We
10455 	 * don't however return details of the host adapter since
10456 	 * fctl_get_remote_port_by_did fails for the host adapter's ALPA
10457 	 * and applications are required to issue the FCIO_GET_HOST_PARAMS
10458 	 * ioctl to obtain details about the host adapter port.
10459 	 */
10460 	lilp_device_count = lilp_map->lilp_length;
10461 
10462 	for (count = index = 0; index < lilp_device_count &&
10463 	    count < num_devices; index++) {
10464 		uint32_t d_id;
10465 		fc_remote_port_t *pd;
10466 
10467 		d_id = alpa_list[index];
10468 
10469 		mutex_exit(&port->fp_mutex);
10470 		pd = fctl_get_remote_port_by_did(port, d_id);
10471 		mutex_enter(&port->fp_mutex);
10472 
10473 		if (pd != NULL) {
10474 			mutex_enter(&pd->pd_mutex);
10475 
10476 			if (pd->pd_state == PORT_DEVICE_INVALID) {
10477 				mutex_exit(&pd->pd_mutex);
10478 				continue;
10479 			}
10480 
10481 			devlist[count].dev_state = pd->pd_state;
10482 			devlist[count].dev_hard_addr = pd->pd_hard_addr;
10483 			devlist[count].dev_did = pd->pd_port_id;
10484 			devlist[count].dev_did.priv_lilp_posit =
10485 			    (uint8_t)(index & 0xff);
10486 			bcopy((caddr_t)pd->pd_fc4types,
10487 			    (caddr_t)devlist[count].dev_type,
10488 			    sizeof (pd->pd_fc4types));
10489 
10490 			bcopy((caddr_t)&pd->pd_port_name,
10491 			    (caddr_t)&devlist[count].dev_pwwn,
10492 			    sizeof (la_wwn_t));
10493 
10494 			node = pd->pd_remote_nodep;
10495 			mutex_exit(&pd->pd_mutex);
10496 
10497 			if (node) {
10498 				mutex_enter(&node->fd_mutex);
10499 				bcopy((caddr_t)&node->fd_node_name,
10500 				    (caddr_t)&devlist[count].dev_nwwn,
10501 				    sizeof (la_wwn_t));
10502 				mutex_exit(&node->fd_mutex);
10503 			}
10504 			count++;
10505 		}
10506 	}
10507 
10508 	if (fp_copyout((void *)&count, (void *)fcio->fcio_abuf,
10509 	    sizeof (count), mode)) {
10510 		rval = FC_FAILURE;
10511 	}
10512 
10513 	if (fp_copyout((void *)devlist, (void *)fcio->fcio_obuf,
10514 	    sizeof (fc_port_dev_t) * num_devices, mode)) {
10515 		rval = FC_FAILURE;
10516 	} else {
10517 		rval = FC_SUCCESS;
10518 	}
10519 
10520 	kmem_free(devlist, sizeof (*devlist) * num_devices);
10521 	ASSERT(MUTEX_HELD(&port->fp_mutex));
10522 
10523 	return (rval);
10524 }
10525 
10526 
10527 /*
10528  * Completion function for responses to unsolicited commands
10529  */
10530 static void
10531 fp_unsol_intr(fc_packet_t *pkt)
10532 {
10533 	fp_cmd_t	*cmd;
10534 	fc_local_port_t *port;
10535 
10536 	cmd = pkt->pkt_ulp_private;
10537 	port = cmd->cmd_port;
10538 
10539 	mutex_enter(&port->fp_mutex);
10540 	port->fp_out_fpcmds--;
10541 	mutex_exit(&port->fp_mutex);
10542 
10543 	if (pkt->pkt_state != FC_PKT_SUCCESS) {
10544 		fp_printf(port, CE_WARN, FP_LOG_ONLY, 0, pkt,
10545 		    "couldn't post response to unsolicited request;"
10546 		    " ox_id=%x rx_id=%x", pkt->pkt_cmd_fhdr.ox_id,
10547 		    pkt->pkt_resp_fhdr.rx_id);
10548 	}
10549 
10550 	if (cmd == port->fp_els_resp_pkt) {
10551 		mutex_enter(&port->fp_mutex);
10552 		port->fp_els_resp_pkt_busy = 0;
10553 		mutex_exit(&port->fp_mutex);
10554 		return;
10555 	}
10556 
10557 	fp_free_pkt(cmd);
10558 }
10559 
10560 
10561 /*
10562  * solicited LINIT ELS completion function
10563  */
10564 static void
10565 fp_linit_intr(fc_packet_t *pkt)
10566 {
10567 	fp_cmd_t		*cmd;
10568 	job_request_t		*job;
10569 	fc_linit_resp_t		acc;
10570 	fc_local_port_t *port = ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port;
10571 
10572 	cmd = (fp_cmd_t *)pkt->pkt_ulp_private;
10573 
10574 	mutex_enter(&cmd->cmd_port->fp_mutex);
10575 	cmd->cmd_port->fp_out_fpcmds--;
10576 	mutex_exit(&cmd->cmd_port->fp_mutex);
10577 
10578 	if (FP_IS_PKT_ERROR(pkt)) {
10579 		(void) fp_common_intr(pkt, 1);
10580 		return;
10581 	}
10582 
10583 	job = cmd->cmd_job;
10584 
10585 	FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&acc,
10586 	    (uint8_t *)pkt->pkt_resp, sizeof (acc), DDI_DEV_AUTOINCR);
10587 	if (acc.status != FC_LINIT_SUCCESS) {
10588 		job->job_result = FC_FAILURE;
10589 	} else {
10590 		job->job_result = FC_SUCCESS;
10591 	}
10592 
10593 	fp_iodone(cmd);
10594 }
10595 
10596 
10597 /*
10598  * Decode the unsolicited request; For FC-4 Device and Link data frames
10599  * notify the registered ULP of this FC-4 type right here. For Unsolicited
10600  * ELS requests, submit a request to the job_handler thread to work on it.
10601  * The intent is to act quickly on the FC-4 unsolicited link and data frames
10602  * and save much of the interrupt time processing of unsolicited ELS requests
10603  * and hand it off to the job_handler thread.
10604  */
10605 static void
10606 fp_unsol_cb(opaque_t port_handle, fc_unsol_buf_t *buf, uint32_t type)
10607 {
10608 	uchar_t		r_ctl;
10609 	uchar_t		ls_code;
10610 	uint32_t	s_id;
10611 	uint32_t	rscn_count = FC_INVALID_RSCN_COUNT;
10612 	uint32_t	cb_arg;
10613 	fp_cmd_t	*cmd;
10614 	fc_local_port_t *port;
10615 	job_request_t	*job;
10616 	fc_remote_port_t	*pd;
10617 
10618 	port = port_handle;
10619 
10620 	FP_TRACE(FP_NHEAD1(1, 0), "fp_unsol_cb: s_id=%x,"
10621 	    " d_id=%x, type=%x, r_ctl=%x, f_ctl=%x"
10622 	    " seq_id=%x, df_ctl=%x, seq_cnt=%x, ox_id=%x, rx_id=%x"
10623 	    " ro=%x, buffer[0]:%x", buf->ub_frame.s_id, buf->ub_frame.d_id,
10624 	    buf->ub_frame.type, buf->ub_frame.r_ctl, buf->ub_frame.f_ctl,
10625 	    buf->ub_frame.seq_id, buf->ub_frame.df_ctl, buf->ub_frame.seq_cnt,
10626 	    buf->ub_frame.ox_id, buf->ub_frame.rx_id, buf->ub_frame.ro,
10627 	    buf->ub_buffer[0]);
10628 
10629 	if (type & 0x80000000) {
10630 		/*
10631 		 * Huh ? Nothing much can be done without
10632 		 * a valid buffer. So just exit.
10633 		 */
10634 		return;
10635 	}
10636 	/*
10637 	 * If the unsolicited interrupts arrive while it isn't
10638 	 * safe to handle unsolicited callbacks; Drop them, yes,
10639 	 * drop them on the floor
10640 	 */
10641 	mutex_enter(&port->fp_mutex);
10642 	port->fp_active_ubs++;
10643 	if ((port->fp_soft_state &
10644 	    (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN)) ||
10645 	    FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) {
10646 
10647 		FP_TRACE(FP_NHEAD1(3, 0), "fp_unsol_cb: port state is "
10648 		    "not ONLINE. s_id=%x, d_id=%x, type=%x, "
10649 		    "seq_id=%x, ox_id=%x, rx_id=%x"
10650 		    "ro=%x", buf->ub_frame.s_id, buf->ub_frame.d_id,
10651 		    buf->ub_frame.type, buf->ub_frame.seq_id,
10652 		    buf->ub_frame.ox_id, buf->ub_frame.rx_id, buf->ub_frame.ro);
10653 
10654 		ASSERT(port->fp_active_ubs > 0);
10655 		if (--(port->fp_active_ubs) == 0) {
10656 			port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB;
10657 		}
10658 
10659 		mutex_exit(&port->fp_mutex);
10660 
10661 		port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
10662 		    1, &buf->ub_token);
10663 
10664 		return;
10665 	}
10666 
10667 	r_ctl = buf->ub_frame.r_ctl;
10668 	s_id = buf->ub_frame.s_id;
10669 	if (port->fp_active_ubs == 1) {
10670 		port->fp_soft_state |= FP_SOFT_IN_UNSOL_CB;
10671 	}
10672 
10673 	if (r_ctl == R_CTL_ELS_REQ && buf->ub_buffer[0] == LA_ELS_LOGO &&
10674 	    port->fp_statec_busy) {
10675 		mutex_exit(&port->fp_mutex);
10676 		pd = fctl_get_remote_port_by_did(port, s_id);
10677 		if (pd) {
10678 			mutex_enter(&pd->pd_mutex);
10679 			if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
10680 				FP_TRACE(FP_NHEAD1(3, 0),
10681 				    "LOGO for LOGGED IN D_ID %x",
10682 				    buf->ub_frame.s_id);
10683 				pd->pd_state = PORT_DEVICE_VALID;
10684 			}
10685 			mutex_exit(&pd->pd_mutex);
10686 		}
10687 
10688 		mutex_enter(&port->fp_mutex);
10689 		ASSERT(port->fp_active_ubs > 0);
10690 		if (--(port->fp_active_ubs) == 0) {
10691 			port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB;
10692 		}
10693 		mutex_exit(&port->fp_mutex);
10694 
10695 		port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
10696 		    1, &buf->ub_token);
10697 
10698 		FP_TRACE(FP_NHEAD1(3, 0),
10699 		    "fp_unsol_cb() bailing out LOGO for D_ID %x",
10700 		    buf->ub_frame.s_id);
10701 		return;
10702 	}
10703 
10704 	if (port->fp_els_resp_pkt_busy == 0) {
10705 		if (r_ctl == R_CTL_ELS_REQ) {
10706 			ls_code = buf->ub_buffer[0];
10707 
10708 			switch (ls_code) {
10709 			case LA_ELS_PLOGI:
10710 			case LA_ELS_FLOGI:
10711 				port->fp_els_resp_pkt_busy = 1;
10712 				mutex_exit(&port->fp_mutex);
10713 				fp_i_handle_unsol_els(port, buf);
10714 
10715 				mutex_enter(&port->fp_mutex);
10716 				ASSERT(port->fp_active_ubs > 0);
10717 				if (--(port->fp_active_ubs) == 0) {
10718 					port->fp_soft_state &=
10719 					    ~FP_SOFT_IN_UNSOL_CB;
10720 				}
10721 				mutex_exit(&port->fp_mutex);
10722 				port->fp_fca_tran->fca_ub_release(
10723 				    port->fp_fca_handle, 1, &buf->ub_token);
10724 
10725 				return;
10726 			case LA_ELS_RSCN:
10727 				if (++(port)->fp_rscn_count ==
10728 				    FC_INVALID_RSCN_COUNT) {
10729 					++(port)->fp_rscn_count;
10730 				}
10731 				rscn_count = port->fp_rscn_count;
10732 				break;
10733 
10734 			default:
10735 				break;
10736 			}
10737 		}
10738 	} else if ((r_ctl == R_CTL_ELS_REQ) &&
10739 	    (buf->ub_buffer[0] == LA_ELS_RSCN)) {
10740 		if (++port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
10741 			++port->fp_rscn_count;
10742 		}
10743 		rscn_count = port->fp_rscn_count;
10744 	}
10745 
10746 	mutex_exit(&port->fp_mutex);
10747 
10748 	switch (r_ctl & R_CTL_ROUTING) {
10749 	case R_CTL_DEVICE_DATA:
10750 		/*
10751 		 * If the unsolicited buffer is a CT IU,
10752 		 * have the job_handler thread work on it.
10753 		 */
10754 		if (buf->ub_frame.type == FC_TYPE_FC_SERVICES) {
10755 			break;
10756 		}
10757 		/* FALLTHROUGH */
10758 
10759 	case R_CTL_FC4_SVC: {
10760 		int sendup = 0;
10761 
10762 		/*
10763 		 * If a LOGIN isn't performed before this request
10764 		 * shut the door on this port with a reply that a
10765 		 * LOGIN is required. We make an exception however
10766 		 * for IP broadcast packets and pass them through
10767 		 * to the IP ULP(s) to handle broadcast requests.
10768 		 * This is not a problem for private loop devices
10769 		 * but for fabric topologies we don't log into the
10770 		 * remote ports during port initialization and
10771 		 * the ULPs need to log into requesting ports on
10772 		 * demand.
10773 		 */
10774 		pd = fctl_get_remote_port_by_did(port, s_id);
10775 		if (pd) {
10776 			mutex_enter(&pd->pd_mutex);
10777 			if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
10778 				sendup++;
10779 			}
10780 			mutex_exit(&pd->pd_mutex);
10781 		} else if ((pd == NULL) &&
10782 		    (buf->ub_frame.type == FC_TYPE_IS8802_SNAP) &&
10783 		    (buf->ub_frame.d_id == 0xffffff ||
10784 		    buf->ub_frame.d_id == 0x00)) {
10785 			/* brodacst IP frame - so sendup via job thread */
10786 			break;
10787 		}
10788 
10789 		/*
10790 		 * Send all FC4 services via job thread too
10791 		 */
10792 		if ((r_ctl & R_CTL_ROUTING) == R_CTL_FC4_SVC) {
10793 			break;
10794 		}
10795 
10796 		if (sendup || !FC_IS_REAL_DEVICE(s_id)) {
10797 			fctl_ulp_unsol_cb(port, buf, buf->ub_frame.type);
10798 			return;
10799 		}
10800 
10801 		if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
10802 			cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t),
10803 			    0, KM_NOSLEEP, pd);
10804 			if (cmd != NULL) {
10805 				fp_els_rjt_init(port, cmd, buf,
10806 				    FC_ACTION_NON_RETRYABLE,
10807 				    FC_REASON_LOGIN_REQUIRED, NULL);
10808 
10809 				if (fp_sendcmd(port, cmd,
10810 				    port->fp_fca_handle) != FC_SUCCESS) {
10811 					fp_free_pkt(cmd);
10812 				}
10813 			}
10814 		}
10815 
10816 		mutex_enter(&port->fp_mutex);
10817 		ASSERT(port->fp_active_ubs > 0);
10818 		if (--(port->fp_active_ubs) == 0) {
10819 			port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB;
10820 		}
10821 		mutex_exit(&port->fp_mutex);
10822 		port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
10823 		    1, &buf->ub_token);
10824 
10825 		return;
10826 	}
10827 
10828 	default:
10829 		break;
10830 	}
10831 
10832 	/*
10833 	 * Submit a Request to the job_handler thread to work
10834 	 * on the unsolicited request. The potential side effect
10835 	 * of this is that the unsolicited buffer takes a little
10836 	 * longer to get released but we save interrupt time in
10837 	 * the bargain.
10838 	 */
10839 	cb_arg = (rscn_count == FC_INVALID_RSCN_COUNT) ? NULL : rscn_count;
10840 
10841 	/*
10842 	 * One way that the rscn_count will get used is described below :
10843 	 *
10844 	 * 1. fp_unsol_cb() gets an RSCN and updates fp_rscn_count.
10845 	 * 2. Before mutex is released, a copy of it is stored in rscn_count.
10846 	 * 3. The count is passed to job thread as JOB_UNSOL_REQUEST (below)
10847 	 *    by overloading the job_cb_arg to pass the rscn_count
10848 	 * 4. When one of the routines processing the RSCN picks it up (ex:
10849 	 *    fp_validate_rscn_page()), it passes this count in the map
10850 	 *    structure (as part of the map_rscn_info structure member) to the
10851 	 *    ULPs.
10852 	 * 5. When ULPs make calls back to the transport (example interfaces for
10853 	 *    this are fc_ulp_transport(), fc_ulp_login(), fc_issue_els()), they
10854 	 *    can now pass back this count as part of the fc_packet's
10855 	 *    pkt_ulp_rscn_count member. fcp does this currently.
10856 	 * 6. When transport gets a call to transport a command on the wire, it
10857 	 *    will check to see if there is a valid pkt_ulp_rsvd1 field in the
10858 	 *    fc_packet. If there is, it will match that info with the current
10859 	 *    rscn_count on that instance of the port. If they don't match up
10860 	 *    then there was a newer RSCN. The ULP gets back an error code which
10861 	 *    informs it about it - FC_DEVICE_BUSY_NEW_RSCN.
10862 	 * 7. At this point the ULP is free to make up its own mind as to how to
10863 	 *    handle this. Currently, fcp will reset its retry counters and keep
10864 	 *    retrying the operation it was doing in anticipation of getting a
10865 	 *    new state change call back for the new RSCN.
10866 	 */
10867 	job = fctl_alloc_job(JOB_UNSOL_REQUEST, 0, NULL,
10868 	    (opaque_t)(uintptr_t)cb_arg, KM_NOSLEEP);
10869 	if (job == NULL) {
10870 		fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, "fp_unsol_cb() "
10871 		    "couldn't submit a job to the thread, failing..");
10872 
10873 		mutex_enter(&port->fp_mutex);
10874 
10875 		if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
10876 			--port->fp_rscn_count;
10877 		}
10878 
10879 		ASSERT(port->fp_active_ubs > 0);
10880 		if (--(port->fp_active_ubs) == 0) {
10881 			port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB;
10882 		}
10883 
10884 		mutex_exit(&port->fp_mutex);
10885 		port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
10886 		    1, &buf->ub_token);
10887 
10888 		return;
10889 	}
10890 	job->job_private = (void *)buf;
10891 	fctl_enque_job(port, job);
10892 }
10893 
10894 
10895 /*
10896  * Handle unsolicited requests
10897  */
10898 static void
10899 fp_handle_unsol_buf(fc_local_port_t *port, fc_unsol_buf_t *buf,
10900     job_request_t *job)
10901 {
10902 	uchar_t			r_ctl;
10903 	uchar_t			ls_code;
10904 	uint32_t		s_id;
10905 	fp_cmd_t		*cmd;
10906 	fc_remote_port_t	*pd;
10907 	fp_unsol_spec_t		*ub_spec;
10908 
10909 	r_ctl = buf->ub_frame.r_ctl;
10910 	s_id = buf->ub_frame.s_id;
10911 
10912 	switch (r_ctl & R_CTL_ROUTING) {
10913 	case R_CTL_EXTENDED_SVC:
10914 		if (r_ctl != R_CTL_ELS_REQ) {
10915 			break;
10916 		}
10917 
10918 		ls_code = buf->ub_buffer[0];
10919 		switch (ls_code) {
10920 		case LA_ELS_LOGO:
10921 		case LA_ELS_ADISC:
10922 		case LA_ELS_PRLO:
10923 			pd = fctl_get_remote_port_by_did(port, s_id);
10924 			if (pd == NULL) {
10925 				if (!FC_IS_REAL_DEVICE(s_id)) {
10926 					break;
10927 				}
10928 				if (!FP_IS_CLASS_1_OR_2(buf->ub_class)) {
10929 					break;
10930 				}
10931 				if ((cmd = fp_alloc_pkt(port,
10932 				    sizeof (la_els_rjt_t), 0, KM_SLEEP,
10933 				    NULL)) == NULL) {
10934 					/*
10935 					 * Can this actually fail when
10936 					 * given KM_SLEEP?  (Could be used
10937 					 * this way in a number of places.)
10938 					 */
10939 					break;
10940 				}
10941 
10942 				fp_els_rjt_init(port, cmd, buf,
10943 				    FC_ACTION_NON_RETRYABLE,
10944 				    FC_REASON_INVALID_LINK_CTRL, job);
10945 
10946 				if (fp_sendcmd(port, cmd,
10947 				    port->fp_fca_handle) != FC_SUCCESS) {
10948 					fp_free_pkt(cmd);
10949 				}
10950 
10951 				break;
10952 			}
10953 			if (ls_code == LA_ELS_LOGO) {
10954 				fp_handle_unsol_logo(port, buf, pd, job);
10955 			} else if (ls_code == LA_ELS_ADISC) {
10956 				fp_handle_unsol_adisc(port, buf, pd, job);
10957 			} else {
10958 				fp_handle_unsol_prlo(port, buf, pd, job);
10959 			}
10960 			break;
10961 
10962 		case LA_ELS_PLOGI:
10963 			fp_handle_unsol_plogi(port, buf, job, KM_SLEEP);
10964 			break;
10965 
10966 		case LA_ELS_FLOGI:
10967 			fp_handle_unsol_flogi(port, buf, job, KM_SLEEP);
10968 			break;
10969 
10970 		case LA_ELS_RSCN:
10971 			fp_handle_unsol_rscn(port, buf, job, KM_SLEEP);
10972 			break;
10973 
10974 		default:
10975 			ub_spec = kmem_zalloc(sizeof (*ub_spec), KM_SLEEP);
10976 			ub_spec->port = port;
10977 			ub_spec->buf = buf;
10978 
10979 			(void) taskq_dispatch(port->fp_taskq,
10980 			    fp_ulp_unsol_cb, ub_spec, KM_SLEEP);
10981 			return;
10982 		}
10983 		break;
10984 
10985 	case R_CTL_BASIC_SVC:
10986 		/*
10987 		 * The unsolicited basic link services could be ABTS
10988 		 * and RMC (Or even a NOP). Just BA_RJT them until
10989 		 * such time there arises a need to handle them more
10990 		 * carefully.
10991 		 */
10992 		if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
10993 			cmd = fp_alloc_pkt(port, sizeof (la_ba_rjt_t),
10994 			    0, KM_SLEEP, NULL);
10995 			if (cmd != NULL) {
10996 				fp_ba_rjt_init(port, cmd, buf, job);
10997 				if (fp_sendcmd(port, cmd,
10998 				    port->fp_fca_handle) != FC_SUCCESS) {
10999 					fp_free_pkt(cmd);
11000 				}
11001 			}
11002 		}
11003 		break;
11004 
11005 	case R_CTL_DEVICE_DATA:
11006 		if (buf->ub_frame.type == FC_TYPE_FC_SERVICES) {
11007 			/*
11008 			 * Mostly this is of type FC_TYPE_FC_SERVICES.
11009 			 * As we don't like any Unsolicited FC services
11010 			 * requests, we would do well to RJT them as
11011 			 * well.
11012 			 */
11013 			if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11014 				cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t),
11015 				    0, KM_SLEEP, NULL);
11016 				if (cmd != NULL) {
11017 					fp_els_rjt_init(port, cmd, buf,
11018 					    FC_ACTION_NON_RETRYABLE,
11019 					    FC_REASON_INVALID_LINK_CTRL, job);
11020 
11021 					if (fp_sendcmd(port, cmd,
11022 					    port->fp_fca_handle) !=
11023 					    FC_SUCCESS) {
11024 						fp_free_pkt(cmd);
11025 					}
11026 				}
11027 			}
11028 			break;
11029 		}
11030 		/* FALLTHROUGH */
11031 
11032 	case R_CTL_FC4_SVC:
11033 		ub_spec = kmem_zalloc(sizeof (*ub_spec), KM_SLEEP);
11034 		ub_spec->port = port;
11035 		ub_spec->buf = buf;
11036 
11037 		(void) taskq_dispatch(port->fp_taskq,
11038 		    fp_ulp_unsol_cb, ub_spec, KM_SLEEP);
11039 		return;
11040 
11041 	case R_CTL_LINK_CTL:
11042 		/*
11043 		 * Turn deaf ear on unsolicited link control frames.
11044 		 * Typical unsolicited link control Frame is an LCR
11045 		 * (to reset End to End credit to the default login
11046 		 * value and abort current sequences for all classes)
11047 		 * An intelligent microcode/firmware should handle
11048 		 * this transparently at its level and not pass all
11049 		 * the way up here.
11050 		 *
11051 		 * Possible responses to LCR are R_RDY, F_RJT, P_RJT
11052 		 * or F_BSY. P_RJT is chosen to be the most appropriate
11053 		 * at this time.
11054 		 */
11055 		/* FALLTHROUGH */
11056 
11057 	default:
11058 		/*
11059 		 * Just reject everything else as an invalid request.
11060 		 */
11061 		if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11062 			cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t),
11063 			    0, KM_SLEEP, NULL);
11064 			if (cmd != NULL) {
11065 				fp_els_rjt_init(port, cmd, buf,
11066 				    FC_ACTION_NON_RETRYABLE,
11067 				    FC_REASON_INVALID_LINK_CTRL, job);
11068 
11069 				if (fp_sendcmd(port, cmd,
11070 				    port->fp_fca_handle) != FC_SUCCESS) {
11071 					fp_free_pkt(cmd);
11072 				}
11073 			}
11074 		}
11075 		break;
11076 	}
11077 
11078 	mutex_enter(&port->fp_mutex);
11079 	ASSERT(port->fp_active_ubs > 0);
11080 	if (--(port->fp_active_ubs) == 0) {
11081 		port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB;
11082 	}
11083 	mutex_exit(&port->fp_mutex);
11084 	port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
11085 	    1, &buf->ub_token);
11086 }
11087 
11088 
11089 /*
11090  * Prepare a BA_RJT and send it over.
11091  */
11092 static void
11093 fp_ba_rjt_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf,
11094     job_request_t *job)
11095 {
11096 	fc_packet_t	*pkt;
11097 	la_ba_rjt_t	payload;
11098 
11099 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
11100 
11101 	cmd->cmd_pkt.pkt_tran_flags = buf->ub_class;
11102 	cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND;
11103 	cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
11104 	cmd->cmd_retry_count = 1;
11105 	cmd->cmd_ulp_pkt = NULL;
11106 
11107 	cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
11108 	cmd->cmd_job = job;
11109 
11110 	pkt = &cmd->cmd_pkt;
11111 
11112 	fp_unsol_resp_init(pkt, buf, R_CTL_LS_BA_RJT, FC_TYPE_BASIC_LS);
11113 
11114 	payload.reserved = 0;
11115 	payload.reason_code = FC_REASON_CMD_UNSUPPORTED;
11116 	payload.explanation = FC_EXPLN_NONE;
11117 	payload.vendor = 0;
11118 
11119 	FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
11120 	    (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
11121 }
11122 
11123 
11124 /*
11125  * Prepare an LS_RJT and send it over
11126  */
11127 static void
11128 fp_els_rjt_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf,
11129     uchar_t action, uchar_t reason, job_request_t *job)
11130 {
11131 	fc_packet_t	*pkt;
11132 	la_els_rjt_t	payload;
11133 
11134 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
11135 
11136 	cmd->cmd_pkt.pkt_tran_flags = buf->ub_class;
11137 	cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND;
11138 	cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
11139 	cmd->cmd_retry_count = 1;
11140 	cmd->cmd_ulp_pkt = NULL;
11141 
11142 	cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
11143 	cmd->cmd_job = job;
11144 
11145 	pkt = &cmd->cmd_pkt;
11146 
11147 	fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP, FC_TYPE_EXTENDED_LS);
11148 
11149 	payload.ls_code.ls_code = LA_ELS_RJT;
11150 	payload.ls_code.mbz = 0;
11151 	payload.action = action;
11152 	payload.reason = reason;
11153 	payload.reserved = 0;
11154 	payload.vu = 0;
11155 
11156 	FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
11157 	    (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
11158 }
11159 
11160 /*
11161  *     Function: fp_prlo_acc_init
11162  *
11163  *  Description: Initializes an Link Service Accept for a PRLO.
11164  *
11165  *    Arguments: *port		Local port through which the PRLO was
11166  *				received.
11167  *		 cmd		Command that will carry the accept.
11168  *		 *buf		Unsolicited buffer containing the PRLO
11169  *				request.
11170  *		 job		Job request.
11171  *		 sleep		Allocation mode.
11172  *
11173  * Return Value: *cmd		Command containing the response.
11174  *
11175  *	Context: Depends on the parameter sleep.
11176  */
11177 fp_cmd_t *
11178 fp_prlo_acc_init(fc_local_port_t *port, fc_remote_port_t *pd,
11179     fc_unsol_buf_t *buf, job_request_t *job, int sleep)
11180 {
11181 	fp_cmd_t	*cmd;
11182 	fc_packet_t	*pkt;
11183 	la_els_prlo_t	*req;
11184 	size_t		len;
11185 	uint16_t	flags;
11186 
11187 	req = (la_els_prlo_t *)buf->ub_buffer;
11188 	len = (size_t)ntohs(req->payload_length);
11189 
11190 	/*
11191 	 * The payload of the accept to a PRLO has to be the exact match of
11192 	 * the payload of the request (at the exception of the code).
11193 	 */
11194 	cmd = fp_alloc_pkt(port, (int)len, 0, sleep, pd);
11195 
11196 	if (cmd) {
11197 		/*
11198 		 * The fp command was successfully allocated.
11199 		 */
11200 		cmd->cmd_pkt.pkt_tran_flags = buf->ub_class;
11201 		cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND;
11202 		cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
11203 		cmd->cmd_retry_count = 1;
11204 		cmd->cmd_ulp_pkt = NULL;
11205 
11206 		cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
11207 		cmd->cmd_job = job;
11208 
11209 		pkt = &cmd->cmd_pkt;
11210 
11211 		fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP,
11212 		    FC_TYPE_EXTENDED_LS);
11213 
11214 		/* The code is overwritten for the copy. */
11215 		req->ls_code = LA_ELS_ACC;
11216 		/* Response code is set. */
11217 		flags = ntohs(req->flags);
11218 		flags &= ~SP_RESP_CODE_MASK;
11219 		flags |= SP_RESP_CODE_REQ_EXECUTED;
11220 		req->flags = htons(flags);
11221 
11222 		FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)req,
11223 		    (uint8_t *)pkt->pkt_cmd, len, DDI_DEV_AUTOINCR);
11224 	}
11225 	return (cmd);
11226 }
11227 
11228 /*
11229  * Prepare an ACC response to an ELS request
11230  */
11231 static void
11232 fp_els_acc_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf,
11233     job_request_t *job)
11234 {
11235 	fc_packet_t	*pkt;
11236 	ls_code_t	payload;
11237 
11238 	cmd->cmd_pkt.pkt_tran_flags = buf->ub_class;
11239 	cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND;
11240 	cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
11241 	cmd->cmd_retry_count = 1;
11242 	cmd->cmd_ulp_pkt = NULL;
11243 
11244 	cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
11245 	cmd->cmd_job = job;
11246 
11247 	pkt = &cmd->cmd_pkt;
11248 
11249 	fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP, FC_TYPE_EXTENDED_LS);
11250 
11251 	payload.ls_code = LA_ELS_ACC;
11252 	payload.mbz = 0;
11253 
11254 	FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
11255 	    (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
11256 }
11257 
11258 /*
11259  * Unsolicited PRLO handler
11260  *
11261  * A Process Logout should be handled by the ULP that established it.  However,
11262  * some devices send a PRLO to trigger a PLOGI followed by a PRLI.  This happens
11263  * when a device implicitly logs out an initiator (for whatever reason) and
11264  * tries to get that initiator to restablish the connection (PLOGI and PRLI).
11265  * The logical thing to do for the device would be to send a LOGO in response
11266  * to any FC4 frame sent by the initiator. Some devices choose, however, to send
11267  * a PRLO instead.
11268  *
11269  * From a Fibre Channel standpoint a PRLO calls for a PRLI. There's no reason to
11270  * think that the Port Login has been lost.  If we follow the Fibre Channel
11271  * protocol to the letter a PRLI should be sent after accepting the PRLO.  If
11272  * the Port Login has also been lost, the remote port will reject the PRLI
11273  * indicating that we must PLOGI first.	 The initiator will then turn around and
11274  * send a PLOGI.  The way Leadville is layered and the way the ULP interface
11275  * is defined doesn't allow this scenario to be followed easily.  If FCP were to
11276  * handle the PRLO and attempt the PRLI, the reject indicating that a PLOGI is
11277  * needed would be received by FCP. FCP would have, then, to tell the transport
11278  * (fp) to PLOGI.  The problem is, the transport would still think the Port
11279  * Login is valid and there is no way for FCP to tell the transport: "PLOGI even
11280  * if you think it's not necessary".  To work around that difficulty, the PRLO
11281  * is treated by the transport as a LOGO.  The downside to it is a Port Login
11282  * may be disrupted (if a PLOGI wasn't actually needed) and another ULP (that
11283  * has nothing to do with the PRLO) may be impacted.  However, this is a
11284  * scenario very unlikely to happen.  As of today the only ULP in Leadville
11285  * using PRLI/PRLOs is FCP.  For a PRLO to disrupt another ULP (that would be
11286  * FCIP), a SCSI target would have to be running FCP and FCIP (which is very
11287  * unlikely).
11288  */
11289 static void
11290 fp_handle_unsol_prlo(fc_local_port_t *port, fc_unsol_buf_t *buf,
11291     fc_remote_port_t *pd, job_request_t *job)
11292 {
11293 	int		busy;
11294 	int		rval;
11295 	int		retain;
11296 	fp_cmd_t	*cmd;
11297 	fc_portmap_t	*listptr;
11298 	boolean_t	tolerance;
11299 	la_els_prlo_t	*req;
11300 
11301 	req = (la_els_prlo_t *)buf->ub_buffer;
11302 
11303 	if ((ntohs(req->payload_length) !=
11304 	    (sizeof (service_parameter_page_t) + sizeof (ls_code_t))) ||
11305 	    (req->page_length != sizeof (service_parameter_page_t))) {
11306 		/*
11307 		 * We are being very restrictive.  Only on page per
11308 		 * payload.  If it is not the case we reject the ELS although
11309 		 * we should reply indicating we handle only single page
11310 		 * per PRLO.
11311 		 */
11312 		goto fp_reject_prlo;
11313 	}
11314 
11315 	if (ntohs(req->payload_length) > buf->ub_bufsize) {
11316 		/*
11317 		 * This is in case the payload advertizes a size bigger than
11318 		 * what it really is.
11319 		 */
11320 		goto fp_reject_prlo;
11321 	}
11322 
11323 	mutex_enter(&port->fp_mutex);
11324 	busy = port->fp_statec_busy;
11325 	mutex_exit(&port->fp_mutex);
11326 
11327 	mutex_enter(&pd->pd_mutex);
11328 	tolerance = fctl_tc_increment(&pd->pd_logo_tc);
11329 	if (!busy) {
11330 		if (pd->pd_state != PORT_DEVICE_LOGGED_IN ||
11331 		    pd->pd_state == PORT_DEVICE_INVALID ||
11332 		    pd->pd_flags == PD_ELS_IN_PROGRESS ||
11333 		    pd->pd_type == PORT_DEVICE_OLD) {
11334 			busy++;
11335 		}
11336 	}
11337 
11338 	if (busy) {
11339 		mutex_exit(&pd->pd_mutex);
11340 
11341 		FP_TRACE(FP_NHEAD1(5, 0), "Logout; D_ID=%x,"
11342 		    "pd=%p - busy",
11343 		    pd->pd_port_id.port_id, pd);
11344 
11345 		if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11346 			goto fp_reject_prlo;
11347 		}
11348 	} else {
11349 		retain = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0;
11350 
11351 		if (tolerance) {
11352 			fctl_tc_reset(&pd->pd_logo_tc);
11353 			retain = 0;
11354 			pd->pd_state = PORT_DEVICE_INVALID;
11355 		}
11356 
11357 		FP_TRACE(FP_NHEAD1(5, 0), "Accepting LOGO; d_id=%x, pd=%p,"
11358 		    " tolerance=%d retain=%d", pd->pd_port_id.port_id, pd,
11359 		    tolerance, retain);
11360 
11361 		pd->pd_aux_flags |= PD_LOGGED_OUT;
11362 		mutex_exit(&pd->pd_mutex);
11363 
11364 		cmd = fp_prlo_acc_init(port, pd, buf, job, KM_SLEEP);
11365 		if (cmd == NULL) {
11366 			return;
11367 		}
11368 
11369 		rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
11370 		if (rval != FC_SUCCESS) {
11371 			fp_free_pkt(cmd);
11372 			return;
11373 		}
11374 
11375 		listptr = kmem_zalloc(sizeof (fc_portmap_t), KM_SLEEP);
11376 
11377 		if (retain) {
11378 			fp_unregister_login(pd);
11379 			fctl_copy_portmap(listptr, pd);
11380 		} else {
11381 			uint32_t	d_id;
11382 			char		ww_name[17];
11383 
11384 			mutex_enter(&pd->pd_mutex);
11385 			d_id = pd->pd_port_id.port_id;
11386 			fc_wwn_to_str(&pd->pd_port_name, ww_name);
11387 			mutex_exit(&pd->pd_mutex);
11388 
11389 			FP_TRACE(FP_NHEAD2(9, 0),
11390 			    "N_x Port with D_ID=%x, PWWN=%s logged out"
11391 			    " %d times in %d us; Giving up", d_id, ww_name,
11392 			    FC_LOGO_TOLERANCE_LIMIT,
11393 			    FC_LOGO_TOLERANCE_TIME_LIMIT);
11394 
11395 			fp_fillout_old_map(listptr, pd, 0);
11396 			listptr->map_type = PORT_DEVICE_OLD;
11397 		}
11398 
11399 		(void) fp_ulp_devc_cb(port, listptr, 1, 1, KM_SLEEP, 0);
11400 		return;
11401 	}
11402 
11403 fp_reject_prlo:
11404 
11405 	cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t), 0, KM_SLEEP, pd);
11406 	if (cmd != NULL) {
11407 		fp_els_rjt_init(port, cmd, buf, FC_ACTION_NON_RETRYABLE,
11408 		    FC_REASON_INVALID_LINK_CTRL, job);
11409 
11410 		if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
11411 			fp_free_pkt(cmd);
11412 		}
11413 	}
11414 }
11415 
11416 /*
11417  * Unsolicited LOGO handler
11418  */
11419 static void
11420 fp_handle_unsol_logo(fc_local_port_t *port, fc_unsol_buf_t *buf,
11421     fc_remote_port_t *pd, job_request_t *job)
11422 {
11423 	int		busy;
11424 	int		rval;
11425 	int		retain;
11426 	fp_cmd_t	*cmd;
11427 	fc_portmap_t	*listptr;
11428 	boolean_t	tolerance;
11429 
11430 	mutex_enter(&port->fp_mutex);
11431 	busy = port->fp_statec_busy;
11432 	mutex_exit(&port->fp_mutex);
11433 
11434 	mutex_enter(&pd->pd_mutex);
11435 	tolerance = fctl_tc_increment(&pd->pd_logo_tc);
11436 	if (!busy) {
11437 		if (pd->pd_state != PORT_DEVICE_LOGGED_IN ||
11438 		    pd->pd_state == PORT_DEVICE_INVALID ||
11439 		    pd->pd_flags == PD_ELS_IN_PROGRESS ||
11440 		    pd->pd_type == PORT_DEVICE_OLD) {
11441 			busy++;
11442 		}
11443 	}
11444 
11445 	if (busy) {
11446 		mutex_exit(&pd->pd_mutex);
11447 
11448 		FP_TRACE(FP_NHEAD1(5, 0), "Logout; D_ID=%x,"
11449 		    "pd=%p - busy",
11450 		    pd->pd_port_id.port_id, pd);
11451 
11452 		if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11453 			cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t),
11454 			    0, KM_SLEEP, pd);
11455 			if (cmd != NULL) {
11456 				fp_els_rjt_init(port, cmd, buf,
11457 				    FC_ACTION_NON_RETRYABLE,
11458 				    FC_REASON_INVALID_LINK_CTRL, job);
11459 
11460 				if (fp_sendcmd(port, cmd,
11461 				    port->fp_fca_handle) != FC_SUCCESS) {
11462 					fp_free_pkt(cmd);
11463 				}
11464 			}
11465 		}
11466 	} else {
11467 		retain = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0;
11468 
11469 		if (tolerance) {
11470 			fctl_tc_reset(&pd->pd_logo_tc);
11471 			retain = 0;
11472 			pd->pd_state = PORT_DEVICE_INVALID;
11473 		}
11474 
11475 		FP_TRACE(FP_NHEAD1(5, 0), "Accepting LOGO; d_id=%x, pd=%p,"
11476 		    " tolerance=%d retain=%d", pd->pd_port_id.port_id, pd,
11477 		    tolerance, retain);
11478 
11479 		pd->pd_aux_flags |= PD_LOGGED_OUT;
11480 		mutex_exit(&pd->pd_mutex);
11481 
11482 		cmd = fp_alloc_pkt(port, FP_PORT_IDENTIFIER_LEN, 0,
11483 		    KM_SLEEP, pd);
11484 		if (cmd == NULL) {
11485 			return;
11486 		}
11487 
11488 		fp_els_acc_init(port, cmd, buf, job);
11489 
11490 		rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
11491 		if (rval != FC_SUCCESS) {
11492 			fp_free_pkt(cmd);
11493 			return;
11494 		}
11495 
11496 		listptr = kmem_zalloc(sizeof (fc_portmap_t), KM_SLEEP);
11497 
11498 		if (retain) {
11499 			job_request_t	*job;
11500 			fctl_ns_req_t	*ns_cmd;
11501 
11502 			/*
11503 			 * when get LOGO, first try to get PID from nameserver
11504 			 * if failed, then we do not need
11505 			 * send PLOGI to that remote port
11506 			 */
11507 			job = fctl_alloc_job(
11508 			    JOB_NS_CMD, 0, NULL, (opaque_t)port, KM_SLEEP);
11509 
11510 			if (job != NULL) {
11511 				ns_cmd = fctl_alloc_ns_cmd(
11512 				    sizeof (ns_req_gid_pn_t),
11513 				    sizeof (ns_resp_gid_pn_t),
11514 				    sizeof (ns_resp_gid_pn_t),
11515 				    0, KM_SLEEP);
11516 				if (ns_cmd != NULL) {
11517 					int ret;
11518 					job->job_result = FC_SUCCESS;
11519 					ns_cmd->ns_cmd_code = NS_GID_PN;
11520 					((ns_req_gid_pn_t *)
11521 					    (ns_cmd->ns_cmd_buf))->pwwn =
11522 					    pd->pd_port_name;
11523 					ret = fp_ns_query(
11524 					    port, ns_cmd, job, 1, KM_SLEEP);
11525 					if ((ret != FC_SUCCESS) ||
11526 					    (job->job_result != FC_SUCCESS)) {
11527 						fctl_free_ns_cmd(ns_cmd);
11528 						fctl_dealloc_job(job);
11529 						FP_TRACE(FP_NHEAD2(9, 0),
11530 						    "NS query failed,",
11531 						    " delete pd");
11532 						goto delete_pd;
11533 					}
11534 					fctl_free_ns_cmd(ns_cmd);
11535 				}
11536 				fctl_dealloc_job(job);
11537 			}
11538 			fp_unregister_login(pd);
11539 			fctl_copy_portmap(listptr, pd);
11540 		} else {
11541 			uint32_t	d_id;
11542 			char		ww_name[17];
11543 
11544 		delete_pd:
11545 			mutex_enter(&pd->pd_mutex);
11546 			d_id = pd->pd_port_id.port_id;
11547 			fc_wwn_to_str(&pd->pd_port_name, ww_name);
11548 			mutex_exit(&pd->pd_mutex);
11549 
11550 			FP_TRACE(FP_NHEAD2(9, 0),
11551 			    "N_x Port with D_ID=%x, PWWN=%s logged out"
11552 			    " %d times in %d us; Giving up", d_id, ww_name,
11553 			    FC_LOGO_TOLERANCE_LIMIT,
11554 			    FC_LOGO_TOLERANCE_TIME_LIMIT);
11555 
11556 			fp_fillout_old_map(listptr, pd, 0);
11557 			listptr->map_type = PORT_DEVICE_OLD;
11558 		}
11559 
11560 		(void) fp_ulp_devc_cb(port, listptr, 1, 1, KM_SLEEP, 0);
11561 	}
11562 }
11563 
11564 
11565 /*
11566  * Perform general purpose preparation of a response to an unsolicited request
11567  */
11568 static void
11569 fp_unsol_resp_init(fc_packet_t *pkt, fc_unsol_buf_t *buf,
11570     uchar_t r_ctl, uchar_t type)
11571 {
11572 	pkt->pkt_cmd_fhdr.r_ctl = r_ctl;
11573 	pkt->pkt_cmd_fhdr.d_id = buf->ub_frame.s_id;
11574 	pkt->pkt_cmd_fhdr.s_id = buf->ub_frame.d_id;
11575 	pkt->pkt_cmd_fhdr.type = type;
11576 	pkt->pkt_cmd_fhdr.f_ctl = F_CTL_LAST_SEQ | F_CTL_XCHG_CONTEXT;
11577 	pkt->pkt_cmd_fhdr.seq_id = buf->ub_frame.seq_id;
11578 	pkt->pkt_cmd_fhdr.df_ctl  = buf->ub_frame.df_ctl;
11579 	pkt->pkt_cmd_fhdr.seq_cnt = buf->ub_frame.seq_cnt;
11580 	pkt->pkt_cmd_fhdr.ox_id = buf->ub_frame.ox_id;
11581 	pkt->pkt_cmd_fhdr.rx_id = buf->ub_frame.rx_id;
11582 	pkt->pkt_cmd_fhdr.ro = 0;
11583 	pkt->pkt_cmd_fhdr.rsvd = 0;
11584 	pkt->pkt_comp = fp_unsol_intr;
11585 	pkt->pkt_timeout = FP_ELS_TIMEOUT;
11586 	pkt->pkt_ub_resp_token = (opaque_t)buf;
11587 }
11588 
11589 /*
11590  * Immediate handling of unsolicited FLOGI and PLOGI requests. In the
11591  * early development days of public loop soc+ firmware, numerous problems
11592  * were encountered (the details are undocumented and history now) which
11593  * led to the birth of this function.
11594  *
11595  * If a pre-allocated unsolicited response packet is free, send out an
11596  * immediate response, otherwise submit the request to the port thread
11597  * to do the deferred processing.
11598  */
11599 static void
11600 fp_i_handle_unsol_els(fc_local_port_t *port, fc_unsol_buf_t *buf)
11601 {
11602 	int			sent;
11603 	int			f_port;
11604 	int			do_acc;
11605 	fp_cmd_t		*cmd;
11606 	la_els_logi_t		*payload;
11607 	fc_remote_port_t	*pd;
11608 	char			dww_name[17];
11609 
11610 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
11611 
11612 	cmd = port->fp_els_resp_pkt;
11613 
11614 	mutex_enter(&port->fp_mutex);
11615 	do_acc = (port->fp_statec_busy == 0) ? 1 : 0;
11616 	mutex_exit(&port->fp_mutex);
11617 
11618 	switch (buf->ub_buffer[0]) {
11619 	case LA_ELS_PLOGI: {
11620 		int small;
11621 
11622 		payload = (la_els_logi_t *)buf->ub_buffer;
11623 
11624 		f_port = FP_IS_F_PORT(payload->
11625 		    common_service.cmn_features) ? 1 : 0;
11626 
11627 		small = fctl_wwn_cmp(&port->fp_service_params.nport_ww_name,
11628 		    &payload->nport_ww_name);
11629 		pd = fctl_get_remote_port_by_pwwn(port,
11630 		    &payload->nport_ww_name);
11631 		if (pd) {
11632 			mutex_enter(&pd->pd_mutex);
11633 			sent = (pd->pd_flags == PD_ELS_IN_PROGRESS) ? 1 : 0;
11634 			/*
11635 			 * Most likely this means a cross login is in
11636 			 * progress or a device about to be yanked out.
11637 			 * Only accept the plogi if my wwn is smaller.
11638 			 */
11639 			if (pd->pd_type == PORT_DEVICE_OLD) {
11640 				sent = 1;
11641 			}
11642 			/*
11643 			 * Stop plogi request (if any)
11644 			 * attempt from local side to speedup
11645 			 * the discovery progress.
11646 			 * Mark the pd as PD_PLOGI_RECEPIENT.
11647 			 */
11648 			if (f_port == 0 && small < 0) {
11649 				pd->pd_recepient = PD_PLOGI_RECEPIENT;
11650 			}
11651 			fc_wwn_to_str(&pd->pd_port_name, dww_name);
11652 
11653 			mutex_exit(&pd->pd_mutex);
11654 
11655 			FP_TRACE(FP_NHEAD1(3, 0), "fp_i_handle_unsol_els: "
11656 			    "Unsol PLOGI received. PD still exists in the "
11657 			    "PWWN list. pd=%p PWWN=%s, sent=%x",
11658 			    pd, dww_name, sent);
11659 
11660 			if (f_port == 0 && small < 0) {
11661 				FP_TRACE(FP_NHEAD1(3, 0),
11662 				    "fp_i_handle_unsol_els: Mark the pd"
11663 				    " as plogi recipient, pd=%p, PWWN=%s"
11664 				    ", sent=%x",
11665 				    pd, dww_name, sent);
11666 			}
11667 		} else {
11668 			sent = 0;
11669 		}
11670 
11671 		/*
11672 		 * To avoid Login collisions, accept only if my WWN
11673 		 * is smaller than the requester (A curious side note
11674 		 * would be that this rule may not satisfy the PLOGIs
11675 		 * initiated by the switch from not-so-well known
11676 		 * ports such as 0xFFFC41)
11677 		 */
11678 		if ((f_port == 0 && small < 0) ||
11679 		    (((small > 0 && do_acc) ||
11680 		    FC_MUST_ACCEPT_D_ID(buf->ub_frame.s_id)) && sent == 0)) {
11681 			if (fp_is_class_supported(port->fp_cos,
11682 			    buf->ub_class) == FC_FAILURE) {
11683 				if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11684 					cmd->cmd_pkt.pkt_cmdlen =
11685 					    sizeof (la_els_rjt_t);
11686 					cmd->cmd_pkt.pkt_rsplen = 0;
11687 					fp_els_rjt_init(port, cmd, buf,
11688 					    FC_ACTION_NON_RETRYABLE,
11689 					    FC_REASON_CLASS_NOT_SUPP, NULL);
11690 					FP_TRACE(FP_NHEAD1(3, 0),
11691 					    "fp_i_handle_unsol_els: "
11692 					    "Unsupported class. "
11693 					    "Rejecting PLOGI");
11694 
11695 				} else {
11696 					mutex_enter(&port->fp_mutex);
11697 					port->fp_els_resp_pkt_busy = 0;
11698 					mutex_exit(&port->fp_mutex);
11699 					return;
11700 				}
11701 			} else {
11702 				cmd->cmd_pkt.pkt_cmdlen =
11703 				    sizeof (la_els_logi_t);
11704 				cmd->cmd_pkt.pkt_rsplen = 0;
11705 
11706 				/*
11707 				 * If fp_port_id is zero and topology is
11708 				 * Point-to-Point, get the local port id from
11709 				 * the d_id in the PLOGI request.
11710 				 * If the outgoing FLOGI hasn't been accepted,
11711 				 * the topology will be unknown here. But it's
11712 				 * still safe to save the d_id to fp_port_id,
11713 				 * just because it will be overwritten later
11714 				 * if the topology is not Point-to-Point.
11715 				 */
11716 				mutex_enter(&port->fp_mutex);
11717 				if ((port->fp_port_id.port_id == 0) &&
11718 				    (port->fp_topology == FC_TOP_PT_PT ||
11719 				    port->fp_topology == FC_TOP_UNKNOWN)) {
11720 					port->fp_port_id.port_id =
11721 					    buf->ub_frame.d_id;
11722 				}
11723 				mutex_exit(&port->fp_mutex);
11724 
11725 				/*
11726 				 * Sometime later, we should validate
11727 				 * the service parameters instead of
11728 				 * just accepting it.
11729 				 */
11730 				fp_login_acc_init(port, cmd, buf, NULL,
11731 				    KM_NOSLEEP);
11732 				FP_TRACE(FP_NHEAD1(3, 0),
11733 				    "fp_i_handle_unsol_els: Accepting PLOGI,"
11734 				    " f_port=%d, small=%d, do_acc=%d,"
11735 				    " sent=%d.", f_port, small, do_acc,
11736 				    sent);
11737 			}
11738 		} else {
11739 			if (FP_IS_CLASS_1_OR_2(buf->ub_class) ||
11740 			    port->fp_options & FP_SEND_RJT) {
11741 				cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_rjt_t);
11742 				cmd->cmd_pkt.pkt_rsplen = 0;
11743 				fp_els_rjt_init(port, cmd, buf,
11744 				    FC_ACTION_NON_RETRYABLE,
11745 				    FC_REASON_LOGICAL_BSY, NULL);
11746 				FP_TRACE(FP_NHEAD1(3, 0),
11747 				    "fp_i_handle_unsol_els: "
11748 				    "Rejecting PLOGI with Logical Busy."
11749 				    "Possible Login collision.");
11750 			} else {
11751 				mutex_enter(&port->fp_mutex);
11752 				port->fp_els_resp_pkt_busy = 0;
11753 				mutex_exit(&port->fp_mutex);
11754 				return;
11755 			}
11756 		}
11757 		break;
11758 	}
11759 
11760 	case LA_ELS_FLOGI:
11761 		if (fp_is_class_supported(port->fp_cos,
11762 		    buf->ub_class) == FC_FAILURE) {
11763 			if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11764 				cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_rjt_t);
11765 				cmd->cmd_pkt.pkt_rsplen = 0;
11766 				fp_els_rjt_init(port, cmd, buf,
11767 				    FC_ACTION_NON_RETRYABLE,
11768 				    FC_REASON_CLASS_NOT_SUPP, NULL);
11769 				FP_TRACE(FP_NHEAD1(3, 0),
11770 				    "fp_i_handle_unsol_els: "
11771 				    "Unsupported Class. Rejecting FLOGI.");
11772 			} else {
11773 				mutex_enter(&port->fp_mutex);
11774 				port->fp_els_resp_pkt_busy = 0;
11775 				mutex_exit(&port->fp_mutex);
11776 				return;
11777 			}
11778 		} else {
11779 			mutex_enter(&port->fp_mutex);
11780 			if (FC_PORT_STATE_MASK(port->fp_state) !=
11781 			    FC_STATE_ONLINE || (port->fp_port_id.port_id &&
11782 			    buf->ub_frame.s_id == port->fp_port_id.port_id)) {
11783 				mutex_exit(&port->fp_mutex);
11784 				if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11785 					cmd->cmd_pkt.pkt_cmdlen =
11786 					    sizeof (la_els_rjt_t);
11787 					cmd->cmd_pkt.pkt_rsplen = 0;
11788 					fp_els_rjt_init(port, cmd, buf,
11789 					    FC_ACTION_NON_RETRYABLE,
11790 					    FC_REASON_INVALID_LINK_CTRL,
11791 					    NULL);
11792 					FP_TRACE(FP_NHEAD1(3, 0),
11793 					    "fp_i_handle_unsol_els: "
11794 					    "Invalid Link Ctrl. "
11795 					    "Rejecting FLOGI.");
11796 				} else {
11797 					mutex_enter(&port->fp_mutex);
11798 					port->fp_els_resp_pkt_busy = 0;
11799 					mutex_exit(&port->fp_mutex);
11800 					return;
11801 				}
11802 			} else {
11803 				mutex_exit(&port->fp_mutex);
11804 				cmd->cmd_pkt.pkt_cmdlen =
11805 				    sizeof (la_els_logi_t);
11806 				cmd->cmd_pkt.pkt_rsplen = 0;
11807 				/*
11808 				 * Let's not aggressively validate the N_Port's
11809 				 * service parameters until PLOGI. Suffice it
11810 				 * to give a hint that we are an N_Port and we
11811 				 * are game to some serious stuff here.
11812 				 */
11813 				fp_login_acc_init(port, cmd, buf,
11814 				    NULL, KM_NOSLEEP);
11815 				FP_TRACE(FP_NHEAD1(3, 0),
11816 				    "fp_i_handle_unsol_els: "
11817 				    "Accepting FLOGI.");
11818 			}
11819 		}
11820 		break;
11821 
11822 	default:
11823 		return;
11824 	}
11825 
11826 	if ((fp_sendcmd(port, cmd, port->fp_fca_handle)) != FC_SUCCESS) {
11827 		mutex_enter(&port->fp_mutex);
11828 		port->fp_els_resp_pkt_busy = 0;
11829 		mutex_exit(&port->fp_mutex);
11830 	}
11831 }
11832 
11833 
11834 /*
11835  * Handle unsolicited PLOGI request
11836  */
11837 static void
11838 fp_handle_unsol_plogi(fc_local_port_t *port, fc_unsol_buf_t *buf,
11839     job_request_t *job, int sleep)
11840 {
11841 	int			sent;
11842 	int			small;
11843 	int			f_port;
11844 	int			do_acc;
11845 	fp_cmd_t		*cmd;
11846 	la_wwn_t		*swwn;
11847 	la_wwn_t		*dwwn;
11848 	la_els_logi_t		*payload;
11849 	fc_remote_port_t	*pd;
11850 	char			dww_name[17];
11851 
11852 	payload = (la_els_logi_t *)buf->ub_buffer;
11853 	f_port = FP_IS_F_PORT(payload->common_service.cmn_features) ? 1 : 0;
11854 
11855 	mutex_enter(&port->fp_mutex);
11856 	do_acc = (port->fp_statec_busy == 0) ? 1 : 0;
11857 	mutex_exit(&port->fp_mutex);
11858 
11859 	FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_plogi: s_id=%x, d_id=%x,"
11860 	    "type=%x, f_ctl=%x"
11861 	    " seq_id=%x, ox_id=%x, rx_id=%x"
11862 	    " ro=%x", buf->ub_frame.s_id, buf->ub_frame.d_id,
11863 	    buf->ub_frame.type, buf->ub_frame.f_ctl, buf->ub_frame.seq_id,
11864 	    buf->ub_frame.ox_id, buf->ub_frame.rx_id, buf->ub_frame.ro);
11865 
11866 	swwn = &port->fp_service_params.nport_ww_name;
11867 	dwwn = &payload->nport_ww_name;
11868 	small = fctl_wwn_cmp(swwn, dwwn);
11869 	pd = fctl_get_remote_port_by_pwwn(port, dwwn);
11870 	if (pd) {
11871 		mutex_enter(&pd->pd_mutex);
11872 		sent = (pd->pd_flags == PD_ELS_IN_PROGRESS) ? 1 : 0;
11873 		/*
11874 		 * Most likely this means a cross login is in
11875 		 * progress or a device about to be yanked out.
11876 		 * Only accept the plogi if my wwn is smaller.
11877 		 */
11878 
11879 		if (pd->pd_type == PORT_DEVICE_OLD) {
11880 			sent = 1;
11881 		}
11882 		/*
11883 		 * Stop plogi request (if any)
11884 		 * attempt from local side to speedup
11885 		 * the discovery progress.
11886 		 * Mark the pd as PD_PLOGI_RECEPIENT.
11887 		 */
11888 		if (f_port == 0 && small < 0) {
11889 			pd->pd_recepient = PD_PLOGI_RECEPIENT;
11890 		}
11891 		fc_wwn_to_str(&pd->pd_port_name, dww_name);
11892 
11893 		mutex_exit(&pd->pd_mutex);
11894 
11895 		FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_plogi: Unsol PLOGI"
11896 		    " received. PD still exists in the PWWN list. pd=%p "
11897 		    "PWWN=%s, sent=%x", pd, dww_name, sent);
11898 
11899 		if (f_port == 0 && small < 0) {
11900 			FP_TRACE(FP_NHEAD1(3, 0),
11901 			    "fp_handle_unsol_plogi: Mark the pd"
11902 			    " as plogi recipient, pd=%p, PWWN=%s"
11903 			    ", sent=%x",
11904 			    pd, dww_name, sent);
11905 		}
11906 	} else {
11907 		sent = 0;
11908 	}
11909 
11910 	/*
11911 	 * Avoid Login collisions by accepting only if my WWN is smaller.
11912 	 *
11913 	 * A side note: There is no need to start a PLOGI from this end in
11914 	 *	this context if login isn't going to be accepted for the
11915 	 *	above reason as either a LIP (in private loop), RSCN (in
11916 	 *	fabric topology), or an FLOGI (in point to point - Huh ?
11917 	 *	check FC-PH) would normally drive the PLOGI from this end.
11918 	 *	At this point of time there is no need for an inbound PLOGI
11919 	 *	to kick an outbound PLOGI when it is going to be rejected
11920 	 *	for the reason of WWN being smaller. However it isn't hard
11921 	 *	to do that either (when such a need arises, start a timer
11922 	 *	for a duration that extends beyond a normal device discovery
11923 	 *	time and check if an outbound PLOGI did go before that, if
11924 	 *	none fire one)
11925 	 *
11926 	 *	Unfortunately, as it turned out, during booting, it is possible
11927 	 *	to miss another initiator in the same loop as port driver
11928 	 *	instances are serially attached. While preserving the above
11929 	 *	comments for belly laughs, please kick an outbound PLOGI in
11930 	 *	a non-switch environment (which is a pt pt between N_Ports or
11931 	 *	a private loop)
11932 	 *
11933 	 *	While preserving the above comments for amusement, send an
11934 	 *	ACC if the PLOGI is going to be rejected for WWN being smaller
11935 	 *	when no discovery is in progress at this end. Turn around
11936 	 *	and make the port device as the PLOGI initiator, so that
11937 	 *	during subsequent link/loop initialization, this end drives
11938 	 *	the PLOGI (In fact both ends do in this particular case, but
11939 	 *	only one wins)
11940 	 *
11941 	 * Make sure the PLOGIs initiated by the switch from not-so-well-known
11942 	 * ports (such as 0xFFFC41) are accepted too.
11943 	 */
11944 	if ((f_port == 0 && small < 0) || (((small > 0 && do_acc) ||
11945 	    FC_MUST_ACCEPT_D_ID(buf->ub_frame.s_id)) && sent == 0)) {
11946 		if (fp_is_class_supported(port->fp_cos,
11947 		    buf->ub_class) == FC_FAILURE) {
11948 			if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11949 				cmd = fp_alloc_pkt(port,
11950 				    sizeof (la_els_logi_t), 0, sleep, pd);
11951 				if (cmd == NULL) {
11952 					return;
11953 				}
11954 				cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_rjt_t);
11955 				cmd->cmd_pkt.pkt_rsplen = 0;
11956 				fp_els_rjt_init(port, cmd, buf,
11957 				    FC_ACTION_NON_RETRYABLE,
11958 				    FC_REASON_CLASS_NOT_SUPP, job);
11959 				FP_TRACE(FP_NHEAD1(3, 0),
11960 				    "fp_handle_unsol_plogi: "
11961 				    "Unsupported class. rejecting PLOGI");
11962 			}
11963 		} else {
11964 			cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t),
11965 			    0, sleep, pd);
11966 			if (cmd == NULL) {
11967 				return;
11968 			}
11969 			cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_logi_t);
11970 			cmd->cmd_pkt.pkt_rsplen = 0;
11971 
11972 			/*
11973 			 * Sometime later, we should validate the service
11974 			 * parameters instead of just accepting it.
11975 			 */
11976 			fp_login_acc_init(port, cmd, buf, job, KM_SLEEP);
11977 			FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_plogi: "
11978 			    "Accepting PLOGI, f_port=%d, small=%d, "
11979 			    "do_acc=%d, sent=%d.", f_port, small, do_acc,
11980 			    sent);
11981 
11982 			/*
11983 			 * If fp_port_id is zero and topology is
11984 			 * Point-to-Point, get the local port id from
11985 			 * the d_id in the PLOGI request.
11986 			 * If the outgoing FLOGI hasn't been accepted,
11987 			 * the topology will be unknown here. But it's
11988 			 * still safe to save the d_id to fp_port_id,
11989 			 * just because it will be overwritten later
11990 			 * if the topology is not Point-to-Point.
11991 			 */
11992 			mutex_enter(&port->fp_mutex);
11993 			if ((port->fp_port_id.port_id == 0) &&
11994 			    (port->fp_topology == FC_TOP_PT_PT ||
11995 			    port->fp_topology == FC_TOP_UNKNOWN)) {
11996 				port->fp_port_id.port_id =
11997 				    buf->ub_frame.d_id;
11998 			}
11999 			mutex_exit(&port->fp_mutex);
12000 		}
12001 	} else {
12002 		if (FP_IS_CLASS_1_OR_2(buf->ub_class) ||
12003 		    port->fp_options & FP_SEND_RJT) {
12004 			cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t),
12005 			    0, sleep, pd);
12006 			if (cmd == NULL) {
12007 				return;
12008 			}
12009 			cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_rjt_t);
12010 			cmd->cmd_pkt.pkt_rsplen = 0;
12011 			/*
12012 			 * Send out Logical busy to indicate
12013 			 * the detection of PLOGI collision
12014 			 */
12015 			fp_els_rjt_init(port, cmd, buf,
12016 			    FC_ACTION_NON_RETRYABLE,
12017 			    FC_REASON_LOGICAL_BSY, job);
12018 
12019 			fc_wwn_to_str(dwwn, dww_name);
12020 			FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_plogi: "
12021 			    "Rejecting Unsol PLOGI with Logical Busy."
12022 			    "possible PLOGI collision. PWWN=%s, sent=%x",
12023 			    dww_name, sent);
12024 		} else {
12025 			return;
12026 		}
12027 	}
12028 
12029 	if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
12030 		fp_free_pkt(cmd);
12031 	}
12032 }
12033 
12034 
12035 /*
12036  * Handle mischievous turning over of our own FLOGI requests back to
12037  * us by the SOC+ microcode. In other words, look at the class of such
12038  * bone headed requests, if 1 or 2, bluntly P_RJT them, if 3 drop them
12039  * on the floor
12040  */
12041 static void
12042 fp_handle_unsol_flogi(fc_local_port_t *port, fc_unsol_buf_t *buf,
12043     job_request_t *job, int sleep)
12044 {
12045 	uint32_t	state;
12046 	uint32_t	s_id;
12047 	fp_cmd_t	*cmd;
12048 
12049 	if (fp_is_class_supported(port->fp_cos, buf->ub_class) == FC_FAILURE) {
12050 		if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
12051 			cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t),
12052 			    0, sleep, NULL);
12053 			if (cmd == NULL) {
12054 				return;
12055 			}
12056 			fp_els_rjt_init(port, cmd, buf,
12057 			    FC_ACTION_NON_RETRYABLE,
12058 			    FC_REASON_CLASS_NOT_SUPP, job);
12059 		} else {
12060 			return;
12061 		}
12062 	} else {
12063 
12064 		FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_flogi:"
12065 		    " s_id=%x, d_id=%x, type=%x, f_ctl=%x"
12066 		    " seq_id=%x, ox_id=%x, rx_id=%x, ro=%x",
12067 		    buf->ub_frame.s_id, buf->ub_frame.d_id,
12068 		    buf->ub_frame.type, buf->ub_frame.f_ctl,
12069 		    buf->ub_frame.seq_id, buf->ub_frame.ox_id,
12070 		    buf->ub_frame.rx_id, buf->ub_frame.ro);
12071 
12072 		mutex_enter(&port->fp_mutex);
12073 		state = FC_PORT_STATE_MASK(port->fp_state);
12074 		s_id = port->fp_port_id.port_id;
12075 		mutex_exit(&port->fp_mutex);
12076 
12077 		if (state != FC_STATE_ONLINE ||
12078 		    (s_id && buf->ub_frame.s_id == s_id)) {
12079 			if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
12080 				cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t),
12081 				    0, sleep, NULL);
12082 				if (cmd == NULL) {
12083 					return;
12084 				}
12085 				fp_els_rjt_init(port, cmd, buf,
12086 				    FC_ACTION_NON_RETRYABLE,
12087 				    FC_REASON_INVALID_LINK_CTRL, job);
12088 				FP_TRACE(FP_NHEAD1(3, 0),
12089 				    "fp_handle_unsol_flogi: "
12090 				    "Rejecting PLOGI. Invalid Link CTRL");
12091 			} else {
12092 				return;
12093 			}
12094 		} else {
12095 			cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t),
12096 			    0, sleep, NULL);
12097 			if (cmd == NULL) {
12098 				return;
12099 			}
12100 			/*
12101 			 * Let's not aggressively validate the N_Port's
12102 			 * service parameters until PLOGI. Suffice it
12103 			 * to give a hint that we are an N_Port and we
12104 			 * are game to some serious stuff here.
12105 			 */
12106 			fp_login_acc_init(port, cmd, buf, job, KM_SLEEP);
12107 			FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_flogi: "
12108 			    "Accepting PLOGI");
12109 		}
12110 	}
12111 
12112 	if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
12113 		fp_free_pkt(cmd);
12114 	}
12115 }
12116 
12117 
12118 /*
12119  * Perform PLOGI accept
12120  */
12121 static void
12122 fp_login_acc_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf,
12123     job_request_t *job, int sleep)
12124 {
12125 	fc_packet_t	*pkt;
12126 	fc_portmap_t	*listptr;
12127 	la_els_logi_t	payload;
12128 
12129 	ASSERT(buf != NULL);
12130 
12131 	/*
12132 	 * If we are sending ACC to PLOGI and we haven't already
12133 	 * create port and node device handles, let's create them
12134 	 * here.
12135 	 */
12136 	if (buf->ub_buffer[0] == LA_ELS_PLOGI &&
12137 	    FC_IS_REAL_DEVICE(buf->ub_frame.s_id)) {
12138 		int			small;
12139 		int			do_acc;
12140 		fc_remote_port_t	*pd;
12141 		la_els_logi_t		*req;
12142 
12143 		req = (la_els_logi_t *)buf->ub_buffer;
12144 		small = fctl_wwn_cmp(&port->fp_service_params.nport_ww_name,
12145 		    &req->nport_ww_name);
12146 
12147 		mutex_enter(&port->fp_mutex);
12148 		do_acc = (port->fp_statec_busy == 0) ? 1 : 0;
12149 		mutex_exit(&port->fp_mutex);
12150 
12151 		FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_acc_init fp %x, pd %x",
12152 		    port->fp_port_id.port_id, buf->ub_frame.s_id);
12153 		pd = fctl_create_remote_port(port, &req->node_ww_name,
12154 		    &req->nport_ww_name, buf->ub_frame.s_id,
12155 		    PD_PLOGI_RECEPIENT, sleep);
12156 		if (pd == NULL) {
12157 			FP_TRACE(FP_NHEAD1(3, 0), "login_acc_init: "
12158 			    "Couldn't create port device for d_id:0x%x",
12159 			    buf->ub_frame.s_id);
12160 
12161 			fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
12162 			    "couldn't create port device d_id=%x",
12163 			    buf->ub_frame.s_id);
12164 		} else {
12165 			/*
12166 			 * usoc currently returns PLOGIs inline and
12167 			 * the maximum buffer size is 60 bytes or so.
12168 			 * So attempt not to look beyond what is in
12169 			 * the unsolicited buffer
12170 			 *
12171 			 * JNI also traverses this path sometimes
12172 			 */
12173 			if (buf->ub_bufsize >= sizeof (la_els_logi_t)) {
12174 				fp_register_login(NULL, pd, req, buf->ub_class);
12175 			} else {
12176 				mutex_enter(&pd->pd_mutex);
12177 				if (pd->pd_login_count == 0) {
12178 					pd->pd_login_count++;
12179 				}
12180 				pd->pd_state = PORT_DEVICE_LOGGED_IN;
12181 				pd->pd_login_class = buf->ub_class;
12182 				mutex_exit(&pd->pd_mutex);
12183 			}
12184 
12185 			listptr = kmem_zalloc(sizeof (fc_portmap_t), sleep);
12186 			if (listptr != NULL) {
12187 				fctl_copy_portmap(listptr, pd);
12188 				(void) fp_ulp_devc_cb(port, listptr,
12189 				    1, 1, sleep, 0);
12190 			}
12191 
12192 			if (small > 0 && do_acc) {
12193 				mutex_enter(&pd->pd_mutex);
12194 				pd->pd_recepient = PD_PLOGI_INITIATOR;
12195 				mutex_exit(&pd->pd_mutex);
12196 			}
12197 		}
12198 	}
12199 
12200 	cmd->cmd_pkt.pkt_tran_flags = buf->ub_class;
12201 	cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND;
12202 	cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
12203 	cmd->cmd_retry_count = 1;
12204 	cmd->cmd_ulp_pkt = NULL;
12205 
12206 	cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
12207 	cmd->cmd_job = job;
12208 
12209 	pkt = &cmd->cmd_pkt;
12210 
12211 	fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP, FC_TYPE_EXTENDED_LS);
12212 
12213 	payload = port->fp_service_params;
12214 	payload.ls_code.ls_code = LA_ELS_ACC;
12215 
12216 	FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
12217 	    (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
12218 
12219 	FP_TRACE(FP_NHEAD1(3, 0), "login_acc_init: ELS:0x%x d_id:0x%x "
12220 	    "bufsize:0x%x sizeof (la_els_logi):0x%x "
12221 	    "port's wwn:0x%01x%03x%04x%08x requestor's wwn:0x%01x%03x%04x%08x "
12222 	    "statec_busy:0x%x", buf->ub_buffer[0], buf->ub_frame.s_id,
12223 	    buf->ub_bufsize, sizeof (la_els_logi_t),
12224 	    port->fp_service_params.nport_ww_name.w.naa_id,
12225 	    port->fp_service_params.nport_ww_name.w.nport_id,
12226 	    port->fp_service_params.nport_ww_name.w.wwn_hi,
12227 	    port->fp_service_params.nport_ww_name.w.wwn_lo,
12228 	    ((la_els_logi_t *)buf->ub_buffer)->nport_ww_name.w.naa_id,
12229 	    ((la_els_logi_t *)buf->ub_buffer)->nport_ww_name.w.nport_id,
12230 	    ((la_els_logi_t *)buf->ub_buffer)->nport_ww_name.w.wwn_hi,
12231 	    ((la_els_logi_t *)buf->ub_buffer)->nport_ww_name.w.wwn_lo,
12232 	    port->fp_statec_busy);
12233 }
12234 
12235 
12236 #define	RSCN_EVENT_NAME_LEN	256
12237 
12238 /*
12239  * Handle RSCNs
12240  */
12241 static void
12242 fp_handle_unsol_rscn(fc_local_port_t *port, fc_unsol_buf_t *buf,
12243     job_request_t *job, int sleep)
12244 {
12245 	uint32_t		mask;
12246 	fp_cmd_t		*cmd;
12247 	uint32_t		count;
12248 	int			listindex;
12249 	int16_t			len;
12250 	fc_rscn_t		*payload;
12251 	fc_portmap_t		*listptr;
12252 	fctl_ns_req_t		*ns_cmd;
12253 	fc_affected_id_t	*page;
12254 	caddr_t			nvname;
12255 	nvlist_t		*attr_list = NULL;
12256 
12257 	mutex_enter(&port->fp_mutex);
12258 	if (!FC_IS_TOP_SWITCH(port->fp_topology)) {
12259 		if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
12260 			--port->fp_rscn_count;
12261 		}
12262 		mutex_exit(&port->fp_mutex);
12263 		return;
12264 	}
12265 	mutex_exit(&port->fp_mutex);
12266 
12267 	cmd = fp_alloc_pkt(port, FP_PORT_IDENTIFIER_LEN, 0, sleep, NULL);
12268 	if (cmd != NULL) {
12269 		fp_els_acc_init(port, cmd, buf, job);
12270 		if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
12271 			fp_free_pkt(cmd);
12272 		}
12273 	}
12274 
12275 	payload = (fc_rscn_t *)buf->ub_buffer;
12276 	ASSERT(payload->rscn_code == LA_ELS_RSCN);
12277 	ASSERT(payload->rscn_len == FP_PORT_IDENTIFIER_LEN);
12278 
12279 	len = payload->rscn_payload_len - FP_PORT_IDENTIFIER_LEN;
12280 
12281 	if (len <= 0) {
12282 		mutex_enter(&port->fp_mutex);
12283 		if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
12284 			--port->fp_rscn_count;
12285 		}
12286 		mutex_exit(&port->fp_mutex);
12287 
12288 		return;
12289 	}
12290 
12291 	ASSERT((len & 0x3) == 0);	/* Must be power of 4 */
12292 	count = (len >> 2) << 1;	/* number of pages multiplied by 2 */
12293 
12294 	listptr = kmem_zalloc(sizeof (fc_portmap_t) * count, sleep);
12295 	page = (fc_affected_id_t *)(buf->ub_buffer + sizeof (fc_rscn_t));
12296 
12297 	ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
12298 
12299 	ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gpn_id_t),
12300 	    sizeof (ns_resp_gpn_id_t), sizeof (ns_resp_gpn_id_t),
12301 	    0, sleep);
12302 	if (ns_cmd == NULL) {
12303 		kmem_free(listptr, sizeof (fc_portmap_t) * count);
12304 
12305 		mutex_enter(&port->fp_mutex);
12306 		if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
12307 			--port->fp_rscn_count;
12308 		}
12309 		mutex_exit(&port->fp_mutex);
12310 
12311 		return;
12312 	}
12313 
12314 	ns_cmd->ns_cmd_code = NS_GPN_ID;
12315 
12316 	FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_rscn: s_id=%x, d_id=%x,"
12317 	    "type=%x, f_ctl=%x seq_id=%x, ox_id=%x, rx_id=%x"
12318 	    " ro=%x", buf->ub_frame.s_id, buf->ub_frame.d_id,
12319 	    buf->ub_frame.type, buf->ub_frame.f_ctl, buf->ub_frame.seq_id,
12320 	    buf->ub_frame.ox_id, buf->ub_frame.rx_id, buf->ub_frame.ro);
12321 
12322 	/* Only proceed if we can allocate nvname and the nvlist */
12323 	if ((nvname = kmem_zalloc(RSCN_EVENT_NAME_LEN, KM_NOSLEEP)) != NULL &&
12324 	    nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE,
12325 	    KM_NOSLEEP) == DDI_SUCCESS) {
12326 		if (!(attr_list && nvlist_add_uint32(attr_list, "instance",
12327 		    port->fp_instance) == DDI_SUCCESS &&
12328 		    nvlist_add_byte_array(attr_list, "port-wwn",
12329 		    port->fp_service_params.nport_ww_name.raw_wwn,
12330 		    sizeof (la_wwn_t)) == DDI_SUCCESS)) {
12331 			nvlist_free(attr_list);
12332 			attr_list = NULL;
12333 		}
12334 	}
12335 
12336 	for (listindex = 0; len; len -= FP_PORT_IDENTIFIER_LEN, page++) {
12337 		/* Add affected page to the event payload */
12338 		if (attr_list != NULL) {
12339 			(void) snprintf(nvname, RSCN_EVENT_NAME_LEN,
12340 			    "affected_page_%d", listindex);
12341 			if (attr_list && nvlist_add_uint32(attr_list, nvname,
12342 			    ntohl(*(uint32_t *)page)) != DDI_SUCCESS) {
12343 				/* We don't send a partial event, so dump it */
12344 				nvlist_free(attr_list);
12345 				attr_list = NULL;
12346 			}
12347 		}
12348 		/*
12349 		 * Query the NS to get the Port WWN for this
12350 		 * affected D_ID.
12351 		 */
12352 		mask = 0;
12353 		switch (page->aff_format & FC_RSCN_ADDRESS_MASK) {
12354 		case FC_RSCN_PORT_ADDRESS:
12355 			fp_validate_rscn_page(port, page, job, ns_cmd,
12356 			    listptr, &listindex, sleep);
12357 
12358 			if (listindex == 0) {
12359 				/*
12360 				 * We essentially did not process this RSCN. So,
12361 				 * ULPs are not going to be called and so we
12362 				 * decrement the rscn_count
12363 				 */
12364 				mutex_enter(&port->fp_mutex);
12365 				if (--port->fp_rscn_count ==
12366 				    FC_INVALID_RSCN_COUNT) {
12367 					--port->fp_rscn_count;
12368 				}
12369 				mutex_exit(&port->fp_mutex);
12370 			}
12371 			break;
12372 
12373 		case FC_RSCN_AREA_ADDRESS:
12374 			mask = 0xFFFF00;
12375 			/* FALLTHROUGH */
12376 
12377 		case FC_RSCN_DOMAIN_ADDRESS:
12378 			if (!mask) {
12379 				mask = 0xFF0000;
12380 			}
12381 			fp_validate_area_domain(port, page->aff_d_id, mask,
12382 			    job, sleep);
12383 			break;
12384 
12385 		case FC_RSCN_FABRIC_ADDRESS:
12386 			/*
12387 			 * We need to discover all the devices on this
12388 			 * port.
12389 			 */
12390 			fp_validate_area_domain(port, 0, 0, job, sleep);
12391 			break;
12392 
12393 		default:
12394 			break;
12395 		}
12396 	}
12397 	if (attr_list != NULL) {
12398 		(void) ddi_log_sysevent(port->fp_port_dip, DDI_VENDOR_SUNW,
12399 		    EC_SUNFC, ESC_SUNFC_PORT_RSCN, attr_list,
12400 		    NULL, DDI_SLEEP);
12401 		nvlist_free(attr_list);
12402 	} else {
12403 		FP_TRACE(FP_NHEAD1(9, 0),
12404 		    "RSCN handled, but event not sent to userland");
12405 	}
12406 	if (nvname != NULL) {
12407 		kmem_free(nvname, RSCN_EVENT_NAME_LEN);
12408 	}
12409 
12410 	if (ns_cmd) {
12411 		fctl_free_ns_cmd(ns_cmd);
12412 	}
12413 
12414 	if (listindex) {
12415 #ifdef	DEBUG
12416 		page = (fc_affected_id_t *)(buf->ub_buffer +
12417 		    sizeof (fc_rscn_t));
12418 
12419 		if (listptr->map_did.port_id != page->aff_d_id) {
12420 			FP_TRACE(FP_NHEAD1(9, 0),
12421 			    "PORT RSCN: processed=%x, reporting=%x",
12422 			    listptr->map_did.port_id, page->aff_d_id);
12423 		}
12424 #endif
12425 
12426 		(void) fp_ulp_devc_cb(port, listptr, listindex, count,
12427 		    sleep, 0);
12428 	} else {
12429 		kmem_free(listptr, sizeof (fc_portmap_t) * count);
12430 	}
12431 }
12432 
12433 
12434 /*
12435  * Fill out old map for ULPs with fp_mutex, fd_mutex and pd_mutex held
12436  */
12437 static void
12438 fp_fillout_old_map_held(fc_portmap_t *map, fc_remote_port_t *pd, uchar_t flag)
12439 {
12440 	int		is_switch;
12441 	int		initiator;
12442 	fc_local_port_t	*port;
12443 
12444 	port = pd->pd_port;
12445 
12446 	/* This function has the following bunch of assumptions */
12447 	ASSERT(port != NULL);
12448 	ASSERT(MUTEX_HELD(&port->fp_mutex));
12449 	ASSERT(MUTEX_HELD(&pd->pd_remote_nodep->fd_mutex));
12450 	ASSERT(MUTEX_HELD(&pd->pd_mutex));
12451 
12452 	pd->pd_state = PORT_DEVICE_INVALID;
12453 	pd->pd_type = PORT_DEVICE_OLD;
12454 	initiator = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0;
12455 	is_switch = FC_IS_TOP_SWITCH(port->fp_topology);
12456 
12457 	fctl_delist_did_table(port, pd);
12458 	fctl_delist_pwwn_table(port, pd);
12459 
12460 	FP_TRACE(FP_NHEAD1(6, 0), "fp_fillout_old_map_held: port=%p, d_id=%x"
12461 	    " removed the PD=%p from DID and PWWN tables",
12462 	    port, pd->pd_port_id.port_id, pd);
12463 
12464 	if ((!flag) && port && initiator && is_switch) {
12465 		(void) fctl_add_orphan_held(port, pd);
12466 	}
12467 	fctl_copy_portmap_held(map, pd);
12468 	map->map_pd = pd;
12469 }
12470 
12471 /*
12472  * Fill out old map for ULPs
12473  */
12474 static void
12475 fp_fillout_old_map(fc_portmap_t *map, fc_remote_port_t *pd, uchar_t flag)
12476 {
12477 	int		is_switch;
12478 	int		initiator;
12479 	fc_local_port_t	*port;
12480 
12481 	mutex_enter(&pd->pd_mutex);
12482 	port = pd->pd_port;
12483 	mutex_exit(&pd->pd_mutex);
12484 
12485 	mutex_enter(&port->fp_mutex);
12486 	mutex_enter(&pd->pd_mutex);
12487 
12488 	pd->pd_state = PORT_DEVICE_INVALID;
12489 	pd->pd_type = PORT_DEVICE_OLD;
12490 	initiator = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0;
12491 	is_switch = FC_IS_TOP_SWITCH(port->fp_topology);
12492 
12493 	fctl_delist_did_table(port, pd);
12494 	fctl_delist_pwwn_table(port, pd);
12495 
12496 	FP_TRACE(FP_NHEAD1(6, 0), "fp_fillout_old_map: port=%p, d_id=%x"
12497 	    " removed the PD=%p from DID and PWWN tables",
12498 	    port, pd->pd_port_id.port_id, pd);
12499 
12500 	mutex_exit(&pd->pd_mutex);
12501 	mutex_exit(&port->fp_mutex);
12502 
12503 	ASSERT(port != NULL);
12504 	if ((!flag) && port && initiator && is_switch) {
12505 		(void) fctl_add_orphan(port, pd, KM_NOSLEEP);
12506 	}
12507 	fctl_copy_portmap(map, pd);
12508 	map->map_pd = pd;
12509 }
12510 
12511 
12512 /*
12513  * Fillout Changed Map for ULPs
12514  */
12515 static void
12516 fp_fillout_changed_map(fc_portmap_t *map, fc_remote_port_t *pd,
12517     uint32_t *new_did, la_wwn_t *new_pwwn)
12518 {
12519 	ASSERT(MUTEX_HELD(&pd->pd_mutex));
12520 
12521 	pd->pd_type = PORT_DEVICE_CHANGED;
12522 	if (new_did) {
12523 		pd->pd_port_id.port_id = *new_did;
12524 	}
12525 	if (new_pwwn) {
12526 		pd->pd_port_name = *new_pwwn;
12527 	}
12528 	mutex_exit(&pd->pd_mutex);
12529 
12530 	fctl_copy_portmap(map, pd);
12531 
12532 	mutex_enter(&pd->pd_mutex);
12533 	pd->pd_type = PORT_DEVICE_NOCHANGE;
12534 }
12535 
12536 
12537 /*
12538  * Fillout New Name Server map
12539  */
12540 static void
12541 fp_fillout_new_nsmap(fc_local_port_t *port, ddi_acc_handle_t *handle,
12542     fc_portmap_t *port_map, ns_resp_gan_t *gan_resp, uint32_t d_id)
12543 {
12544 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
12545 
12546 	if (handle) {
12547 		FC_GET_RSP(port, *handle, (uint8_t *)&port_map->map_pwwn,
12548 		    (uint8_t *)&gan_resp->gan_pwwn, sizeof (gan_resp->gan_pwwn),
12549 		    DDI_DEV_AUTOINCR);
12550 		FC_GET_RSP(port, *handle, (uint8_t *)&port_map->map_nwwn,
12551 		    (uint8_t *)&gan_resp->gan_nwwn, sizeof (gan_resp->gan_nwwn),
12552 		    DDI_DEV_AUTOINCR);
12553 		FC_GET_RSP(port, *handle, (uint8_t *)port_map->map_fc4_types,
12554 		    (uint8_t *)gan_resp->gan_fc4types,
12555 		    sizeof (gan_resp->gan_fc4types), DDI_DEV_AUTOINCR);
12556 	} else {
12557 		bcopy(&gan_resp->gan_pwwn, &port_map->map_pwwn,
12558 		    sizeof (gan_resp->gan_pwwn));
12559 		bcopy(&gan_resp->gan_nwwn, &port_map->map_nwwn,
12560 		    sizeof (gan_resp->gan_nwwn));
12561 		bcopy(gan_resp->gan_fc4types, port_map->map_fc4_types,
12562 		    sizeof (gan_resp->gan_fc4types));
12563 	}
12564 	port_map->map_did.port_id = d_id;
12565 	port_map->map_did.priv_lilp_posit = 0;
12566 	port_map->map_hard_addr.hard_addr = 0;
12567 	port_map->map_hard_addr.rsvd = 0;
12568 	port_map->map_state = PORT_DEVICE_INVALID;
12569 	port_map->map_type = PORT_DEVICE_NEW;
12570 	port_map->map_flags = 0;
12571 	port_map->map_pd = NULL;
12572 
12573 	(void) fctl_remove_if_orphan(port, &port_map->map_pwwn);
12574 
12575 	ASSERT(port != NULL);
12576 }
12577 
12578 
12579 /*
12580  * Perform LINIT ELS
12581  */
12582 static int
12583 fp_remote_lip(fc_local_port_t *port, la_wwn_t *pwwn, int sleep,
12584     job_request_t *job)
12585 {
12586 	int			rval;
12587 	uint32_t		d_id;
12588 	uint32_t		s_id;
12589 	uint32_t		lfa;
12590 	uchar_t			class;
12591 	uint32_t		ret;
12592 	fp_cmd_t		*cmd;
12593 	fc_porttype_t		ptype;
12594 	fc_packet_t		*pkt;
12595 	fc_linit_req_t		payload;
12596 	fc_remote_port_t	*pd;
12597 
12598 	rval = 0;
12599 
12600 	ASSERT(job != NULL);
12601 	ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
12602 
12603 	pd = fctl_get_remote_port_by_pwwn(port, pwwn);
12604 	if (pd == NULL) {
12605 		fctl_ns_req_t *ns_cmd;
12606 
12607 		ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t),
12608 		    sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t),
12609 		    0, sleep);
12610 
12611 		if (ns_cmd == NULL) {
12612 			return (FC_NOMEM);
12613 		}
12614 		job->job_result = FC_SUCCESS;
12615 		ns_cmd->ns_cmd_code = NS_GID_PN;
12616 		((ns_req_gid_pn_t *)(ns_cmd->ns_cmd_buf))->pwwn = *pwwn;
12617 
12618 		ret = fp_ns_query(port, ns_cmd, job, 1, sleep);
12619 		if (ret != FC_SUCCESS || job->job_result != FC_SUCCESS) {
12620 			fctl_free_ns_cmd(ns_cmd);
12621 			return (FC_FAILURE);
12622 		}
12623 		bcopy(ns_cmd->ns_data_buf, (caddr_t)&d_id, sizeof (d_id));
12624 		d_id = BE_32(*((uint32_t *)ns_cmd->ns_data_buf));
12625 
12626 		fctl_free_ns_cmd(ns_cmd);
12627 		lfa = d_id & 0xFFFF00;
12628 
12629 		/*
12630 		 * Given this D_ID, get the port type to see if
12631 		 * we can do LINIT on the LFA
12632 		 */
12633 		ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gpt_id_t),
12634 		    sizeof (ns_resp_gpt_id_t), sizeof (ns_resp_gpt_id_t),
12635 		    0, sleep);
12636 
12637 		if (ns_cmd == NULL) {
12638 			return (FC_NOMEM);
12639 		}
12640 
12641 		job->job_result = FC_SUCCESS;
12642 		ns_cmd->ns_cmd_code = NS_GPT_ID;
12643 
12644 		((ns_req_gpt_id_t *)(ns_cmd->ns_cmd_buf))->pid.port_id = d_id;
12645 		((ns_req_gpt_id_t *)
12646 		    (ns_cmd->ns_cmd_buf))->pid.priv_lilp_posit = 0;
12647 
12648 		ret = fp_ns_query(port, ns_cmd, job, 1, sleep);
12649 		if (ret != FC_SUCCESS || job->job_result != FC_SUCCESS) {
12650 			fctl_free_ns_cmd(ns_cmd);
12651 			return (FC_FAILURE);
12652 		}
12653 		bcopy(ns_cmd->ns_data_buf, (caddr_t)&ptype, sizeof (ptype));
12654 
12655 		fctl_free_ns_cmd(ns_cmd);
12656 
12657 		switch (ptype.port_type) {
12658 		case FC_NS_PORT_NL:
12659 		case FC_NS_PORT_F_NL:
12660 		case FC_NS_PORT_FL:
12661 			break;
12662 
12663 		default:
12664 			return (FC_FAILURE);
12665 		}
12666 	} else {
12667 		mutex_enter(&pd->pd_mutex);
12668 		ptype = pd->pd_porttype;
12669 
12670 		switch (pd->pd_porttype.port_type) {
12671 		case FC_NS_PORT_NL:
12672 		case FC_NS_PORT_F_NL:
12673 		case FC_NS_PORT_FL:
12674 			lfa = pd->pd_port_id.port_id & 0xFFFF00;
12675 			break;
12676 
12677 		default:
12678 			mutex_exit(&pd->pd_mutex);
12679 			return (FC_FAILURE);
12680 		}
12681 		mutex_exit(&pd->pd_mutex);
12682 	}
12683 
12684 	mutex_enter(&port->fp_mutex);
12685 	s_id = port->fp_port_id.port_id;
12686 	class = port->fp_ns_login_class;
12687 	mutex_exit(&port->fp_mutex);
12688 
12689 	cmd = fp_alloc_pkt(port, sizeof (fc_linit_req_t),
12690 	    sizeof (fc_linit_resp_t), sleep, pd);
12691 	if (cmd == NULL) {
12692 		return (FC_NOMEM);
12693 	}
12694 
12695 	cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class;
12696 	cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
12697 	cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
12698 	cmd->cmd_retry_count = fp_retry_count;
12699 	cmd->cmd_ulp_pkt = NULL;
12700 
12701 	pkt = &cmd->cmd_pkt;
12702 	cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
12703 
12704 	fp_els_init(cmd, s_id, lfa, fp_linit_intr, job);
12705 
12706 	/*
12707 	 * How does LIP work by the way ?
12708 	 *	If the L_Port receives three consecutive identical ordered
12709 	 *	sets whose first two characters (fully decoded) are equal to
12710 	 *	the values shown in Table 3 of FC-AL-2 then the L_Port shall
12711 	 *	recognize a Loop Initialization Primitive sequence. The
12712 	 *	character 3 determines the type of lip:
12713 	 *		LIP(F7)		Normal LIP
12714 	 *		LIP(F8)		Loop Failure LIP
12715 	 *
12716 	 * The possible combination for the 3rd and 4th bytes are:
12717 	 *	F7,	F7	Normal Lip	- No valid AL_PA
12718 	 *	F8,	F8	Loop Failure	- No valid AL_PA
12719 	 *	F7,	AL_PS	Normal Lip	- Valid source AL_PA
12720 	 *	F8,	AL_PS	Loop Failure	- Valid source AL_PA
12721 	 *	AL_PD	AL_PS	Loop reset of AL_PD originated by AL_PS
12722 	 *			And Normal Lip for all other loop members
12723 	 *	0xFF	AL_PS	Vendor specific reset of all loop members
12724 	 *
12725 	 * Now, it may not always be that we, at the source, may have an
12726 	 * AL_PS (AL_PA of source) for 4th character slot, so we decide
12727 	 * to do (Normal Lip, No Valid AL_PA), that means, in the LINIT
12728 	 * payload we are going to set:
12729 	 *	lip_b3 = 0xF7;		Normal LIP
12730 	 *	lip_b4 = 0xF7;		No valid source AL_PA
12731 	 */
12732 	payload.ls_code.ls_code = LA_ELS_LINIT;
12733 	payload.ls_code.mbz = 0;
12734 	payload.rsvd = 0;
12735 	payload.func = 0;		/* Let Fabric determine the best way */
12736 	payload.lip_b3 = 0xF7;		/* Normal LIP */
12737 	payload.lip_b4 = 0xF7;		/* No valid source AL_PA */
12738 
12739 	FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
12740 	    (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
12741 
12742 	job->job_counter = 1;
12743 
12744 	ret = fp_sendcmd(port, cmd, port->fp_fca_handle);
12745 	if (ret == FC_SUCCESS) {
12746 		fp_jobwait(job);
12747 		rval = job->job_result;
12748 	} else {
12749 		rval = FC_FAILURE;
12750 		fp_free_pkt(cmd);
12751 	}
12752 
12753 	return (rval);
12754 }
12755 
12756 
12757 /*
12758  * Fill out the device handles with GAN response
12759  */
12760 static void
12761 fp_stuff_device_with_gan(ddi_acc_handle_t *handle, fc_remote_port_t *pd,
12762     ns_resp_gan_t *gan_resp)
12763 {
12764 	fc_remote_node_t	*node;
12765 	fc_porttype_t		type;
12766 	fc_local_port_t		*port;
12767 
12768 	ASSERT(pd != NULL);
12769 	ASSERT(handle != NULL);
12770 
12771 	port = pd->pd_port;
12772 
12773 	FP_TRACE(FP_NHEAD1(1, 0), "GAN PD stuffing; pd=%p,"
12774 	    " port_id=%x, sym_len=%d fc4-type=%x",
12775 	    pd, gan_resp->gan_type_id.rsvd,
12776 	    gan_resp->gan_spnlen, gan_resp->gan_fc4types[0]);
12777 
12778 	mutex_enter(&pd->pd_mutex);
12779 
12780 	FC_GET_RSP(port, *handle, (uint8_t *)&type,
12781 	    (uint8_t *)&gan_resp->gan_type_id, sizeof (type), DDI_DEV_AUTOINCR);
12782 
12783 	pd->pd_porttype.port_type = type.port_type;
12784 	pd->pd_porttype.rsvd = 0;
12785 
12786 	pd->pd_spn_len = gan_resp->gan_spnlen;
12787 	if (pd->pd_spn_len) {
12788 		FC_GET_RSP(port, *handle, (uint8_t *)pd->pd_spn,
12789 		    (uint8_t *)gan_resp->gan_spname, pd->pd_spn_len,
12790 		    DDI_DEV_AUTOINCR);
12791 	}
12792 
12793 	FC_GET_RSP(port, *handle, (uint8_t *)pd->pd_ip_addr,
12794 	    (uint8_t *)gan_resp->gan_ip, sizeof (pd->pd_ip_addr),
12795 	    DDI_DEV_AUTOINCR);
12796 	FC_GET_RSP(port, *handle, (uint8_t *)&pd->pd_cos,
12797 	    (uint8_t *)&gan_resp->gan_cos, sizeof (pd->pd_cos),
12798 	    DDI_DEV_AUTOINCR);
12799 	FC_GET_RSP(port, *handle, (uint8_t *)pd->pd_fc4types,
12800 	    (uint8_t *)gan_resp->gan_fc4types, sizeof (pd->pd_fc4types),
12801 	    DDI_DEV_AUTOINCR);
12802 
12803 	node = pd->pd_remote_nodep;
12804 	mutex_exit(&pd->pd_mutex);
12805 
12806 	mutex_enter(&node->fd_mutex);
12807 
12808 	FC_GET_RSP(port, *handle, (uint8_t *)node->fd_ipa,
12809 	    (uint8_t *)gan_resp->gan_ipa, sizeof (node->fd_ipa),
12810 	    DDI_DEV_AUTOINCR);
12811 
12812 	node->fd_snn_len = gan_resp->gan_snnlen;
12813 	if (node->fd_snn_len) {
12814 		FC_GET_RSP(port, *handle, (uint8_t *)node->fd_snn,
12815 		    (uint8_t *)gan_resp->gan_snname, node->fd_snn_len,
12816 		    DDI_DEV_AUTOINCR);
12817 	}
12818 
12819 	mutex_exit(&node->fd_mutex);
12820 }
12821 
12822 
12823 /*
12824  * Handles all NS Queries (also means that this function
12825  * doesn't handle NS object registration)
12826  */
12827 static int
12828 fp_ns_query(fc_local_port_t *port, fctl_ns_req_t *ns_cmd, job_request_t *job,
12829     int polled, int sleep)
12830 {
12831 	int		rval;
12832 	fp_cmd_t	*cmd;
12833 
12834 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
12835 
12836 	if (ns_cmd->ns_cmd_code == NS_GA_NXT) {
12837 		FP_TRACE(FP_NHEAD1(1, 0), "fp_ns_query GA_NXT fp %x pd %x",
12838 		    port->fp_port_id.port_id, ns_cmd->ns_gan_sid);
12839 	}
12840 
12841 	if (ns_cmd->ns_cmd_size == 0) {
12842 		return (FC_FAILURE);
12843 	}
12844 
12845 	cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
12846 	    ns_cmd->ns_cmd_size, sizeof (fc_ct_header_t) +
12847 	    ns_cmd->ns_resp_size, sleep, NULL);
12848 	if (cmd == NULL) {
12849 		return (FC_NOMEM);
12850 	}
12851 
12852 	fp_ct_init(port, cmd, ns_cmd, ns_cmd->ns_cmd_code, ns_cmd->ns_cmd_buf,
12853 	    ns_cmd->ns_cmd_size, ns_cmd->ns_resp_size, job);
12854 
12855 	if (polled) {
12856 		job->job_counter = 1;
12857 		ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
12858 	}
12859 	rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
12860 	if (rval != FC_SUCCESS) {
12861 		job->job_result = rval;
12862 		fp_iodone(cmd);
12863 		if (polled == 0) {
12864 			/*
12865 			 * Return FC_SUCCESS to indicate that
12866 			 * fp_iodone is performed already.
12867 			 */
12868 			rval = FC_SUCCESS;
12869 		}
12870 	}
12871 
12872 	if (polled) {
12873 		fp_jobwait(job);
12874 		rval = job->job_result;
12875 	}
12876 
12877 	return (rval);
12878 }
12879 
12880 
12881 /*
12882  * Initialize Common Transport request
12883  */
12884 static void
12885 fp_ct_init(fc_local_port_t *port, fp_cmd_t *cmd, fctl_ns_req_t *ns_cmd,
12886     uint16_t cmd_code, caddr_t cmd_buf, uint16_t cmd_len,
12887     uint16_t resp_len, job_request_t *job)
12888 {
12889 	uint32_t	s_id;
12890 	uchar_t		class;
12891 	fc_packet_t	*pkt;
12892 	fc_ct_header_t	ct;
12893 
12894 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
12895 
12896 	mutex_enter(&port->fp_mutex);
12897 	s_id = port->fp_port_id.port_id;
12898 	class = port->fp_ns_login_class;
12899 	mutex_exit(&port->fp_mutex);
12900 
12901 	cmd->cmd_job = job;
12902 	cmd->cmd_private = ns_cmd;
12903 	pkt = &cmd->cmd_pkt;
12904 
12905 	ct.ct_rev = CT_REV;
12906 	ct.ct_inid = 0;
12907 	ct.ct_fcstype = FCSTYPE_DIRECTORY;
12908 	ct.ct_fcssubtype = FCSSUB_DS_NAME_SERVER;
12909 	ct.ct_options = 0;
12910 	ct.ct_reserved1 = 0;
12911 	ct.ct_cmdrsp = cmd_code;
12912 	ct.ct_aiusize = resp_len >> 2;
12913 	ct.ct_reserved2 = 0;
12914 	ct.ct_reason = 0;
12915 	ct.ct_expln = 0;
12916 	ct.ct_vendor = 0;
12917 
12918 	FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&ct,
12919 	    (uint8_t *)pkt->pkt_cmd, sizeof (ct), DDI_DEV_AUTOINCR);
12920 
12921 	pkt->pkt_cmd_fhdr.r_ctl = R_CTL_UNSOL_CONTROL;
12922 	pkt->pkt_cmd_fhdr.d_id = 0xFFFFFC;
12923 	pkt->pkt_cmd_fhdr.s_id = s_id;
12924 	pkt->pkt_cmd_fhdr.type = FC_TYPE_FC_SERVICES;
12925 	pkt->pkt_cmd_fhdr.f_ctl = F_CTL_SEQ_INITIATIVE |
12926 	    F_CTL_FIRST_SEQ | F_CTL_END_SEQ;
12927 	pkt->pkt_cmd_fhdr.seq_id = 0;
12928 	pkt->pkt_cmd_fhdr.df_ctl  = 0;
12929 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
12930 	pkt->pkt_cmd_fhdr.ox_id = 0xffff;
12931 	pkt->pkt_cmd_fhdr.rx_id = 0xffff;
12932 	pkt->pkt_cmd_fhdr.ro = 0;
12933 	pkt->pkt_cmd_fhdr.rsvd = 0;
12934 
12935 	pkt->pkt_comp = fp_ns_intr;
12936 	pkt->pkt_ulp_private = (opaque_t)cmd;
12937 	pkt->pkt_timeout = FP_NS_TIMEOUT;
12938 
12939 	if (cmd_buf) {
12940 		FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)cmd_buf,
12941 		    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
12942 		    cmd_len, DDI_DEV_AUTOINCR);
12943 	}
12944 
12945 	cmd->cmd_transport = port->fp_fca_tran->fca_transport;
12946 
12947 	cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class;
12948 	cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
12949 	cmd->cmd_flags = FP_CMD_PLOGI_DONT_CARE;
12950 	cmd->cmd_retry_count = fp_retry_count;
12951 	cmd->cmd_ulp_pkt = NULL;
12952 }
12953 
12954 
12955 /*
12956  * Name Server request interrupt routine
12957  */
12958 static void
12959 fp_ns_intr(fc_packet_t *pkt)
12960 {
12961 	fp_cmd_t	*cmd;
12962 	fc_local_port_t	*port;
12963 	fc_ct_header_t	resp_hdr;
12964 	fc_ct_header_t	cmd_hdr;
12965 	fctl_ns_req_t	*ns_cmd;
12966 
12967 	cmd = pkt->pkt_ulp_private;
12968 	port = cmd->cmd_port;
12969 
12970 	mutex_enter(&port->fp_mutex);
12971 	port->fp_out_fpcmds--;
12972 	mutex_exit(&port->fp_mutex);
12973 
12974 	FC_GET_RSP(port, pkt->pkt_cmd_acc, (uint8_t *)&cmd_hdr,
12975 	    (uint8_t *)pkt->pkt_cmd, sizeof (cmd_hdr), DDI_DEV_AUTOINCR);
12976 	ns_cmd = (fctl_ns_req_t *)
12977 	    (((fp_cmd_t *)(pkt->pkt_ulp_private))->cmd_private);
12978 	if (!FP_IS_PKT_ERROR(pkt)) {
12979 		FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp_hdr,
12980 		    (uint8_t *)pkt->pkt_resp, sizeof (resp_hdr),
12981 		    DDI_DEV_AUTOINCR);
12982 
12983 		/*
12984 		 * On x86 architectures, make sure the resp_hdr is big endian.
12985 		 * This macro is a NOP on sparc architectures mainly because
12986 		 * we don't want to end up wasting time since the end result
12987 		 * is going to be the same.
12988 		 */
12989 		MAKE_BE_32(&resp_hdr);
12990 
12991 		if (ns_cmd) {
12992 			/*
12993 			 * Always copy out the response CT_HDR
12994 			 */
12995 			bcopy(&resp_hdr, &ns_cmd->ns_resp_hdr,
12996 			    sizeof (resp_hdr));
12997 		}
12998 
12999 		if (resp_hdr.ct_cmdrsp == FS_RJT_IU) {
13000 			pkt->pkt_state = FC_PKT_FS_RJT;
13001 			pkt->pkt_reason = resp_hdr.ct_reason;
13002 			pkt->pkt_expln = resp_hdr.ct_expln;
13003 		}
13004 	}
13005 
13006 	if (FP_IS_PKT_ERROR(pkt)) {
13007 		if (ns_cmd) {
13008 			if (ns_cmd->ns_flags & FCTL_NS_VALIDATE_PD) {
13009 				ASSERT(ns_cmd->ns_pd != NULL);
13010 
13011 				/* Mark it OLD if not already done */
13012 				mutex_enter(&ns_cmd->ns_pd->pd_mutex);
13013 				ns_cmd->ns_pd->pd_type = PORT_DEVICE_OLD;
13014 				mutex_exit(&ns_cmd->ns_pd->pd_mutex);
13015 			}
13016 
13017 			if (ns_cmd->ns_flags & FCTL_NS_ASYNC_REQUEST) {
13018 				fctl_free_ns_cmd(ns_cmd);
13019 				((fp_cmd_t *)
13020 				    (pkt->pkt_ulp_private))->cmd_private = NULL;
13021 			}
13022 
13023 		}
13024 
13025 		FP_TRACE(FP_NHEAD2(9, 0), "%x NS failure pkt state=%x"
13026 		    "reason=%x, expln=%x, NSCMD=%04X, NSRSP=%04X",
13027 		    port->fp_port_id.port_id, pkt->pkt_state,
13028 		    pkt->pkt_reason, pkt->pkt_expln,
13029 		    cmd_hdr.ct_cmdrsp,  resp_hdr.ct_cmdrsp);
13030 
13031 		(void) fp_common_intr(pkt, 1);
13032 
13033 		return;
13034 	}
13035 
13036 	if (resp_hdr.ct_cmdrsp != FS_ACC_IU) {
13037 		uint32_t	d_id;
13038 		fc_local_port_t	*port;
13039 		fp_cmd_t	*cmd;
13040 
13041 		d_id = pkt->pkt_cmd_fhdr.d_id;
13042 		cmd = pkt->pkt_ulp_private;
13043 		port = cmd->cmd_port;
13044 		FP_TRACE(FP_NHEAD2(9, 0),
13045 		    "Bogus NS response received for D_ID=%x", d_id);
13046 	}
13047 
13048 	if (cmd_hdr.ct_cmdrsp == NS_GA_NXT) {
13049 		fp_gan_handler(pkt, ns_cmd);
13050 		return;
13051 	}
13052 
13053 	if (cmd_hdr.ct_cmdrsp >= NS_GPN_ID &&
13054 	    cmd_hdr.ct_cmdrsp <= NS_GID_PT) {
13055 		if (ns_cmd) {
13056 			if ((ns_cmd->ns_flags & FCTL_NS_NO_DATA_BUF) == 0) {
13057 				fp_ns_query_handler(pkt, ns_cmd);
13058 				return;
13059 			}
13060 		}
13061 	}
13062 
13063 	fp_iodone(pkt->pkt_ulp_private);
13064 }
13065 
13066 
13067 /*
13068  * Process NS_GAN response
13069  */
13070 static void
13071 fp_gan_handler(fc_packet_t *pkt, fctl_ns_req_t *ns_cmd)
13072 {
13073 	int			my_did;
13074 	fc_portid_t		d_id;
13075 	fp_cmd_t		*cmd;
13076 	fc_local_port_t		*port;
13077 	fc_remote_port_t	*pd;
13078 	ns_req_gan_t		gan_req;
13079 	ns_resp_gan_t		*gan_resp;
13080 
13081 	ASSERT(ns_cmd != NULL);
13082 
13083 	cmd = pkt->pkt_ulp_private;
13084 	port = cmd->cmd_port;
13085 
13086 	gan_resp = (ns_resp_gan_t *)(pkt->pkt_resp + sizeof (fc_ct_header_t));
13087 
13088 	FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&d_id,
13089 	    (uint8_t *)&gan_resp->gan_type_id, sizeof (d_id), DDI_DEV_AUTOINCR);
13090 
13091 	*(uint32_t *)&d_id = BE_32(*(uint32_t *)&d_id);
13092 
13093 	/*
13094 	 * In this case the priv_lilp_posit field  in reality
13095 	 * is actually represents the relative position on a private loop.
13096 	 * So zero it while dealing with Port Identifiers.
13097 	 */
13098 	d_id.priv_lilp_posit = 0;
13099 	pd = fctl_get_remote_port_by_did(port, d_id.port_id);
13100 	if (ns_cmd->ns_gan_sid == d_id.port_id) {
13101 		/*
13102 		 * We've come a full circle; time to get out.
13103 		 */
13104 		fp_iodone(cmd);
13105 		return;
13106 	}
13107 
13108 	if (ns_cmd->ns_gan_sid == FCTL_GAN_START_ID) {
13109 		ns_cmd->ns_gan_sid = d_id.port_id;
13110 	}
13111 
13112 	mutex_enter(&port->fp_mutex);
13113 	my_did = (d_id.port_id == port->fp_port_id.port_id) ? 1 : 0;
13114 	mutex_exit(&port->fp_mutex);
13115 
13116 	FP_TRACE(FP_NHEAD1(1, 0), "GAN response; port=%p, fp %x pd %x", port,
13117 	    port->fp_port_id.port_id, d_id.port_id);
13118 	if (my_did == 0) {
13119 		la_wwn_t pwwn;
13120 		la_wwn_t nwwn;
13121 
13122 		FP_TRACE(FP_NHEAD1(1, 0), "GAN response details; "
13123 		    "port=%p, d_id=%x, type_id=%x, "
13124 		    "pwwn=%x %x %x %x %x %x %x %x, "
13125 		    "nwwn=%x %x %x %x %x %x %x %x",
13126 		    port, d_id.port_id, gan_resp->gan_type_id,
13127 
13128 		    gan_resp->gan_pwwn.raw_wwn[0],
13129 		    gan_resp->gan_pwwn.raw_wwn[1],
13130 		    gan_resp->gan_pwwn.raw_wwn[2],
13131 		    gan_resp->gan_pwwn.raw_wwn[3],
13132 		    gan_resp->gan_pwwn.raw_wwn[4],
13133 		    gan_resp->gan_pwwn.raw_wwn[5],
13134 		    gan_resp->gan_pwwn.raw_wwn[6],
13135 		    gan_resp->gan_pwwn.raw_wwn[7],
13136 
13137 		    gan_resp->gan_nwwn.raw_wwn[0],
13138 		    gan_resp->gan_nwwn.raw_wwn[1],
13139 		    gan_resp->gan_nwwn.raw_wwn[2],
13140 		    gan_resp->gan_nwwn.raw_wwn[3],
13141 		    gan_resp->gan_nwwn.raw_wwn[4],
13142 		    gan_resp->gan_nwwn.raw_wwn[5],
13143 		    gan_resp->gan_nwwn.raw_wwn[6],
13144 		    gan_resp->gan_nwwn.raw_wwn[7]);
13145 
13146 		FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&nwwn,
13147 		    (uint8_t *)&gan_resp->gan_nwwn, sizeof (nwwn),
13148 		    DDI_DEV_AUTOINCR);
13149 
13150 		FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&pwwn,
13151 		    (uint8_t *)&gan_resp->gan_pwwn, sizeof (pwwn),
13152 		    DDI_DEV_AUTOINCR);
13153 
13154 		if (ns_cmd->ns_flags & FCTL_NS_CREATE_DEVICE && pd == NULL) {
13155 			FP_TRACE(FP_NHEAD1(1, 0), "fp %x gan_hander create"
13156 			    "pd %x", port->fp_port_id.port_id, d_id.port_id);
13157 			pd = fctl_create_remote_port(port, &nwwn, &pwwn,
13158 			    d_id.port_id, PD_PLOGI_INITIATOR, KM_NOSLEEP);
13159 		}
13160 		if (pd != NULL) {
13161 			fp_stuff_device_with_gan(&pkt->pkt_resp_acc,
13162 			    pd, gan_resp);
13163 		}
13164 
13165 		if (ns_cmd->ns_flags & FCTL_NS_GET_DEV_COUNT) {
13166 			*((int *)ns_cmd->ns_data_buf) += 1;
13167 		}
13168 
13169 		if (ns_cmd->ns_flags & FCTL_NS_FILL_NS_MAP) {
13170 			ASSERT((ns_cmd->ns_flags & FCTL_NS_NO_DATA_BUF) == 0);
13171 
13172 			if (ns_cmd->ns_flags & FCTL_NS_BUF_IS_USERLAND) {
13173 				fc_port_dev_t *userbuf;
13174 
13175 				userbuf = ((fc_port_dev_t *)
13176 				    ns_cmd->ns_data_buf) +
13177 				    ns_cmd->ns_gan_index++;
13178 
13179 				userbuf->dev_did = d_id;
13180 
13181 				FC_GET_RSP(port, pkt->pkt_resp_acc,
13182 				    (uint8_t *)userbuf->dev_type,
13183 				    (uint8_t *)gan_resp->gan_fc4types,
13184 				    sizeof (userbuf->dev_type),
13185 				    DDI_DEV_AUTOINCR);
13186 
13187 				userbuf->dev_nwwn = nwwn;
13188 				userbuf->dev_pwwn = pwwn;
13189 
13190 				if (pd != NULL) {
13191 					mutex_enter(&pd->pd_mutex);
13192 					userbuf->dev_state = pd->pd_state;
13193 					userbuf->dev_hard_addr =
13194 					    pd->pd_hard_addr;
13195 					mutex_exit(&pd->pd_mutex);
13196 				} else {
13197 					userbuf->dev_state =
13198 					    PORT_DEVICE_INVALID;
13199 				}
13200 			} else if (ns_cmd->ns_flags &
13201 			    FCTL_NS_BUF_IS_FC_PORTMAP) {
13202 				fc_portmap_t *map;
13203 
13204 				map = ((fc_portmap_t *)
13205 				    ns_cmd->ns_data_buf) +
13206 				    ns_cmd->ns_gan_index++;
13207 
13208 				/*
13209 				 * First fill it like any new map
13210 				 * and update the port device info
13211 				 * below.
13212 				 */
13213 				fp_fillout_new_nsmap(port, &pkt->pkt_resp_acc,
13214 				    map, gan_resp, d_id.port_id);
13215 				if (pd != NULL) {
13216 					fctl_copy_portmap(map, pd);
13217 				} else {
13218 					map->map_state = PORT_DEVICE_INVALID;
13219 					map->map_type = PORT_DEVICE_NOCHANGE;
13220 				}
13221 			} else {
13222 				caddr_t dst_ptr;
13223 
13224 				dst_ptr = ns_cmd->ns_data_buf +
13225 				    (NS_GAN_RESP_LEN) * ns_cmd->ns_gan_index++;
13226 
13227 				FC_GET_RSP(port, pkt->pkt_resp_acc,
13228 				    (uint8_t *)dst_ptr, (uint8_t *)gan_resp,
13229 				    NS_GAN_RESP_LEN, DDI_DEV_AUTOINCR);
13230 			}
13231 		} else {
13232 			ns_cmd->ns_gan_index++;
13233 		}
13234 		if (ns_cmd->ns_gan_index >= ns_cmd->ns_gan_max) {
13235 			fp_iodone(cmd);
13236 			return;
13237 		}
13238 	}
13239 
13240 	gan_req.pid = d_id;
13241 
13242 	FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&gan_req,
13243 	    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
13244 	    sizeof (gan_req), DDI_DEV_AUTOINCR);
13245 
13246 	if (cmd->cmd_transport(port->fp_fca_handle, pkt) != FC_SUCCESS) {
13247 		pkt->pkt_state = FC_PKT_TRAN_ERROR;
13248 		fp_iodone(cmd);
13249 	} else {
13250 		mutex_enter(&port->fp_mutex);
13251 		port->fp_out_fpcmds++;
13252 		mutex_exit(&port->fp_mutex);
13253 	}
13254 }
13255 
13256 
13257 /*
13258  * Handle NS Query interrupt
13259  */
13260 static void
13261 fp_ns_query_handler(fc_packet_t *pkt, fctl_ns_req_t *ns_cmd)
13262 {
13263 	fp_cmd_t	*cmd;
13264 	fc_local_port_t	*port;
13265 	caddr_t		src_ptr;
13266 	uint32_t	xfer_len;
13267 
13268 	cmd = pkt->pkt_ulp_private;
13269 	port = cmd->cmd_port;
13270 
13271 	xfer_len = ns_cmd->ns_resp_size;
13272 
13273 	FP_TRACE(FP_NHEAD1(1, 0), "NS Query response, cmd_code=%x, xfer_len=%x",
13274 	    ns_cmd->ns_cmd_code, xfer_len);
13275 
13276 	if (ns_cmd->ns_cmd_code == NS_GPN_ID) {
13277 		src_ptr = (caddr_t)pkt->pkt_resp + sizeof (fc_ct_header_t);
13278 
13279 		FP_TRACE(FP_NHEAD1(6, 0), "GPN_ID results; %x %x %x %x %x",
13280 		    src_ptr[0], src_ptr[1], src_ptr[2], src_ptr[3], src_ptr[4]);
13281 	}
13282 
13283 	if (xfer_len <= ns_cmd->ns_data_len) {
13284 		src_ptr = (caddr_t)pkt->pkt_resp + sizeof (fc_ct_header_t);
13285 		FC_GET_RSP(port, pkt->pkt_resp_acc,
13286 		    (uint8_t *)ns_cmd->ns_data_buf,
13287 		    (uint8_t *)src_ptr, xfer_len, DDI_DEV_AUTOINCR);
13288 	}
13289 
13290 	if (ns_cmd->ns_flags & FCTL_NS_VALIDATE_PD) {
13291 		ASSERT(ns_cmd->ns_pd != NULL);
13292 
13293 		mutex_enter(&ns_cmd->ns_pd->pd_mutex);
13294 		if (ns_cmd->ns_pd->pd_type == PORT_DEVICE_OLD) {
13295 			ns_cmd->ns_pd->pd_type = PORT_DEVICE_NOCHANGE;
13296 		}
13297 		mutex_exit(&ns_cmd->ns_pd->pd_mutex);
13298 	}
13299 
13300 	if (ns_cmd->ns_flags & FCTL_NS_ASYNC_REQUEST) {
13301 		fctl_free_ns_cmd(ns_cmd);
13302 		((fp_cmd_t *)(pkt->pkt_ulp_private))->cmd_private = NULL;
13303 	}
13304 	fp_iodone(cmd);
13305 }
13306 
13307 
13308 /*
13309  * Handle unsolicited ADISC ELS request
13310  */
13311 static void
13312 fp_handle_unsol_adisc(fc_local_port_t *port, fc_unsol_buf_t *buf,
13313     fc_remote_port_t *pd, job_request_t *job)
13314 {
13315 	int		rval;
13316 	fp_cmd_t	*cmd;
13317 
13318 	FP_TRACE(FP_NHEAD1(5, 0), "ADISC; port=%p, D_ID=%x state=%x, pd=%p",
13319 	    port, pd->pd_port_id.port_id, pd->pd_state, pd);
13320 	mutex_enter(&pd->pd_mutex);
13321 	if (pd->pd_state != PORT_DEVICE_LOGGED_IN) {
13322 		mutex_exit(&pd->pd_mutex);
13323 		if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
13324 			cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t),
13325 			    0, KM_SLEEP, pd);
13326 			if (cmd != NULL) {
13327 				fp_els_rjt_init(port, cmd, buf,
13328 				    FC_ACTION_NON_RETRYABLE,
13329 				    FC_REASON_INVALID_LINK_CTRL, job);
13330 
13331 				if (fp_sendcmd(port, cmd,
13332 				    port->fp_fca_handle) != FC_SUCCESS) {
13333 					fp_free_pkt(cmd);
13334 				}
13335 			}
13336 		}
13337 	} else {
13338 		mutex_exit(&pd->pd_mutex);
13339 		/*
13340 		 * Yes, yes, we don't have a hard address. But we
13341 		 * we should still respond. Huh ? Visit 21.19.2
13342 		 * of FC-PH-2 which essentially says that if an
13343 		 * NL_Port doesn't have a hard address, or if a port
13344 		 * does not have FC-AL capability, it shall report
13345 		 * zeroes in this field.
13346 		 */
13347 		cmd = fp_alloc_pkt(port, sizeof (la_els_adisc_t),
13348 		    0, KM_SLEEP, pd);
13349 		if (cmd == NULL) {
13350 			return;
13351 		}
13352 		fp_adisc_acc_init(port, cmd, buf, job);
13353 		rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
13354 		if (rval != FC_SUCCESS) {
13355 			fp_free_pkt(cmd);
13356 		}
13357 	}
13358 }
13359 
13360 
13361 /*
13362  * Initialize ADISC response.
13363  */
13364 static void
13365 fp_adisc_acc_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf,
13366     job_request_t *job)
13367 {
13368 	fc_packet_t	*pkt;
13369 	la_els_adisc_t	payload;
13370 
13371 	cmd->cmd_pkt.pkt_tran_flags = buf->ub_class;
13372 	cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND;
13373 	cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
13374 	cmd->cmd_retry_count = 1;
13375 	cmd->cmd_ulp_pkt = NULL;
13376 
13377 	cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
13378 	cmd->cmd_job = job;
13379 
13380 	pkt = &cmd->cmd_pkt;
13381 
13382 	fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP, FC_TYPE_EXTENDED_LS);
13383 
13384 	payload.ls_code.ls_code = LA_ELS_ACC;
13385 	payload.ls_code.mbz = 0;
13386 
13387 	mutex_enter(&port->fp_mutex);
13388 	payload.nport_id = port->fp_port_id;
13389 	payload.hard_addr = port->fp_hard_addr;
13390 	mutex_exit(&port->fp_mutex);
13391 
13392 	payload.port_wwn = port->fp_service_params.nport_ww_name;
13393 	payload.node_wwn = port->fp_service_params.node_ww_name;
13394 
13395 	FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
13396 	    (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
13397 }
13398 
13399 
13400 /*
13401  * Hold and Install the requested ULP drivers
13402  */
13403 static void
13404 fp_load_ulp_modules(dev_info_t *dip, fc_local_port_t *port)
13405 {
13406 	int		len;
13407 	int		count;
13408 	int		data_len;
13409 	major_t		ulp_major;
13410 	caddr_t		ulp_name;
13411 	caddr_t		data_ptr;
13412 	caddr_t		data_buf;
13413 
13414 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
13415 
13416 	data_buf = NULL;
13417 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
13418 	    DDI_PROP_DONTPASS, "load-ulp-list",
13419 	    (caddr_t)&data_buf, &data_len) != DDI_PROP_SUCCESS) {
13420 		return;
13421 	}
13422 
13423 	len = strlen(data_buf);
13424 	port->fp_ulp_nload = fctl_atoi(data_buf, 10);
13425 
13426 	data_ptr = data_buf + len + 1;
13427 	for (count = 0; count < port->fp_ulp_nload; count++) {
13428 		len = strlen(data_ptr) + 1;
13429 		ulp_name = kmem_zalloc(len, KM_SLEEP);
13430 		bcopy(data_ptr, ulp_name, len);
13431 
13432 		ulp_major = ddi_name_to_major(ulp_name);
13433 
13434 		if (ulp_major != (major_t)-1) {
13435 			if (modload("drv", ulp_name) < 0) {
13436 				fp_printf(port, CE_NOTE, FP_LOG_ONLY,
13437 				    0, NULL, "failed to load %s",
13438 				    ulp_name);
13439 			}
13440 		} else {
13441 			fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
13442 			    "%s isn't a valid driver", ulp_name);
13443 		}
13444 
13445 		kmem_free(ulp_name, len);
13446 		data_ptr += len;	/* Skip to next field */
13447 	}
13448 
13449 	/*
13450 	 * Free the memory allocated by DDI
13451 	 */
13452 	if (data_buf != NULL) {
13453 		kmem_free(data_buf, data_len);
13454 	}
13455 }
13456 
13457 
13458 /*
13459  * Perform LOGO operation
13460  */
13461 static int
13462 fp_logout(fc_local_port_t *port, fc_remote_port_t *pd, job_request_t *job)
13463 {
13464 	int		rval;
13465 	fp_cmd_t	*cmd;
13466 
13467 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
13468 	ASSERT(!MUTEX_HELD(&pd->pd_mutex));
13469 
13470 	cmd = fp_alloc_pkt(port, sizeof (la_els_logo_t),
13471 	    FP_PORT_IDENTIFIER_LEN, KM_SLEEP, pd);
13472 
13473 	mutex_enter(&port->fp_mutex);
13474 	mutex_enter(&pd->pd_mutex);
13475 
13476 	ASSERT(pd->pd_state == PORT_DEVICE_LOGGED_IN);
13477 	ASSERT(pd->pd_login_count == 1);
13478 
13479 	cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
13480 	cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
13481 	cmd->cmd_flags = 0;
13482 	cmd->cmd_retry_count = 1;
13483 	cmd->cmd_ulp_pkt = NULL;
13484 
13485 	fp_logo_init(pd, cmd, job);
13486 
13487 	mutex_exit(&pd->pd_mutex);
13488 	mutex_exit(&port->fp_mutex);
13489 
13490 	rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
13491 	if (rval != FC_SUCCESS) {
13492 		fp_iodone(cmd);
13493 	}
13494 
13495 	return (rval);
13496 }
13497 
13498 
13499 /*
13500  * Perform Port attach callbacks to registered ULPs
13501  */
13502 static void
13503 fp_attach_ulps(fc_local_port_t *port, fc_attach_cmd_t cmd)
13504 {
13505 	fp_soft_attach_t *att;
13506 
13507 	att = kmem_zalloc(sizeof (*att), KM_SLEEP);
13508 	att->att_cmd = cmd;
13509 	att->att_port = port;
13510 
13511 	/*
13512 	 * We need to remember whether or not fctl_busy_port
13513 	 * succeeded so we know whether or not to call
13514 	 * fctl_idle_port when the task is complete.
13515 	 */
13516 
13517 	if (fctl_busy_port(port) == 0) {
13518 		att->att_need_pm_idle = B_TRUE;
13519 	} else {
13520 		att->att_need_pm_idle = B_FALSE;
13521 	}
13522 
13523 	(void) taskq_dispatch(port->fp_taskq, fp_ulp_port_attach,
13524 	    att, KM_SLEEP);
13525 }
13526 
13527 
13528 /*
13529  * Forward state change notifications on to interested ULPs.
13530  * Spawns a call to fctl_ulp_statec_cb() in a taskq thread to do all the
13531  * real work.
13532  */
13533 static int
13534 fp_ulp_notify(fc_local_port_t *port, uint32_t statec, int sleep)
13535 {
13536 	fc_port_clist_t *clist;
13537 
13538 	clist = kmem_zalloc(sizeof (*clist), sleep);
13539 	if (clist == NULL) {
13540 		return (FC_NOMEM);
13541 	}
13542 
13543 	clist->clist_state = statec;
13544 
13545 	mutex_enter(&port->fp_mutex);
13546 	clist->clist_flags = port->fp_topology;
13547 	mutex_exit(&port->fp_mutex);
13548 
13549 	clist->clist_port = (opaque_t)port;
13550 	clist->clist_len = 0;
13551 	clist->clist_size = 0;
13552 	clist->clist_map = NULL;
13553 
13554 	(void) taskq_dispatch(port->fp_taskq, fctl_ulp_statec_cb,
13555 	    clist, KM_SLEEP);
13556 
13557 	return (FC_SUCCESS);
13558 }
13559 
13560 
13561 /*
13562  * Get name server map
13563  */
13564 static int
13565 fp_ns_getmap(fc_local_port_t *port, job_request_t *job, fc_portmap_t **map,
13566     uint32_t *len, uint32_t sid)
13567 {
13568 	int ret;
13569 	fctl_ns_req_t *ns_cmd;
13570 
13571 	/*
13572 	 * Don't let the allocator do anything for response;
13573 	 * we have have buffer ready to fillout.
13574 	 */
13575 	ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t),
13576 	    sizeof (ns_resp_gan_t), 0, (FCTL_NS_FILL_NS_MAP |
13577 	    FCTL_NS_BUF_IS_FC_PORTMAP), KM_SLEEP);
13578 
13579 	ns_cmd->ns_data_len = sizeof (**map) * (*len);
13580 	ns_cmd->ns_data_buf = (caddr_t)*map;
13581 
13582 	ASSERT(ns_cmd != NULL);
13583 
13584 	ns_cmd->ns_gan_index = 0;
13585 	ns_cmd->ns_gan_sid = sid;
13586 	ns_cmd->ns_cmd_code = NS_GA_NXT;
13587 	ns_cmd->ns_gan_max = *len;
13588 
13589 	ret = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP);
13590 
13591 	if (ns_cmd->ns_gan_index != *len) {
13592 		*len = ns_cmd->ns_gan_index;
13593 	}
13594 	ns_cmd->ns_data_len = 0;
13595 	ns_cmd->ns_data_buf = NULL;
13596 	fctl_free_ns_cmd(ns_cmd);
13597 
13598 	return (ret);
13599 }
13600 
13601 
13602 /*
13603  * Create a remote port in Fabric topology by using NS services
13604  */
13605 static fc_remote_port_t *
13606 fp_create_remote_port_by_ns(fc_local_port_t *port, uint32_t d_id, int sleep)
13607 {
13608 	int			rval;
13609 	job_request_t		*job;
13610 	fctl_ns_req_t		*ns_cmd;
13611 	fc_remote_port_t	*pd;
13612 
13613 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
13614 
13615 	FP_TRACE(FP_NHEAD1(1, 0), "PD creation begin; port=%p, d_id=%x",
13616 	    port, d_id);
13617 
13618 #ifdef	DEBUG
13619 	mutex_enter(&port->fp_mutex);
13620 	ASSERT(FC_IS_TOP_SWITCH(port->fp_topology));
13621 	mutex_exit(&port->fp_mutex);
13622 #endif
13623 
13624 	job = fctl_alloc_job(JOB_NS_CMD, 0, NULL, (opaque_t)port, sleep);
13625 	if (job == NULL) {
13626 		return (NULL);
13627 	}
13628 
13629 	ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t),
13630 	    sizeof (ns_resp_gan_t), 0, (FCTL_NS_CREATE_DEVICE |
13631 	    FCTL_NS_NO_DATA_BUF), sleep);
13632 	if (ns_cmd == NULL) {
13633 		return (NULL);
13634 	}
13635 
13636 	job->job_result = FC_SUCCESS;
13637 	ns_cmd->ns_gan_max = 1;
13638 	ns_cmd->ns_cmd_code = NS_GA_NXT;
13639 	ns_cmd->ns_gan_sid = FCTL_GAN_START_ID;
13640 	((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.port_id = d_id - 1;
13641 	((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.priv_lilp_posit = 0;
13642 
13643 	ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
13644 	rval = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP);
13645 	fctl_free_ns_cmd(ns_cmd);
13646 
13647 	if (rval != FC_SUCCESS || job->job_result != FC_SUCCESS) {
13648 		fctl_dealloc_job(job);
13649 		return (NULL);
13650 	}
13651 	fctl_dealloc_job(job);
13652 
13653 	pd = fctl_get_remote_port_by_did(port, d_id);
13654 
13655 	FP_TRACE(FP_NHEAD1(1, 0), "PD creation end; port=%p, d_id=%x, pd=%p",
13656 	    port, d_id, pd);
13657 
13658 	return (pd);
13659 }
13660 
13661 
13662 /*
13663  * Check for the permissions on an ioctl command. If it is required to have an
13664  * EXCLUSIVE open performed, return a FAILURE to just shut the door on it. If
13665  * the ioctl command isn't in one of the list built, shut the door on that too.
13666  *
13667  *	Certain ioctls perform hardware accesses in FCA drivers, and it needs
13668  *	to be made sure that users open the port for an exclusive access while
13669  *	performing those operations.
13670  *
13671  *	This can prevent a casual user from inflicting damage on the port by
13672  *	sending these ioctls from multiple processes/threads (there is no good
13673  *	reason why one would need to do that) without actually realizing how
13674  *	expensive such commands could turn out to be.
13675  *
13676  *	It is also important to note that, even with an exclusive access,
13677  *	multiple threads can share the same file descriptor and fire down
13678  *	commands in parallel. To prevent that the driver needs to make sure
13679  *	that such commands aren't in progress already. This is taken care of
13680  *	in the FP_EXCL_BUSY bit of fp_flag.
13681  */
13682 static int
13683 fp_check_perms(uchar_t open_flag, uint16_t ioctl_cmd)
13684 {
13685 	int ret = FC_FAILURE;
13686 	int count;
13687 
13688 	for (count = 0;
13689 	    count < sizeof (fp_perm_list) / sizeof (fp_perm_list[0]);
13690 	    count++) {
13691 		if (fp_perm_list[count].fp_ioctl_cmd == ioctl_cmd) {
13692 			if (fp_perm_list[count].fp_open_flag & open_flag) {
13693 				ret = FC_SUCCESS;
13694 			}
13695 			break;
13696 		}
13697 	}
13698 
13699 	return (ret);
13700 }
13701 
13702 
13703 /*
13704  * Bind Port driver's unsolicited, state change callbacks
13705  */
13706 static int
13707 fp_bind_callbacks(fc_local_port_t *port)
13708 {
13709 	fc_fca_bind_info_t	bind_info = {0};
13710 	fc_fca_port_info_t	*port_info;
13711 	int		rval =	DDI_SUCCESS;
13712 	uint16_t	class;
13713 	int		node_namelen, port_namelen;
13714 	char		*nname = NULL, *pname = NULL;
13715 
13716 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
13717 
13718 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, port->fp_port_dip,
13719 	    DDI_PROP_NOTPROM | DDI_PROP_DONTPASS,
13720 	    "node-name", &nname) != DDI_PROP_SUCCESS) {
13721 		FP_TRACE(FP_NHEAD1(1, 0),
13722 		    "fp_bind_callback fail to get node-name");
13723 	}
13724 	if (nname) {
13725 		fc_str_to_wwn(nname, &(bind_info.port_nwwn));
13726 	}
13727 
13728 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, port->fp_port_dip,
13729 	    DDI_PROP_NOTPROM | DDI_PROP_DONTPASS,
13730 	    "port-name", &pname) != DDI_PROP_SUCCESS) {
13731 		FP_TRACE(FP_NHEAD1(1, 0),
13732 		    "fp_bind_callback fail to get port-name");
13733 	}
13734 	if (pname) {
13735 		fc_str_to_wwn(pname, &(bind_info.port_pwwn));
13736 	}
13737 
13738 	if (port->fp_npiv_type == FC_NPIV_PORT) {
13739 		bind_info.port_npiv = 1;
13740 	}
13741 
13742 	/*
13743 	 * fca_bind_port returns the FCA driver's handle for the local
13744 	 * port instance. If the port number isn't supported it returns NULL.
13745 	 * It also sets up callback in the FCA for various
13746 	 * things like state change, ELS etc..
13747 	 */
13748 	bind_info.port_statec_cb = fp_statec_cb;
13749 	bind_info.port_unsol_cb = fp_unsol_cb;
13750 	bind_info.port_num = port->fp_port_num;
13751 	bind_info.port_handle = (opaque_t)port;
13752 
13753 	port_info = kmem_zalloc(sizeof (*port_info), KM_SLEEP);
13754 
13755 	/*
13756 	 * Hold the port driver mutex as the callbacks are bound until the
13757 	 * service parameters are properly filled in (in order to be able to
13758 	 * properly respond to unsolicited ELS requests)
13759 	 */
13760 	mutex_enter(&port->fp_mutex);
13761 
13762 	port->fp_fca_handle = port->fp_fca_tran->fca_bind_port(
13763 	    port->fp_fca_dip, port_info, &bind_info);
13764 
13765 	if (port->fp_fca_handle == NULL) {
13766 		rval = DDI_FAILURE;
13767 		goto exit;
13768 	}
13769 
13770 	/*
13771 	 * Only fcoei will set this bit
13772 	 */
13773 	if (port_info->pi_port_state & FC_STATE_FCA_IS_NODMA) {
13774 		port->fp_soft_state |= FP_SOFT_FCA_IS_NODMA;
13775 		port_info->pi_port_state &= ~(FC_STATE_FCA_IS_NODMA);
13776 	}
13777 
13778 	port->fp_bind_state = port->fp_state = port_info->pi_port_state;
13779 	port->fp_service_params = port_info->pi_login_params;
13780 	port->fp_hard_addr = port_info->pi_hard_addr;
13781 
13782 	/* Copy from the FCA structure to the FP structure */
13783 	port->fp_hba_port_attrs = port_info->pi_attrs;
13784 
13785 	if (port_info->pi_rnid_params.status == FC_SUCCESS) {
13786 		port->fp_rnid_init = 1;
13787 		bcopy(&port_info->pi_rnid_params.params,
13788 		    &port->fp_rnid_params,
13789 		    sizeof (port->fp_rnid_params));
13790 	} else {
13791 		port->fp_rnid_init = 0;
13792 	}
13793 
13794 	node_namelen = strlen((char *)&port_info->pi_attrs.sym_node_name);
13795 	if (node_namelen) {
13796 		bcopy(&port_info->pi_attrs.sym_node_name,
13797 		    &port->fp_sym_node_name,
13798 		    node_namelen);
13799 		port->fp_sym_node_namelen = node_namelen;
13800 	}
13801 	port_namelen = strlen((char *)&port_info->pi_attrs.sym_port_name);
13802 	if (port_namelen) {
13803 		bcopy(&port_info->pi_attrs.sym_port_name,
13804 		    &port->fp_sym_port_name,
13805 		    port_namelen);
13806 		port->fp_sym_port_namelen = port_namelen;
13807 	}
13808 
13809 	/* zero out the normally unused fields right away */
13810 	port->fp_service_params.ls_code.mbz = 0;
13811 	port->fp_service_params.ls_code.ls_code = 0;
13812 	bzero(&port->fp_service_params.reserved,
13813 	    sizeof (port->fp_service_params.reserved));
13814 
13815 	class = port_info->pi_login_params.class_1.class_opt;
13816 	port->fp_cos |= (class & 0x8000) ? FC_NS_CLASS1 : 0;
13817 
13818 	class = port_info->pi_login_params.class_2.class_opt;
13819 	port->fp_cos |= (class & 0x8000) ? FC_NS_CLASS2 : 0;
13820 
13821 	class = port_info->pi_login_params.class_3.class_opt;
13822 	port->fp_cos |= (class & 0x8000) ? FC_NS_CLASS3 : 0;
13823 
13824 exit:
13825 	if (nname) {
13826 		ddi_prop_free(nname);
13827 	}
13828 	if (pname) {
13829 		ddi_prop_free(pname);
13830 	}
13831 	mutex_exit(&port->fp_mutex);
13832 	kmem_free(port_info, sizeof (*port_info));
13833 
13834 	return (rval);
13835 }
13836 
13837 
13838 /*
13839  * Retrieve FCA capabilities
13840  */
13841 static void
13842 fp_retrieve_caps(fc_local_port_t *port)
13843 {
13844 	int			rval;
13845 	int			ub_count;
13846 	fc_fcp_dma_t		fcp_dma;
13847 	fc_reset_action_t	action;
13848 	fc_dma_behavior_t	dma_behavior;
13849 
13850 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
13851 
13852 	rval = port->fp_fca_tran->fca_get_cap(port->fp_fca_handle,
13853 	    FC_CAP_UNSOL_BUF, &ub_count);
13854 
13855 	switch (rval) {
13856 	case FC_CAP_FOUND:
13857 	case FC_CAP_SETTABLE:
13858 		switch (ub_count) {
13859 		case 0:
13860 			break;
13861 
13862 		case -1:
13863 			ub_count = fp_unsol_buf_count;
13864 			break;
13865 
13866 		default:
13867 			/* 1/4th of total buffers is my share */
13868 			ub_count =
13869 			    (ub_count / port->fp_fca_tran->fca_numports) >> 2;
13870 			break;
13871 		}
13872 		break;
13873 
13874 	default:
13875 		ub_count = 0;
13876 		break;
13877 	}
13878 
13879 	mutex_enter(&port->fp_mutex);
13880 	port->fp_ub_count = ub_count;
13881 	mutex_exit(&port->fp_mutex);
13882 
13883 	rval = port->fp_fca_tran->fca_get_cap(port->fp_fca_handle,
13884 	    FC_CAP_POST_RESET_BEHAVIOR, &action);
13885 
13886 	switch (rval) {
13887 	case FC_CAP_FOUND:
13888 	case FC_CAP_SETTABLE:
13889 		switch (action) {
13890 		case FC_RESET_RETURN_NONE:
13891 		case FC_RESET_RETURN_ALL:
13892 		case FC_RESET_RETURN_OUTSTANDING:
13893 			break;
13894 
13895 		default:
13896 			action = FC_RESET_RETURN_NONE;
13897 			break;
13898 		}
13899 		break;
13900 
13901 	default:
13902 		action = FC_RESET_RETURN_NONE;
13903 		break;
13904 	}
13905 	mutex_enter(&port->fp_mutex);
13906 	port->fp_reset_action = action;
13907 	mutex_exit(&port->fp_mutex);
13908 
13909 	rval = port->fp_fca_tran->fca_get_cap(port->fp_fca_handle,
13910 	    FC_CAP_NOSTREAM_ON_UNALIGN_BUF, &dma_behavior);
13911 
13912 	switch (rval) {
13913 	case FC_CAP_FOUND:
13914 		switch (dma_behavior) {
13915 		case FC_ALLOW_STREAMING:
13916 			/* FALLTHROUGH */
13917 		case FC_NO_STREAMING:
13918 			break;
13919 
13920 		default:
13921 			/*
13922 			 * If capability was found and the value
13923 			 * was incorrect assume the worst
13924 			 */
13925 			dma_behavior = FC_NO_STREAMING;
13926 			break;
13927 		}
13928 		break;
13929 
13930 	default:
13931 		/*
13932 		 * If capability was not defined - allow streaming; existing
13933 		 * FCAs should not be affected.
13934 		 */
13935 		dma_behavior = FC_ALLOW_STREAMING;
13936 		break;
13937 	}
13938 	mutex_enter(&port->fp_mutex);
13939 	port->fp_dma_behavior = dma_behavior;
13940 	mutex_exit(&port->fp_mutex);
13941 
13942 	rval = port->fp_fca_tran->fca_get_cap(port->fp_fca_handle,
13943 	    FC_CAP_FCP_DMA, &fcp_dma);
13944 
13945 	if (rval != FC_CAP_FOUND || (fcp_dma != FC_NO_DVMA_SPACE &&
13946 	    fcp_dma != FC_DVMA_SPACE)) {
13947 		fcp_dma = FC_DVMA_SPACE;
13948 	}
13949 
13950 	mutex_enter(&port->fp_mutex);
13951 	port->fp_fcp_dma = fcp_dma;
13952 	mutex_exit(&port->fp_mutex);
13953 }
13954 
13955 
13956 /*
13957  * Handle Domain, Area changes in the Fabric.
13958  */
13959 static void
13960 fp_validate_area_domain(fc_local_port_t *port, uint32_t id, uint32_t mask,
13961     job_request_t *job, int sleep)
13962 {
13963 #ifdef	DEBUG
13964 	uint32_t		dcnt;
13965 #endif
13966 	int			rval;
13967 	int			send;
13968 	int			index;
13969 	int			listindex;
13970 	int			login;
13971 	int			job_flags;
13972 	char			ww_name[17];
13973 	uint32_t		d_id;
13974 	uint32_t		count;
13975 	fctl_ns_req_t		*ns_cmd;
13976 	fc_portmap_t		*list;
13977 	fc_orphan_t		*orp;
13978 	fc_orphan_t		*norp;
13979 	fc_orphan_t		*prev;
13980 	fc_remote_port_t	*pd;
13981 	fc_remote_port_t	*npd;
13982 	struct pwwn_hash	*head;
13983 
13984 	ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t),
13985 	    sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t),
13986 	    0, sleep);
13987 	if (ns_cmd == NULL) {
13988 		mutex_enter(&port->fp_mutex);
13989 		if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
13990 			--port->fp_rscn_count;
13991 		}
13992 		mutex_exit(&port->fp_mutex);
13993 
13994 		return;
13995 	}
13996 	ns_cmd->ns_cmd_code = NS_GID_PN;
13997 
13998 	/*
13999 	 * We need to get a new count of devices from the
14000 	 * name server, which will also create any new devices
14001 	 * as needed.
14002 	 */
14003 
14004 	(void) fp_ns_get_devcount(port, job, 1, sleep);
14005 
14006 	FP_TRACE(FP_NHEAD1(3, 0),
14007 	    "fp_validate_area_domain: get_devcount found %d devices",
14008 	    port->fp_total_devices);
14009 
14010 	mutex_enter(&port->fp_mutex);
14011 
14012 	for (count = index = 0; index < pwwn_table_size; index++) {
14013 		head = &port->fp_pwwn_table[index];
14014 		pd = head->pwwn_head;
14015 		while (pd != NULL) {
14016 			mutex_enter(&pd->pd_mutex);
14017 			if (pd->pd_flags != PD_ELS_IN_PROGRESS) {
14018 				if ((pd->pd_port_id.port_id & mask) == id &&
14019 				    pd->pd_recepient == PD_PLOGI_INITIATOR) {
14020 					count++;
14021 					pd->pd_type = PORT_DEVICE_OLD;
14022 					pd->pd_flags = PD_ELS_MARK;
14023 				}
14024 			}
14025 			mutex_exit(&pd->pd_mutex);
14026 			pd = pd->pd_wwn_hnext;
14027 		}
14028 	}
14029 
14030 #ifdef	DEBUG
14031 	dcnt = count;
14032 #endif /* DEBUG */
14033 
14034 	/*
14035 	 * Since port->fp_orphan_count is declared an 'int' it is
14036 	 * theoretically possible that the count could go negative.
14037 	 *
14038 	 * This would be bad and if that happens we really do want
14039 	 * to know.
14040 	 */
14041 
14042 	ASSERT(port->fp_orphan_count >= 0);
14043 
14044 	count += port->fp_orphan_count;
14045 
14046 	/*
14047 	 * We add the port->fp_total_devices value to the count
14048 	 * in the case where our port is newly attached. This is
14049 	 * because we haven't done any discovery and we don't have
14050 	 * any orphans in the port's orphan list. If we do not do
14051 	 * this addition to count then we won't alloc enough kmem
14052 	 * to do discovery with.
14053 	 */
14054 
14055 	if (count == 0) {
14056 		count += port->fp_total_devices;
14057 		FP_TRACE(FP_NHEAD1(3, 0), "fp_validate_area_domain: "
14058 		    "0x%x orphans found, using 0x%x",
14059 		    port->fp_orphan_count, count);
14060 	}
14061 
14062 	mutex_exit(&port->fp_mutex);
14063 
14064 	/*
14065 	 * Allocate the change list
14066 	 */
14067 
14068 	list = kmem_zalloc(sizeof (fc_portmap_t) * count, sleep);
14069 	if (list == NULL) {
14070 		fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
14071 		    " Not enough memory to service RSCNs"
14072 		    " for %d ports, continuing...", count);
14073 
14074 		fctl_free_ns_cmd(ns_cmd);
14075 
14076 		mutex_enter(&port->fp_mutex);
14077 		if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
14078 			--port->fp_rscn_count;
14079 		}
14080 		mutex_exit(&port->fp_mutex);
14081 
14082 		return;
14083 	}
14084 
14085 	/*
14086 	 * Attempt to validate or invalidate the devices that were
14087 	 * already in the pwwn hash table.
14088 	 */
14089 
14090 	mutex_enter(&port->fp_mutex);
14091 	for (listindex = 0, index = 0; index < pwwn_table_size; index++) {
14092 		head = &port->fp_pwwn_table[index];
14093 		npd = head->pwwn_head;
14094 
14095 		while ((pd = npd) != NULL) {
14096 			npd = pd->pd_wwn_hnext;
14097 
14098 			mutex_enter(&pd->pd_mutex);
14099 			if ((pd->pd_port_id.port_id & mask) == id &&
14100 			    pd->pd_flags == PD_ELS_MARK) {
14101 				la_wwn_t *pwwn;
14102 
14103 				job->job_result = FC_SUCCESS;
14104 
14105 				((ns_req_gid_pn_t *)
14106 				    (ns_cmd->ns_cmd_buf))->pwwn =
14107 				    pd->pd_port_name;
14108 
14109 				pwwn = &pd->pd_port_name;
14110 				d_id = pd->pd_port_id.port_id;
14111 
14112 				mutex_exit(&pd->pd_mutex);
14113 				mutex_exit(&port->fp_mutex);
14114 
14115 				rval = fp_ns_query(port, ns_cmd, job, 1,
14116 				    sleep);
14117 				if (rval != FC_SUCCESS) {
14118 					fc_wwn_to_str(pwwn, ww_name);
14119 
14120 					FP_TRACE(FP_NHEAD1(3, 0),
14121 					    "AREA RSCN: PD disappeared; "
14122 					    "d_id=%x, PWWN=%s", d_id, ww_name);
14123 
14124 					FP_TRACE(FP_NHEAD2(9, 0),
14125 					    "N_x Port with D_ID=%x,"
14126 					    " PWWN=%s disappeared from fabric",
14127 					    d_id, ww_name);
14128 
14129 					fp_fillout_old_map(list + listindex++,
14130 					    pd, 1);
14131 				} else {
14132 					fctl_copy_portmap(list + listindex++,
14133 					    pd);
14134 
14135 					mutex_enter(&pd->pd_mutex);
14136 					pd->pd_flags = PD_ELS_IN_PROGRESS;
14137 					mutex_exit(&pd->pd_mutex);
14138 				}
14139 
14140 				mutex_enter(&port->fp_mutex);
14141 			} else {
14142 				mutex_exit(&pd->pd_mutex);
14143 			}
14144 		}
14145 	}
14146 
14147 	mutex_exit(&port->fp_mutex);
14148 
14149 	ASSERT(listindex == dcnt);
14150 
14151 	job->job_counter = listindex;
14152 	job_flags = job->job_flags;
14153 	job->job_flags |= JOB_TYPE_FP_ASYNC;
14154 
14155 	/*
14156 	 * Login (if we were the initiator) or validate devices in the
14157 	 * port map.
14158 	 */
14159 
14160 	for (index = 0; index < listindex; index++) {
14161 		pd = list[index].map_pd;
14162 
14163 		mutex_enter(&pd->pd_mutex);
14164 		ASSERT((pd->pd_port_id.port_id & mask) == id);
14165 
14166 		if (pd->pd_flags != PD_ELS_IN_PROGRESS) {
14167 			ASSERT(pd->pd_type == PORT_DEVICE_OLD);
14168 			mutex_exit(&pd->pd_mutex);
14169 			fp_jobdone(job);
14170 			continue;
14171 		}
14172 
14173 		login = (pd->pd_state == PORT_DEVICE_LOGGED_IN) ? 1 : 0;
14174 		send = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0;
14175 		d_id = pd->pd_port_id.port_id;
14176 		mutex_exit(&pd->pd_mutex);
14177 
14178 		if ((d_id & mask) == id && send) {
14179 			if (login) {
14180 				FP_TRACE(FP_NHEAD1(6, 0),
14181 				    "RSCN and PLOGI request;"
14182 				    " pd=%p, job=%p d_id=%x, index=%d", pd,
14183 				    job, d_id, index);
14184 
14185 				rval = fp_port_login(port, d_id, job,
14186 				    FP_CMD_PLOGI_RETAIN, sleep, pd, NULL);
14187 				if (rval != FC_SUCCESS) {
14188 					mutex_enter(&pd->pd_mutex);
14189 					pd->pd_flags = PD_IDLE;
14190 					mutex_exit(&pd->pd_mutex);
14191 
14192 					job->job_result = rval;
14193 					fp_jobdone(job);
14194 				}
14195 				FP_TRACE(FP_NHEAD1(1, 0),
14196 				    "PLOGI succeeded:no skip(1) for "
14197 				    "D_ID %x", d_id);
14198 				list[index].map_flags |=
14199 				    PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY;
14200 			} else {
14201 				FP_TRACE(FP_NHEAD1(6, 0), "RSCN and NS request;"
14202 				    " pd=%p, job=%p d_id=%x, index=%d", pd,
14203 				    job, d_id, index);
14204 
14205 				rval = fp_ns_validate_device(port, pd, job,
14206 				    0, sleep);
14207 				if (rval != FC_SUCCESS) {
14208 					fp_jobdone(job);
14209 				}
14210 				mutex_enter(&pd->pd_mutex);
14211 				pd->pd_flags = PD_IDLE;
14212 				mutex_exit(&pd->pd_mutex);
14213 			}
14214 		} else {
14215 			FP_TRACE(FP_NHEAD1(6, 0),
14216 			    "RSCN and NO request sent; pd=%p,"
14217 			    " d_id=%x, index=%d", pd, d_id, index);
14218 
14219 			mutex_enter(&pd->pd_mutex);
14220 			pd->pd_flags = PD_IDLE;
14221 			mutex_exit(&pd->pd_mutex);
14222 
14223 			fp_jobdone(job);
14224 		}
14225 	}
14226 
14227 	if (listindex) {
14228 		fctl_jobwait(job);
14229 	}
14230 	job->job_flags = job_flags;
14231 
14232 	/*
14233 	 * Orphan list validation.
14234 	 */
14235 	mutex_enter(&port->fp_mutex);
14236 	for (prev = NULL, orp = port->fp_orphan_list; port->fp_orphan_count &&
14237 	    orp != NULL; orp = norp) {
14238 		norp = orp->orp_next;
14239 		mutex_exit(&port->fp_mutex);
14240 
14241 		job->job_counter = 1;
14242 		job->job_result = FC_SUCCESS;
14243 		ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
14244 
14245 		((ns_req_gid_pn_t *)ns_cmd->ns_cmd_buf)->pwwn = orp->orp_pwwn;
14246 
14247 		((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->pid.port_id = 0;
14248 		((ns_resp_gid_pn_t *)
14249 		    ns_cmd->ns_data_buf)->pid.priv_lilp_posit = 0;
14250 
14251 		rval = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP);
14252 		if (rval == FC_SUCCESS) {
14253 			d_id = BE_32(*((uint32_t *)ns_cmd->ns_data_buf));
14254 			pd = fp_create_remote_port_by_ns(port, d_id, KM_SLEEP);
14255 			if (pd != NULL) {
14256 				fc_wwn_to_str(&orp->orp_pwwn, ww_name);
14257 
14258 				FP_TRACE(FP_NHEAD1(6, 0),
14259 				    "RSCN and ORPHAN list "
14260 				    "success; d_id=%x, PWWN=%s", d_id, ww_name);
14261 
14262 				FP_TRACE(FP_NHEAD2(6, 0),
14263 				    "N_x Port with D_ID=%x, PWWN=%s reappeared"
14264 				    " in fabric", d_id, ww_name);
14265 
14266 				mutex_enter(&port->fp_mutex);
14267 				if (prev) {
14268 					prev->orp_next = orp->orp_next;
14269 				} else {
14270 					ASSERT(orp == port->fp_orphan_list);
14271 					port->fp_orphan_list = orp->orp_next;
14272 				}
14273 				port->fp_orphan_count--;
14274 				mutex_exit(&port->fp_mutex);
14275 
14276 				kmem_free(orp, sizeof (*orp));
14277 				fctl_copy_portmap(list + listindex++, pd);
14278 			} else {
14279 				prev = orp;
14280 			}
14281 		} else {
14282 			prev = orp;
14283 		}
14284 		mutex_enter(&port->fp_mutex);
14285 	}
14286 	mutex_exit(&port->fp_mutex);
14287 
14288 	/*
14289 	 * One more pass through the list to delist old devices from
14290 	 * the d_id and pwwn tables and possibly add to the orphan list.
14291 	 */
14292 
14293 	for (index = 0; index < listindex; index++) {
14294 		pd = list[index].map_pd;
14295 		ASSERT(pd != NULL);
14296 
14297 		/*
14298 		 * Update PLOGI results; For NS validation
14299 		 * of orphan list, it is redundant
14300 		 *
14301 		 * Take care to preserve PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY if
14302 		 * appropriate as fctl_copy_portmap() will clear map_flags.
14303 		 */
14304 		if (list[index].map_flags &
14305 		    PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY) {
14306 			fctl_copy_portmap(list + index, pd);
14307 			list[index].map_flags |=
14308 			    PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY;
14309 		} else {
14310 			fctl_copy_portmap(list + index, pd);
14311 		}
14312 
14313 		FP_TRACE(FP_NHEAD1(6, 0), "RSCN with Area DOMAIN "
14314 		    "results; pd=%p, d_id=%x pwwn=%x %x %x %x %x %x %x %x",
14315 		    pd, pd->pd_port_id.port_id,
14316 		    pd->pd_port_name.raw_wwn[0],
14317 		    pd->pd_port_name.raw_wwn[1],
14318 		    pd->pd_port_name.raw_wwn[2],
14319 		    pd->pd_port_name.raw_wwn[3],
14320 		    pd->pd_port_name.raw_wwn[4],
14321 		    pd->pd_port_name.raw_wwn[5],
14322 		    pd->pd_port_name.raw_wwn[6],
14323 		    pd->pd_port_name.raw_wwn[7]);
14324 
14325 		FP_TRACE(FP_NHEAD1(6, 0), "RSCN with Area DOMAIN "
14326 		    "results continued, pd=%p type=%x, flags=%x, state=%x",
14327 		    pd, pd->pd_type, pd->pd_flags, pd->pd_state);
14328 
14329 		mutex_enter(&pd->pd_mutex);
14330 		if (pd->pd_type == PORT_DEVICE_OLD) {
14331 			int initiator;
14332 
14333 			pd->pd_flags = PD_IDLE;
14334 			initiator = (pd->pd_recepient ==
14335 			    PD_PLOGI_INITIATOR) ? 1 : 0;
14336 
14337 			mutex_exit(&pd->pd_mutex);
14338 
14339 			mutex_enter(&port->fp_mutex);
14340 			mutex_enter(&pd->pd_mutex);
14341 
14342 			pd->pd_state = PORT_DEVICE_INVALID;
14343 			fctl_delist_did_table(port, pd);
14344 			fctl_delist_pwwn_table(port, pd);
14345 
14346 			mutex_exit(&pd->pd_mutex);
14347 			mutex_exit(&port->fp_mutex);
14348 
14349 			if (initiator) {
14350 				(void) fctl_add_orphan(port, pd, sleep);
14351 			}
14352 			list[index].map_pd = pd;
14353 		} else {
14354 			ASSERT(pd->pd_flags == PD_IDLE);
14355 			if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
14356 				/*
14357 				 * Reset LOGO tolerance to zero
14358 				 */
14359 				fctl_tc_reset(&pd->pd_logo_tc);
14360 			}
14361 			mutex_exit(&pd->pd_mutex);
14362 		}
14363 	}
14364 
14365 	if (ns_cmd) {
14366 		fctl_free_ns_cmd(ns_cmd);
14367 	}
14368 	if (listindex) {
14369 		(void) fp_ulp_devc_cb(port, list, listindex, count,
14370 		    sleep, 0);
14371 	} else {
14372 		kmem_free(list, sizeof (*list) * count);
14373 
14374 		mutex_enter(&port->fp_mutex);
14375 		if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
14376 			--port->fp_rscn_count;
14377 		}
14378 		mutex_exit(&port->fp_mutex);
14379 	}
14380 }
14381 
14382 
14383 /*
14384  * Work hard to make sense out of an RSCN page.
14385  */
14386 static void
14387 fp_validate_rscn_page(fc_local_port_t *port, fc_affected_id_t *page,
14388     job_request_t *job, fctl_ns_req_t *ns_cmd, fc_portmap_t *listptr,
14389     int *listindex, int sleep)
14390 {
14391 	int			rval;
14392 	char			ww_name[17];
14393 	la_wwn_t		*pwwn;
14394 	fc_remote_port_t	*pwwn_pd;
14395 	fc_remote_port_t	*did_pd;
14396 
14397 	did_pd = fctl_get_remote_port_by_did(port, page->aff_d_id);
14398 
14399 	FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page; "
14400 	    "port=%p, d_id=%x, pd=%p, rscn_count:0x%x", port, page->aff_d_id,
14401 	    did_pd, (uint32_t)(uintptr_t)job->job_cb_arg);
14402 
14403 	if (did_pd != NULL) {
14404 		mutex_enter(&did_pd->pd_mutex);
14405 		if (did_pd->pd_flags != PD_IDLE) {
14406 			mutex_exit(&did_pd->pd_mutex);
14407 			FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page: "
14408 			    "PD is BUSY; port=%p, d_id=%x, pd=%p",
14409 			    port, page->aff_d_id, did_pd);
14410 			return;
14411 		}
14412 		did_pd->pd_flags = PD_ELS_IN_PROGRESS;
14413 		mutex_exit(&did_pd->pd_mutex);
14414 	}
14415 
14416 	job->job_counter = 1;
14417 
14418 	pwwn = &((ns_resp_gpn_id_t *)ns_cmd->ns_data_buf)->pwwn;
14419 
14420 	((ns_req_gpn_id_t *)ns_cmd->ns_cmd_buf)->pid.port_id = page->aff_d_id;
14421 	((ns_req_gpn_id_t *)ns_cmd->ns_cmd_buf)->pid.priv_lilp_posit = 0;
14422 
14423 	bzero(ns_cmd->ns_data_buf, sizeof (la_wwn_t));
14424 	rval = fp_ns_query(port, ns_cmd, job, 1, sleep);
14425 
14426 	FP_TRACE(FP_NHEAD1(1, 0), "NS Query Response for D_ID page; rev=%x,"
14427 	    " in_id=%x, cmdrsp=%x, reason=%x, expln=%x",
14428 	    ns_cmd->ns_resp_hdr.ct_rev, ns_cmd->ns_resp_hdr.ct_inid,
14429 	    ns_cmd->ns_resp_hdr.ct_cmdrsp, ns_cmd->ns_resp_hdr.ct_reason,
14430 	    ns_cmd->ns_resp_hdr.ct_expln);
14431 
14432 	job->job_counter = 1;
14433 
14434 	if (rval != FC_SUCCESS || fctl_is_wwn_zero(pwwn) == FC_SUCCESS) {
14435 		/*
14436 		 * What this means is that the D_ID
14437 		 * disappeared from the Fabric.
14438 		 */
14439 		if (did_pd == NULL) {
14440 			FP_TRACE(FP_NHEAD1(1, 0), "RSCN with D_ID page;"
14441 			    " NULL PD disappeared, rval=%x", rval);
14442 			return;
14443 		}
14444 
14445 		fc_wwn_to_str(&did_pd->pd_port_name, ww_name);
14446 
14447 		(listptr + *listindex)->map_rscn_info.ulp_rscn_count =
14448 		    (uint32_t)(uintptr_t)job->job_cb_arg;
14449 
14450 		fp_fillout_old_map(listptr + (*listindex)++, did_pd, 0);
14451 
14452 		FP_TRACE(FP_NHEAD1(3, 0), "RSCN: PD disappeared; "
14453 		    "d_id=%x, PWWN=%s", page->aff_d_id, ww_name);
14454 
14455 		FP_TRACE(FP_NHEAD2(9, 0),
14456 		    "GPN_ID for D_ID=%x failed", page->aff_d_id);
14457 
14458 		FP_TRACE(FP_NHEAD2(9, 0),
14459 		    "N_x Port with D_ID=%x, PWWN=%s disappeared from"
14460 		    " fabric", page->aff_d_id, ww_name);
14461 
14462 		mutex_enter(&did_pd->pd_mutex);
14463 		did_pd->pd_flags = PD_IDLE;
14464 		mutex_exit(&did_pd->pd_mutex);
14465 
14466 		FP_TRACE(FP_NHEAD1(3, 0), "RSCN with D_ID (%x) page; "
14467 		    "PD disappeared, pd=%p", page->aff_d_id, did_pd);
14468 
14469 		return;
14470 	}
14471 
14472 	pwwn_pd = fctl_get_remote_port_by_pwwn(port, pwwn);
14473 
14474 	if (did_pd != NULL && pwwn_pd != NULL && did_pd == pwwn_pd) {
14475 		/*
14476 		 * There is no change. Do PLOGI again and add it to
14477 		 * ULP portmap baggage and return. Note: When RSCNs
14478 		 * arrive with per page states, the need for PLOGI
14479 		 * can be determined correctly.
14480 		 */
14481 		mutex_enter(&pwwn_pd->pd_mutex);
14482 		pwwn_pd->pd_type = PORT_DEVICE_NOCHANGE;
14483 		mutex_exit(&pwwn_pd->pd_mutex);
14484 
14485 		(listptr + *listindex)->map_rscn_info.ulp_rscn_count =
14486 		    (uint32_t)(uintptr_t)job->job_cb_arg;
14487 
14488 		fctl_copy_portmap(listptr + (*listindex)++, pwwn_pd);
14489 
14490 		mutex_enter(&pwwn_pd->pd_mutex);
14491 		if ((pwwn_pd->pd_state == PORT_DEVICE_LOGGED_IN) ||
14492 		    (pwwn_pd->pd_aux_flags & PD_LOGGED_OUT)) {
14493 			fc_wwn_to_str(&pwwn_pd->pd_port_name, ww_name);
14494 			mutex_exit(&pwwn_pd->pd_mutex);
14495 
14496 			rval = fp_port_login(port, page->aff_d_id, job,
14497 			    FP_CMD_PLOGI_RETAIN, sleep, pwwn_pd, NULL);
14498 			if (rval == FC_SUCCESS) {
14499 				fp_jobwait(job);
14500 				rval = job->job_result;
14501 
14502 				/*
14503 				 * Reset LOGO tolerance to zero
14504 				 * Also we are the PLOGI initiator now.
14505 				 */
14506 				mutex_enter(&pwwn_pd->pd_mutex);
14507 				fctl_tc_reset(&pwwn_pd->pd_logo_tc);
14508 				pwwn_pd->pd_recepient = PD_PLOGI_INITIATOR;
14509 				mutex_exit(&pwwn_pd->pd_mutex);
14510 			}
14511 
14512 			if (rval == FC_SUCCESS) {
14513 				struct fc_portmap *map =
14514 				    listptr + *listindex - 1;
14515 
14516 				FP_TRACE(FP_NHEAD1(1, 0),
14517 				    "PLOGI succeeded: no skip(2)"
14518 				    " for D_ID %x", page->aff_d_id);
14519 				map->map_flags |=
14520 				    PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY;
14521 			} else {
14522 				FP_TRACE(FP_NHEAD2(9, rval),
14523 				    "PLOGI to D_ID=%x failed", page->aff_d_id);
14524 
14525 				FP_TRACE(FP_NHEAD2(9, 0),
14526 				    "N_x Port with D_ID=%x, PWWN=%s"
14527 				    " disappeared from fabric",
14528 				    page->aff_d_id, ww_name);
14529 
14530 				fp_fillout_old_map(listptr +
14531 				    *listindex - 1, pwwn_pd, 0);
14532 			}
14533 		} else {
14534 			mutex_exit(&pwwn_pd->pd_mutex);
14535 		}
14536 
14537 		mutex_enter(&did_pd->pd_mutex);
14538 		did_pd->pd_flags = PD_IDLE;
14539 		mutex_exit(&did_pd->pd_mutex);
14540 
14541 		FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID (0x%x) page; "
14542 		    "Case ONE, rval=%x, result=%x pd=%p", page->aff_d_id, rval,
14543 		    job->job_result, pwwn_pd);
14544 
14545 		return;
14546 	}
14547 
14548 	if (did_pd == NULL && pwwn_pd == NULL) {
14549 
14550 		fc_orphan_t	*orp  = NULL;
14551 		fc_orphan_t	*norp = NULL;
14552 		fc_orphan_t	*prev = NULL;
14553 
14554 		/*
14555 		 * Hunt down the orphan list before giving up.
14556 		 */
14557 
14558 		mutex_enter(&port->fp_mutex);
14559 		if (port->fp_orphan_count) {
14560 
14561 			for (orp = port->fp_orphan_list; orp; orp = norp) {
14562 				norp = orp->orp_next;
14563 
14564 				if (fctl_wwn_cmp(&orp->orp_pwwn, pwwn) != 0) {
14565 					prev = orp;
14566 					continue;
14567 				}
14568 
14569 				if (prev) {
14570 					prev->orp_next = orp->orp_next;
14571 				} else {
14572 					ASSERT(orp ==
14573 					    port->fp_orphan_list);
14574 					port->fp_orphan_list =
14575 					    orp->orp_next;
14576 				}
14577 				port->fp_orphan_count--;
14578 				break;
14579 			}
14580 		}
14581 
14582 		mutex_exit(&port->fp_mutex);
14583 		pwwn_pd = fp_create_remote_port_by_ns(port,
14584 		    page->aff_d_id, sleep);
14585 
14586 		if (pwwn_pd != NULL) {
14587 
14588 			if (orp) {
14589 				fc_wwn_to_str(&orp->orp_pwwn,
14590 				    ww_name);
14591 
14592 				FP_TRACE(FP_NHEAD2(9, 0),
14593 				    "N_x Port with D_ID=%x,"
14594 				    " PWWN=%s reappeared in fabric",
14595 				    page->aff_d_id, ww_name);
14596 
14597 				kmem_free(orp, sizeof (*orp));
14598 			}
14599 
14600 			(listptr + *listindex)->
14601 			    map_rscn_info.ulp_rscn_count =
14602 			    (uint32_t)(uintptr_t)job->job_cb_arg;
14603 
14604 			fctl_copy_portmap(listptr +
14605 			    (*listindex)++, pwwn_pd);
14606 		}
14607 
14608 		FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID (0x%x) page; "
14609 		    "Case TWO", page->aff_d_id);
14610 
14611 		return;
14612 	}
14613 
14614 	if (pwwn_pd != NULL && did_pd == NULL) {
14615 		uint32_t old_d_id;
14616 		uint32_t d_id = page->aff_d_id;
14617 
14618 		/*
14619 		 * What this means is there is a new D_ID for this
14620 		 * Port WWN. Take out the port device off D_ID
14621 		 * list and put it back with a new D_ID. Perform
14622 		 * PLOGI if already logged in.
14623 		 */
14624 		mutex_enter(&port->fp_mutex);
14625 		mutex_enter(&pwwn_pd->pd_mutex);
14626 
14627 		old_d_id = pwwn_pd->pd_port_id.port_id;
14628 
14629 		fctl_delist_did_table(port, pwwn_pd);
14630 
14631 		(listptr + *listindex)->map_rscn_info.ulp_rscn_count =
14632 		    (uint32_t)(uintptr_t)job->job_cb_arg;
14633 
14634 		fp_fillout_changed_map(listptr + (*listindex)++, pwwn_pd,
14635 		    &d_id, NULL);
14636 		fctl_enlist_did_table(port, pwwn_pd);
14637 
14638 		FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page;"
14639 		    " Case THREE, pd=%p,"
14640 		    " state=%x", pwwn_pd, pwwn_pd->pd_state);
14641 
14642 		if ((pwwn_pd->pd_state == PORT_DEVICE_LOGGED_IN) ||
14643 		    (pwwn_pd->pd_aux_flags & PD_LOGGED_OUT)) {
14644 			fc_wwn_to_str(&pwwn_pd->pd_port_name, ww_name);
14645 
14646 			mutex_exit(&pwwn_pd->pd_mutex);
14647 			mutex_exit(&port->fp_mutex);
14648 
14649 			FP_TRACE(FP_NHEAD2(9, 0),
14650 			    "N_x Port with D_ID=%x, PWWN=%s has a new"
14651 			    " D_ID=%x now", old_d_id, ww_name, d_id);
14652 
14653 			rval = fp_port_login(port, page->aff_d_id, job,
14654 			    FP_CMD_PLOGI_RETAIN, sleep, pwwn_pd, NULL);
14655 			if (rval == FC_SUCCESS) {
14656 				fp_jobwait(job);
14657 				rval = job->job_result;
14658 			}
14659 
14660 			if (rval != FC_SUCCESS) {
14661 				fp_fillout_old_map(listptr +
14662 				    *listindex - 1, pwwn_pd, 0);
14663 			}
14664 		} else {
14665 			mutex_exit(&pwwn_pd->pd_mutex);
14666 			mutex_exit(&port->fp_mutex);
14667 		}
14668 
14669 		return;
14670 	}
14671 
14672 	if (pwwn_pd == NULL && did_pd != NULL) {
14673 		fc_portmap_t	*ptr;
14674 		uint32_t	len = 1;
14675 		char		old_ww_name[17];
14676 
14677 		mutex_enter(&did_pd->pd_mutex);
14678 		fc_wwn_to_str(&did_pd->pd_port_name, old_ww_name);
14679 		mutex_exit(&did_pd->pd_mutex);
14680 
14681 		fc_wwn_to_str(pwwn, ww_name);
14682 
14683 		(listptr + *listindex)->map_rscn_info.ulp_rscn_count =
14684 		    (uint32_t)(uintptr_t)job->job_cb_arg;
14685 
14686 		/*
14687 		 * What this means is that there is a new Port WWN for
14688 		 * this D_ID; Mark the Port device as old and provide
14689 		 * the new PWWN and D_ID combination as new.
14690 		 */
14691 		fp_fillout_old_map(listptr + (*listindex)++, did_pd, 0);
14692 
14693 		FP_TRACE(FP_NHEAD2(9, 0),
14694 		    "N_x Port with D_ID=%x, PWWN=%s has a new PWWN=%s now",
14695 		    page->aff_d_id, old_ww_name, ww_name);
14696 
14697 		(listptr + *listindex)->map_rscn_info.ulp_rscn_count =
14698 		    (uint32_t)(uintptr_t)job->job_cb_arg;
14699 
14700 		ptr = listptr + (*listindex)++;
14701 
14702 		job->job_counter = 1;
14703 
14704 		if (fp_ns_getmap(port, job, &ptr, &len,
14705 		    page->aff_d_id - 1) != FC_SUCCESS) {
14706 			(*listindex)--;
14707 		}
14708 
14709 		mutex_enter(&did_pd->pd_mutex);
14710 		did_pd->pd_flags = PD_IDLE;
14711 		mutex_exit(&did_pd->pd_mutex);
14712 
14713 		return;
14714 	}
14715 
14716 	/*
14717 	 * A weird case of Port WWN and D_ID existence but not matching up
14718 	 * between them. Trust your instincts - Take the port device handle
14719 	 * off Port WWN list, fix it with new Port WWN and put it back, In
14720 	 * the mean time mark the port device corresponding to the old port
14721 	 * WWN as OLD.
14722 	 */
14723 	FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page; Case WEIRD, pwwn_pd=%p,"
14724 	    " did_pd=%p", pwwn_pd, did_pd);
14725 
14726 	mutex_enter(&port->fp_mutex);
14727 	mutex_enter(&pwwn_pd->pd_mutex);
14728 
14729 	pwwn_pd->pd_type = PORT_DEVICE_OLD;
14730 	pwwn_pd->pd_state = PORT_DEVICE_INVALID;
14731 	fctl_delist_did_table(port, pwwn_pd);
14732 	fctl_delist_pwwn_table(port, pwwn_pd);
14733 
14734 	FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page; case WEIRD continued,"
14735 	    " pwwn-d_id=%x pwwn-wwn=%x %x %x %x %x %x %x %x",
14736 	    pwwn_pd->pd_port_id.port_id,
14737 
14738 	    pwwn_pd->pd_port_name.raw_wwn[0],
14739 	    pwwn_pd->pd_port_name.raw_wwn[1],
14740 	    pwwn_pd->pd_port_name.raw_wwn[2],
14741 	    pwwn_pd->pd_port_name.raw_wwn[3],
14742 	    pwwn_pd->pd_port_name.raw_wwn[4],
14743 	    pwwn_pd->pd_port_name.raw_wwn[5],
14744 	    pwwn_pd->pd_port_name.raw_wwn[6],
14745 	    pwwn_pd->pd_port_name.raw_wwn[7]);
14746 
14747 	mutex_exit(&pwwn_pd->pd_mutex);
14748 	mutex_exit(&port->fp_mutex);
14749 
14750 	(listptr + *listindex)->map_rscn_info.ulp_rscn_count =
14751 	    (uint32_t)(uintptr_t)job->job_cb_arg;
14752 
14753 	fctl_copy_portmap(listptr + (*listindex)++, pwwn_pd);
14754 
14755 	mutex_enter(&port->fp_mutex);
14756 	mutex_enter(&did_pd->pd_mutex);
14757 
14758 	fctl_delist_pwwn_table(port, did_pd);
14759 
14760 	(listptr + *listindex)->map_rscn_info.ulp_rscn_count =
14761 	    (uint32_t)(uintptr_t)job->job_cb_arg;
14762 
14763 	fp_fillout_changed_map(listptr + (*listindex)++, did_pd, NULL, pwwn);
14764 	fctl_enlist_pwwn_table(port, did_pd);
14765 
14766 	FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page; case WEIRD continued,"
14767 	    " d_id=%x, state=%x, did-wwn=%x %x %x %x %x %x %x %x",
14768 	    did_pd->pd_port_id.port_id, did_pd->pd_state,
14769 
14770 	    did_pd->pd_port_name.raw_wwn[0],
14771 	    did_pd->pd_port_name.raw_wwn[1],
14772 	    did_pd->pd_port_name.raw_wwn[2],
14773 	    did_pd->pd_port_name.raw_wwn[3],
14774 	    did_pd->pd_port_name.raw_wwn[4],
14775 	    did_pd->pd_port_name.raw_wwn[5],
14776 	    did_pd->pd_port_name.raw_wwn[6],
14777 	    did_pd->pd_port_name.raw_wwn[7]);
14778 
14779 	if ((did_pd->pd_state == PORT_DEVICE_LOGGED_IN) ||
14780 	    (did_pd->pd_aux_flags & PD_LOGGED_OUT)) {
14781 		mutex_exit(&did_pd->pd_mutex);
14782 		mutex_exit(&port->fp_mutex);
14783 
14784 		rval = fp_port_login(port, page->aff_d_id, job,
14785 		    FP_CMD_PLOGI_RETAIN, sleep, did_pd, NULL);
14786 		if (rval == FC_SUCCESS) {
14787 			fp_jobwait(job);
14788 			if (job->job_result != FC_SUCCESS) {
14789 				fp_fillout_old_map(listptr +
14790 				    *listindex - 1, did_pd, 0);
14791 			}
14792 		} else {
14793 			fp_fillout_old_map(listptr + *listindex - 1, did_pd, 0);
14794 		}
14795 	} else {
14796 		mutex_exit(&did_pd->pd_mutex);
14797 		mutex_exit(&port->fp_mutex);
14798 	}
14799 
14800 	mutex_enter(&did_pd->pd_mutex);
14801 	did_pd->pd_flags = PD_IDLE;
14802 	mutex_exit(&did_pd->pd_mutex);
14803 }
14804 
14805 
14806 /*
14807  * Check with NS for the presence of this port WWN
14808  */
14809 static int
14810 fp_ns_validate_device(fc_local_port_t *port, fc_remote_port_t *pd,
14811     job_request_t *job, int polled, int sleep)
14812 {
14813 	la_wwn_t	pwwn;
14814 	uint32_t	flags;
14815 	fctl_ns_req_t	*ns_cmd;
14816 
14817 	flags = FCTL_NS_VALIDATE_PD | ((polled) ? 0: FCTL_NS_ASYNC_REQUEST);
14818 	ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t),
14819 	    sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t),
14820 	    flags, sleep);
14821 	if (ns_cmd == NULL) {
14822 		return (FC_NOMEM);
14823 	}
14824 
14825 	mutex_enter(&pd->pd_mutex);
14826 	pwwn = pd->pd_port_name;
14827 	mutex_exit(&pd->pd_mutex);
14828 
14829 	ns_cmd->ns_cmd_code = NS_GID_PN;
14830 	ns_cmd->ns_pd = pd;
14831 	((ns_req_gid_pn_t *)ns_cmd->ns_cmd_buf)->pwwn = pwwn;
14832 	((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->pid.port_id = 0;
14833 	((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->pid.priv_lilp_posit = 0;
14834 
14835 	return (fp_ns_query(port, ns_cmd, job, polled, sleep));
14836 }
14837 
14838 
14839 /*
14840  * Sanity check the LILP map returned by FCA
14841  */
14842 static int
14843 fp_validate_lilp_map(fc_lilpmap_t *lilp_map)
14844 {
14845 	int	count;
14846 
14847 	if (lilp_map->lilp_length == 0) {
14848 		return (FC_FAILURE);
14849 	}
14850 
14851 	for (count = 0; count < lilp_map->lilp_length; count++) {
14852 		if (fp_is_valid_alpa(lilp_map->lilp_alpalist[count]) !=
14853 		    FC_SUCCESS) {
14854 			return (FC_FAILURE);
14855 		}
14856 	}
14857 
14858 	return (FC_SUCCESS);
14859 }
14860 
14861 
14862 /*
14863  * Sanity check if the AL_PA is a valid address
14864  */
14865 static int
14866 fp_is_valid_alpa(uchar_t al_pa)
14867 {
14868 	int	count;
14869 
14870 	for (count = 0; count < sizeof (fp_valid_alpas); count++) {
14871 		if (al_pa == fp_valid_alpas[count] || al_pa == 0) {
14872 			return (FC_SUCCESS);
14873 		}
14874 	}
14875 
14876 	return (FC_FAILURE);
14877 }
14878 
14879 
14880 /*
14881  * Post unsolicited callbacks to ULPs
14882  */
14883 static void
14884 fp_ulp_unsol_cb(void *arg)
14885 {
14886 	fp_unsol_spec_t	*ub_spec = (fp_unsol_spec_t *)arg;
14887 
14888 	fctl_ulp_unsol_cb(ub_spec->port, ub_spec->buf,
14889 	    ub_spec->buf->ub_frame.type);
14890 	kmem_free(ub_spec, sizeof (*ub_spec));
14891 }
14892 
14893 
14894 /*
14895  * Perform message reporting in a consistent manner. Unless there is
14896  * a strong reason NOT to use this function (which is very very rare)
14897  * all message reporting should go through this.
14898  */
14899 static void
14900 fp_printf(fc_local_port_t *port, int level, fp_mesg_dest_t dest, int fc_errno,
14901     fc_packet_t *pkt, const char *fmt, ...)
14902 {
14903 	caddr_t		buf;
14904 	va_list		ap;
14905 
14906 	switch (level) {
14907 	case CE_NOTE:
14908 		if ((port->fp_verbose & FP_WARNING_MESSAGES) == 0) {
14909 			return;
14910 		}
14911 		break;
14912 
14913 	case CE_WARN:
14914 		if ((port->fp_verbose & FP_FATAL_MESSAGES) == 0) {
14915 			return;
14916 		}
14917 		break;
14918 	}
14919 
14920 	buf = kmem_zalloc(256, KM_NOSLEEP);
14921 	if (buf == NULL) {
14922 		return;
14923 	}
14924 
14925 	(void) sprintf(buf, "fp(%d): ", port->fp_instance);
14926 
14927 	va_start(ap, fmt);
14928 	(void) vsprintf(buf + strlen(buf), fmt, ap);
14929 	va_end(ap);
14930 
14931 	if (fc_errno) {
14932 		char *errmsg;
14933 
14934 		(void) fc_ulp_error(fc_errno, &errmsg);
14935 		(void) sprintf(buf + strlen(buf), " FC Error=%s", errmsg);
14936 	} else {
14937 		if (pkt) {
14938 			caddr_t	state, reason, action, expln;
14939 
14940 			(void) fc_ulp_pkt_error(pkt, &state, &reason,
14941 			    &action, &expln);
14942 
14943 			(void) sprintf(buf + strlen(buf),
14944 			    " state=%s, reason=%s", state, reason);
14945 
14946 			if (pkt->pkt_resp_resid) {
14947 				(void) sprintf(buf + strlen(buf),
14948 				    " resp resid=%x\n", pkt->pkt_resp_resid);
14949 			}
14950 		}
14951 	}
14952 
14953 	switch (dest) {
14954 	case FP_CONSOLE_ONLY:
14955 		cmn_err(level, "^%s", buf);
14956 		break;
14957 
14958 	case FP_LOG_ONLY:
14959 		cmn_err(level, "!%s", buf);
14960 		break;
14961 
14962 	default:
14963 		cmn_err(level, "%s", buf);
14964 		break;
14965 	}
14966 
14967 	kmem_free(buf, 256);
14968 }
14969 
14970 static int
14971 fp_fcio_login(fc_local_port_t *port, fcio_t *fcio, job_request_t *job)
14972 {
14973 	int			ret;
14974 	uint32_t		d_id;
14975 	la_wwn_t		pwwn;
14976 	fc_remote_port_t	*pd = NULL;
14977 	fc_remote_port_t	*held_pd = NULL;
14978 	fctl_ns_req_t		*ns_cmd;
14979 	fc_portmap_t		*changelist;
14980 
14981 	bcopy(fcio->fcio_ibuf, &pwwn, sizeof (pwwn));
14982 
14983 	mutex_enter(&port->fp_mutex);
14984 	if (FC_IS_TOP_SWITCH(port->fp_topology)) {
14985 		mutex_exit(&port->fp_mutex);
14986 		job->job_counter = 1;
14987 
14988 		job->job_result = FC_SUCCESS;
14989 
14990 		ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t),
14991 		    sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t),
14992 		    FCTL_NS_BUF_IS_USERLAND, KM_SLEEP);
14993 
14994 		ASSERT(ns_cmd != NULL);
14995 
14996 		ns_cmd->ns_cmd_code = NS_GID_PN;
14997 		((ns_req_gid_pn_t *)(ns_cmd->ns_cmd_buf))->pwwn = pwwn;
14998 
14999 		ret = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP);
15000 
15001 		if (ret != FC_SUCCESS || job->job_result != FC_SUCCESS) {
15002 			if (ret != FC_SUCCESS) {
15003 				fcio->fcio_errno = ret;
15004 			} else {
15005 				fcio->fcio_errno = job->job_result;
15006 			}
15007 			fctl_free_ns_cmd(ns_cmd);
15008 			return (EIO);
15009 		}
15010 		d_id = BE_32(*((uint32_t *)ns_cmd->ns_data_buf));
15011 		fctl_free_ns_cmd(ns_cmd);
15012 	} else {
15013 		mutex_exit(&port->fp_mutex);
15014 
15015 		held_pd = fctl_hold_remote_port_by_pwwn(port, &pwwn);
15016 		if (held_pd == NULL) {
15017 			fcio->fcio_errno = FC_BADWWN;
15018 			return (EIO);
15019 		}
15020 		pd = held_pd;
15021 
15022 		mutex_enter(&pd->pd_mutex);
15023 		d_id = pd->pd_port_id.port_id;
15024 		mutex_exit(&pd->pd_mutex);
15025 	}
15026 
15027 	job->job_counter = 1;
15028 
15029 	pd = fctl_get_remote_port_by_did(port, d_id);
15030 
15031 	if (pd) {
15032 		mutex_enter(&pd->pd_mutex);
15033 		if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
15034 			pd->pd_login_count++;
15035 			mutex_exit(&pd->pd_mutex);
15036 
15037 			fcio->fcio_errno = FC_SUCCESS;
15038 			if (held_pd) {
15039 				fctl_release_remote_port(held_pd);
15040 			}
15041 
15042 			return (0);
15043 		}
15044 		mutex_exit(&pd->pd_mutex);
15045 	} else {
15046 		mutex_enter(&port->fp_mutex);
15047 		if (FC_IS_TOP_SWITCH(port->fp_topology)) {
15048 			mutex_exit(&port->fp_mutex);
15049 			pd = fp_create_remote_port_by_ns(port, d_id, KM_SLEEP);
15050 			if (pd == NULL) {
15051 				fcio->fcio_errno = FC_FAILURE;
15052 				if (held_pd) {
15053 					fctl_release_remote_port(held_pd);
15054 				}
15055 				return (EIO);
15056 			}
15057 		} else {
15058 			mutex_exit(&port->fp_mutex);
15059 		}
15060 	}
15061 
15062 	job->job_flags &= ~JOB_TYPE_FP_ASYNC;
15063 	job->job_counter = 1;
15064 
15065 	ret = fp_port_login(port, d_id, job, FP_CMD_PLOGI_RETAIN,
15066 	    KM_SLEEP, pd, NULL);
15067 
15068 	if (ret != FC_SUCCESS) {
15069 		fcio->fcio_errno = ret;
15070 		if (held_pd) {
15071 			fctl_release_remote_port(held_pd);
15072 		}
15073 		return (EIO);
15074 	}
15075 	fp_jobwait(job);
15076 
15077 	fcio->fcio_errno = job->job_result;
15078 
15079 	if (held_pd) {
15080 		fctl_release_remote_port(held_pd);
15081 	}
15082 
15083 	if (job->job_result != FC_SUCCESS) {
15084 		return (EIO);
15085 	}
15086 
15087 	pd = fctl_hold_remote_port_by_pwwn(port, &pwwn);
15088 	if (pd == NULL) {
15089 		fcio->fcio_errno = FC_BADDEV;
15090 		return (ENODEV);
15091 	}
15092 
15093 	changelist = kmem_zalloc(sizeof (*changelist), KM_SLEEP);
15094 
15095 	fctl_copy_portmap(changelist, pd);
15096 	changelist->map_type = PORT_DEVICE_USER_LOGIN;
15097 
15098 	(void) fp_ulp_devc_cb(port, changelist, 1, 1, KM_SLEEP, 1);
15099 
15100 	mutex_enter(&pd->pd_mutex);
15101 	pd->pd_type = PORT_DEVICE_NOCHANGE;
15102 	mutex_exit(&pd->pd_mutex);
15103 
15104 	fctl_release_remote_port(pd);
15105 
15106 	return (0);
15107 }
15108 
15109 
15110 static int
15111 fp_fcio_logout(fc_local_port_t *port, fcio_t *fcio, job_request_t *job)
15112 {
15113 	la_wwn_t		pwwn;
15114 	fp_cmd_t		*cmd;
15115 	fc_portmap_t		*changelist;
15116 	fc_remote_port_t	*pd;
15117 
15118 	bcopy(fcio->fcio_ibuf, &pwwn, sizeof (pwwn));
15119 
15120 	pd = fctl_hold_remote_port_by_pwwn(port, &pwwn);
15121 	if (pd == NULL) {
15122 		fcio->fcio_errno = FC_BADWWN;
15123 		return (ENXIO);
15124 	}
15125 
15126 	mutex_enter(&pd->pd_mutex);
15127 	if (pd->pd_state != PORT_DEVICE_LOGGED_IN) {
15128 		fcio->fcio_errno = FC_LOGINREQ;
15129 		mutex_exit(&pd->pd_mutex);
15130 
15131 		fctl_release_remote_port(pd);
15132 
15133 		return (EINVAL);
15134 	}
15135 
15136 	ASSERT(pd->pd_login_count >= 1);
15137 
15138 	if (pd->pd_flags == PD_ELS_IN_PROGRESS) {
15139 		fcio->fcio_errno = FC_FAILURE;
15140 		mutex_exit(&pd->pd_mutex);
15141 
15142 		fctl_release_remote_port(pd);
15143 
15144 		return (EBUSY);
15145 	}
15146 
15147 	if (pd->pd_login_count > 1) {
15148 		pd->pd_login_count--;
15149 		fcio->fcio_errno = FC_SUCCESS;
15150 		mutex_exit(&pd->pd_mutex);
15151 
15152 		changelist = kmem_zalloc(sizeof (*changelist), KM_SLEEP);
15153 
15154 		fctl_copy_portmap(changelist, pd);
15155 		changelist->map_type = PORT_DEVICE_USER_LOGOUT;
15156 
15157 		fctl_release_remote_port(pd);
15158 
15159 		(void) fp_ulp_devc_cb(port, changelist, 1, 1, KM_SLEEP, 1);
15160 
15161 		return (0);
15162 	}
15163 
15164 	pd->pd_flags = PD_ELS_IN_PROGRESS;
15165 	mutex_exit(&pd->pd_mutex);
15166 
15167 	job->job_counter = 1;
15168 
15169 	cmd = fp_alloc_pkt(port, sizeof (la_els_logo_t),
15170 	    FP_PORT_IDENTIFIER_LEN, KM_SLEEP, pd);
15171 	if (cmd == NULL) {
15172 		fcio->fcio_errno = FC_NOMEM;
15173 		fctl_release_remote_port(pd);
15174 
15175 		mutex_enter(&pd->pd_mutex);
15176 		pd->pd_flags = PD_IDLE;
15177 		mutex_exit(&pd->pd_mutex);
15178 
15179 		return (ENOMEM);
15180 	}
15181 
15182 	mutex_enter(&port->fp_mutex);
15183 	mutex_enter(&pd->pd_mutex);
15184 
15185 	cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
15186 	cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
15187 	cmd->cmd_flags = FP_CMD_PLOGI_DONT_CARE;
15188 	cmd->cmd_retry_count = 1;
15189 	cmd->cmd_ulp_pkt = NULL;
15190 
15191 	fp_logo_init(pd, cmd, job);
15192 
15193 	mutex_exit(&pd->pd_mutex);
15194 	mutex_exit(&port->fp_mutex);
15195 
15196 	if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
15197 		mutex_enter(&pd->pd_mutex);
15198 		pd->pd_flags = PD_IDLE;
15199 		mutex_exit(&pd->pd_mutex);
15200 
15201 		fp_free_pkt(cmd);
15202 		fctl_release_remote_port(pd);
15203 
15204 		return (EIO);
15205 	}
15206 
15207 	fp_jobwait(job);
15208 
15209 	fcio->fcio_errno = job->job_result;
15210 	if (job->job_result != FC_SUCCESS) {
15211 		mutex_enter(&pd->pd_mutex);
15212 		pd->pd_flags = PD_IDLE;
15213 		mutex_exit(&pd->pd_mutex);
15214 
15215 		fctl_release_remote_port(pd);
15216 
15217 		return (EIO);
15218 	}
15219 
15220 	ASSERT(pd != NULL);
15221 
15222 	changelist = kmem_zalloc(sizeof (*changelist), KM_SLEEP);
15223 
15224 	fctl_copy_portmap(changelist, pd);
15225 	changelist->map_type = PORT_DEVICE_USER_LOGOUT;
15226 	changelist->map_state = PORT_DEVICE_INVALID;
15227 
15228 	mutex_enter(&port->fp_mutex);
15229 	mutex_enter(&pd->pd_mutex);
15230 
15231 	fctl_delist_did_table(port, pd);
15232 	fctl_delist_pwwn_table(port, pd);
15233 	pd->pd_flags = PD_IDLE;
15234 
15235 	mutex_exit(&pd->pd_mutex);
15236 	mutex_exit(&port->fp_mutex);
15237 
15238 	(void) fp_ulp_devc_cb(port, changelist, 1, 1, KM_SLEEP, 1);
15239 
15240 	fctl_release_remote_port(pd);
15241 
15242 	return (0);
15243 }
15244 
15245 
15246 
15247 /*
15248  * Send a syslog event for adapter port level events.
15249  */
15250 static void
15251 fp_log_port_event(fc_local_port_t *port, char *subclass)
15252 {
15253 	nvlist_t *attr_list;
15254 
15255 	if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE,
15256 	    KM_SLEEP) != DDI_SUCCESS) {
15257 		goto alloc_failed;
15258 	}
15259 
15260 	if (nvlist_add_uint32(attr_list, "instance",
15261 	    port->fp_instance) != DDI_SUCCESS) {
15262 		goto error;
15263 	}
15264 
15265 	if (nvlist_add_byte_array(attr_list, "port-wwn",
15266 	    port->fp_service_params.nport_ww_name.raw_wwn,
15267 	    sizeof (la_wwn_t)) != DDI_SUCCESS) {
15268 		goto error;
15269 	}
15270 
15271 	(void) ddi_log_sysevent(port->fp_port_dip, DDI_VENDOR_SUNW, EC_SUNFC,
15272 	    subclass, attr_list, NULL, DDI_SLEEP);
15273 
15274 	nvlist_free(attr_list);
15275 	return;
15276 
15277 error:
15278 	nvlist_free(attr_list);
15279 alloc_failed:
15280 	FP_TRACE(FP_NHEAD1(9, 0), "Unable to send %s event", subclass);
15281 }
15282 
15283 
15284 static void
15285 fp_log_target_event(fc_local_port_t *port, char *subclass, la_wwn_t tgt_pwwn,
15286     uint32_t port_id)
15287 {
15288 	nvlist_t *attr_list;
15289 
15290 	if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE,
15291 	    KM_SLEEP) != DDI_SUCCESS) {
15292 		goto alloc_failed;
15293 	}
15294 
15295 	if (nvlist_add_uint32(attr_list, "instance",
15296 	    port->fp_instance) != DDI_SUCCESS) {
15297 		goto error;
15298 	}
15299 
15300 	if (nvlist_add_byte_array(attr_list, "port-wwn",
15301 	    port->fp_service_params.nport_ww_name.raw_wwn,
15302 	    sizeof (la_wwn_t)) != DDI_SUCCESS) {
15303 		goto error;
15304 	}
15305 
15306 	if (nvlist_add_byte_array(attr_list, "target-port-wwn",
15307 	    tgt_pwwn.raw_wwn, sizeof (la_wwn_t)) != DDI_SUCCESS) {
15308 		goto error;
15309 	}
15310 
15311 	if (nvlist_add_uint32(attr_list, "target-port-id",
15312 	    port_id) != DDI_SUCCESS) {
15313 		goto error;
15314 	}
15315 
15316 	(void) ddi_log_sysevent(port->fp_port_dip, DDI_VENDOR_SUNW, EC_SUNFC,
15317 	    subclass, attr_list, NULL, DDI_SLEEP);
15318 
15319 	nvlist_free(attr_list);
15320 	return;
15321 
15322 error:
15323 	nvlist_free(attr_list);
15324 alloc_failed:
15325 	FP_TRACE(FP_NHEAD1(9, 0), "Unable to send %s event", subclass);
15326 }
15327 
15328 static uint32_t
15329 fp_map_remote_port_state(uint32_t rm_state)
15330 {
15331 	switch (rm_state) {
15332 	case PORT_DEVICE_LOGGED_IN:
15333 		return (FC_HBA_PORTSTATE_ONLINE);
15334 	case PORT_DEVICE_VALID:
15335 	case PORT_DEVICE_INVALID:
15336 	default:
15337 		return (FC_HBA_PORTSTATE_UNKNOWN);
15338 	}
15339 }
15340