xref: /titanic_44/usr/src/uts/common/io/fibre-channel/impl/fp.c (revision d0f3f37e7f24f68fdbd85386c60e576883622762)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  *
25  * 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 };
96 
97 #define	FP_VERSION		"1.96"
98 #define	FP_NAME_VERSION		"SunFC Port v" FP_VERSION
99 
100 char *fp_version = FP_NAME_VERSION;
101 
102 static struct modldrv modldrv = {
103 	&mod_driverops,			/* Type of Module */
104 	FP_NAME_VERSION,		/* Name/Version of fp */
105 	&fp_ops				/* driver ops */
106 };
107 
108 static struct modlinkage modlinkage = {
109 	MODREV_1,	/* Rev of the loadable modules system */
110 	&modldrv,	/* NULL terminated list of */
111 	NULL		/* Linkage structures */
112 };
113 
114 
115 
116 static uint16_t ns_reg_cmds[] = {
117 	NS_RPN_ID,
118 	NS_RNN_ID,
119 	NS_RCS_ID,
120 	NS_RFT_ID,
121 	NS_RPT_ID,
122 	NS_RSPN_ID,
123 	NS_RSNN_NN
124 };
125 
126 struct fp_xlat {
127 	uchar_t	xlat_state;
128 	int	xlat_rval;
129 } fp_xlat [] = {
130 	{ FC_PKT_SUCCESS,	FC_SUCCESS },
131 	{ FC_PKT_REMOTE_STOP,	FC_FAILURE },
132 	{ FC_PKT_LOCAL_RJT,	FC_FAILURE },
133 	{ FC_PKT_NPORT_RJT,	FC_ELS_PREJECT },
134 	{ FC_PKT_FABRIC_RJT,	FC_ELS_FREJECT },
135 	{ FC_PKT_LOCAL_BSY,	FC_TRAN_BUSY },
136 	{ FC_PKT_TRAN_BSY,	FC_TRAN_BUSY },
137 	{ FC_PKT_NPORT_BSY,	FC_PBUSY },
138 	{ FC_PKT_FABRIC_BSY,	FC_FBUSY },
139 	{ FC_PKT_LS_RJT,	FC_FAILURE },
140 	{ FC_PKT_BA_RJT,	FC_FAILURE },
141 	{ FC_PKT_TIMEOUT,	FC_FAILURE },
142 	{ FC_PKT_TRAN_ERROR,	FC_TRANSPORT_ERROR },
143 	{ FC_PKT_FAILURE,	FC_FAILURE },
144 	{ FC_PKT_PORT_OFFLINE,	FC_OFFLINE }
145 };
146 
147 static uchar_t fp_valid_alpas[] = {
148 	0x01, 0x02, 0x04, 0x08, 0x0F, 0x10, 0x17, 0x18, 0x1B,
149 	0x1D, 0x1E, 0x1F, 0x23, 0x25, 0x26, 0x27, 0x29, 0x2A,
150 	0x2B, 0x2C, 0x2D, 0x2E, 0x31, 0x32, 0x33, 0x34, 0x35,
151 	0x36, 0x39, 0x3A, 0x3C, 0x43, 0x45, 0x46, 0x47, 0x49,
152 	0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x51, 0x52, 0x53, 0x54,
153 	0x55, 0x56, 0x59, 0x5A, 0x5C, 0x63, 0x65, 0x66, 0x67,
154 	0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x71, 0x72, 0x73,
155 	0x74, 0x75, 0x76, 0x79, 0x7A, 0x7C, 0x80, 0x81, 0x82,
156 	0x84, 0x88, 0x8F, 0x90, 0x97, 0x98, 0x9B, 0x9D, 0x9E,
157 	0x9F, 0xA3, 0xA5, 0xA6, 0xA7, 0xA9, 0xAA, 0xAB, 0xAC,
158 	0xAD, 0xAE, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB9,
159 	0xBA, 0xBC, 0xC3, 0xC5, 0xC6, 0xC7, 0xC9, 0xCA, 0xCB,
160 	0xCC, 0xCD, 0xCE, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
161 	0xD9, 0xDA, 0xDC, 0xE0, 0xE1, 0xE2, 0xE4, 0xE8, 0xEF
162 };
163 
164 static struct fp_perms {
165 	uint16_t	fp_ioctl_cmd;
166 	uchar_t		fp_open_flag;
167 } fp_perm_list [] = {
168 	{ FCIO_GET_NUM_DEVS, 		FP_OPEN },
169 	{ FCIO_GET_DEV_LIST,		FP_OPEN },
170 	{ FCIO_GET_SYM_PNAME,		FP_OPEN },
171 	{ FCIO_GET_SYM_NNAME,		FP_OPEN },
172 	{ FCIO_SET_SYM_PNAME,		FP_EXCL },
173 	{ FCIO_SET_SYM_NNAME,		FP_EXCL },
174 	{ FCIO_GET_LOGI_PARAMS,		FP_OPEN },
175 	{ FCIO_DEV_LOGIN,		FP_EXCL },
176 	{ FCIO_DEV_LOGOUT,		FP_EXCL },
177 	{ FCIO_GET_STATE,		FP_OPEN },
178 	{ FCIO_DEV_REMOVE,		FP_EXCL },
179 	{ FCIO_GET_FCODE_REV,		FP_OPEN },
180 	{ FCIO_GET_FW_REV,		FP_OPEN },
181 	{ FCIO_GET_DUMP_SIZE,		FP_OPEN },
182 	{ FCIO_FORCE_DUMP,		FP_EXCL },
183 	{ FCIO_GET_DUMP,		FP_OPEN },
184 	{ FCIO_GET_TOPOLOGY,		FP_OPEN },
185 	{ FCIO_RESET_LINK,		FP_EXCL },
186 	{ FCIO_RESET_HARD,		FP_EXCL },
187 	{ FCIO_RESET_HARD_CORE,		FP_EXCL },
188 	{ FCIO_DIAG,			FP_OPEN },
189 	{ FCIO_NS,			FP_EXCL },
190 	{ FCIO_DOWNLOAD_FW,		FP_EXCL },
191 	{ FCIO_DOWNLOAD_FCODE,		FP_EXCL },
192 	{ FCIO_LINK_STATUS,		FP_OPEN },
193 	{ FCIO_GET_HOST_PARAMS,		FP_OPEN },
194 	{ FCIO_GET_NODE_ID,		FP_OPEN },
195 	{ FCIO_SET_NODE_ID,		FP_EXCL },
196 	{ FCIO_SEND_NODE_ID,		FP_OPEN },
197 	{ FCIO_GET_ADAPTER_ATTRIBUTES,	FP_OPEN },
198 	{ FCIO_GET_OTHER_ADAPTER_PORTS,	FP_OPEN },
199 	{ FCIO_GET_ADAPTER_PORT_ATTRIBUTES,	FP_OPEN },
200 	{ FCIO_GET_DISCOVERED_PORT_ATTRIBUTES,	FP_OPEN },
201 	{ FCIO_GET_PORT_ATTRIBUTES,	FP_OPEN },
202 	{ FCIO_GET_ADAPTER_PORT_STATS,	FP_OPEN },
203 	{ FCIO_GET_ADAPTER_PORT_NPIV_ATTRIBUTES, FP_OPEN },
204 	{ FCIO_GET_NPIV_PORT_LIST, FP_OPEN },
205 	{ FCIO_DELETE_NPIV_PORT, FP_OPEN },
206 	{ FCIO_GET_NPIV_ATTRIBUTES, FP_OPEN },
207 	{ FCIO_CREATE_NPIV_PORT, FP_OPEN },
208 	{ FCIO_NPIV_GET_ADAPTER_ATTRIBUTES, FP_OPEN }
209 };
210 
211 static char *fp_pm_comps[] = {
212 	"NAME=FC Port",
213 	"0=Port Down",
214 	"1=Port Up"
215 };
216 
217 
218 #ifdef	_LITTLE_ENDIAN
219 #define	MAKE_BE_32(x)	{ \
220 	uint32_t	*ptr1, i; \
221 		ptr1 = (uint32_t *)(x); \
222 		for (i = 0; i < sizeof (*(x)) / sizeof (uint32_t); i++) { \
223 			*ptr1 = BE_32(*ptr1); \
224 			ptr1++; \
225 		} \
226 	}
227 #else
228 #define	MAKE_BE_32(x)
229 #endif
230 
231 static uchar_t fp_verbosity = (FP_WARNING_MESSAGES | FP_FATAL_MESSAGES);
232 static uint32_t fp_options = 0;
233 
234 static int fp_cmd_wait_cnt = FP_CMDWAIT_DELAY;
235 static int fp_retry_delay = FP_RETRY_DELAY;	/* retry after this delay */
236 static int fp_retry_count = FP_RETRY_COUNT;	/* number of retries */
237 unsigned int fp_offline_ticker;			/* seconds */
238 
239 /*
240  * Driver global variable to anchor the list of soft state structs for
241  * all fp driver instances.  Used with the Solaris DDI soft state functions.
242  */
243 static void *fp_driver_softstate;
244 
245 static clock_t	fp_retry_ticks;
246 static clock_t	fp_offline_ticks;
247 
248 static int fp_retry_ticker;
249 static uint32_t fp_unsol_buf_count = FP_UNSOL_BUF_COUNT;
250 static uint32_t fp_unsol_buf_size = FP_UNSOL_BUF_SIZE;
251 
252 static int		fp_log_size = FP_LOG_SIZE;
253 static int		fp_trace = FP_TRACE_DEFAULT;
254 static fc_trace_logq_t	*fp_logq = NULL;
255 
256 int fp_get_adapter_paths(char *pathList, int count);
257 static void fp_log_port_event(fc_local_port_t *port, char *subclass);
258 static void fp_log_target_event(fc_local_port_t *port, char *subclass,
259 	    la_wwn_t tgt_pwwn, uint32_t port_id);
260 static uint32_t fp_map_remote_port_state(uint32_t rm_state);
261 static void fp_init_symbolic_names(fc_local_port_t *port);
262 
263 
264 /*
265  * Perform global initialization
266  */
267 int
268 _init(void)
269 {
270 	int ret;
271 
272 	if ((ret = ddi_soft_state_init(&fp_driver_softstate,
273 	    sizeof (struct fc_local_port), 8)) != 0) {
274 		return (ret);
275 	}
276 
277 	if ((ret = scsi_hba_init(&modlinkage)) != 0) {
278 		ddi_soft_state_fini(&fp_driver_softstate);
279 		return (ret);
280 	}
281 
282 	fp_logq = fc_trace_alloc_logq(fp_log_size);
283 
284 	if ((ret = mod_install(&modlinkage)) != 0) {
285 		fc_trace_free_logq(fp_logq);
286 		ddi_soft_state_fini(&fp_driver_softstate);
287 		scsi_hba_fini(&modlinkage);
288 	}
289 
290 	return (ret);
291 }
292 
293 
294 /*
295  * Prepare for driver unload
296  */
297 int
298 _fini(void)
299 {
300 	int ret;
301 
302 	if ((ret = mod_remove(&modlinkage)) == 0) {
303 		fc_trace_free_logq(fp_logq);
304 		ddi_soft_state_fini(&fp_driver_softstate);
305 		scsi_hba_fini(&modlinkage);
306 	}
307 
308 	return (ret);
309 }
310 
311 
312 /*
313  * Request mod_info() to handle all cases
314  */
315 int
316 _info(struct modinfo *modinfo)
317 {
318 	return (mod_info(&modlinkage, modinfo));
319 }
320 
321 
322 /*
323  * fp_attach:
324  *
325  * The respective cmd handlers take care of performing
326  * ULP related invocations
327  */
328 static int
329 fp_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
330 {
331 	int rval;
332 
333 	/*
334 	 * We check the value of fp_offline_ticker at this
335 	 * point. The variable is global for the driver and
336 	 * not specific to an instance.
337 	 *
338 	 * If there is no user-defined value found in /etc/system
339 	 * or fp.conf, then we use 90 seconds (FP_OFFLINE_TICKER).
340 	 * The minimum setting for this offline timeout according
341 	 * to the FC-FS2 standard (Fibre Channel Framing and
342 	 * Signalling-2, see www.t11.org) is R_T_TOV == 100msec.
343 	 *
344 	 * We do not recommend setting the value to less than 10
345 	 * seconds (RA_TOV) or more than 90 seconds. If this
346 	 * variable is greater than 90 seconds then drivers above
347 	 * fp (fcp, sd, scsi_vhci, vxdmp et al) might complain.
348 	 */
349 
350 	fp_offline_ticker = ddi_prop_get_int(DDI_DEV_T_ANY,
351 	    dip, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "fp_offline_ticker",
352 	    FP_OFFLINE_TICKER);
353 
354 	if ((fp_offline_ticker < 10) ||
355 	    (fp_offline_ticker > 90)) {
356 		cmn_err(CE_WARN, "Setting fp_offline_ticker to "
357 		    "%d second(s). This is outside the "
358 		    "recommended range of 10..90 seconds",
359 		    fp_offline_ticker);
360 	}
361 
362 	/*
363 	 * Tick every second when there are commands to retry.
364 	 * It should tick at the least granular value of pkt_timeout
365 	 * (which is one second)
366 	 */
367 	fp_retry_ticker = 1;
368 
369 	fp_retry_ticks = drv_usectohz(fp_retry_ticker * 1000 * 1000);
370 	fp_offline_ticks = drv_usectohz(fp_offline_ticker * 1000 * 1000);
371 
372 	switch (cmd) {
373 	case DDI_ATTACH:
374 		rval = fp_attach_handler(dip);
375 		break;
376 
377 	case DDI_RESUME:
378 		rval = fp_resume_handler(dip);
379 		break;
380 
381 	default:
382 		rval = DDI_FAILURE;
383 		break;
384 	}
385 	return (rval);
386 }
387 
388 
389 /*
390  * fp_detach:
391  *
392  * If a ULP fails to handle cmd request converse of
393  * cmd is invoked for ULPs that previously succeeded
394  * cmd request.
395  */
396 static int
397 fp_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
398 {
399 	int 			rval = DDI_FAILURE;
400 	fc_local_port_t 	*port;
401 	fc_attach_cmd_t 	converse;
402 	uint8_t			cnt;
403 
404 	if ((port = ddi_get_soft_state(fp_driver_softstate,
405 	    ddi_get_instance(dip))) == NULL) {
406 		return (DDI_FAILURE);
407 	}
408 
409 	mutex_enter(&port->fp_mutex);
410 
411 	if (port->fp_ulp_attach) {
412 		mutex_exit(&port->fp_mutex);
413 		return (DDI_FAILURE);
414 	}
415 
416 	switch (cmd) {
417 	case DDI_DETACH:
418 		if (port->fp_task != FP_TASK_IDLE) {
419 			mutex_exit(&port->fp_mutex);
420 			return (DDI_FAILURE);
421 		}
422 
423 		/* Let's attempt to quit the job handler gracefully */
424 		port->fp_soft_state |= FP_DETACH_INPROGRESS;
425 
426 		mutex_exit(&port->fp_mutex);
427 		converse = FC_CMD_ATTACH;
428 		if (fctl_detach_ulps(port, FC_CMD_DETACH,
429 		    &modlinkage) != FC_SUCCESS) {
430 			mutex_enter(&port->fp_mutex);
431 			port->fp_soft_state &= ~FP_DETACH_INPROGRESS;
432 			mutex_exit(&port->fp_mutex);
433 			rval = DDI_FAILURE;
434 			break;
435 		}
436 
437 		mutex_enter(&port->fp_mutex);
438 		for (cnt = 0; (port->fp_job_head) && (cnt < fp_cmd_wait_cnt);
439 		    cnt++) {
440 			mutex_exit(&port->fp_mutex);
441 			delay(drv_usectohz(1000000));
442 			mutex_enter(&port->fp_mutex);
443 		}
444 
445 		if (port->fp_job_head) {
446 			mutex_exit(&port->fp_mutex);
447 			rval = DDI_FAILURE;
448 			break;
449 		}
450 		mutex_exit(&port->fp_mutex);
451 
452 		rval = fp_detach_handler(port);
453 		break;
454 
455 	case DDI_SUSPEND:
456 		mutex_exit(&port->fp_mutex);
457 		converse = FC_CMD_RESUME;
458 		if (fctl_detach_ulps(port, FC_CMD_SUSPEND,
459 		    &modlinkage) != FC_SUCCESS) {
460 			rval = DDI_FAILURE;
461 			break;
462 		}
463 		if ((rval = fp_suspend_handler(port)) != DDI_SUCCESS) {
464 			(void) callb_generic_cpr(&port->fp_cpr_info,
465 			    CB_CODE_CPR_RESUME);
466 		}
467 		break;
468 
469 	default:
470 		mutex_exit(&port->fp_mutex);
471 		break;
472 	}
473 
474 	/*
475 	 * Use softint to perform reattach.  Mark fp_ulp_attach so we
476 	 * don't attempt to do this repeatedly on behalf of some persistent
477 	 * caller.
478 	 */
479 	if (rval != DDI_SUCCESS) {
480 		mutex_enter(&port->fp_mutex);
481 		port->fp_ulp_attach = 1;
482 
483 		/*
484 		 * If the port is in the low power mode then there is
485 		 * possibility that fca too could be in low power mode.
486 		 * Try to raise the power before calling attach ulps.
487 		 */
488 
489 		if ((port->fp_soft_state & FP_SOFT_POWER_DOWN) &&
490 		    (!(port->fp_soft_state & FP_SOFT_NO_PMCOMP))) {
491 			mutex_exit(&port->fp_mutex);
492 			(void) pm_raise_power(port->fp_port_dip,
493 			    FP_PM_COMPONENT, FP_PM_PORT_UP);
494 		} else {
495 			mutex_exit(&port->fp_mutex);
496 		}
497 
498 
499 		fp_attach_ulps(port, converse);
500 
501 		mutex_enter(&port->fp_mutex);
502 		while (port->fp_ulp_attach) {
503 			cv_wait(&port->fp_attach_cv, &port->fp_mutex);
504 		}
505 
506 		port->fp_soft_state &= ~FP_DETACH_INPROGRESS;
507 
508 		/*
509 		 * Mark state as detach failed so asynchronous ULP attach
510 		 * events (downstream, not the ones we're initiating with
511 		 * the call to fp_attach_ulps) are not honored.  We're
512 		 * really still in pending detach.
513 		 */
514 		port->fp_soft_state |= FP_DETACH_FAILED;
515 
516 		mutex_exit(&port->fp_mutex);
517 	}
518 
519 	return (rval);
520 }
521 
522 
523 /*
524  * fp_getinfo:
525  *   Given the device number, return either the
526  *   dev_info_t pointer or the instance number.
527  */
528 
529 /* ARGSUSED */
530 static int
531 fp_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
532 {
533 	int 		rval;
534 	minor_t		instance;
535 	fc_local_port_t *port;
536 
537 	rval = DDI_SUCCESS;
538 	instance = getminor((dev_t)arg);
539 
540 	switch (cmd) {
541 	case DDI_INFO_DEVT2DEVINFO:
542 		if ((port = ddi_get_soft_state(fp_driver_softstate,
543 		    instance)) == NULL) {
544 			rval = DDI_FAILURE;
545 			break;
546 		}
547 		*result = (void *)port->fp_port_dip;
548 		break;
549 
550 	case DDI_INFO_DEVT2INSTANCE:
551 		*result = (void *)(uintptr_t)instance;
552 		break;
553 
554 	default:
555 		rval = DDI_FAILURE;
556 		break;
557 	}
558 
559 	return (rval);
560 }
561 
562 
563 /*
564  * Entry point for power up and power down request from kernel
565  */
566 static int
567 fp_power(dev_info_t *dip, int comp, int level)
568 {
569 	int		rval = DDI_FAILURE;
570 	fc_local_port_t	*port;
571 
572 	port = ddi_get_soft_state(fp_driver_softstate, ddi_get_instance(dip));
573 	if (port == NULL || comp != FP_PM_COMPONENT) {
574 		return (rval);
575 	}
576 
577 	switch (level) {
578 	case FP_PM_PORT_UP:
579 		rval = DDI_SUCCESS;
580 
581 		/*
582 		 * If the port is DDI_SUSPENDed, let the DDI_RESUME
583 		 * code complete the rediscovery.
584 		 */
585 		mutex_enter(&port->fp_mutex);
586 		if (port->fp_soft_state & FP_SOFT_SUSPEND) {
587 			port->fp_soft_state &= ~FP_SOFT_POWER_DOWN;
588 			port->fp_pm_level = FP_PM_PORT_UP;
589 			mutex_exit(&port->fp_mutex);
590 			fctl_attach_ulps(port, FC_CMD_POWER_UP, &modlinkage);
591 			break;
592 		}
593 
594 		if (port->fp_soft_state & FP_SOFT_POWER_DOWN) {
595 			ASSERT(port->fp_pm_level == FP_PM_PORT_DOWN);
596 
597 			port->fp_pm_level = FP_PM_PORT_UP;
598 			rval = fp_power_up(port);
599 			if (rval != DDI_SUCCESS) {
600 				port->fp_pm_level = FP_PM_PORT_DOWN;
601 			}
602 		} else {
603 			port->fp_pm_level = FP_PM_PORT_UP;
604 		}
605 		mutex_exit(&port->fp_mutex);
606 		break;
607 
608 	case FP_PM_PORT_DOWN:
609 		mutex_enter(&port->fp_mutex);
610 
611 		ASSERT(!(port->fp_soft_state & FP_SOFT_NO_PMCOMP));
612 		if (port->fp_soft_state & FP_SOFT_NO_PMCOMP) {
613 			/*
614 			 * PM framework goofed up. We have don't
615 			 * have any PM components. Let's never go down.
616 			 */
617 			mutex_exit(&port->fp_mutex);
618 			break;
619 
620 		}
621 
622 		if (port->fp_ulp_attach) {
623 			/* We shouldn't let the power go down */
624 			mutex_exit(&port->fp_mutex);
625 			break;
626 		}
627 
628 		/*
629 		 * Not a whole lot to do if we are detaching
630 		 */
631 		if (port->fp_soft_state & FP_SOFT_IN_DETACH) {
632 			port->fp_pm_level = FP_PM_PORT_DOWN;
633 			mutex_exit(&port->fp_mutex);
634 			rval = DDI_SUCCESS;
635 			break;
636 		}
637 
638 		if (!port->fp_pm_busy && !port->fp_pm_busy_nocomp) {
639 			port->fp_pm_level = FP_PM_PORT_DOWN;
640 
641 			rval = fp_power_down(port);
642 			if (rval != DDI_SUCCESS) {
643 				port->fp_pm_level = FP_PM_PORT_UP;
644 				ASSERT(!(port->fp_soft_state &
645 				    FP_SOFT_POWER_DOWN));
646 			} else {
647 				ASSERT(port->fp_soft_state &
648 				    FP_SOFT_POWER_DOWN);
649 			}
650 		}
651 		mutex_exit(&port->fp_mutex);
652 		break;
653 
654 	default:
655 		break;
656 	}
657 
658 	return (rval);
659 }
660 
661 
662 /*
663  * Open FC port devctl node
664  */
665 static int
666 fp_open(dev_t *devp, int flag, int otype, cred_t *credp)
667 {
668 	int 		instance;
669 	fc_local_port_t *port;
670 
671 	if (otype != OTYP_CHR) {
672 		return (EINVAL);
673 	}
674 
675 	/*
676 	 * This is not a toy to play with. Allow only powerful
677 	 * users (hopefully knowledgeable) to access the port
678 	 * (A hacker potentially could download a sick binary
679 	 * file into FCA)
680 	 */
681 	if (drv_priv(credp)) {
682 		return (EPERM);
683 	}
684 
685 	instance = (int)getminor(*devp);
686 
687 	port = ddi_get_soft_state(fp_driver_softstate, instance);
688 	if (port == NULL) {
689 		return (ENXIO);
690 	}
691 
692 	mutex_enter(&port->fp_mutex);
693 	if (port->fp_flag & FP_EXCL) {
694 		/*
695 		 * It is already open for exclusive access.
696 		 * So shut the door on this caller.
697 		 */
698 		mutex_exit(&port->fp_mutex);
699 		return (EBUSY);
700 	}
701 
702 	if (flag & FEXCL) {
703 		if (port->fp_flag & FP_OPEN) {
704 			/*
705 			 * Exclusive operation not possible
706 			 * as it is already opened
707 			 */
708 			mutex_exit(&port->fp_mutex);
709 			return (EBUSY);
710 		}
711 		port->fp_flag |= FP_EXCL;
712 	}
713 	port->fp_flag |= FP_OPEN;
714 	mutex_exit(&port->fp_mutex);
715 
716 	return (0);
717 }
718 
719 
720 /*
721  * The driver close entry point is called on the last close()
722  * of a device. So it is perfectly alright to just clobber the
723  * open flag and reset it to idle (instead of having to reset
724  * each flag bits). For any confusion, check out close(9E).
725  */
726 
727 /* ARGSUSED */
728 static int
729 fp_close(dev_t dev, int flag, int otype, cred_t *credp)
730 {
731 	int 		instance;
732 	fc_local_port_t *port;
733 
734 	if (otype != OTYP_CHR) {
735 		return (EINVAL);
736 	}
737 
738 	instance = (int)getminor(dev);
739 
740 	port = ddi_get_soft_state(fp_driver_softstate, instance);
741 	if (port == NULL) {
742 		return (ENXIO);
743 	}
744 
745 	mutex_enter(&port->fp_mutex);
746 	if ((port->fp_flag & FP_OPEN) == 0) {
747 		mutex_exit(&port->fp_mutex);
748 		return (ENODEV);
749 	}
750 	port->fp_flag = FP_IDLE;
751 	mutex_exit(&port->fp_mutex);
752 
753 	return (0);
754 }
755 
756 /*
757  * Handle IOCTL requests
758  */
759 
760 /* ARGSUSED */
761 static int
762 fp_ioctl(dev_t dev, int cmd, intptr_t data, int mode, cred_t *credp, int *rval)
763 {
764 	int 		instance;
765 	int		ret = 0;
766 	fcio_t		fcio;
767 	fc_local_port_t *port;
768 
769 	instance = (int)getminor(dev);
770 
771 	port = ddi_get_soft_state(fp_driver_softstate, instance);
772 	if (port == NULL) {
773 		return (ENXIO);
774 	}
775 
776 	mutex_enter(&port->fp_mutex);
777 	if ((port->fp_flag & FP_OPEN) == 0) {
778 		mutex_exit(&port->fp_mutex);
779 		return (ENXIO);
780 	}
781 
782 	if (port->fp_soft_state & FP_SOFT_SUSPEND) {
783 		mutex_exit(&port->fp_mutex);
784 		return (ENXIO);
785 	}
786 
787 	mutex_exit(&port->fp_mutex);
788 
789 	/* this will raise power if necessary */
790 	ret = fctl_busy_port(port);
791 	if (ret != 0) {
792 		return (ret);
793 	}
794 
795 	ASSERT(port->fp_pm_level == FP_PM_PORT_UP);
796 
797 
798 	switch (cmd) {
799 	case FCIO_CMD: {
800 #ifdef	_MULTI_DATAMODEL
801 		switch (ddi_model_convert_from(mode & FMODELS)) {
802 		case DDI_MODEL_ILP32: {
803 			struct fcio32 fcio32;
804 
805 			if (ddi_copyin((void *)data, (void *)&fcio32,
806 			    sizeof (struct fcio32), mode)) {
807 				ret = EFAULT;
808 				break;
809 			}
810 			fcio.fcio_xfer = fcio32.fcio_xfer;
811 			fcio.fcio_cmd = fcio32.fcio_cmd;
812 			fcio.fcio_flags = fcio32.fcio_flags;
813 			fcio.fcio_cmd_flags = fcio32.fcio_cmd_flags;
814 			fcio.fcio_ilen = (size_t)fcio32.fcio_ilen;
815 			fcio.fcio_ibuf =
816 				(caddr_t)(uintptr_t)fcio32.fcio_ibuf;
817 			fcio.fcio_olen = (size_t)fcio32.fcio_olen;
818 			fcio.fcio_obuf =
819 				(caddr_t)(uintptr_t)fcio32.fcio_obuf;
820 			fcio.fcio_alen = (size_t)fcio32.fcio_alen;
821 			fcio.fcio_abuf =
822 				(caddr_t)(uintptr_t)fcio32.fcio_abuf;
823 			fcio.fcio_errno = fcio32.fcio_errno;
824 			break;
825 		}
826 
827 		case DDI_MODEL_NONE:
828 			if (ddi_copyin((void *)data, (void *)&fcio,
829 			    sizeof (fcio_t), mode)) {
830 				ret = EFAULT;
831 			}
832 			break;
833 		}
834 #else	/* _MULTI_DATAMODEL */
835 		if (ddi_copyin((void *)data, (void *)&fcio,
836 		sizeof (fcio_t), mode)) {
837 			ret = EFAULT;
838 			break;
839 		}
840 #endif	/* _MULTI_DATAMODEL */
841 		if (!ret) {
842 			ret = fp_fciocmd(port, data, mode, &fcio);
843 		}
844 		break;
845 	}
846 
847 	default:
848 		ret = fctl_ulp_port_ioctl(port, dev, cmd, data,
849 		    mode, credp, rval);
850 	}
851 
852 	fctl_idle_port(port);
853 
854 	return (ret);
855 }
856 
857 
858 /*
859  * Init Symbolic Port Name and Node Name
860  * LV will try to get symbolic names from FCA driver
861  * and register these to name server,
862  * if LV fails to get these,
863  * LV will register its default symbolic names to name server.
864  * The Default symbolic node name format is :
865  * 	<hostname>:<hba driver name>(instance)
866  * The Default symbolic port name format is :
867  * 	<fp path name>
868  */
869 static void
870 fp_init_symbolic_names(fc_local_port_t *port)
871 {
872 	const char *vendorname = ddi_driver_name(port->fp_fca_dip);
873 	char *sym_name;
874 	char fcaname[50] = {0};
875 	int hostnlen, fcanlen;
876 
877 	if (port->fp_sym_node_namelen == 0) {
878 		hostnlen = strlen(utsname.nodename);
879 		(void) snprintf(fcaname, sizeof (fcaname),
880 		    "%s%d", vendorname, ddi_get_instance(port->fp_fca_dip));
881 		fcanlen = strlen(fcaname);
882 
883 		sym_name = kmem_zalloc(hostnlen + fcanlen + 2, KM_SLEEP);
884 		(void) sprintf(sym_name, "%s:%s", utsname.nodename, fcaname);
885 		port->fp_sym_node_namelen = strlen(sym_name);
886 		if (port->fp_sym_node_namelen >= FCHBA_SYMB_NAME_LEN) {
887 			port->fp_sym_node_namelen = FCHBA_SYMB_NAME_LEN;
888 		}
889 		(void) strncpy(port->fp_sym_node_name, sym_name,
890 		    port->fp_sym_node_namelen);
891 		kmem_free(sym_name, hostnlen + fcanlen + 2);
892 	}
893 
894 	if (port->fp_sym_port_namelen == 0) {
895 		char *pathname = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
896 
897 		(void) ddi_pathname(port->fp_port_dip, pathname);
898 		port->fp_sym_port_namelen = strlen(pathname);
899 		if (port->fp_sym_port_namelen >= FCHBA_SYMB_NAME_LEN) {
900 			port->fp_sym_port_namelen = FCHBA_SYMB_NAME_LEN;
901 		}
902 		(void) strncpy(port->fp_sym_port_name, pathname,
903 		    port->fp_sym_port_namelen);
904 		kmem_free(pathname, MAXPATHLEN);
905 	}
906 }
907 
908 
909 /*
910  * Perform port attach
911  */
912 static int
913 fp_attach_handler(dev_info_t *dip)
914 {
915 	int			rval;
916 	int			instance;
917 	int 			port_num;
918 	int			port_len;
919 	char 			name[30];
920 	char			i_pwwn[17];
921 	fp_cmd_t		*pkt;
922 	uint32_t		ub_count;
923 	fc_local_port_t 	*port;
924 	job_request_t 		*job;
925 	fc_local_port_t *phyport = NULL;
926 	int portpro1;
927 	char pwwn[17], nwwn[17];
928 
929 	instance = ddi_get_instance(dip);
930 
931 	port_len = sizeof (port_num);
932 
933 	rval = ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF,
934 	    DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "port",
935 	    (caddr_t)&port_num, &port_len);
936 
937 	if (rval != DDI_SUCCESS) {
938 		cmn_err(CE_WARN, "fp(%d): No port property in devinfo",
939 		    instance);
940 		return (DDI_FAILURE);
941 	}
942 
943 	if (ddi_create_minor_node(dip, "devctl", S_IFCHR, instance,
944 	    DDI_NT_NEXUS, 0) != DDI_SUCCESS) {
945 		cmn_err(CE_WARN, "fp(%d): failed to create devctl minor node",
946 		    instance);
947 		return (DDI_FAILURE);
948 	}
949 
950 	if (ddi_create_minor_node(dip, "fc", S_IFCHR, instance,
951 	    DDI_NT_FC_ATTACHMENT_POINT, 0) != DDI_SUCCESS) {
952 		cmn_err(CE_WARN, "fp(%d): failed to create fc attachment"
953 		    " point minor node", instance);
954 		ddi_remove_minor_node(dip, NULL);
955 		return (DDI_FAILURE);
956 	}
957 
958 	if (ddi_soft_state_zalloc(fp_driver_softstate, instance)
959 	    != DDI_SUCCESS) {
960 		cmn_err(CE_WARN, "fp(%d): failed to alloc soft state",
961 		    instance);
962 		ddi_remove_minor_node(dip, NULL);
963 		return (DDI_FAILURE);
964 	}
965 	port = ddi_get_soft_state(fp_driver_softstate, instance);
966 
967 	(void) sprintf(port->fp_ibuf, "fp(%d)", instance);
968 
969 	port->fp_instance = instance;
970 	port->fp_ulp_attach = 1;
971 	port->fp_port_num = port_num;
972 	port->fp_verbose = fp_verbosity;
973 	port->fp_options = fp_options;
974 
975 	port->fp_fca_dip = ddi_get_parent(dip);
976 	port->fp_port_dip = dip;
977 	port->fp_fca_tran = (fc_fca_tran_t *)
978 	    ddi_get_driver_private(port->fp_fca_dip);
979 
980 	port->fp_task = port->fp_last_task = FP_TASK_IDLE;
981 
982 	/*
983 	 * Init the starting value of fp_rscn_count. Note that if
984 	 * FC_INVALID_RSCN_COUNT is 0 (which is what it currently is), the
985 	 * actual # of RSCNs will be (fp_rscn_count - 1)
986 	 */
987 	port->fp_rscn_count = FC_INVALID_RSCN_COUNT + 1;
988 
989 	mutex_init(&port->fp_mutex, NULL, MUTEX_DRIVER, NULL);
990 	cv_init(&port->fp_cv, NULL, CV_DRIVER, NULL);
991 	cv_init(&port->fp_attach_cv, NULL, CV_DRIVER, NULL);
992 
993 	(void) sprintf(name, "fp%d_cache", instance);
994 
995 	if ((portpro1 = ddi_prop_get_int(DDI_DEV_T_ANY,
996 	    dip, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
997 	    "phyport-instance", -1)) != -1) {
998 		phyport = ddi_get_soft_state(fp_driver_softstate, portpro1);
999 		fc_wwn_to_str(&phyport->fp_service_params.nport_ww_name, pwwn);
1000 		fc_wwn_to_str(&phyport->fp_service_params.node_ww_name, nwwn);
1001 		port->fp_npiv_type = FC_NPIV_PORT;
1002 	}
1003 
1004 	/*
1005 	 * Allocate the pool of fc_packet_t structs to be used with
1006 	 * this fp instance.
1007 	 */
1008 	port->fp_pkt_cache = kmem_cache_create(name,
1009 	    (port->fp_fca_tran->fca_pkt_size) + sizeof (fp_cmd_t), 8,
1010 	    fp_cache_constructor, fp_cache_destructor, NULL, (void *)port,
1011 	    NULL, 0);
1012 
1013 	if (port->fp_pkt_cache == NULL) {
1014 		goto cache_alloc_failed;
1015 	}
1016 
1017 
1018 	/*
1019 	 * Allocate the d_id and pwwn hash tables for all remote ports
1020 	 * connected to this local port.
1021 	 */
1022 	port->fp_did_table = kmem_zalloc(did_table_size *
1023 	    sizeof (struct d_id_hash), KM_SLEEP);
1024 
1025 	port->fp_pwwn_table = kmem_zalloc(pwwn_table_size *
1026 	    sizeof (struct pwwn_hash), KM_SLEEP);
1027 
1028 	port->fp_taskq = taskq_create("fp_ulp_callback", 1,
1029 	    MINCLSYSPRI, 1, 16, 0);
1030 
1031 	/* Indicate that don't have the pm components yet */
1032 	port->fp_soft_state |=  FP_SOFT_NO_PMCOMP;
1033 
1034 	/*
1035 	 * Bind the callbacks with the FCA driver. This will open the gate
1036 	 * for asynchronous callbacks, so after this call the fp_mutex
1037 	 * must be held when updating the fc_local_port_t struct.
1038 	 *
1039 	 * This is done _before_ setting up the job thread so we can avoid
1040 	 * cleaning up after the thread_create() in the error path. This
1041 	 * also means fp will be operating with fp_els_resp_pkt set to NULL.
1042 	 */
1043 	if (fp_bind_callbacks(port) != DDI_SUCCESS) {
1044 		goto bind_callbacks_failed;
1045 	}
1046 
1047 	if (phyport) {
1048 		mutex_enter(&phyport->fp_mutex);
1049 		if (phyport->fp_port_next) {
1050 			phyport->fp_port_next->fp_port_prev = port;
1051 			port->fp_port_next =  phyport->fp_port_next;
1052 			phyport->fp_port_next = port;
1053 			port->fp_port_prev = phyport;
1054 		} else {
1055 			phyport->fp_port_next = port;
1056 			phyport->fp_port_prev = port;
1057 			port->fp_port_next =  phyport;
1058 			port->fp_port_prev = phyport;
1059 		}
1060 		mutex_exit(&phyport->fp_mutex);
1061 	}
1062 
1063 	/*
1064 	 * Init Symbolic Names
1065 	 */
1066 	fp_init_symbolic_names(port);
1067 
1068 	pkt = fp_alloc_pkt(port, sizeof (la_els_logi_t), sizeof (la_els_logi_t),
1069 	    KM_SLEEP, NULL);
1070 
1071 	if (pkt == NULL) {
1072 		cmn_err(CE_WARN, "fp(%d): failed to allocate ELS packet",
1073 		    instance);
1074 		goto alloc_els_packet_failed;
1075 	}
1076 
1077 	(void) thread_create(NULL, 0, fp_job_handler, port, 0, &p0, TS_RUN,
1078 	    v.v_maxsyspri - 2);
1079 
1080 	fc_wwn_to_str(&port->fp_service_params.nport_ww_name, i_pwwn);
1081 	if (ddi_prop_update_string(DDI_DEV_T_NONE, dip, "initiator-port",
1082 	    i_pwwn) != DDI_PROP_SUCCESS) {
1083 		fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
1084 		    "fp(%d): Updating 'initiator-port' property"
1085 		    " on fp dev_info node failed", instance);
1086 	}
1087 
1088 	fc_wwn_to_str(&port->fp_service_params.node_ww_name, i_pwwn);
1089 	if (ddi_prop_update_string(DDI_DEV_T_NONE, dip, "initiator-node",
1090 	    i_pwwn) != DDI_PROP_SUCCESS) {
1091 		fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
1092 		    "fp(%d): Updating 'initiator-node' property"
1093 		    " on fp dev_info node failed", instance);
1094 	}
1095 
1096 	mutex_enter(&port->fp_mutex);
1097 	port->fp_els_resp_pkt = pkt;
1098 	mutex_exit(&port->fp_mutex);
1099 
1100 	/*
1101 	 * Determine the count of unsolicited buffers this FCA can support
1102 	 */
1103 	fp_retrieve_caps(port);
1104 
1105 	/*
1106 	 * Allocate unsolicited buffer tokens
1107 	 */
1108 	if (port->fp_ub_count) {
1109 		ub_count = port->fp_ub_count;
1110 		port->fp_ub_tokens = kmem_zalloc(ub_count *
1111 		    sizeof (*port->fp_ub_tokens), KM_SLEEP);
1112 		/*
1113 		 * Do not fail the attach if unsolicited buffer allocation
1114 		 * fails; Just try to get along with whatever the FCA can do.
1115 		 */
1116 		if (fc_ulp_uballoc(port, &ub_count, fp_unsol_buf_size,
1117 		    FC_TYPE_EXTENDED_LS, port->fp_ub_tokens) !=
1118 		    FC_SUCCESS || ub_count != port->fp_ub_count) {
1119 			cmn_err(CE_WARN, "fp(%d): failed to allocate "
1120 			    " Unsolicited buffers. proceeding with attach...",
1121 			    instance);
1122 			kmem_free(port->fp_ub_tokens,
1123 			    sizeof (*port->fp_ub_tokens) * port->fp_ub_count);
1124 			port->fp_ub_tokens = NULL;
1125 		}
1126 	}
1127 
1128 	fp_load_ulp_modules(dip, port);
1129 
1130 	/*
1131 	 * Enable DDI_SUSPEND and DDI_RESUME for this instance.
1132 	 */
1133 	(void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
1134 	    "pm-hardware-state", "needs-suspend-resume",
1135 	    strlen("needs-suspend-resume") + 1);
1136 
1137 	/*
1138 	 * fctl maintains a list of all port handles, so
1139 	 * help fctl add this one to its list now.
1140 	 */
1141 	mutex_enter(&port->fp_mutex);
1142 	fctl_add_port(port);
1143 
1144 	/*
1145 	 * If a state change is already in progress, set the bind state t
1146 	 * OFFLINE as well, so further state change callbacks into ULPs
1147 	 * will pass the appropriate states
1148 	 */
1149 	if (FC_PORT_STATE_MASK(port->fp_bind_state) == FC_STATE_OFFLINE ||
1150 	    port->fp_statec_busy) {
1151 		port->fp_bind_state = FC_STATE_OFFLINE;
1152 		mutex_exit(&port->fp_mutex);
1153 
1154 		fp_startup_done((opaque_t)port, FC_PKT_SUCCESS);
1155 	} else {
1156 		/*
1157 		 * Without dropping the mutex, ensure that the port
1158 		 * startup happens ahead of state change callback
1159 		 * processing
1160 		 */
1161 		ASSERT(port->fp_job_tail == NULL && port->fp_job_head == NULL);
1162 
1163 		port->fp_last_task = port->fp_task;
1164 		port->fp_task = FP_TASK_PORT_STARTUP;
1165 
1166 		job = fctl_alloc_job(JOB_PORT_STARTUP, JOB_TYPE_FCTL_ASYNC,
1167 		    fp_startup_done, (opaque_t)port, KM_SLEEP);
1168 
1169 		port->fp_job_head = port->fp_job_tail = job;
1170 
1171 		cv_signal(&port->fp_cv);
1172 
1173 		mutex_exit(&port->fp_mutex);
1174 	}
1175 
1176 	mutex_enter(&port->fp_mutex);
1177 	while (port->fp_ulp_attach) {
1178 		cv_wait(&port->fp_attach_cv, &port->fp_mutex);
1179 	}
1180 	mutex_exit(&port->fp_mutex);
1181 
1182 	if (ddi_prop_update_string_array(DDI_DEV_T_NONE, dip,
1183 	    "pm-components", fp_pm_comps,
1184 	    sizeof (fp_pm_comps) / sizeof (fp_pm_comps[0])) !=
1185 	    DDI_PROP_SUCCESS) {
1186 		FP_TRACE(FP_NHEAD2(9, 0), "Failed to create PM"
1187 		    " components property, PM disabled on this port.");
1188 		mutex_enter(&port->fp_mutex);
1189 		port->fp_pm_level = FP_PM_PORT_UP;
1190 		mutex_exit(&port->fp_mutex);
1191 	} else {
1192 		if (pm_raise_power(dip, FP_PM_COMPONENT,
1193 		    FP_PM_PORT_UP) != DDI_SUCCESS) {
1194 			FP_TRACE(FP_NHEAD2(9, 0), "Failed to raise"
1195 			    " power level");
1196 			mutex_enter(&port->fp_mutex);
1197 			port->fp_pm_level = FP_PM_PORT_UP;
1198 			mutex_exit(&port->fp_mutex);
1199 		}
1200 
1201 		/*
1202 		 * Don't unset the FP_SOFT_NO_PMCOMP flag until after
1203 		 * the call to pm_raise_power.  The PM framework can't
1204 		 * handle multiple threads calling into it during attach.
1205 		 */
1206 
1207 		mutex_enter(&port->fp_mutex);
1208 		port->fp_soft_state &=  ~FP_SOFT_NO_PMCOMP;
1209 		mutex_exit(&port->fp_mutex);
1210 	}
1211 
1212 	ddi_report_dev(dip);
1213 
1214 	fp_log_port_event(port, ESC_SUNFC_PORT_ATTACH);
1215 
1216 	return (DDI_SUCCESS);
1217 
1218 	/*
1219 	 * Unwind any/all preceeding allocations in the event of an error.
1220 	 */
1221 
1222 alloc_els_packet_failed:
1223 
1224 	if (port->fp_fca_handle != NULL) {
1225 		port->fp_fca_tran->fca_unbind_port(port->fp_fca_handle);
1226 		port->fp_fca_handle = NULL;
1227 	}
1228 
1229 	if (port->fp_ub_tokens != NULL) {
1230 		(void) fc_ulp_ubfree(port, port->fp_ub_count,
1231 		    port->fp_ub_tokens);
1232 		kmem_free(port->fp_ub_tokens,
1233 		    port->fp_ub_count * sizeof (*port->fp_ub_tokens));
1234 		port->fp_ub_tokens = NULL;
1235 	}
1236 
1237 	if (port->fp_els_resp_pkt != NULL) {
1238 		fp_free_pkt(port->fp_els_resp_pkt);
1239 		port->fp_els_resp_pkt = NULL;
1240 	}
1241 
1242 bind_callbacks_failed:
1243 
1244 	if (port->fp_taskq != NULL) {
1245 		taskq_destroy(port->fp_taskq);
1246 	}
1247 
1248 	if (port->fp_pwwn_table != NULL) {
1249 		kmem_free(port->fp_pwwn_table,
1250 		    pwwn_table_size * sizeof (struct pwwn_hash));
1251 		port->fp_pwwn_table = NULL;
1252 	}
1253 
1254 	if (port->fp_did_table != NULL) {
1255 		kmem_free(port->fp_did_table,
1256 		    did_table_size * sizeof (struct d_id_hash));
1257 		port->fp_did_table = NULL;
1258 	}
1259 
1260 	if (port->fp_pkt_cache != NULL) {
1261 		kmem_cache_destroy(port->fp_pkt_cache);
1262 		port->fp_pkt_cache = NULL;
1263 	}
1264 
1265 cache_alloc_failed:
1266 
1267 	cv_destroy(&port->fp_attach_cv);
1268 	cv_destroy(&port->fp_cv);
1269 	mutex_destroy(&port->fp_mutex);
1270 	ddi_remove_minor_node(port->fp_port_dip, NULL);
1271 	ddi_soft_state_free(fp_driver_softstate, instance);
1272 	ddi_prop_remove_all(dip);
1273 
1274 	return (DDI_FAILURE);
1275 }
1276 
1277 
1278 /*
1279  * Handle DDI_RESUME request
1280  */
1281 static int
1282 fp_resume_handler(dev_info_t *dip)
1283 {
1284 	int		rval;
1285 	fc_local_port_t *port;
1286 
1287 	port = ddi_get_soft_state(fp_driver_softstate, ddi_get_instance(dip));
1288 
1289 	ASSERT(port != NULL);
1290 
1291 #ifdef	DEBUG
1292 	mutex_enter(&port->fp_mutex);
1293 	ASSERT(port->fp_soft_state & FP_SOFT_SUSPEND);
1294 	mutex_exit(&port->fp_mutex);
1295 #endif
1296 
1297 	/*
1298 	 * If the port was power suspended, raise the power level
1299 	 */
1300 	mutex_enter(&port->fp_mutex);
1301 	if ((port->fp_soft_state & FP_SOFT_POWER_DOWN) &&
1302 	    (!(port->fp_soft_state & FP_SOFT_NO_PMCOMP))) {
1303 		ASSERT(port->fp_pm_level == FP_PM_PORT_DOWN);
1304 
1305 		mutex_exit(&port->fp_mutex);
1306 		if (pm_raise_power(dip, FP_PM_COMPONENT,
1307 		    FP_PM_PORT_UP) != DDI_SUCCESS) {
1308 			FP_TRACE(FP_NHEAD2(9, 0),
1309 			    "Failed to raise the power level");
1310 			return (DDI_FAILURE);
1311 		}
1312 		mutex_enter(&port->fp_mutex);
1313 	}
1314 	port->fp_soft_state &= ~FP_SOFT_SUSPEND;
1315 	mutex_exit(&port->fp_mutex);
1316 
1317 	/*
1318 	 * All the discovery is initiated and handled by per-port thread.
1319 	 * Further all the discovery is done in handled in callback mode
1320 	 * (not polled mode); In a specific case such as this, the discovery
1321 	 * is required to happen in polled mode. The easiest way out is
1322 	 * to bail out port thread and get started. Come back and fix this
1323 	 * to do on demand discovery initiated by ULPs. ULPs such as FCP
1324 	 * will do on-demand discovery during pre-power-up busctl handling
1325 	 * which will only be possible when SCSA provides a new HBA vector
1326 	 * for sending down the PM busctl requests.
1327 	 */
1328 	(void) callb_generic_cpr(&port->fp_cpr_info, CB_CODE_CPR_RESUME);
1329 
1330 	rval = fp_resume_all(port, FC_CMD_RESUME);
1331 	if (rval != DDI_SUCCESS) {
1332 		mutex_enter(&port->fp_mutex);
1333 		port->fp_soft_state |= FP_SOFT_SUSPEND;
1334 		mutex_exit(&port->fp_mutex);
1335 		(void) callb_generic_cpr(&port->fp_cpr_info,
1336 		    CB_CODE_CPR_CHKPT);
1337 	}
1338 
1339 	return (rval);
1340 }
1341 
1342 /*
1343  * Perform FC Port power on initialization
1344  */
1345 static int
1346 fp_power_up(fc_local_port_t *port)
1347 {
1348 	int	rval;
1349 
1350 	ASSERT(MUTEX_HELD(&port->fp_mutex));
1351 
1352 	ASSERT((port->fp_soft_state & FP_SOFT_SUSPEND) == 0);
1353 	ASSERT(port->fp_soft_state & FP_SOFT_POWER_DOWN);
1354 
1355 	port->fp_soft_state &= ~FP_SOFT_POWER_DOWN;
1356 
1357 	mutex_exit(&port->fp_mutex);
1358 
1359 	rval = fp_resume_all(port, FC_CMD_POWER_UP);
1360 	if (rval != DDI_SUCCESS) {
1361 		mutex_enter(&port->fp_mutex);
1362 		port->fp_soft_state |= FP_SOFT_POWER_DOWN;
1363 	} else {
1364 		mutex_enter(&port->fp_mutex);
1365 	}
1366 
1367 	return (rval);
1368 }
1369 
1370 
1371 /*
1372  * It is important to note that the power may possibly be removed between
1373  * SUSPEND and the ensuing RESUME operation. In such a context the underlying
1374  * FC port hardware would have gone through an OFFLINE to ONLINE transition
1375  * (hardware state). In this case, the port driver may need to rediscover the
1376  * topology, perform LOGINs, register with the name server again and perform
1377  * any such port initialization procedures. To perform LOGINs, the driver could
1378  * use the port device handle to see if a LOGIN needs to be performed and use
1379  * the D_ID and WWN in it. The LOGINs may fail (if the hardware is reconfigured
1380  * or removed) which will be reflected in the map the ULPs will see.
1381  */
1382 static int
1383 fp_resume_all(fc_local_port_t *port, fc_attach_cmd_t cmd)
1384 {
1385 
1386 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
1387 
1388 	if (fp_bind_callbacks(port) != DDI_SUCCESS) {
1389 		return (DDI_FAILURE);
1390 	}
1391 
1392 	mutex_enter(&port->fp_mutex);
1393 
1394 	/*
1395 	 * If there are commands queued for delayed retry, instead of
1396 	 * working the hard way to figure out which ones are good for
1397 	 * restart and which ones not (ELSs are definitely not good
1398 	 * as the port will have to go through a new spin of rediscovery
1399 	 * now), so just flush them out.
1400 	 */
1401 	if (port->fp_restore & FP_RESTORE_WAIT_TIMEOUT) {
1402 		fp_cmd_t	*cmd;
1403 
1404 		port->fp_restore &= ~FP_RESTORE_WAIT_TIMEOUT;
1405 
1406 		mutex_exit(&port->fp_mutex);
1407 		while ((cmd = fp_deque_cmd(port)) != NULL) {
1408 			cmd->cmd_pkt.pkt_state = FC_PKT_TRAN_ERROR;
1409 			fp_iodone(cmd);
1410 		}
1411 		mutex_enter(&port->fp_mutex);
1412 	}
1413 
1414 	if (FC_PORT_STATE_MASK(port->fp_bind_state) == FC_STATE_OFFLINE) {
1415 		if ((port->fp_restore & FP_RESTORE_OFFLINE_TIMEOUT) ||
1416 		    port->fp_dev_count) {
1417 			port->fp_restore &= ~FP_RESTORE_OFFLINE_TIMEOUT;
1418 			port->fp_offline_tid = timeout(fp_offline_timeout,
1419 			    (caddr_t)port, fp_offline_ticks);
1420 		}
1421 		if (port->fp_job_head) {
1422 			cv_signal(&port->fp_cv);
1423 		}
1424 		mutex_exit(&port->fp_mutex);
1425 		fctl_attach_ulps(port, cmd, &modlinkage);
1426 	} else {
1427 		struct job_request *job;
1428 
1429 		/*
1430 		 * If an OFFLINE timer was running at the time of
1431 		 * suspending, there is no need to restart it as
1432 		 * the port is ONLINE now.
1433 		 */
1434 		port->fp_restore &= ~FP_RESTORE_OFFLINE_TIMEOUT;
1435 		if (port->fp_statec_busy == 0) {
1436 			port->fp_soft_state |= FP_SOFT_IN_STATEC_CB;
1437 		}
1438 		port->fp_statec_busy++;
1439 		mutex_exit(&port->fp_mutex);
1440 
1441 		job = fctl_alloc_job(JOB_PORT_ONLINE,
1442 		    JOB_CANCEL_ULP_NOTIFICATION, NULL, NULL, KM_SLEEP);
1443 		fctl_enque_job(port, job);
1444 
1445 		fctl_jobwait(job);
1446 		fctl_remove_oldies(port);
1447 
1448 		fctl_attach_ulps(port, cmd, &modlinkage);
1449 		fctl_dealloc_job(job);
1450 	}
1451 
1452 	return (DDI_SUCCESS);
1453 }
1454 
1455 
1456 /*
1457  * At this time, there shouldn't be any I/O requests on this port.
1458  * But the unsolicited callbacks from the underlying FCA port need
1459  * to be handled very carefully. The steps followed to handle the
1460  * DDI_DETACH are:
1461  *	+ 	Grab the port driver mutex, check if the unsolicited
1462  *		callback is currently under processing. If true, fail
1463  *		the DDI_DETACH request by printing a message; If false
1464  *		mark the DDI_DETACH as under progress, so that any
1465  *		further unsolicited callbacks get bounced.
1466  *	+	Perform PRLO/LOGO if necessary, cleanup all the data
1467  *		structures.
1468  *	+	Get the job_handler thread to gracefully exit.
1469  *	+	Unregister callbacks with the FCA port.
1470  *	+	Now that some peace is found, notify all the ULPs of
1471  *		DDI_DETACH request (using ulp_port_detach entry point)
1472  *	+	Free all mutexes, semaphores, conditional variables.
1473  *	+	Free the soft state, return success.
1474  *
1475  * Important considerations:
1476  *		Port driver de-registers state change and unsolicited
1477  *		callbacks before taking up the task of notifying ULPs
1478  *		and performing PRLO and LOGOs.
1479  *
1480  *		A port may go offline at the time PRLO/LOGO is being
1481  *		requested. It is expected of all FCA drivers to fail
1482  *		such requests either immediately with a FC_OFFLINE
1483  *		return code to fc_fca_transport() or return the packet
1484  *		asynchronously with pkt state set to FC_PKT_PORT_OFFLINE
1485  */
1486 static int
1487 fp_detach_handler(fc_local_port_t *port)
1488 {
1489 	job_request_t 	*job;
1490 	uint32_t	delay_count;
1491 	fc_orphan_t	*orp, *tmporp;
1492 
1493 	/*
1494 	 * In a Fabric topology with many host ports connected to
1495 	 * a switch, another detaching instance of fp might have
1496 	 * triggered a LOGO (which is an unsolicited request to
1497 	 * this instance). So in order to be able to successfully
1498 	 * detach by taking care of such cases a delay of about
1499 	 * 30 seconds is introduced.
1500 	 */
1501 	delay_count = 0;
1502 	mutex_enter(&port->fp_mutex);
1503 	while ((port->fp_soft_state &
1504 	    (FP_SOFT_IN_STATEC_CB | FP_SOFT_IN_UNSOL_CB)) &&
1505 	    (delay_count < 30)) {
1506 		mutex_exit(&port->fp_mutex);
1507 		delay_count++;
1508 		delay(drv_usectohz(1000000));
1509 		mutex_enter(&port->fp_mutex);
1510 	}
1511 
1512 	if (port->fp_soft_state &
1513 	    (FP_SOFT_IN_STATEC_CB | FP_SOFT_IN_UNSOL_CB)) {
1514 		port->fp_soft_state &= ~FP_DETACH_INPROGRESS;
1515 		mutex_exit(&port->fp_mutex);
1516 		cmn_err(CE_WARN, "fp(%d): FCA callback in progress: "
1517 		    " Failing detach", port->fp_instance);
1518 		return (DDI_FAILURE);
1519 	}
1520 
1521 	port->fp_soft_state |= FP_SOFT_IN_DETACH;
1522 	port->fp_soft_state &= ~FP_DETACH_INPROGRESS;
1523 	mutex_exit(&port->fp_mutex);
1524 
1525 	/*
1526 	 * If we're powered down, we need to raise power prior to submitting
1527 	 * the JOB_PORT_SHUTDOWN job.  Otherwise, the job handler will never
1528 	 * process the shutdown job.
1529 	 */
1530 	if (fctl_busy_port(port) != 0) {
1531 		cmn_err(CE_WARN, "fp(%d): fctl_busy_port failed",
1532 		    port->fp_instance);
1533 		mutex_enter(&port->fp_mutex);
1534 		port->fp_soft_state &= ~FP_SOFT_IN_DETACH;
1535 		mutex_exit(&port->fp_mutex);
1536 		return (DDI_FAILURE);
1537 	}
1538 
1539 	/*
1540 	 * This will deallocate data structs and cause the "job" thread
1541 	 * to exit, in preparation for DDI_DETACH on the instance.
1542 	 * This can sleep for an arbitrary duration, since it waits for
1543 	 * commands over the wire, timeout(9F) callbacks, etc.
1544 	 *
1545 	 * CAUTION: There is still a race here, where the "job" thread
1546 	 * can still be executing code even tho the fctl_jobwait() call
1547 	 * below has returned to us.  In theory the fp driver could even be
1548 	 * modunloaded even tho the job thread isn't done executing.
1549 	 * without creating the race condition.
1550 	 */
1551 	job = fctl_alloc_job(JOB_PORT_SHUTDOWN, 0, NULL,
1552 	    (opaque_t)port, KM_SLEEP);
1553 	fctl_enque_job(port, job);
1554 	fctl_jobwait(job);
1555 	fctl_dealloc_job(job);
1556 
1557 
1558 	(void) pm_lower_power(port->fp_port_dip, FP_PM_COMPONENT,
1559 	    FP_PM_PORT_DOWN);
1560 
1561 	if (port->fp_taskq) {
1562 		taskq_destroy(port->fp_taskq);
1563 	}
1564 
1565 	ddi_prop_remove_all(port->fp_port_dip);
1566 
1567 	ddi_remove_minor_node(port->fp_port_dip, NULL);
1568 
1569 	fctl_remove_port(port);
1570 
1571 	fp_free_pkt(port->fp_els_resp_pkt);
1572 
1573 	if (port->fp_ub_tokens) {
1574 		if (fc_ulp_ubfree(port, port->fp_ub_count,
1575 		    port->fp_ub_tokens) != FC_SUCCESS) {
1576 			cmn_err(CE_WARN, "fp(%d): couldn't free "
1577 			    " unsolicited buffers", port->fp_instance);
1578 		}
1579 		kmem_free(port->fp_ub_tokens,
1580 		    sizeof (*port->fp_ub_tokens) * port->fp_ub_count);
1581 		port->fp_ub_tokens = NULL;
1582 	}
1583 
1584 	if (port->fp_pkt_cache != NULL) {
1585 		kmem_cache_destroy(port->fp_pkt_cache);
1586 	}
1587 
1588 	port->fp_fca_tran->fca_unbind_port(port->fp_fca_handle);
1589 
1590 	mutex_enter(&port->fp_mutex);
1591 	if (port->fp_did_table) {
1592 		kmem_free(port->fp_did_table, did_table_size *
1593 			sizeof (struct d_id_hash));
1594 	}
1595 
1596 	if (port->fp_pwwn_table) {
1597 		kmem_free(port->fp_pwwn_table, pwwn_table_size *
1598 		    sizeof (struct pwwn_hash));
1599 	}
1600 	orp = port->fp_orphan_list;
1601 	while (orp) {
1602 		tmporp = orp;
1603 		orp = orp->orp_next;
1604 		kmem_free(tmporp, sizeof (*orp));
1605 	}
1606 
1607 	mutex_exit(&port->fp_mutex);
1608 
1609 	fp_log_port_event(port, ESC_SUNFC_PORT_DETACH);
1610 
1611 	mutex_destroy(&port->fp_mutex);
1612 	cv_destroy(&port->fp_attach_cv);
1613 	cv_destroy(&port->fp_cv);
1614 	ddi_soft_state_free(fp_driver_softstate, port->fp_instance);
1615 
1616 	return (DDI_SUCCESS);
1617 }
1618 
1619 
1620 /*
1621  * Steps to perform DDI_SUSPEND operation on a FC port
1622  *
1623  *	- If already suspended return DDI_FAILURE
1624  *	- If already power-suspended return DDI_SUCCESS
1625  *	- If an unsolicited callback or state change handling is in
1626  *	    in progress, throw a warning message, return DDI_FAILURE
1627  *	- Cancel timeouts
1628  *	- SUSPEND the job_handler thread (means do nothing as it is
1629  *          taken care of by the CPR frame work)
1630  */
1631 static int
1632 fp_suspend_handler(fc_local_port_t *port)
1633 {
1634 	uint32_t	delay_count;
1635 
1636 	mutex_enter(&port->fp_mutex);
1637 
1638 	/*
1639 	 * The following should never happen, but
1640 	 * let the driver be more defensive here
1641 	 */
1642 	if (port->fp_soft_state & FP_SOFT_SUSPEND) {
1643 		mutex_exit(&port->fp_mutex);
1644 		return (DDI_FAILURE);
1645 	}
1646 
1647 	/*
1648 	 * If the port is already power suspended, there
1649 	 * is nothing else to do, So return DDI_SUCCESS,
1650 	 * but mark the SUSPEND bit in the soft state
1651 	 * before leaving.
1652 	 */
1653 	if (port->fp_soft_state & FP_SOFT_POWER_DOWN) {
1654 		port->fp_soft_state |= FP_SOFT_SUSPEND;
1655 		mutex_exit(&port->fp_mutex);
1656 		return (DDI_SUCCESS);
1657 	}
1658 
1659 	/*
1660 	 * Check if an unsolicited callback or state change handling is
1661 	 * in progress. If true, fail the suspend operation; also throw
1662 	 * a warning message notifying the failure. Note that Sun PCI
1663 	 * hotplug spec recommends messages in cases of failure (but
1664 	 * not flooding the console)
1665 	 *
1666 	 * Busy waiting for a short interval (500 millisecond ?) to see
1667 	 * if the callback processing completes may be another idea. Since
1668 	 * most of the callback processing involves a lot of work, it
1669 	 * is safe to just fail the SUSPEND operation. It is definitely
1670 	 * not bad to fail the SUSPEND operation if the driver is busy.
1671 	 */
1672 	delay_count = 0;
1673 	while ((port->fp_soft_state & (FP_SOFT_IN_STATEC_CB |
1674 	    FP_SOFT_IN_UNSOL_CB)) && (delay_count < 30)) {
1675 		mutex_exit(&port->fp_mutex);
1676 		delay_count++;
1677 		delay(drv_usectohz(1000000));
1678 		mutex_enter(&port->fp_mutex);
1679 	}
1680 
1681 	if (port->fp_soft_state & (FP_SOFT_IN_STATEC_CB |
1682 	    FP_SOFT_IN_UNSOL_CB)) {
1683 		mutex_exit(&port->fp_mutex);
1684 		cmn_err(CE_WARN, "fp(%d): FCA callback in progress: "
1685 		    " Failing suspend", port->fp_instance);
1686 		return (DDI_FAILURE);
1687 	}
1688 
1689 	/*
1690 	 * Check of FC port thread is busy
1691 	 */
1692 	if (port->fp_job_head) {
1693 		mutex_exit(&port->fp_mutex);
1694 		FP_TRACE(FP_NHEAD2(9, 0),
1695 		    "FC port thread is busy: Failing suspend");
1696 		return (DDI_FAILURE);
1697 	}
1698 	port->fp_soft_state |= FP_SOFT_SUSPEND;
1699 
1700 	fp_suspend_all(port);
1701 	mutex_exit(&port->fp_mutex);
1702 
1703 	return (DDI_SUCCESS);
1704 }
1705 
1706 
1707 /*
1708  * Prepare for graceful power down of a FC port
1709  */
1710 static int
1711 fp_power_down(fc_local_port_t *port)
1712 {
1713 	ASSERT(MUTEX_HELD(&port->fp_mutex));
1714 
1715 	/*
1716 	 * Power down request followed by a DDI_SUSPEND should
1717 	 * never happen; If it does return DDI_SUCCESS
1718 	 */
1719 	if (port->fp_soft_state & FP_SOFT_SUSPEND) {
1720 		port->fp_soft_state |= FP_SOFT_POWER_DOWN;
1721 		return (DDI_SUCCESS);
1722 	}
1723 
1724 	/*
1725 	 * If the port is already power suspended, there
1726 	 * is nothing else to do, So return DDI_SUCCESS,
1727 	 */
1728 	if (port->fp_soft_state & FP_SOFT_POWER_DOWN) {
1729 		return (DDI_SUCCESS);
1730 	}
1731 
1732 	/*
1733 	 * Check if an unsolicited callback or state change handling
1734 	 * is in progress. If true, fail the PM suspend operation.
1735 	 * But don't print a message unless the verbosity of the
1736 	 * driver desires otherwise.
1737 	 */
1738 	if ((port->fp_soft_state & FP_SOFT_IN_STATEC_CB) ||
1739 	    (port->fp_soft_state & FP_SOFT_IN_UNSOL_CB)) {
1740 		FP_TRACE(FP_NHEAD2(9, 0),
1741 		    "Unsolicited callback in progress: Failing power down");
1742 		return (DDI_FAILURE);
1743 	}
1744 
1745 	/*
1746 	 * Check of FC port thread is busy
1747 	 */
1748 	if (port->fp_job_head) {
1749 		FP_TRACE(FP_NHEAD2(9, 0),
1750 		    "FC port thread is busy: Failing power down");
1751 		return (DDI_FAILURE);
1752 	}
1753 	port->fp_soft_state |= FP_SOFT_POWER_DOWN;
1754 
1755 	/*
1756 	 * check if the ULPs are ready for power down
1757 	 */
1758 	mutex_exit(&port->fp_mutex);
1759 	if (fctl_detach_ulps(port, FC_CMD_POWER_DOWN,
1760 	    &modlinkage) != FC_SUCCESS) {
1761 		mutex_enter(&port->fp_mutex);
1762 		port->fp_soft_state &= ~FP_SOFT_POWER_DOWN;
1763 		mutex_exit(&port->fp_mutex);
1764 
1765 		/*
1766 		 * Power back up the obedient ULPs that went down
1767 		 */
1768 		fp_attach_ulps(port, FC_CMD_POWER_UP);
1769 
1770 		FP_TRACE(FP_NHEAD2(9, 0),
1771 		    "ULP(s) busy, detach_ulps failed. Failing power down");
1772 		mutex_enter(&port->fp_mutex);
1773 		return (DDI_FAILURE);
1774 	}
1775 	mutex_enter(&port->fp_mutex);
1776 
1777 	fp_suspend_all(port);
1778 
1779 	return (DDI_SUCCESS);
1780 }
1781 
1782 
1783 /*
1784  * Suspend the entire FC port
1785  */
1786 static void
1787 fp_suspend_all(fc_local_port_t *port)
1788 {
1789 	int			index;
1790 	struct pwwn_hash 	*head;
1791 	fc_remote_port_t 	*pd;
1792 
1793 	ASSERT(MUTEX_HELD(&port->fp_mutex));
1794 
1795 	if (port->fp_wait_tid != 0) {
1796 		timeout_id_t 	tid;
1797 
1798 		tid = port->fp_wait_tid;
1799 		port->fp_wait_tid = (timeout_id_t)NULL;
1800 		mutex_exit(&port->fp_mutex);
1801 		(void) untimeout(tid);
1802 		mutex_enter(&port->fp_mutex);
1803 		port->fp_restore |= FP_RESTORE_WAIT_TIMEOUT;
1804 	}
1805 
1806 	if (port->fp_offline_tid) {
1807 		timeout_id_t 	tid;
1808 
1809 		tid = port->fp_offline_tid;
1810 		port->fp_offline_tid = (timeout_id_t)NULL;
1811 		mutex_exit(&port->fp_mutex);
1812 		(void) untimeout(tid);
1813 		mutex_enter(&port->fp_mutex);
1814 		port->fp_restore |= FP_RESTORE_OFFLINE_TIMEOUT;
1815 	}
1816 	mutex_exit(&port->fp_mutex);
1817 	port->fp_fca_tran->fca_unbind_port(port->fp_fca_handle);
1818 	mutex_enter(&port->fp_mutex);
1819 
1820 	/*
1821 	 * Mark all devices as OLD, and reset the LOGIN state as well
1822 	 * (this will force the ULPs to perform a LOGIN after calling
1823 	 * fc_portgetmap() during RESUME/PM_RESUME)
1824 	 */
1825 	for (index = 0; index < pwwn_table_size; index++) {
1826 		head = &port->fp_pwwn_table[index];
1827 		pd = head->pwwn_head;
1828 		while (pd != NULL) {
1829 			mutex_enter(&pd->pd_mutex);
1830 			fp_remote_port_offline(pd);
1831 			fctl_delist_did_table(port, pd);
1832 			pd->pd_state = PORT_DEVICE_VALID;
1833 			pd->pd_login_count = 0;
1834 			mutex_exit(&pd->pd_mutex);
1835 			pd = pd->pd_wwn_hnext;
1836 		}
1837 	}
1838 }
1839 
1840 
1841 /*
1842  * fp_cache_constructor: Constructor function for kmem_cache_create(9F).
1843  * Performs intializations for fc_packet_t structs.
1844  * Returns 0 for success or -1 for failure.
1845  *
1846  * This function allocates DMA handles for both command and responses.
1847  * Most of the ELSs used have both command and responses so it is strongly
1848  * desired to move them to cache constructor routine.
1849  *
1850  * Context: Can sleep iff called with KM_SLEEP flag.
1851  */
1852 static int
1853 fp_cache_constructor(void *buf, void *cdarg, int kmflags)
1854 {
1855 	int 		(*cb) (caddr_t);
1856 	fc_packet_t 	*pkt;
1857 	fp_cmd_t 	*cmd = (fp_cmd_t *)buf;
1858 	fc_local_port_t *port = (fc_local_port_t *)cdarg;
1859 
1860 	cb = (kmflags == KM_SLEEP) ? DDI_DMA_SLEEP : DDI_DMA_DONTWAIT;
1861 
1862 	cmd->cmd_next = NULL;
1863 	cmd->cmd_flags = 0;
1864 	cmd->cmd_dflags = 0;
1865 	cmd->cmd_job = NULL;
1866 	cmd->cmd_port = port;
1867 	pkt = &cmd->cmd_pkt;
1868 
1869 	if (ddi_dma_alloc_handle(port->fp_fca_dip,
1870 	    port->fp_fca_tran->fca_dma_attr, cb, NULL,
1871 	    &pkt->pkt_cmd_dma) != DDI_SUCCESS) {
1872 		return (-1);
1873 	}
1874 
1875 	if (ddi_dma_alloc_handle(port->fp_fca_dip,
1876 	    port->fp_fca_tran->fca_dma_attr, cb, NULL,
1877 	    &pkt->pkt_resp_dma) != DDI_SUCCESS) {
1878 		ddi_dma_free_handle(&pkt->pkt_cmd_dma);
1879 		return (-1);
1880 	}
1881 
1882 	pkt->pkt_cmd_acc = pkt->pkt_resp_acc = NULL;
1883 	pkt->pkt_cmd_cookie_cnt = pkt->pkt_resp_cookie_cnt =
1884 	    pkt->pkt_data_cookie_cnt = 0;
1885 	pkt->pkt_cmd_cookie = pkt->pkt_resp_cookie =
1886 	    pkt->pkt_data_cookie = NULL;
1887 	pkt->pkt_fca_private = (caddr_t)buf + sizeof (fp_cmd_t);
1888 
1889 	return (0);
1890 }
1891 
1892 
1893 /*
1894  * fp_cache_destructor: Destructor function for kmem_cache_create().
1895  * Performs un-intializations for fc_packet_t structs.
1896  */
1897 /* ARGSUSED */
1898 static void
1899 fp_cache_destructor(void *buf, void *cdarg)
1900 {
1901 	fp_cmd_t 	*cmd = (fp_cmd_t *)buf;
1902 	fc_packet_t	*pkt;
1903 
1904 	pkt = &cmd->cmd_pkt;
1905 	if (pkt->pkt_cmd_dma) {
1906 		ddi_dma_free_handle(&pkt->pkt_cmd_dma);
1907 	}
1908 
1909 	if (pkt->pkt_resp_dma) {
1910 		ddi_dma_free_handle(&pkt->pkt_resp_dma);
1911 	}
1912 }
1913 
1914 
1915 /*
1916  * Packet allocation for ELS and any other port driver commands
1917  *
1918  * Some ELSs like FLOGI and PLOGI are critical for topology and
1919  * device discovery and a system's inability to allocate memory
1920  * or DVMA resources while performing some of these critical ELSs
1921  * cause a lot of problem. While memory allocation failures are
1922  * rare, DVMA resource failures are common as the applications
1923  * are becoming more and more powerful on huge servers.  So it
1924  * is desirable to have a framework support to reserve a fragment
1925  * of DVMA. So until this is fixed the correct way, the suffering
1926  * is huge whenever a LIP happens at a time DVMA resources are
1927  * drained out completely - So an attempt needs to be made to
1928  * KM_SLEEP while requesting for these resources, hoping that
1929  * the requests won't hang forever.
1930  *
1931  * The fc_remote_port_t argument is stored into the pkt_pd field in the
1932  * fc_packet_t struct prior to the fc_ulp_init_packet() call.  This
1933  * ensures that the pd_ref_count for the fc_remote_port_t is valid.
1934  * If there is no fc_remote_port_t associated with the fc_packet_t, then
1935  * fp_alloc_pkt() must be called with pd set to NULL.
1936  */
1937 
1938 static fp_cmd_t *
1939 fp_alloc_pkt(fc_local_port_t *port, int cmd_len, int resp_len, int kmflags,
1940     fc_remote_port_t *pd)
1941 {
1942 	int		rval;
1943 	ulong_t		real_len;
1944 	fp_cmd_t 	*cmd;
1945 	fc_packet_t	*pkt;
1946 	int 		(*cb) (caddr_t);
1947 	ddi_dma_cookie_t	pkt_cookie;
1948 	ddi_dma_cookie_t	*cp;
1949 	uint32_t		cnt;
1950 
1951 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
1952 
1953 	cb = (kmflags == KM_SLEEP) ? DDI_DMA_SLEEP : DDI_DMA_DONTWAIT;
1954 
1955 	cmd = (fp_cmd_t *)kmem_cache_alloc(port->fp_pkt_cache, kmflags);
1956 	if (cmd == NULL) {
1957 		return (cmd);
1958 	}
1959 
1960 	cmd->cmd_ulp_pkt = NULL;
1961 	cmd->cmd_flags = 0;
1962 	pkt = &cmd->cmd_pkt;
1963 	ASSERT(cmd->cmd_dflags == 0);
1964 
1965 	pkt->pkt_datalen = 0;
1966 	pkt->pkt_data = NULL;
1967 	pkt->pkt_state = 0;
1968 	pkt->pkt_action = 0;
1969 	pkt->pkt_reason = 0;
1970 	pkt->pkt_expln = 0;
1971 
1972 	/*
1973 	 * Init pkt_pd with the given pointer; this must be done _before_
1974 	 * the call to fc_ulp_init_packet().
1975 	 */
1976 	pkt->pkt_pd = pd;
1977 
1978 	/* Now call the FCA driver to init its private, per-packet fields */
1979 	if (fc_ulp_init_packet((opaque_t)port, pkt, kmflags) != FC_SUCCESS) {
1980 		goto alloc_pkt_failed;
1981 	}
1982 
1983 	if (cmd_len) {
1984 		ASSERT(pkt->pkt_cmd_dma != NULL);
1985 
1986 		rval = ddi_dma_mem_alloc(pkt->pkt_cmd_dma, cmd_len,
1987 		    port->fp_fca_tran->fca_acc_attr, DDI_DMA_CONSISTENT,
1988 		    cb, NULL, (caddr_t *)&pkt->pkt_cmd, &real_len,
1989 		    &pkt->pkt_cmd_acc);
1990 
1991 		if (rval != DDI_SUCCESS) {
1992 			goto alloc_pkt_failed;
1993 		}
1994 		cmd->cmd_dflags |= FP_CMD_VALID_DMA_MEM;
1995 
1996 		if (real_len < cmd_len) {
1997 			goto alloc_pkt_failed;
1998 		}
1999 
2000 		rval = ddi_dma_addr_bind_handle(pkt->pkt_cmd_dma, NULL,
2001 		    pkt->pkt_cmd, real_len, DDI_DMA_WRITE |
2002 		    DDI_DMA_CONSISTENT, cb, NULL,
2003 		    &pkt_cookie, &pkt->pkt_cmd_cookie_cnt);
2004 
2005 		if (rval != DDI_DMA_MAPPED) {
2006 			goto alloc_pkt_failed;
2007 		}
2008 
2009 		cmd->cmd_dflags |= FP_CMD_VALID_DMA_BIND;
2010 
2011 		if (pkt->pkt_cmd_cookie_cnt >
2012 		    port->fp_fca_tran->fca_dma_attr->dma_attr_sgllen) {
2013 			goto alloc_pkt_failed;
2014 		}
2015 
2016 		ASSERT(pkt->pkt_cmd_cookie_cnt != 0);
2017 
2018 		cp = pkt->pkt_cmd_cookie = (ddi_dma_cookie_t *)kmem_alloc(
2019 		    pkt->pkt_cmd_cookie_cnt * sizeof (pkt_cookie),
2020 		    KM_NOSLEEP);
2021 
2022 		if (cp == NULL) {
2023 			goto alloc_pkt_failed;
2024 		}
2025 
2026 		*cp = pkt_cookie;
2027 		cp++;
2028 		for (cnt = 1; cnt < pkt->pkt_cmd_cookie_cnt; cnt++, cp++) {
2029 			ddi_dma_nextcookie(pkt->pkt_cmd_dma, &pkt_cookie);
2030 			*cp = pkt_cookie;
2031 		}
2032 	}
2033 
2034 	if (resp_len) {
2035 		ASSERT(pkt->pkt_resp_dma != NULL);
2036 
2037 		rval = ddi_dma_mem_alloc(pkt->pkt_resp_dma, resp_len,
2038 		    port->fp_fca_tran->fca_acc_attr,
2039 		    DDI_DMA_CONSISTENT, cb, NULL,
2040 		    (caddr_t *)&pkt->pkt_resp, &real_len,
2041 		    &pkt->pkt_resp_acc);
2042 
2043 		if (rval != DDI_SUCCESS) {
2044 			goto alloc_pkt_failed;
2045 		}
2046 		cmd->cmd_dflags |= FP_RESP_VALID_DMA_MEM;
2047 
2048 		if (real_len < resp_len) {
2049 			goto alloc_pkt_failed;
2050 		}
2051 
2052 		rval = ddi_dma_addr_bind_handle(pkt->pkt_resp_dma, NULL,
2053 		    pkt->pkt_resp, real_len, DDI_DMA_READ |
2054 		    DDI_DMA_CONSISTENT, cb, NULL,
2055 		    &pkt_cookie, &pkt->pkt_resp_cookie_cnt);
2056 
2057 		if (rval != DDI_DMA_MAPPED) {
2058 			goto alloc_pkt_failed;
2059 		}
2060 
2061 		cmd->cmd_dflags |= FP_RESP_VALID_DMA_BIND;
2062 
2063 		if (pkt->pkt_resp_cookie_cnt >
2064 		    port->fp_fca_tran->fca_dma_attr->dma_attr_sgllen) {
2065 			goto alloc_pkt_failed;
2066 		}
2067 
2068 		ASSERT(pkt->pkt_cmd_cookie_cnt != 0);
2069 
2070 		cp = pkt->pkt_resp_cookie = (ddi_dma_cookie_t *)kmem_alloc(
2071 		    pkt->pkt_resp_cookie_cnt * sizeof (pkt_cookie),
2072 		    KM_NOSLEEP);
2073 
2074 		if (cp == NULL) {
2075 			goto alloc_pkt_failed;
2076 		}
2077 
2078 		*cp = pkt_cookie;
2079 		cp++;
2080 		for (cnt = 1; cnt < pkt->pkt_resp_cookie_cnt; cnt++, cp++) {
2081 			ddi_dma_nextcookie(pkt->pkt_resp_dma, &pkt_cookie);
2082 			*cp = pkt_cookie;
2083 		}
2084 	}
2085 
2086 	pkt->pkt_cmdlen = cmd_len;
2087 	pkt->pkt_rsplen = resp_len;
2088 	pkt->pkt_ulp_private = cmd;
2089 
2090 	return (cmd);
2091 
2092 alloc_pkt_failed:
2093 
2094 	fp_free_dma(cmd);
2095 
2096 	if (pkt->pkt_cmd_cookie != NULL) {
2097 		kmem_free(pkt->pkt_cmd_cookie,
2098 		    pkt->pkt_cmd_cookie_cnt * sizeof (ddi_dma_cookie_t));
2099 		pkt->pkt_cmd_cookie = NULL;
2100 	}
2101 
2102 	if (pkt->pkt_resp_cookie != NULL) {
2103 		kmem_free(pkt->pkt_resp_cookie,
2104 		    pkt->pkt_resp_cookie_cnt * sizeof (ddi_dma_cookie_t));
2105 		pkt->pkt_resp_cookie = NULL;
2106 	}
2107 
2108 	kmem_cache_free(port->fp_pkt_cache, cmd);
2109 
2110 	return (NULL);
2111 }
2112 
2113 
2114 /*
2115  * Free FC packet
2116  */
2117 static void
2118 fp_free_pkt(fp_cmd_t *cmd)
2119 {
2120 	fc_local_port_t *port;
2121 	fc_packet_t 	*pkt;
2122 
2123 	ASSERT(!MUTEX_HELD(&cmd->cmd_port->fp_mutex));
2124 
2125 	cmd->cmd_next = NULL;
2126 	cmd->cmd_job = NULL;
2127 	pkt = &cmd->cmd_pkt;
2128 	pkt->pkt_ulp_private = 0;
2129 	pkt->pkt_tran_flags = 0;
2130 	pkt->pkt_tran_type = 0;
2131 	port = cmd->cmd_port;
2132 
2133 	if (pkt->pkt_cmd_cookie != NULL) {
2134 		kmem_free(pkt->pkt_cmd_cookie, pkt->pkt_cmd_cookie_cnt *
2135 		    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, pkt->pkt_resp_cookie_cnt *
2141 		    sizeof (ddi_dma_cookie_t));
2142 		pkt->pkt_resp_cookie = NULL;
2143 	}
2144 
2145 	fp_free_dma(cmd);
2146 	(void) fc_ulp_uninit_packet((opaque_t)port, pkt);
2147 	kmem_cache_free(port->fp_pkt_cache, (void *)cmd);
2148 }
2149 
2150 
2151 /*
2152  * Release DVMA resources
2153  */
2154 static void
2155 fp_free_dma(fp_cmd_t *cmd)
2156 {
2157 	fc_packet_t *pkt = &cmd->cmd_pkt;
2158 
2159 	pkt->pkt_cmdlen = 0;
2160 	pkt->pkt_rsplen = 0;
2161 	pkt->pkt_tran_type = 0;
2162 	pkt->pkt_tran_flags = 0;
2163 
2164 	if (cmd->cmd_dflags & FP_CMD_VALID_DMA_BIND) {
2165 		(void) ddi_dma_unbind_handle(pkt->pkt_cmd_dma);
2166 	}
2167 
2168 	if (cmd->cmd_dflags & FP_CMD_VALID_DMA_MEM) {
2169 		if (pkt->pkt_cmd_acc) {
2170 			ddi_dma_mem_free(&pkt->pkt_cmd_acc);
2171 		}
2172 	}
2173 
2174 	if (cmd->cmd_dflags & FP_RESP_VALID_DMA_BIND) {
2175 		(void) ddi_dma_unbind_handle(pkt->pkt_resp_dma);
2176 	}
2177 
2178 	if (cmd->cmd_dflags & FP_RESP_VALID_DMA_MEM) {
2179 		if (pkt->pkt_resp_acc) {
2180 			ddi_dma_mem_free(&pkt->pkt_resp_acc);
2181 		}
2182 	}
2183 	cmd->cmd_dflags = 0;
2184 }
2185 
2186 
2187 /*
2188  * Dedicated thread to perform various activities.  One thread for
2189  * each fc_local_port_t (driver soft state) instance.
2190  * Note, this effectively works out to one thread for each local
2191  * port, but there are also some Solaris taskq threads in use on a per-local
2192  * port basis; these also need to be taken into consideration.
2193  */
2194 static void
2195 fp_job_handler(fc_local_port_t *port)
2196 {
2197 	int			rval;
2198 	uint32_t		*d_id;
2199 	fc_remote_port_t 	*pd;
2200 	job_request_t 		*job;
2201 
2202 #ifndef	__lock_lint
2203 	/*
2204 	 * Solaris-internal stuff for proper operation of kernel threads
2205 	 * with Solaris CPR.
2206 	 */
2207 	CALLB_CPR_INIT(&port->fp_cpr_info, &port->fp_mutex,
2208 	    callb_generic_cpr, "fp_job_handler");
2209 #endif
2210 
2211 
2212 	/* Loop forever waiting for work to do */
2213 	for (;;) {
2214 
2215 		mutex_enter(&port->fp_mutex);
2216 
2217 		/*
2218 		 * Sleep if no work to do right now, or if we want
2219 		 * to suspend or power-down.
2220 		 */
2221 		while (port->fp_job_head == NULL ||
2222 		    (port->fp_soft_state & (FP_SOFT_POWER_DOWN |
2223 		    FP_SOFT_SUSPEND))) {
2224 			CALLB_CPR_SAFE_BEGIN(&port->fp_cpr_info);
2225 			cv_wait(&port->fp_cv, &port->fp_mutex);
2226 			CALLB_CPR_SAFE_END(&port->fp_cpr_info, &port->fp_mutex);
2227 		}
2228 
2229 		/*
2230 		 * OK, we've just been woken up, so retrieve the next entry
2231 		 * from the head of the job queue for this local port.
2232 		 */
2233 		job = fctl_deque_job(port);
2234 
2235 		/*
2236 		 * Handle all the fp driver's supported job codes here
2237 		 * in this big honkin' switch.
2238 		 */
2239 		switch (job->job_code) {
2240 		case JOB_PORT_SHUTDOWN:
2241 			/*
2242 			 * fp_port_shutdown() is only called from here. This
2243 			 * will prepare the local port instance (softstate)
2244 			 * for detaching.  This cancels timeout callbacks,
2245 			 * executes LOGOs with remote ports, cleans up tables,
2246 			 * and deallocates data structs.
2247 			 */
2248 			fp_port_shutdown(port, job);
2249 
2250 			/*
2251 			 * This will exit the job thread.
2252 			 */
2253 #ifndef __lock_lint
2254 			CALLB_CPR_EXIT(&(port->fp_cpr_info));
2255 #else
2256 			mutex_exit(&port->fp_mutex);
2257 #endif
2258 			fctl_jobdone(job);
2259 			thread_exit();
2260 
2261 			/* NOTREACHED */
2262 
2263 		case JOB_ATTACH_ULP: {
2264 			/*
2265 			 * This job is spawned in response to a ULP calling
2266 			 * fc_ulp_add().
2267 			 */
2268 
2269 			boolean_t do_attach_ulps = B_TRUE;
2270 
2271 			/*
2272 			 * If fp is detaching, we don't want to call
2273 			 * fp_startup_done as this asynchronous
2274 			 * notification may interfere with the re-attach.
2275 			 */
2276 
2277 			if (port->fp_soft_state & (FP_DETACH_INPROGRESS |
2278 			    FP_SOFT_IN_DETACH | FP_DETACH_FAILED)) {
2279 				do_attach_ulps = B_FALSE;
2280 			} else {
2281 				/*
2282 				 * We are going to force the transport
2283 				 * to attach to the ULPs, so set
2284 				 * fp_ulp_attach.  This will keep any
2285 				 * potential detach from occurring until
2286 				 * we are done.
2287 				 */
2288 				port->fp_ulp_attach = 1;
2289 			}
2290 
2291 			mutex_exit(&port->fp_mutex);
2292 
2293 			/*
2294 			 * NOTE: Since we just dropped the mutex, there is now
2295 			 * a race window where the fp_soft_state check above
2296 			 * could change here.  This race is covered because an
2297 			 * additional check was added in the functions hidden
2298 			 * under fp_startup_done().
2299 			 */
2300 			if (do_attach_ulps == B_TRUE) {
2301 				/*
2302 				 * This goes thru a bit of a convoluted call
2303 				 * chain before spawning off a DDI taskq
2304 				 * request to perform the actual attach
2305 				 * operations. Blocking can occur at a number
2306 				 * of points.
2307 				 */
2308 				fp_startup_done((opaque_t)port, FC_PKT_SUCCESS);
2309 			}
2310 			job->job_result = FC_SUCCESS;
2311 			fctl_jobdone(job);
2312 			break;
2313 		}
2314 
2315 		case JOB_ULP_NOTIFY: {
2316 			/*
2317 			 * Pass state change notifications up to any/all
2318 			 * registered ULPs.
2319 			 */
2320 			uint32_t statec;
2321 
2322 			statec = job->job_ulp_listlen;
2323 			if (statec == FC_STATE_RESET_REQUESTED) {
2324 				port->fp_last_task = port->fp_task;
2325 				port->fp_task = FP_TASK_OFFLINE;
2326 				fp_port_offline(port, 0);
2327 				port->fp_task = port->fp_last_task;
2328 				port->fp_last_task = FP_TASK_IDLE;
2329 			}
2330 
2331 			if (--port->fp_statec_busy == 0) {
2332 				port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
2333 			}
2334 
2335 			mutex_exit(&port->fp_mutex);
2336 
2337 			job->job_result = fp_ulp_notify(port, statec, KM_SLEEP);
2338 			fctl_jobdone(job);
2339 			break;
2340 		}
2341 
2342 		case JOB_PLOGI_ONE:
2343 			/*
2344 			 * Issue a PLOGI to a single remote port. Multiple
2345 			 * PLOGIs to different remote ports may occur in
2346 			 * parallel.
2347 			 * This can create the fc_remote_port_t if it does not
2348 			 * already exist.
2349 			 */
2350 
2351 			mutex_exit(&port->fp_mutex);
2352 			d_id = (uint32_t *)job->job_private;
2353 			pd = fctl_get_remote_port_by_did(port, *d_id);
2354 
2355 			if (pd) {
2356 				mutex_enter(&pd->pd_mutex);
2357 				if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
2358 					pd->pd_login_count++;
2359 					mutex_exit(&pd->pd_mutex);
2360 					job->job_result = FC_SUCCESS;
2361 					fctl_jobdone(job);
2362 					break;
2363 				}
2364 				mutex_exit(&pd->pd_mutex);
2365 			} else {
2366 				mutex_enter(&port->fp_mutex);
2367 				if (FC_IS_TOP_SWITCH(port->fp_topology)) {
2368 					mutex_exit(&port->fp_mutex);
2369 					pd = fp_create_remote_port_by_ns(port,
2370 					    *d_id, KM_SLEEP);
2371 					if (pd == NULL) {
2372 						job->job_result = FC_FAILURE;
2373 						fctl_jobdone(job);
2374 						break;
2375 					}
2376 				} else {
2377 					mutex_exit(&port->fp_mutex);
2378 				}
2379 			}
2380 
2381 			job->job_flags |= JOB_TYPE_FP_ASYNC;
2382 			job->job_counter = 1;
2383 
2384 			rval = fp_port_login(port, *d_id, job,
2385 			    FP_CMD_PLOGI_RETAIN, KM_SLEEP, pd, NULL);
2386 
2387 			if (rval != FC_SUCCESS) {
2388 				job->job_result = rval;
2389 				fctl_jobdone(job);
2390 			}
2391 			break;
2392 
2393 		case JOB_LOGO_ONE: {
2394 			/*
2395 			 * Issue a PLOGO to a single remote port. Multiple
2396 			 * PLOGOs to different remote ports may occur in
2397 			 * parallel.
2398 			 */
2399 			fc_remote_port_t *pd;
2400 
2401 #ifndef	__lock_lint
2402 			ASSERT(job->job_counter > 0);
2403 #endif
2404 
2405 			pd = (fc_remote_port_t *)job->job_ulp_pkts;
2406 
2407 			mutex_enter(&pd->pd_mutex);
2408 			if (pd->pd_state != PORT_DEVICE_LOGGED_IN) {
2409 				mutex_exit(&pd->pd_mutex);
2410 				job->job_result = FC_LOGINREQ;
2411 				mutex_exit(&port->fp_mutex);
2412 				fctl_jobdone(job);
2413 				break;
2414 			}
2415 			if (pd->pd_login_count > 1) {
2416 				pd->pd_login_count--;
2417 				mutex_exit(&pd->pd_mutex);
2418 				job->job_result = FC_SUCCESS;
2419 				mutex_exit(&port->fp_mutex);
2420 				fctl_jobdone(job);
2421 				break;
2422 			}
2423 			mutex_exit(&pd->pd_mutex);
2424 			mutex_exit(&port->fp_mutex);
2425 			job->job_flags |= JOB_TYPE_FP_ASYNC;
2426 			(void) fp_logout(port, pd, job);
2427 			break;
2428 		}
2429 
2430 		case JOB_FCIO_LOGIN:
2431 			/*
2432 			 * PLOGI initiated at ioctl request.
2433 			 */
2434 			mutex_exit(&port->fp_mutex);
2435 			job->job_result =
2436 			    fp_fcio_login(port, job->job_private, job);
2437 			fctl_jobdone(job);
2438 			break;
2439 
2440 		case JOB_FCIO_LOGOUT:
2441 			/*
2442 			 * PLOGO initiated at ioctl request.
2443 			 */
2444 			mutex_exit(&port->fp_mutex);
2445 			job->job_result =
2446 			    fp_fcio_logout(port, job->job_private, job);
2447 			fctl_jobdone(job);
2448 			break;
2449 
2450 		case JOB_PORT_GETMAP:
2451 		case JOB_PORT_GETMAP_PLOGI_ALL: {
2452 			port->fp_last_task = port->fp_task;
2453 			port->fp_task = FP_TASK_GETMAP;
2454 
2455 			switch (port->fp_topology) {
2456 			case FC_TOP_PRIVATE_LOOP:
2457 				job->job_counter = 1;
2458 
2459 				fp_get_loopmap(port, job);
2460 				mutex_exit(&port->fp_mutex);
2461 				fp_jobwait(job);
2462 				fctl_fillout_map(port,
2463 				    (fc_portmap_t **)job->job_private,
2464 				    (uint32_t *)job->job_arg, 1, 0, 0);
2465 				fctl_jobdone(job);
2466 				mutex_enter(&port->fp_mutex);
2467 				break;
2468 
2469 			case FC_TOP_PUBLIC_LOOP:
2470 			case FC_TOP_FABRIC:
2471 				mutex_exit(&port->fp_mutex);
2472 				job->job_counter = 1;
2473 
2474 				job->job_result = fp_ns_getmap(port,
2475 				    job, (fc_portmap_t **)job->job_private,
2476 				    (uint32_t *)job->job_arg,
2477 				    FCTL_GAN_START_ID);
2478 				fctl_jobdone(job);
2479 				mutex_enter(&port->fp_mutex);
2480 				break;
2481 
2482 			case FC_TOP_PT_PT:
2483 				mutex_exit(&port->fp_mutex);
2484 				fctl_fillout_map(port,
2485 				    (fc_portmap_t **)job->job_private,
2486 				    (uint32_t *)job->job_arg, 1, 0, 0);
2487 				fctl_jobdone(job);
2488 				mutex_enter(&port->fp_mutex);
2489 				break;
2490 
2491 			default:
2492 				mutex_exit(&port->fp_mutex);
2493 				fctl_jobdone(job);
2494 				mutex_enter(&port->fp_mutex);
2495 				break;
2496 			}
2497 			port->fp_task = port->fp_last_task;
2498 			port->fp_last_task = FP_TASK_IDLE;
2499 			mutex_exit(&port->fp_mutex);
2500 			break;
2501 		}
2502 
2503 		case JOB_PORT_OFFLINE: {
2504 			fp_log_port_event(port, ESC_SUNFC_PORT_OFFLINE);
2505 
2506 			port->fp_last_task = port->fp_task;
2507 			port->fp_task = FP_TASK_OFFLINE;
2508 
2509 			if (port->fp_statec_busy > 2) {
2510 				job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION;
2511 				fp_port_offline(port, 0);
2512 				if (--port->fp_statec_busy == 0) {
2513 					port->fp_soft_state &=
2514 					    ~FP_SOFT_IN_STATEC_CB;
2515 				}
2516 			} else {
2517 				fp_port_offline(port, 1);
2518 			}
2519 
2520 			port->fp_task = port->fp_last_task;
2521 			port->fp_last_task = FP_TASK_IDLE;
2522 
2523 			mutex_exit(&port->fp_mutex);
2524 
2525 			fctl_jobdone(job);
2526 			break;
2527 		}
2528 
2529 		case JOB_PORT_STARTUP: {
2530 			if ((rval = fp_port_startup(port, job)) != FC_SUCCESS) {
2531 				if (port->fp_statec_busy > 1) {
2532 					mutex_exit(&port->fp_mutex);
2533 					break;
2534 				}
2535 				mutex_exit(&port->fp_mutex);
2536 
2537 				FP_TRACE(FP_NHEAD2(9, rval),
2538 				    "Topology discovery failed");
2539 				break;
2540 			}
2541 
2542 			/*
2543 			 * Attempt building device handles in case
2544 			 * of private Loop.
2545 			 */
2546 			if (port->fp_topology == FC_TOP_PRIVATE_LOOP) {
2547 				job->job_counter = 1;
2548 
2549 				fp_get_loopmap(port, job);
2550 				mutex_exit(&port->fp_mutex);
2551 				fp_jobwait(job);
2552 				mutex_enter(&port->fp_mutex);
2553 				if (port->fp_lilp_map.lilp_magic < MAGIC_LIRP) {
2554 					ASSERT(port->fp_total_devices == 0);
2555 					port->fp_total_devices =
2556 					    port->fp_dev_count;
2557 				}
2558 			} else if (FC_IS_TOP_SWITCH(port->fp_topology)) {
2559 				/*
2560 				 * Hack to avoid state changes going up early
2561 				 */
2562 				port->fp_statec_busy++;
2563 				port->fp_soft_state |= FP_SOFT_IN_STATEC_CB;
2564 
2565 				job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION;
2566 				fp_fabric_online(port, job);
2567 				job->job_flags &= ~JOB_CANCEL_ULP_NOTIFICATION;
2568 			}
2569 			mutex_exit(&port->fp_mutex);
2570 			fctl_jobdone(job);
2571 			break;
2572 		}
2573 
2574 		case JOB_PORT_ONLINE: {
2575 			char 		*newtop;
2576 			char 		*oldtop;
2577 			uint32_t	old_top;
2578 
2579 			fp_log_port_event(port, ESC_SUNFC_PORT_ONLINE);
2580 
2581 			/*
2582 			 * Bail out early if there are a lot of
2583 			 * state changes in the pipeline
2584 			 */
2585 			if (port->fp_statec_busy > 1) {
2586 				--port->fp_statec_busy;
2587 				mutex_exit(&port->fp_mutex);
2588 				fctl_jobdone(job);
2589 				break;
2590 			}
2591 
2592 			switch (old_top = port->fp_topology) {
2593 			case FC_TOP_PRIVATE_LOOP:
2594 				oldtop = "Private Loop";
2595 				break;
2596 
2597 			case FC_TOP_PUBLIC_LOOP:
2598 				oldtop = "Public Loop";
2599 				break;
2600 
2601 			case FC_TOP_PT_PT:
2602 				oldtop = "Point to Point";
2603 				break;
2604 
2605 			case FC_TOP_FABRIC:
2606 				oldtop = "Fabric";
2607 				break;
2608 
2609 			default:
2610 				oldtop = NULL;
2611 				break;
2612 			}
2613 
2614 			port->fp_last_task = port->fp_task;
2615 			port->fp_task = FP_TASK_ONLINE;
2616 
2617 			if ((rval = fp_port_startup(port, job)) != FC_SUCCESS) {
2618 
2619 				port->fp_task = port->fp_last_task;
2620 				port->fp_last_task = FP_TASK_IDLE;
2621 
2622 				if (port->fp_statec_busy > 1) {
2623 					--port->fp_statec_busy;
2624 					mutex_exit(&port->fp_mutex);
2625 					break;
2626 				}
2627 
2628 				port->fp_state = FC_STATE_OFFLINE;
2629 
2630 				FP_TRACE(FP_NHEAD2(9, rval),
2631 				    "Topology discovery failed");
2632 
2633 				if (--port->fp_statec_busy == 0) {
2634 					port->fp_soft_state &=
2635 					    ~FP_SOFT_IN_STATEC_CB;
2636 				}
2637 
2638 				if (port->fp_offline_tid == NULL) {
2639 					port->fp_offline_tid =
2640 					    timeout(fp_offline_timeout,
2641 					    (caddr_t)port, fp_offline_ticks);
2642 				}
2643 
2644 				mutex_exit(&port->fp_mutex);
2645 				break;
2646 			}
2647 
2648 			switch (port->fp_topology) {
2649 			case FC_TOP_PRIVATE_LOOP:
2650 				newtop = "Private Loop";
2651 				break;
2652 
2653 			case FC_TOP_PUBLIC_LOOP:
2654 				newtop = "Public Loop";
2655 				break;
2656 
2657 			case FC_TOP_PT_PT:
2658 				newtop = "Point to Point";
2659 				break;
2660 
2661 			case FC_TOP_FABRIC:
2662 				newtop = "Fabric";
2663 				break;
2664 
2665 			default:
2666 				newtop = NULL;
2667 				break;
2668 			}
2669 
2670 			if (oldtop && newtop && strcmp(oldtop, newtop)) {
2671 				fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
2672 				    "Change in FC Topology old = %s new = %s",
2673 				    oldtop, newtop);
2674 			}
2675 
2676 			switch (port->fp_topology) {
2677 			case FC_TOP_PRIVATE_LOOP: {
2678 				int orphan = (old_top == FC_TOP_FABRIC ||
2679 				    old_top == FC_TOP_PUBLIC_LOOP) ? 1 : 0;
2680 
2681 				mutex_exit(&port->fp_mutex);
2682 				fp_loop_online(port, job, orphan);
2683 				break;
2684 			}
2685 
2686 			case FC_TOP_PUBLIC_LOOP:
2687 				/* FALLTHROUGH */
2688 			case FC_TOP_FABRIC:
2689 				fp_fabric_online(port, job);
2690 				mutex_exit(&port->fp_mutex);
2691 				break;
2692 
2693 			case FC_TOP_PT_PT:
2694 				fp_p2p_online(port, job);
2695 				mutex_exit(&port->fp_mutex);
2696 				break;
2697 
2698 			default:
2699 				if (--port->fp_statec_busy != 0) {
2700 					/*
2701 					 * Watch curiously at what the next
2702 					 * state transition can do.
2703 					 */
2704 					mutex_exit(&port->fp_mutex);
2705 					break;
2706 				}
2707 
2708 				FP_TRACE(FP_NHEAD2(9, 0),
2709 				    "Topology Unknown, Offlining the port..");
2710 
2711 				port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
2712 				port->fp_state = FC_STATE_OFFLINE;
2713 
2714 				if (port->fp_offline_tid == NULL) {
2715 					port->fp_offline_tid =
2716 					    timeout(fp_offline_timeout,
2717 					    (caddr_t)port, fp_offline_ticks);
2718 				}
2719 				mutex_exit(&port->fp_mutex);
2720 				break;
2721 			}
2722 
2723 			mutex_enter(&port->fp_mutex);
2724 
2725 			port->fp_task = port->fp_last_task;
2726 			port->fp_last_task = FP_TASK_IDLE;
2727 
2728 			mutex_exit(&port->fp_mutex);
2729 
2730 			fctl_jobdone(job);
2731 			break;
2732 		}
2733 
2734 		case JOB_PLOGI_GROUP: {
2735 			mutex_exit(&port->fp_mutex);
2736 			fp_plogi_group(port, job);
2737 			break;
2738 		}
2739 
2740 		case JOB_UNSOL_REQUEST: {
2741 			mutex_exit(&port->fp_mutex);
2742 			fp_handle_unsol_buf(port,
2743 			    (fc_unsol_buf_t *)job->job_private, job);
2744 			fctl_dealloc_job(job);
2745 			break;
2746 		}
2747 
2748 		case JOB_NS_CMD: {
2749 			fctl_ns_req_t *ns_cmd;
2750 
2751 			mutex_exit(&port->fp_mutex);
2752 
2753 			job->job_flags |= JOB_TYPE_FP_ASYNC;
2754 			ns_cmd = (fctl_ns_req_t *)job->job_private;
2755 			if (ns_cmd->ns_cmd_code < NS_GA_NXT ||
2756 			    ns_cmd->ns_cmd_code > NS_DA_ID) {
2757 				job->job_result = FC_BADCMD;
2758 				fctl_jobdone(job);
2759 				break;
2760 			}
2761 
2762 			if (FC_IS_CMD_A_REG(ns_cmd->ns_cmd_code)) {
2763 				if (ns_cmd->ns_pd != NULL) {
2764 					job->job_result = FC_BADOBJECT;
2765 					fctl_jobdone(job);
2766 					break;
2767 				}
2768 
2769 				job->job_counter = 1;
2770 
2771 				rval = fp_ns_reg(port, ns_cmd->ns_pd,
2772 				    ns_cmd->ns_cmd_code, job, 0, KM_SLEEP);
2773 
2774 				if (rval != FC_SUCCESS) {
2775 					job->job_result = rval;
2776 					fctl_jobdone(job);
2777 				}
2778 				break;
2779 			}
2780 			job->job_result = FC_SUCCESS;
2781 			job->job_counter = 1;
2782 
2783 			rval = fp_ns_query(port, ns_cmd, job, 0, KM_SLEEP);
2784 			if (rval != FC_SUCCESS) {
2785 				fctl_jobdone(job);
2786 			}
2787 			break;
2788 		}
2789 
2790 		case JOB_LINK_RESET: {
2791 			la_wwn_t *pwwn;
2792 			uint32_t topology;
2793 
2794 			pwwn = (la_wwn_t *)job->job_private;
2795 			ASSERT(pwwn != NULL);
2796 
2797 			topology = port->fp_topology;
2798 			mutex_exit(&port->fp_mutex);
2799 
2800 			if (fctl_is_wwn_zero(pwwn) == FC_SUCCESS ||
2801 			    topology == FC_TOP_PRIVATE_LOOP) {
2802 				job->job_flags |= JOB_TYPE_FP_ASYNC;
2803 				rval = port->fp_fca_tran->fca_reset(
2804 				    port->fp_fca_handle, FC_FCA_LINK_RESET);
2805 				job->job_result = rval;
2806 				fp_jobdone(job);
2807 			} else {
2808 				ASSERT((job->job_flags &
2809 				    JOB_TYPE_FP_ASYNC) == 0);
2810 
2811 				if (FC_IS_TOP_SWITCH(topology)) {
2812 					rval = fp_remote_lip(port, pwwn,
2813 					    KM_SLEEP, job);
2814 				} else {
2815 					rval = FC_FAILURE;
2816 				}
2817 				if (rval != FC_SUCCESS) {
2818 					job->job_result = rval;
2819 				}
2820 				fctl_jobdone(job);
2821 			}
2822 			break;
2823 		}
2824 
2825 		default:
2826 			mutex_exit(&port->fp_mutex);
2827 			job->job_result = FC_BADCMD;
2828 			fctl_jobdone(job);
2829 			break;
2830 		}
2831 	}
2832 	/* NOTREACHED */
2833 }
2834 
2835 
2836 /*
2837  * Perform FC port bring up initialization
2838  */
2839 static int
2840 fp_port_startup(fc_local_port_t *port, job_request_t *job)
2841 {
2842 	int		rval;
2843 	uint32_t	state;
2844 	uint32_t	src_id;
2845 	fc_lilpmap_t 	*lilp_map;
2846 
2847 	ASSERT(MUTEX_HELD(&port->fp_mutex));
2848 	ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
2849 
2850 	FP_DTRACE(FP_NHEAD1(2, 0), "Entering fp_port_startup;"
2851 	    " port=%p, job=%p", port, job);
2852 
2853 	port->fp_topology = FC_TOP_UNKNOWN;
2854 	port->fp_port_id.port_id = 0;
2855 	state = FC_PORT_STATE_MASK(port->fp_state);
2856 
2857 	if (state == FC_STATE_OFFLINE) {
2858 		port->fp_port_type.port_type = FC_NS_PORT_UNKNOWN;
2859 		job->job_result = FC_OFFLINE;
2860 		mutex_exit(&port->fp_mutex);
2861 		fctl_jobdone(job);
2862 		mutex_enter(&port->fp_mutex);
2863 		return (FC_OFFLINE);
2864 	}
2865 
2866 	if (state == FC_STATE_LOOP) {
2867 		port->fp_port_type.port_type = FC_NS_PORT_NL;
2868 		mutex_exit(&port->fp_mutex);
2869 
2870 		lilp_map = &port->fp_lilp_map;
2871 		if ((rval = fp_get_lilpmap(port, lilp_map)) != FC_SUCCESS) {
2872 			job->job_result = FC_FAILURE;
2873 			fctl_jobdone(job);
2874 
2875 			FP_TRACE(FP_NHEAD1(9, rval),
2876 			    "LILP map Invalid or not present");
2877 			mutex_enter(&port->fp_mutex);
2878 			return (FC_FAILURE);
2879 		}
2880 
2881 		if (lilp_map->lilp_length == 0) {
2882 			job->job_result = FC_NO_MAP;
2883 			fctl_jobdone(job);
2884 			fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
2885 			    "LILP map length zero");
2886 			mutex_enter(&port->fp_mutex);
2887 			return (FC_NO_MAP);
2888 		}
2889 		src_id = lilp_map->lilp_myalpa & 0xFF;
2890 	} else {
2891 		fc_remote_port_t	*pd;
2892 		fc_fca_pm_t		pm;
2893 		fc_fca_p2p_info_t	p2p_info;
2894 		int			pd_recepient;
2895 
2896 		/*
2897 		 * Get P2P remote port info if possible
2898 		 */
2899 		bzero((caddr_t)&pm, sizeof (pm));
2900 
2901 		pm.pm_cmd_flags = FC_FCA_PM_READ;
2902 		pm.pm_cmd_code = FC_PORT_GET_P2P_INFO;
2903 		pm.pm_data_len = sizeof (fc_fca_p2p_info_t);
2904 		pm.pm_data_buf = (caddr_t)&p2p_info;
2905 
2906 		rval = port->fp_fca_tran->fca_port_manage(
2907 		    port->fp_fca_handle, &pm);
2908 
2909 		if (rval == FC_SUCCESS) {
2910 			port->fp_port_id.port_id = p2p_info.fca_d_id;
2911 			port->fp_port_type.port_type = FC_NS_PORT_N;
2912 			port->fp_topology = FC_TOP_PT_PT;
2913 			port->fp_total_devices = 1;
2914 			pd_recepient = fctl_wwn_cmp(
2915 			    &port->fp_service_params.nport_ww_name,
2916 			    &p2p_info.pwwn) < 0 ?
2917 			    PD_PLOGI_RECEPIENT : PD_PLOGI_INITIATOR;
2918 			mutex_exit(&port->fp_mutex);
2919 			pd = fctl_create_remote_port(port,
2920 			    &p2p_info.nwwn,
2921 			    &p2p_info.pwwn,
2922 			    p2p_info.d_id,
2923 			    pd_recepient, KM_NOSLEEP);
2924 			FP_DTRACE(FP_NHEAD1(2, 0), "Exiting fp_port_startup;"
2925 			    " P2P port=%p pd=%p", port, pd);
2926 			mutex_enter(&port->fp_mutex);
2927 			return (FC_SUCCESS);
2928 		}
2929 		port->fp_port_type.port_type = FC_NS_PORT_N;
2930 		mutex_exit(&port->fp_mutex);
2931 		src_id = 0;
2932 	}
2933 
2934 	job->job_counter = 1;
2935 	job->job_result = FC_SUCCESS;
2936 
2937 	if ((rval = fp_fabric_login(port, src_id, job, FP_CMD_PLOGI_DONT_CARE,
2938 	    KM_SLEEP)) != FC_SUCCESS) {
2939 		port->fp_port_type.port_type = FC_NS_PORT_UNKNOWN;
2940 		job->job_result = FC_FAILURE;
2941 		fctl_jobdone(job);
2942 
2943 		mutex_enter(&port->fp_mutex);
2944 		if (port->fp_statec_busy <= 1) {
2945 			mutex_exit(&port->fp_mutex);
2946 			fp_printf(port, CE_NOTE, FP_LOG_ONLY, rval, NULL,
2947 			    "Couldn't transport FLOGI");
2948 			mutex_enter(&port->fp_mutex);
2949 		}
2950 		return (FC_FAILURE);
2951 	}
2952 
2953 	fp_jobwait(job);
2954 
2955 	mutex_enter(&port->fp_mutex);
2956 	if (job->job_result == FC_SUCCESS) {
2957 		if (FC_IS_TOP_SWITCH(port->fp_topology)) {
2958 			mutex_exit(&port->fp_mutex);
2959 			fp_ns_init(port, job, KM_SLEEP);
2960 			mutex_enter(&port->fp_mutex);
2961 		}
2962 	} else {
2963 		if (state == FC_STATE_LOOP) {
2964 			port->fp_topology = FC_TOP_PRIVATE_LOOP;
2965 			port->fp_port_id.port_id =
2966 			    port->fp_lilp_map.lilp_myalpa & 0xFF;
2967 		}
2968 	}
2969 
2970 	FP_DTRACE(FP_NHEAD1(2, 0), "Exiting fp_port_startup; port=%p, job=%p",
2971 	    port, job);
2972 
2973 	return (FC_SUCCESS);
2974 }
2975 
2976 
2977 /*
2978  * Perform ULP invocations following FC port startup
2979  */
2980 /* ARGSUSED */
2981 static void
2982 fp_startup_done(opaque_t arg, uchar_t result)
2983 {
2984 	fc_local_port_t *port = arg;
2985 
2986 	fp_attach_ulps(port, FC_CMD_ATTACH);
2987 
2988 	FP_DTRACE(FP_NHEAD1(2, 0), "fp_startup almost complete; port=%p", port);
2989 }
2990 
2991 
2992 /*
2993  * Perform ULP port attach
2994  */
2995 static void
2996 fp_ulp_port_attach(void *arg)
2997 {
2998 	fp_soft_attach_t *att = (fp_soft_attach_t *)arg;
2999 	fc_local_port_t	 *port = att->att_port;
3000 
3001 	FP_DTRACE(FP_NHEAD1(1, 0), "port attach of"
3002 	    " ULPs begin; port=%p, cmd=%x", port, att->att_cmd);
3003 
3004 	fctl_attach_ulps(att->att_port, att->att_cmd, &modlinkage);
3005 
3006 	if (att->att_need_pm_idle == B_TRUE) {
3007 		fctl_idle_port(port);
3008 	}
3009 
3010 	FP_DTRACE(FP_NHEAD1(1, 0), "port attach of"
3011 	    " ULPs end; port=%p, cmd=%x", port, att->att_cmd);
3012 
3013 	mutex_enter(&att->att_port->fp_mutex);
3014 	att->att_port->fp_ulp_attach = 0;
3015 
3016 	port->fp_task = port->fp_last_task;
3017 	port->fp_last_task = FP_TASK_IDLE;
3018 
3019 	cv_signal(&att->att_port->fp_attach_cv);
3020 
3021 	mutex_exit(&att->att_port->fp_mutex);
3022 
3023 	kmem_free(att, sizeof (fp_soft_attach_t));
3024 }
3025 
3026 /*
3027  * Entry point to funnel all requests down to FCAs
3028  */
3029 static int
3030 fp_sendcmd(fc_local_port_t *port, fp_cmd_t *cmd, opaque_t fca_handle)
3031 {
3032 	int rval;
3033 
3034 	mutex_enter(&port->fp_mutex);
3035 	if (port->fp_statec_busy > 1 || (cmd->cmd_ulp_pkt != NULL &&
3036 	    (port->fp_statec_busy || FC_PORT_STATE_MASK(port->fp_state) ==
3037 	    FC_STATE_OFFLINE))) {
3038 		/*
3039 		 * This means there is more than one state change
3040 		 * at this point of time - Since they are processed
3041 		 * serially, any processing of the current one should
3042 		 * be failed, failed and move up in processing the next
3043 		 */
3044 		cmd->cmd_pkt.pkt_state = FC_PKT_ELS_IN_PROGRESS;
3045 		cmd->cmd_pkt.pkt_reason = FC_REASON_OFFLINE;
3046 		if (cmd->cmd_job) {
3047 			/*
3048 			 * A state change that is going to be invalidated
3049 			 * by another one already in the port driver's queue
3050 			 * need not go up to all ULPs. This will minimize
3051 			 * needless processing and ripples in ULP modules
3052 			 */
3053 			cmd->cmd_job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION;
3054 		}
3055 		mutex_exit(&port->fp_mutex);
3056 		return (FC_STATEC_BUSY);
3057 	}
3058 
3059 	if (FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) {
3060 		cmd->cmd_pkt.pkt_state = FC_PKT_PORT_OFFLINE;
3061 		cmd->cmd_pkt.pkt_reason = FC_REASON_OFFLINE;
3062 		mutex_exit(&port->fp_mutex);
3063 
3064 		return (FC_OFFLINE);
3065 	}
3066 	mutex_exit(&port->fp_mutex);
3067 
3068 	rval = cmd->cmd_transport(fca_handle, &cmd->cmd_pkt);
3069 	if (rval != FC_SUCCESS) {
3070 		if (rval == FC_TRAN_BUSY) {
3071 			cmd->cmd_retry_interval = fp_retry_delay;
3072 			rval = fp_retry_cmd(&cmd->cmd_pkt);
3073 			if (rval == FC_FAILURE) {
3074 				cmd->cmd_pkt.pkt_state = FC_PKT_TRAN_BSY;
3075 			}
3076 		}
3077 	}
3078 
3079 	return (rval);
3080 }
3081 
3082 
3083 /*
3084  * Each time a timeout kicks in, walk the wait queue, decrement the
3085  * the retry_interval, when the retry_interval becomes less than
3086  * or equal to zero, re-transport the command: If the re-transport
3087  * fails with BUSY, enqueue the command in the wait queue.
3088  *
3089  * In order to prevent looping forever because of commands enqueued
3090  * from within this function itself, save the current tail pointer
3091  * (in cur_tail) and exit the loop after serving this command.
3092  */
3093 static void
3094 fp_resendcmd(void *port_handle)
3095 {
3096 	int		rval;
3097 	fc_local_port_t	*port;
3098 	fp_cmd_t 	*cmd;
3099 	fp_cmd_t	*cur_tail;
3100 
3101 	port = port_handle;
3102 	mutex_enter(&port->fp_mutex);
3103 	cur_tail = port->fp_wait_tail;
3104 	mutex_exit(&port->fp_mutex);
3105 
3106 	while ((cmd = fp_deque_cmd(port)) != NULL) {
3107 		cmd->cmd_retry_interval -= fp_retry_ticker;
3108 		/* Check if we are detaching */
3109 		if (port->fp_soft_state &
3110 		    (FP_SOFT_IN_DETACH | FP_DETACH_INPROGRESS)) {
3111 			cmd->cmd_pkt.pkt_state = FC_PKT_TRAN_ERROR;
3112 			cmd->cmd_pkt.pkt_reason = 0;
3113 			fp_iodone(cmd);
3114 		} else if (cmd->cmd_retry_interval <= 0) {
3115 			rval = cmd->cmd_transport(port->fp_fca_handle,
3116 			    &cmd->cmd_pkt);
3117 
3118 			if (rval != FC_SUCCESS) {
3119 				if (cmd->cmd_pkt.pkt_state == FC_PKT_TRAN_BSY) {
3120 					if (--cmd->cmd_retry_count) {
3121 						fp_enque_cmd(port, cmd);
3122 						if (cmd == cur_tail) {
3123 							break;
3124 						}
3125 						continue;
3126 					}
3127 					cmd->cmd_pkt.pkt_state =
3128 					    FC_PKT_TRAN_BSY;
3129 				} else {
3130 					cmd->cmd_pkt.pkt_state =
3131 					    FC_PKT_TRAN_ERROR;
3132 				}
3133 				cmd->cmd_pkt.pkt_reason = 0;
3134 				fp_iodone(cmd);
3135 			}
3136 		} else {
3137 			fp_enque_cmd(port, cmd);
3138 		}
3139 
3140 		if (cmd == cur_tail) {
3141 			break;
3142 		}
3143 	}
3144 
3145 	mutex_enter(&port->fp_mutex);
3146 	if (port->fp_wait_head) {
3147 		timeout_id_t tid;
3148 
3149 		mutex_exit(&port->fp_mutex);
3150 		tid = timeout(fp_resendcmd, (caddr_t)port,
3151 		    fp_retry_ticks);
3152 		mutex_enter(&port->fp_mutex);
3153 		port->fp_wait_tid = tid;
3154 	} else {
3155 		port->fp_wait_tid = NULL;
3156 	}
3157 	mutex_exit(&port->fp_mutex);
3158 }
3159 
3160 
3161 /*
3162  * Handle Local, Fabric, N_Port, Transport (whatever that means) BUSY here.
3163  *
3164  * Yes, as you can see below, cmd_retry_count is used here too.  That means
3165  * the retries for BUSY are less if there were transport failures (transport
3166  * failure means fca_transport failure). The goal is not to exceed overall
3167  * retries set in the cmd_retry_count (whatever may be the reason for retry)
3168  *
3169  * Return Values:
3170  *	FC_SUCCESS
3171  *	FC_FAILURE
3172  */
3173 static int
3174 fp_retry_cmd(fc_packet_t *pkt)
3175 {
3176 	fp_cmd_t *cmd;
3177 
3178 	cmd = pkt->pkt_ulp_private;
3179 
3180 	if (--cmd->cmd_retry_count) {
3181 		fp_enque_cmd(cmd->cmd_port, cmd);
3182 		return (FC_SUCCESS);
3183 	} else {
3184 		return (FC_FAILURE);
3185 	}
3186 }
3187 
3188 
3189 /*
3190  * Queue up FC packet for deferred retry
3191  */
3192 static void
3193 fp_enque_cmd(fc_local_port_t *port, fp_cmd_t *cmd)
3194 {
3195 	timeout_id_t tid;
3196 
3197 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
3198 
3199 #ifdef	DEBUG
3200 	fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, &cmd->cmd_pkt,
3201 	    "Retrying ELS for %x", cmd->cmd_pkt.pkt_cmd_fhdr.d_id);
3202 #endif
3203 
3204 	mutex_enter(&port->fp_mutex);
3205 	if (port->fp_wait_tail) {
3206 		port->fp_wait_tail->cmd_next = cmd;
3207 		port->fp_wait_tail = cmd;
3208 	} else {
3209 		ASSERT(port->fp_wait_head == NULL);
3210 		port->fp_wait_head = port->fp_wait_tail = cmd;
3211 		if (port->fp_wait_tid == NULL) {
3212 			mutex_exit(&port->fp_mutex);
3213 			tid = timeout(fp_resendcmd, (caddr_t)port,
3214 			    fp_retry_ticks);
3215 			mutex_enter(&port->fp_mutex);
3216 			port->fp_wait_tid = tid;
3217 		}
3218 	}
3219 	mutex_exit(&port->fp_mutex);
3220 }
3221 
3222 
3223 /*
3224  * Handle all RJT codes
3225  */
3226 static int
3227 fp_handle_reject(fc_packet_t *pkt)
3228 {
3229 	int 		rval = FC_FAILURE;
3230 	uchar_t		next_class;
3231 	fp_cmd_t 	*cmd;
3232 	fc_local_port_t *port;
3233 
3234 	cmd = pkt->pkt_ulp_private;
3235 	port = cmd->cmd_port;
3236 
3237 	switch (pkt->pkt_state) {
3238 	case FC_PKT_FABRIC_RJT:
3239 	case FC_PKT_NPORT_RJT:
3240 		if (pkt->pkt_reason == FC_REASON_CLASS_NOT_SUPP) {
3241 			next_class = fp_get_nextclass(cmd->cmd_port,
3242 			    FC_TRAN_CLASS(pkt->pkt_tran_flags));
3243 
3244 			if (next_class == FC_TRAN_CLASS_INVALID) {
3245 				return (rval);
3246 			}
3247 			pkt->pkt_tran_flags = FC_TRAN_INTR | next_class;
3248 			pkt->pkt_tran_type = FC_PKT_EXCHANGE;
3249 
3250 			rval = fp_sendcmd(cmd->cmd_port, cmd,
3251 			    cmd->cmd_port->fp_fca_handle);
3252 
3253 			if (rval != FC_SUCCESS) {
3254 				pkt->pkt_state = FC_PKT_TRAN_ERROR;
3255 			}
3256 		}
3257 			break;
3258 
3259 	case FC_PKT_LS_RJT:
3260 	case FC_PKT_BA_RJT:
3261 		if ((pkt->pkt_reason == FC_REASON_LOGICAL_ERROR) ||
3262 		    (pkt->pkt_reason == FC_REASON_LOGICAL_BSY)) {
3263 			cmd->cmd_retry_interval = fp_retry_delay;
3264 			rval = fp_retry_cmd(pkt);
3265 		}
3266 		break;
3267 
3268 	case FC_PKT_FS_RJT:
3269 		if (pkt->pkt_reason == FC_REASON_FS_LOGICAL_BUSY) {
3270 			cmd->cmd_retry_interval = fp_retry_delay;
3271 			rval = fp_retry_cmd(pkt);
3272 		}
3273 		break;
3274 
3275 	case FC_PKT_LOCAL_RJT:
3276 		if (pkt->pkt_reason == FC_REASON_QFULL) {
3277 			cmd->cmd_retry_interval = fp_retry_delay;
3278 			rval = fp_retry_cmd(pkt);
3279 		}
3280 		break;
3281 
3282 	default:
3283 		FP_TRACE(FP_NHEAD1(1, 0),
3284 		    "fp_handle_reject(): Invalid pkt_state");
3285 		break;
3286 	}
3287 
3288 	return (rval);
3289 }
3290 
3291 
3292 /*
3293  * Return the next class of service supported by the FCA
3294  */
3295 static uchar_t
3296 fp_get_nextclass(fc_local_port_t *port, uchar_t cur_class)
3297 {
3298 	uchar_t next_class;
3299 
3300 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
3301 
3302 	switch (cur_class) {
3303 	case FC_TRAN_CLASS_INVALID:
3304 		if (port->fp_cos & FC_NS_CLASS1) {
3305 			next_class = FC_TRAN_CLASS1;
3306 			break;
3307 		}
3308 		/* FALLTHROUGH */
3309 
3310 	case FC_TRAN_CLASS1:
3311 		if (port->fp_cos & FC_NS_CLASS2) {
3312 			next_class = FC_TRAN_CLASS2;
3313 			break;
3314 		}
3315 		/* FALLTHROUGH */
3316 
3317 	case FC_TRAN_CLASS2:
3318 		if (port->fp_cos & FC_NS_CLASS3) {
3319 			next_class = FC_TRAN_CLASS3;
3320 			break;
3321 		}
3322 		/* FALLTHROUGH */
3323 
3324 	case FC_TRAN_CLASS3:
3325 	default:
3326 		next_class = FC_TRAN_CLASS_INVALID;
3327 		break;
3328 	}
3329 
3330 	return (next_class);
3331 }
3332 
3333 
3334 /*
3335  * Determine if a class of service is supported by the FCA
3336  */
3337 static int
3338 fp_is_class_supported(uint32_t cos, uchar_t tran_class)
3339 {
3340 	int rval;
3341 
3342 	switch (tran_class) {
3343 	case FC_TRAN_CLASS1:
3344 		if (cos & FC_NS_CLASS1) {
3345 			rval = FC_SUCCESS;
3346 		} else {
3347 			rval = FC_FAILURE;
3348 		}
3349 		break;
3350 
3351 	case FC_TRAN_CLASS2:
3352 		if (cos & FC_NS_CLASS2) {
3353 			rval = FC_SUCCESS;
3354 		} else {
3355 			rval = FC_FAILURE;
3356 		}
3357 		break;
3358 
3359 	case FC_TRAN_CLASS3:
3360 		if (cos & FC_NS_CLASS3) {
3361 			rval = FC_SUCCESS;
3362 		} else {
3363 			rval = FC_FAILURE;
3364 		}
3365 		break;
3366 
3367 	default:
3368 		rval = FC_FAILURE;
3369 		break;
3370 	}
3371 
3372 	return (rval);
3373 }
3374 
3375 
3376 /*
3377  * Dequeue FC packet for retry
3378  */
3379 static fp_cmd_t *
3380 fp_deque_cmd(fc_local_port_t *port)
3381 {
3382 	fp_cmd_t *cmd;
3383 
3384 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
3385 
3386 	mutex_enter(&port->fp_mutex);
3387 
3388 	if (port->fp_wait_head == NULL) {
3389 		/*
3390 		 * To avoid races, NULL the fp_wait_tid as
3391 		 * we are about to exit the timeout thread.
3392 		 */
3393 		port->fp_wait_tid = NULL;
3394 		mutex_exit(&port->fp_mutex);
3395 		return (NULL);
3396 	}
3397 
3398 	cmd = port->fp_wait_head;
3399 	port->fp_wait_head = cmd->cmd_next;
3400 	cmd->cmd_next = NULL;
3401 
3402 	if (port->fp_wait_head == NULL) {
3403 		port->fp_wait_tail = NULL;
3404 	}
3405 	mutex_exit(&port->fp_mutex);
3406 
3407 	return (cmd);
3408 }
3409 
3410 
3411 /*
3412  * Wait for job completion
3413  */
3414 static void
3415 fp_jobwait(job_request_t *job)
3416 {
3417 	sema_p(&job->job_port_sema);
3418 }
3419 
3420 
3421 /*
3422  * Convert FC packet state to FC errno
3423  */
3424 int
3425 fp_state_to_rval(uchar_t state)
3426 {
3427 	int count;
3428 
3429 	for (count = 0; count < sizeof (fp_xlat) /
3430 	sizeof (fp_xlat[0]); count++) {
3431 		if (fp_xlat[count].xlat_state == state) {
3432 			return (fp_xlat[count].xlat_rval);
3433 		}
3434 	}
3435 
3436 	return (FC_FAILURE);
3437 }
3438 
3439 
3440 /*
3441  * For Synchronous I/O requests, the caller is
3442  * expected to do fctl_jobdone(if necessary)
3443  *
3444  * We want to preserve at least one failure in the
3445  * job_result if it happens.
3446  *
3447  */
3448 static void
3449 fp_iodone(fp_cmd_t *cmd)
3450 {
3451 	fc_packet_t		*ulp_pkt = cmd->cmd_ulp_pkt;
3452 	job_request_t 		*job = cmd->cmd_job;
3453 	fc_remote_port_t 	*pd = cmd->cmd_pkt.pkt_pd;
3454 
3455 	ASSERT(job != NULL);
3456 	ASSERT(cmd->cmd_port != NULL);
3457 	ASSERT(&cmd->cmd_pkt != NULL);
3458 
3459 	mutex_enter(&job->job_mutex);
3460 	if (job->job_result == FC_SUCCESS) {
3461 		job->job_result = fp_state_to_rval(cmd->cmd_pkt.pkt_state);
3462 	}
3463 	mutex_exit(&job->job_mutex);
3464 
3465 	if (pd) {
3466 		mutex_enter(&pd->pd_mutex);
3467 		pd->pd_flags = PD_IDLE;
3468 		mutex_exit(&pd->pd_mutex);
3469 	}
3470 
3471 	if (ulp_pkt) {
3472 		if (pd && cmd->cmd_flags & FP_CMD_DELDEV_ON_ERROR &&
3473 		    FP_IS_PKT_ERROR(ulp_pkt)) {
3474 			fc_local_port_t 	*port;
3475 			fc_remote_node_t	*node;
3476 
3477 			port = cmd->cmd_port;
3478 
3479 			mutex_enter(&pd->pd_mutex);
3480 			pd->pd_state = PORT_DEVICE_INVALID;
3481 			pd->pd_ref_count--;
3482 			node = pd->pd_remote_nodep;
3483 			mutex_exit(&pd->pd_mutex);
3484 
3485 			ASSERT(node != NULL);
3486 			ASSERT(port != NULL);
3487 
3488 			if (fctl_destroy_remote_port(port, pd) == 0) {
3489 				fctl_destroy_remote_node(node);
3490 			}
3491 
3492 			ulp_pkt->pkt_pd = NULL;
3493 		}
3494 
3495 		ulp_pkt->pkt_comp(ulp_pkt);
3496 	}
3497 
3498 	fp_free_pkt(cmd);
3499 	fp_jobdone(job);
3500 }
3501 
3502 
3503 /*
3504  * Job completion handler
3505  */
3506 static void
3507 fp_jobdone(job_request_t *job)
3508 {
3509 	mutex_enter(&job->job_mutex);
3510 	ASSERT(job->job_counter > 0);
3511 
3512 	if (--job->job_counter != 0) {
3513 		mutex_exit(&job->job_mutex);
3514 		return;
3515 	}
3516 
3517 	if (job->job_ulp_pkts) {
3518 		ASSERT(job->job_ulp_listlen > 0);
3519 		kmem_free(job->job_ulp_pkts,
3520 		    sizeof (fc_packet_t *) * job->job_ulp_listlen);
3521 	}
3522 
3523 	if (job->job_flags & JOB_TYPE_FP_ASYNC) {
3524 		mutex_exit(&job->job_mutex);
3525 		fctl_jobdone(job);
3526 	} else {
3527 		mutex_exit(&job->job_mutex);
3528 		sema_v(&job->job_port_sema);
3529 	}
3530 }
3531 
3532 
3533 /*
3534  * Try to perform shutdown of a port during a detach. No return
3535  * value since the detach should not fail because the port shutdown
3536  * failed.
3537  */
3538 static void
3539 fp_port_shutdown(fc_local_port_t *port, job_request_t *job)
3540 {
3541 	int			index;
3542 	int			count;
3543 	int			flags;
3544 	fp_cmd_t 		*cmd;
3545 	struct pwwn_hash 	*head;
3546 	fc_remote_port_t 	*pd;
3547 
3548 	ASSERT(MUTEX_HELD(&port->fp_mutex));
3549 
3550 	job->job_result = FC_SUCCESS;
3551 
3552 	if (port->fp_taskq) {
3553 		/*
3554 		 * We must release the mutex here to ensure that other
3555 		 * potential jobs can complete their processing.  Many
3556 		 * also need this mutex.
3557 		 */
3558 		mutex_exit(&port->fp_mutex);
3559 		taskq_wait(port->fp_taskq);
3560 		mutex_enter(&port->fp_mutex);
3561 	}
3562 
3563 	if (port->fp_offline_tid) {
3564 		timeout_id_t tid;
3565 
3566 		tid = port->fp_offline_tid;
3567 		port->fp_offline_tid = NULL;
3568 		mutex_exit(&port->fp_mutex);
3569 		(void) untimeout(tid);
3570 		mutex_enter(&port->fp_mutex);
3571 	}
3572 
3573 	if (port->fp_wait_tid) {
3574 		timeout_id_t tid;
3575 
3576 		tid = port->fp_wait_tid;
3577 		port->fp_wait_tid = NULL;
3578 		mutex_exit(&port->fp_mutex);
3579 		(void) untimeout(tid);
3580 	} else {
3581 		mutex_exit(&port->fp_mutex);
3582 	}
3583 
3584 	/*
3585 	 * While we cancel the timeout, let's also return the
3586 	 * the outstanding requests back to the callers.
3587 	 */
3588 	while ((cmd = fp_deque_cmd(port)) != NULL) {
3589 		ASSERT(cmd->cmd_job != NULL);
3590 		cmd->cmd_job->job_result = FC_OFFLINE;
3591 		fp_iodone(cmd);
3592 	}
3593 
3594 	/*
3595 	 * Gracefully LOGO with all the devices logged in.
3596 	 */
3597 	mutex_enter(&port->fp_mutex);
3598 
3599 	for (count = index = 0; index < pwwn_table_size; index++) {
3600 		head = &port->fp_pwwn_table[index];
3601 		pd = head->pwwn_head;
3602 		while (pd != NULL) {
3603 			mutex_enter(&pd->pd_mutex);
3604 			if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
3605 				count++;
3606 			}
3607 			mutex_exit(&pd->pd_mutex);
3608 			pd = pd->pd_wwn_hnext;
3609 		}
3610 	}
3611 
3612 	if (job->job_flags & JOB_TYPE_FP_ASYNC) {
3613 		flags = job->job_flags;
3614 		job->job_flags &= ~JOB_TYPE_FP_ASYNC;
3615 	} else {
3616 		flags = 0;
3617 	}
3618 	if (count) {
3619 		job->job_counter = count;
3620 
3621 		for (index = 0; index < pwwn_table_size; index++) {
3622 			head = &port->fp_pwwn_table[index];
3623 			pd = head->pwwn_head;
3624 			while (pd != NULL) {
3625 				mutex_enter(&pd->pd_mutex);
3626 				if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
3627 					ASSERT(pd->pd_login_count > 0);
3628 					/*
3629 					 * Force the counter to ONE in order
3630 					 * for us to really send LOGO els.
3631 					 */
3632 					pd->pd_login_count = 1;
3633 					mutex_exit(&pd->pd_mutex);
3634 					mutex_exit(&port->fp_mutex);
3635 					(void) fp_logout(port, pd, job);
3636 					mutex_enter(&port->fp_mutex);
3637 				} else {
3638 					mutex_exit(&pd->pd_mutex);
3639 				}
3640 				pd = pd->pd_wwn_hnext;
3641 			}
3642 		}
3643 		mutex_exit(&port->fp_mutex);
3644 		fp_jobwait(job);
3645 	} else {
3646 		mutex_exit(&port->fp_mutex);
3647 	}
3648 
3649 	if (job->job_result != FC_SUCCESS) {
3650 		FP_TRACE(FP_NHEAD1(9, 0),
3651 		    "Can't logout all devices. Proceeding with"
3652 		    " port shutdown");
3653 		job->job_result = FC_SUCCESS;
3654 	}
3655 
3656 	fctl_destroy_all_remote_ports(port);
3657 
3658 	mutex_enter(&port->fp_mutex);
3659 	if (FC_IS_TOP_SWITCH(port->fp_topology)) {
3660 		mutex_exit(&port->fp_mutex);
3661 		fp_ns_fini(port, job);
3662 	} else {
3663 		mutex_exit(&port->fp_mutex);
3664 	}
3665 
3666 	if (flags) {
3667 		job->job_flags = flags;
3668 	}
3669 
3670 	mutex_enter(&port->fp_mutex);
3671 
3672 }
3673 
3674 
3675 /*
3676  * Build the port driver's data structures based on the AL_PA list
3677  */
3678 static void
3679 fp_get_loopmap(fc_local_port_t *port, job_request_t *job)
3680 {
3681 	int 			rval;
3682 	int			flag;
3683 	int 			count;
3684 	uint32_t		d_id;
3685 	fc_remote_port_t 	*pd;
3686 	fc_lilpmap_t 		*lilp_map;
3687 
3688 	ASSERT(MUTEX_HELD(&port->fp_mutex));
3689 
3690 	if (FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) {
3691 		job->job_result = FC_OFFLINE;
3692 		mutex_exit(&port->fp_mutex);
3693 		fp_jobdone(job);
3694 		mutex_enter(&port->fp_mutex);
3695 		return;
3696 	}
3697 
3698 	if (port->fp_lilp_map.lilp_length == 0) {
3699 		mutex_exit(&port->fp_mutex);
3700 		job->job_result = FC_NO_MAP;
3701 		fp_jobdone(job);
3702 		mutex_enter(&port->fp_mutex);
3703 		return;
3704 	}
3705 	mutex_exit(&port->fp_mutex);
3706 
3707 	lilp_map = &port->fp_lilp_map;
3708 	job->job_counter = lilp_map->lilp_length;
3709 
3710 	if (job->job_code == JOB_PORT_GETMAP_PLOGI_ALL) {
3711 		flag = FP_CMD_PLOGI_RETAIN;
3712 	} else {
3713 		flag = FP_CMD_PLOGI_DONT_CARE;
3714 	}
3715 
3716 	for (count = 0; count < lilp_map->lilp_length; count++) {
3717 		d_id = lilp_map->lilp_alpalist[count];
3718 
3719 		if (d_id == (lilp_map->lilp_myalpa & 0xFF)) {
3720 			fp_jobdone(job);
3721 			continue;
3722 		}
3723 
3724 		pd = fctl_get_remote_port_by_did(port, d_id);
3725 		if (pd) {
3726 			mutex_enter(&pd->pd_mutex);
3727 			if (flag == FP_CMD_PLOGI_DONT_CARE ||
3728 			    pd->pd_state == PORT_DEVICE_LOGGED_IN) {
3729 				mutex_exit(&pd->pd_mutex);
3730 				fp_jobdone(job);
3731 				continue;
3732 			}
3733 			mutex_exit(&pd->pd_mutex);
3734 		}
3735 
3736 		rval = fp_port_login(port, d_id, job, flag,
3737 		    KM_SLEEP, pd, NULL);
3738 		if (rval != FC_SUCCESS) {
3739 			fp_jobdone(job);
3740 		}
3741 	}
3742 
3743 	mutex_enter(&port->fp_mutex);
3744 }
3745 
3746 
3747 /*
3748  * Perform loop ONLINE processing
3749  */
3750 static void
3751 fp_loop_online(fc_local_port_t *port, job_request_t *job, int orphan)
3752 {
3753 	int			count;
3754 	int			rval;
3755 	uint32_t		d_id;
3756 	uint32_t		listlen;
3757 	fc_lilpmap_t		*lilp_map;
3758 	fc_remote_port_t	*pd;
3759 	fc_portmap_t		*changelist;
3760 
3761 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
3762 
3763 	FP_TRACE(FP_NHEAD1(1, 0), "fp_loop_online begin; port=%p, job=%p",
3764 	    port, job);
3765 
3766 	lilp_map = &port->fp_lilp_map;
3767 
3768 	if (lilp_map->lilp_length) {
3769 		mutex_enter(&port->fp_mutex);
3770 		if (port->fp_soft_state & FP_SOFT_IN_FCA_RESET) {
3771 			port->fp_soft_state &= ~FP_SOFT_IN_FCA_RESET;
3772 			mutex_exit(&port->fp_mutex);
3773 			delay(drv_usectohz(PLDA_RR_TOV * 1000 * 1000));
3774 		} else {
3775 			mutex_exit(&port->fp_mutex);
3776 		}
3777 
3778 		job->job_counter = lilp_map->lilp_length;
3779 
3780 		for (count = 0; count < lilp_map->lilp_length; count++) {
3781 			d_id = lilp_map->lilp_alpalist[count];
3782 
3783 			if (d_id == (lilp_map->lilp_myalpa & 0xFF)) {
3784 				fp_jobdone(job);
3785 				continue;
3786 			}
3787 
3788 			pd = fctl_get_remote_port_by_did(port, d_id);
3789 			if (pd != NULL) {
3790 #ifdef	DEBUG
3791 				mutex_enter(&pd->pd_mutex);
3792 				if (pd->pd_recepient == PD_PLOGI_INITIATOR) {
3793 					ASSERT(pd->pd_type != PORT_DEVICE_OLD);
3794 				}
3795 				mutex_exit(&pd->pd_mutex);
3796 #endif
3797 				fp_jobdone(job);
3798 				continue;
3799 			}
3800 
3801 			rval = fp_port_login(port, d_id, job,
3802 			    FP_CMD_PLOGI_DONT_CARE, KM_SLEEP, pd, NULL);
3803 
3804 			if (rval != FC_SUCCESS) {
3805 				fp_jobdone(job);
3806 			}
3807 		}
3808 		fp_jobwait(job);
3809 	}
3810 	listlen = 0;
3811 	changelist = NULL;
3812 
3813 	if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) {
3814 		mutex_enter(&port->fp_mutex);
3815 		ASSERT(port->fp_statec_busy > 0);
3816 		if (port->fp_statec_busy == 1) {
3817 			mutex_exit(&port->fp_mutex);
3818 			fctl_fillout_map(port, &changelist, &listlen,
3819 			    1, 0, orphan);
3820 
3821 			mutex_enter(&port->fp_mutex);
3822 			if (port->fp_lilp_map.lilp_magic < MAGIC_LIRP) {
3823 				ASSERT(port->fp_total_devices == 0);
3824 				port->fp_total_devices = port->fp_dev_count;
3825 			}
3826 		} else {
3827 			job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION;
3828 		}
3829 		mutex_exit(&port->fp_mutex);
3830 	}
3831 
3832 	if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) {
3833 		(void) fp_ulp_statec_cb(port, FC_STATE_ONLINE, changelist,
3834 		    listlen, listlen, KM_SLEEP);
3835 	} else {
3836 		mutex_enter(&port->fp_mutex);
3837 		if (--port->fp_statec_busy == 0) {
3838 			port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
3839 		}
3840 		ASSERT(changelist == NULL && listlen == 0);
3841 		mutex_exit(&port->fp_mutex);
3842 	}
3843 
3844 	FP_TRACE(FP_NHEAD1(1, 0), "fp_loop_online end; port=%p, job=%p",
3845 	    port, job);
3846 }
3847 
3848 
3849 /*
3850  * Get an Arbitrated Loop map from the underlying FCA
3851  */
3852 static int
3853 fp_get_lilpmap(fc_local_port_t *port, fc_lilpmap_t *lilp_map)
3854 {
3855 	int rval;
3856 
3857 	FP_TRACE(FP_NHEAD1(1, 0), "fp_get_lilpmap Begin; port=%p, map=%p",
3858 	    port, lilp_map);
3859 
3860 	bzero((caddr_t)lilp_map, sizeof (fc_lilpmap_t));
3861 	rval = port->fp_fca_tran->fca_getmap(port->fp_fca_handle, lilp_map);
3862 	lilp_map->lilp_magic &= 0xFF;	/* Ignore upper byte */
3863 
3864 	if (rval != FC_SUCCESS) {
3865 		rval = FC_NO_MAP;
3866 	} else if (lilp_map->lilp_length == 0 &&
3867 	    (lilp_map->lilp_magic >= MAGIC_LISM &&
3868 	    lilp_map->lilp_magic < MAGIC_LIRP)) {
3869 		uchar_t lilp_length;
3870 
3871 		/*
3872 		 * Since the map length is zero, provide all
3873 		 * the valid AL_PAs for NL_ports discovery.
3874 		 */
3875 		lilp_length = sizeof (fp_valid_alpas) /
3876 		    sizeof (fp_valid_alpas[0]);
3877 		lilp_map->lilp_length = lilp_length;
3878 		bcopy(fp_valid_alpas, lilp_map->lilp_alpalist,
3879 		    lilp_length);
3880 	} else {
3881 		rval = fp_validate_lilp_map(lilp_map);
3882 
3883 		if (rval == FC_SUCCESS) {
3884 			mutex_enter(&port->fp_mutex);
3885 			port->fp_total_devices = lilp_map->lilp_length - 1;
3886 			mutex_exit(&port->fp_mutex);
3887 		}
3888 	}
3889 
3890 	mutex_enter(&port->fp_mutex);
3891 	if (rval != FC_SUCCESS && !(port->fp_soft_state & FP_SOFT_BAD_LINK)) {
3892 		port->fp_soft_state |= FP_SOFT_BAD_LINK;
3893 		mutex_exit(&port->fp_mutex);
3894 
3895 		if (port->fp_fca_tran->fca_reset(port->fp_fca_handle,
3896 		    FC_FCA_RESET_CORE) != FC_SUCCESS) {
3897 			FP_TRACE(FP_NHEAD1(9, 0),
3898 			    "FCA reset failed after LILP map was found"
3899 			    " to be invalid");
3900 		}
3901 	} else if (rval == FC_SUCCESS) {
3902 		port->fp_soft_state &= ~FP_SOFT_BAD_LINK;
3903 		mutex_exit(&port->fp_mutex);
3904 	} else {
3905 		mutex_exit(&port->fp_mutex);
3906 	}
3907 
3908 	FP_TRACE(FP_NHEAD1(1, 0), "fp_get_lilpmap End; port=%p, map=%p", port,
3909 	    lilp_map);
3910 
3911 	return (rval);
3912 }
3913 
3914 
3915 /*
3916  * Perform Fabric Login:
3917  *
3918  * Return Values:
3919  *		FC_SUCCESS
3920  *		FC_FAILURE
3921  *		FC_NOMEM
3922  *		FC_TRANSPORT_ERROR
3923  *		and a lot others defined in fc_error.h
3924  */
3925 static int
3926 fp_fabric_login(fc_local_port_t *port, uint32_t s_id, job_request_t *job,
3927     int flag, int sleep)
3928 {
3929 	int		rval;
3930 	fp_cmd_t 	*cmd;
3931 	uchar_t 	class;
3932 
3933 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
3934 
3935 	FP_TRACE(FP_NHEAD1(1, 0), "fp_fabric_login Begin; port=%p, job=%p",
3936 	    port, job);
3937 
3938 	class = fp_get_nextclass(port, FC_TRAN_CLASS_INVALID);
3939 	if (class == FC_TRAN_CLASS_INVALID) {
3940 		return (FC_ELS_BAD);
3941 	}
3942 
3943 	cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t),
3944 	    sizeof (la_els_logi_t), sleep, NULL);
3945 	if (cmd == NULL) {
3946 		return (FC_NOMEM);
3947 	}
3948 
3949 	cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class;
3950 	cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
3951 	cmd->cmd_flags = flag;
3952 	cmd->cmd_retry_count = fp_retry_count;
3953 	cmd->cmd_ulp_pkt = NULL;
3954 
3955 	fp_xlogi_init(port, cmd, s_id, 0xFFFFFE, fp_flogi_intr,
3956 	    job, LA_ELS_FLOGI);
3957 
3958 	rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
3959 	if (rval != FC_SUCCESS) {
3960 		fp_free_pkt(cmd);
3961 	}
3962 
3963 	FP_TRACE(FP_NHEAD1(1, 0), "fp_fabric_login End; port=%p, job=%p",
3964 	    port, job);
3965 
3966 	return (rval);
3967 }
3968 
3969 
3970 /*
3971  * In some scenarios such as private loop device discovery period
3972  * the fc_remote_port_t data structure isn't allocated. The allocation
3973  * is done when the PLOGI is successful. In some other scenarios
3974  * such as Fabric topology, the fc_remote_port_t is already created
3975  * and initialized with appropriate values (as the NS provides
3976  * them)
3977  */
3978 static int
3979 fp_port_login(fc_local_port_t *port, uint32_t d_id, job_request_t *job,
3980     int cmd_flag, int sleep, fc_remote_port_t *pd, fc_packet_t *ulp_pkt)
3981 {
3982 	uchar_t class;
3983 	fp_cmd_t *cmd;
3984 	uint32_t src_id;
3985 	fc_remote_port_t *tmp_pd;
3986 	int relogin;
3987 	int found = 0;
3988 
3989 #ifdef	DEBUG
3990 	if (pd == NULL) {
3991 		ASSERT(fctl_get_remote_port_by_did(port, d_id) == NULL);
3992 	}
3993 #endif
3994 	ASSERT(job->job_counter > 0);
3995 
3996 	class = fp_get_nextclass(port, FC_TRAN_CLASS_INVALID);
3997 	if (class == FC_TRAN_CLASS_INVALID) {
3998 		return (FC_ELS_BAD);
3999 	}
4000 
4001 	mutex_enter(&port->fp_mutex);
4002 	tmp_pd = fctl_lookup_pd_by_did(port, d_id);
4003 	mutex_exit(&port->fp_mutex);
4004 
4005 	relogin = 1;
4006 	if (tmp_pd) {
4007 		mutex_enter(&tmp_pd->pd_mutex);
4008 		if ((tmp_pd->pd_aux_flags & PD_DISABLE_RELOGIN) &&
4009 		    !(tmp_pd->pd_aux_flags & PD_LOGGED_OUT)) {
4010 			tmp_pd->pd_state = PORT_DEVICE_LOGGED_IN;
4011 			relogin = 0;
4012 		}
4013 		mutex_exit(&tmp_pd->pd_mutex);
4014 	}
4015 
4016 	if (!relogin) {
4017 		mutex_enter(&tmp_pd->pd_mutex);
4018 		if (tmp_pd->pd_state == PORT_DEVICE_LOGGED_IN) {
4019 			cmd_flag |= FP_CMD_PLOGI_RETAIN;
4020 		}
4021 		mutex_exit(&tmp_pd->pd_mutex);
4022 
4023 		cmd = fp_alloc_pkt(port, sizeof (la_els_adisc_t),
4024 		    sizeof (la_els_adisc_t), sleep, tmp_pd);
4025 		if (cmd == NULL) {
4026 			return (FC_NOMEM);
4027 		}
4028 
4029 		cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class;
4030 		cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
4031 		cmd->cmd_flags = cmd_flag;
4032 		cmd->cmd_retry_count = fp_retry_count;
4033 		cmd->cmd_ulp_pkt = ulp_pkt;
4034 
4035 		mutex_enter(&port->fp_mutex);
4036 		mutex_enter(&tmp_pd->pd_mutex);
4037 		fp_adisc_init(cmd, job);
4038 		mutex_exit(&tmp_pd->pd_mutex);
4039 		mutex_exit(&port->fp_mutex);
4040 
4041 		cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_adisc_t);
4042 		cmd->cmd_pkt.pkt_rsplen = sizeof (la_els_adisc_t);
4043 
4044 	} else {
4045 		cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t),
4046 		    sizeof (la_els_logi_t), sleep, pd);
4047 		if (cmd == NULL) {
4048 			return (FC_NOMEM);
4049 		}
4050 
4051 		cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class;
4052 		cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
4053 		cmd->cmd_flags = cmd_flag;
4054 		cmd->cmd_retry_count = fp_retry_count;
4055 		cmd->cmd_ulp_pkt = ulp_pkt;
4056 
4057 		mutex_enter(&port->fp_mutex);
4058 		src_id = port->fp_port_id.port_id;
4059 		mutex_exit(&port->fp_mutex);
4060 
4061 		fp_xlogi_init(port, cmd, src_id, d_id, fp_plogi_intr,
4062 		    job, LA_ELS_PLOGI);
4063 	}
4064 
4065 	if (pd) {
4066 		mutex_enter(&pd->pd_mutex);
4067 		pd->pd_flags = PD_ELS_IN_PROGRESS;
4068 		mutex_exit(&pd->pd_mutex);
4069 	}
4070 
4071 	/* npiv check to make sure we don't log into ourself */
4072 	if (relogin && (port->fp_topology == FC_TOP_FABRIC)) {
4073 		if ((d_id & 0xffff00) ==
4074 		    (port->fp_port_id.port_id & 0xffff00)) {
4075 			found = 1;
4076 		}
4077 	}
4078 
4079 	if (found ||
4080 	    (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS)) {
4081 		if (found) {
4082 			fc_packet_t *pkt = &cmd->cmd_pkt;
4083 			pkt->pkt_state = FC_PKT_NPORT_RJT;
4084 		}
4085 		if (pd) {
4086 			mutex_enter(&pd->pd_mutex);
4087 			pd->pd_flags = PD_IDLE;
4088 			mutex_exit(&pd->pd_mutex);
4089 		}
4090 
4091 		if (ulp_pkt) {
4092 			fc_packet_t *pkt = &cmd->cmd_pkt;
4093 
4094 			ulp_pkt->pkt_state = pkt->pkt_state;
4095 			ulp_pkt->pkt_reason = pkt->pkt_reason;
4096 			ulp_pkt->pkt_action = pkt->pkt_action;
4097 			ulp_pkt->pkt_expln = pkt->pkt_expln;
4098 		}
4099 
4100 		fp_iodone(cmd);
4101 	}
4102 
4103 	return (FC_SUCCESS);
4104 }
4105 
4106 
4107 /*
4108  * Register the LOGIN parameters with a port device
4109  */
4110 static void
4111 fp_register_login(ddi_acc_handle_t *handle, fc_remote_port_t *pd,
4112     la_els_logi_t *acc, uchar_t class)
4113 {
4114 	fc_remote_node_t 	*node;
4115 
4116 	ASSERT(pd != NULL);
4117 
4118 	mutex_enter(&pd->pd_mutex);
4119 	node = pd->pd_remote_nodep;
4120 	if (pd->pd_login_count == 0) {
4121 		pd->pd_login_count++;
4122 	}
4123 
4124 	if (handle) {
4125 		ddi_rep_get8(*handle, (uint8_t *)&pd->pd_csp,
4126 		    (uint8_t *)&acc->common_service,
4127 		    sizeof (acc->common_service), DDI_DEV_AUTOINCR);
4128 		ddi_rep_get8(*handle, (uint8_t *)&pd->pd_clsp1,
4129 		    (uint8_t *)&acc->class_1, sizeof (acc->class_1),
4130 		    DDI_DEV_AUTOINCR);
4131 		ddi_rep_get8(*handle, (uint8_t *)&pd->pd_clsp2,
4132 		    (uint8_t *)&acc->class_2, sizeof (acc->class_2),
4133 		    DDI_DEV_AUTOINCR);
4134 		ddi_rep_get8(*handle, (uint8_t *)&pd->pd_clsp3,
4135 		    (uint8_t *)&acc->class_3, sizeof (acc->class_3),
4136 		    DDI_DEV_AUTOINCR);
4137 	} else {
4138 		pd->pd_csp = acc->common_service;
4139 		pd->pd_clsp1 = acc->class_1;
4140 		pd->pd_clsp2 = acc->class_2;
4141 		pd->pd_clsp3 = acc->class_3;
4142 	}
4143 
4144 	pd->pd_state = PORT_DEVICE_LOGGED_IN;
4145 	pd->pd_login_class = class;
4146 	mutex_exit(&pd->pd_mutex);
4147 
4148 #ifndef	__lock_lint
4149 	ASSERT(fctl_get_remote_port_by_did(pd->pd_port,
4150 	    pd->pd_port_id.port_id) == pd);
4151 #endif
4152 
4153 	mutex_enter(&node->fd_mutex);
4154 	if (handle) {
4155 		ddi_rep_get8(*handle, (uint8_t *)node->fd_vv,
4156 		    (uint8_t *)acc->vendor_version, sizeof (node->fd_vv),
4157 		    DDI_DEV_AUTOINCR);
4158 	} else {
4159 		bcopy(acc->vendor_version, node->fd_vv, sizeof (node->fd_vv));
4160 	}
4161 	mutex_exit(&node->fd_mutex);
4162 }
4163 
4164 
4165 /*
4166  * Mark the remote port as OFFLINE
4167  */
4168 static void
4169 fp_remote_port_offline(fc_remote_port_t *pd)
4170 {
4171 	ASSERT(MUTEX_HELD(&pd->pd_mutex));
4172 	if (pd->pd_login_count &&
4173 	    ((pd->pd_aux_flags & PD_DISABLE_RELOGIN) == 0)) {
4174 		bzero((caddr_t)&pd->pd_csp, sizeof (struct common_service));
4175 		bzero((caddr_t)&pd->pd_clsp1, sizeof (struct service_param));
4176 		bzero((caddr_t)&pd->pd_clsp2, sizeof (struct service_param));
4177 		bzero((caddr_t)&pd->pd_clsp3, sizeof (struct service_param));
4178 		pd->pd_login_class = 0;
4179 	}
4180 	pd->pd_type = PORT_DEVICE_OLD;
4181 	pd->pd_flags = PD_IDLE;
4182 	fctl_tc_reset(&pd->pd_logo_tc);
4183 }
4184 
4185 
4186 /*
4187  * Deregistration of a port device
4188  */
4189 static void
4190 fp_unregister_login(fc_remote_port_t *pd)
4191 {
4192 	fc_remote_node_t *node;
4193 
4194 	ASSERT(pd != NULL);
4195 
4196 	mutex_enter(&pd->pd_mutex);
4197 	pd->pd_login_count = 0;
4198 	bzero((caddr_t)&pd->pd_csp, sizeof (struct common_service));
4199 	bzero((caddr_t)&pd->pd_clsp1, sizeof (struct service_param));
4200 	bzero((caddr_t)&pd->pd_clsp2, sizeof (struct service_param));
4201 	bzero((caddr_t)&pd->pd_clsp3, sizeof (struct service_param));
4202 
4203 	pd->pd_state = PORT_DEVICE_VALID;
4204 	pd->pd_login_class = 0;
4205 	node = pd->pd_remote_nodep;
4206 	mutex_exit(&pd->pd_mutex);
4207 
4208 	mutex_enter(&node->fd_mutex);
4209 	bzero(node->fd_vv, sizeof (node->fd_vv));
4210 	mutex_exit(&node->fd_mutex);
4211 }
4212 
4213 
4214 /*
4215  * Handle OFFLINE state of an FCA port
4216  */
4217 static void
4218 fp_port_offline(fc_local_port_t *port, int notify)
4219 {
4220 	int			index;
4221 	int			statec;
4222 	timeout_id_t		tid;
4223 	struct pwwn_hash 	*head;
4224 	fc_remote_port_t 	*pd;
4225 
4226 	ASSERT(MUTEX_HELD(&port->fp_mutex));
4227 
4228 	for (index = 0; index < pwwn_table_size; index++) {
4229 		head = &port->fp_pwwn_table[index];
4230 		pd = head->pwwn_head;
4231 		while (pd != NULL) {
4232 			mutex_enter(&pd->pd_mutex);
4233 			fp_remote_port_offline(pd);
4234 			fctl_delist_did_table(port, pd);
4235 			mutex_exit(&pd->pd_mutex);
4236 			pd = pd->pd_wwn_hnext;
4237 		}
4238 	}
4239 	port->fp_total_devices = 0;
4240 
4241 	statec = 0;
4242 	if (notify) {
4243 		/*
4244 		 * Decrement the statec busy counter as we
4245 		 * are almost done with handling the state
4246 		 * change
4247 		 */
4248 		ASSERT(port->fp_statec_busy > 0);
4249 		if (--port->fp_statec_busy == 0) {
4250 			port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
4251 		}
4252 		mutex_exit(&port->fp_mutex);
4253 		(void) fp_ulp_statec_cb(port, FC_STATE_OFFLINE, NULL,
4254 		    0, 0, KM_SLEEP);
4255 		mutex_enter(&port->fp_mutex);
4256 
4257 		if (port->fp_statec_busy) {
4258 			statec++;
4259 		}
4260 	} else if (port->fp_statec_busy > 1) {
4261 		statec++;
4262 	}
4263 
4264 	if ((tid = port->fp_offline_tid) != NULL) {
4265 		mutex_exit(&port->fp_mutex);
4266 		(void) untimeout(tid);
4267 		mutex_enter(&port->fp_mutex);
4268 	}
4269 
4270 	if (!statec) {
4271 		port->fp_offline_tid = timeout(fp_offline_timeout,
4272 		    (caddr_t)port, fp_offline_ticks);
4273 	}
4274 }
4275 
4276 
4277 /*
4278  * Offline devices and send up a state change notification to ULPs
4279  */
4280 static void
4281 fp_offline_timeout(void *port_handle)
4282 {
4283 	int		ret;
4284 	fc_local_port_t *port = port_handle;
4285 	uint32_t	listlen = 0;
4286 	fc_portmap_t 	*changelist = NULL;
4287 
4288 	mutex_enter(&port->fp_mutex);
4289 
4290 	if ((FC_PORT_STATE_MASK(port->fp_state) != FC_STATE_OFFLINE) ||
4291 	    (port->fp_soft_state &
4292 	    (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN)) ||
4293 	    port->fp_dev_count == 0 || port->fp_statec_busy) {
4294 		port->fp_offline_tid = NULL;
4295 		mutex_exit(&port->fp_mutex);
4296 		return;
4297 	}
4298 
4299 	mutex_exit(&port->fp_mutex);
4300 
4301 	FP_TRACE(FP_NHEAD2(9, 0), "OFFLINE timeout");
4302 
4303 	if (port->fp_options & FP_CORE_ON_OFFLINE_TIMEOUT) {
4304 		if ((ret = port->fp_fca_tran->fca_reset(port->fp_fca_handle,
4305 		    FC_FCA_CORE)) != FC_SUCCESS) {
4306 			FP_TRACE(FP_NHEAD1(9, ret),
4307 			    "Failed to force adapter dump");
4308 		} else {
4309 			FP_TRACE(FP_NHEAD1(9, 0),
4310 			    "Forced adapter dump successfully");
4311 		}
4312 	} else if (port->fp_options & FP_RESET_CORE_ON_OFFLINE_TIMEOUT) {
4313 		if ((ret = port->fp_fca_tran->fca_reset(port->fp_fca_handle,
4314 		    FC_FCA_RESET_CORE)) != FC_SUCCESS) {
4315 			FP_TRACE(FP_NHEAD1(9, ret),
4316 			    "Failed to force adapter dump and reset");
4317 		} else {
4318 			FP_TRACE(FP_NHEAD1(9, 0),
4319 			    "Forced adapter dump and reset successfully");
4320 		}
4321 	}
4322 
4323 	fctl_fillout_map(port, &changelist, &listlen, 1, 0, 0);
4324 	(void) fp_ulp_statec_cb(port, FC_STATE_OFFLINE, changelist,
4325 	    listlen, listlen, KM_SLEEP);
4326 
4327 	mutex_enter(&port->fp_mutex);
4328 	port->fp_offline_tid = NULL;
4329 	mutex_exit(&port->fp_mutex);
4330 }
4331 
4332 
4333 /*
4334  * Perform general purpose ELS request initialization
4335  */
4336 static void
4337 fp_els_init(fp_cmd_t *cmd, uint32_t s_id, uint32_t d_id,
4338     void (*comp) (), job_request_t *job)
4339 {
4340 	fc_packet_t *pkt;
4341 
4342 	pkt = &cmd->cmd_pkt;
4343 	cmd->cmd_job = job;
4344 
4345 	pkt->pkt_cmd_fhdr.r_ctl = R_CTL_ELS_REQ;
4346 	pkt->pkt_cmd_fhdr.d_id = d_id;
4347 	pkt->pkt_cmd_fhdr.s_id = s_id;
4348 	pkt->pkt_cmd_fhdr.type = FC_TYPE_EXTENDED_LS;
4349 	pkt->pkt_cmd_fhdr.f_ctl = F_CTL_SEQ_INITIATIVE | F_CTL_FIRST_SEQ;
4350 	pkt->pkt_cmd_fhdr.seq_id = 0;
4351 	pkt->pkt_cmd_fhdr.df_ctl  = 0;
4352 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
4353 	pkt->pkt_cmd_fhdr.ox_id = 0xffff;
4354 	pkt->pkt_cmd_fhdr.rx_id = 0xffff;
4355 	pkt->pkt_cmd_fhdr.ro = 0;
4356 	pkt->pkt_cmd_fhdr.rsvd = 0;
4357 	pkt->pkt_comp = comp;
4358 	pkt->pkt_timeout = FP_ELS_TIMEOUT;
4359 }
4360 
4361 
4362 /*
4363  * Initialize PLOGI/FLOGI ELS request
4364  */
4365 static void
4366 fp_xlogi_init(fc_local_port_t *port, fp_cmd_t *cmd, uint32_t s_id,
4367     uint32_t d_id, void (*intr) (), job_request_t *job, uchar_t ls_code)
4368 {
4369 	ls_code_t	payload;
4370 
4371 	fp_els_init(cmd, s_id, d_id, intr, job);
4372 	cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
4373 
4374 	payload.ls_code = ls_code;
4375 	payload.mbz = 0;
4376 
4377 	ddi_rep_put8(cmd->cmd_pkt.pkt_cmd_acc,
4378 	    (uint8_t *)&port->fp_service_params,
4379 	    (uint8_t *)cmd->cmd_pkt.pkt_cmd, sizeof (port->fp_service_params),
4380 	    DDI_DEV_AUTOINCR);
4381 
4382 	ddi_rep_put8(cmd->cmd_pkt.pkt_cmd_acc, (uint8_t *)&payload,
4383 	    (uint8_t *)cmd->cmd_pkt.pkt_cmd, sizeof (payload),
4384 	    DDI_DEV_AUTOINCR);
4385 }
4386 
4387 
4388 /*
4389  * Initialize LOGO ELS request
4390  */
4391 static void
4392 fp_logo_init(fc_remote_port_t *pd, fp_cmd_t *cmd, job_request_t *job)
4393 {
4394 	fc_local_port_t	*port;
4395 	fc_packet_t	*pkt;
4396 	la_els_logo_t 	payload;
4397 
4398 	port = pd->pd_port;
4399 	pkt = &cmd->cmd_pkt;
4400 	ASSERT(MUTEX_HELD(&port->fp_mutex));
4401 	ASSERT(MUTEX_HELD(&pd->pd_mutex));
4402 
4403 	fp_els_init(cmd, port->fp_port_id.port_id, pd->pd_port_id.port_id,
4404 	    fp_logo_intr, job);
4405 
4406 	cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
4407 
4408 	pkt->pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
4409 	pkt->pkt_tran_type = FC_PKT_EXCHANGE;
4410 
4411 	payload.ls_code.ls_code = LA_ELS_LOGO;
4412 	payload.ls_code.mbz = 0;
4413 	payload.nport_ww_name = port->fp_service_params.nport_ww_name;
4414 	payload.nport_id = port->fp_port_id;
4415 
4416 	ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&payload,
4417 	    (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
4418 }
4419 
4420 /*
4421  * Initialize RNID ELS request
4422  */
4423 static void
4424 fp_rnid_init(fp_cmd_t *cmd, uint16_t flag, job_request_t *job)
4425 {
4426 	fc_local_port_t	*port;
4427 	fc_packet_t	*pkt;
4428 	la_els_rnid_t 	payload;
4429 	fc_remote_port_t	*pd;
4430 
4431 	pkt = &cmd->cmd_pkt;
4432 	pd = pkt->pkt_pd;
4433 	port = pd->pd_port;
4434 
4435 	ASSERT(MUTEX_HELD(&port->fp_mutex));
4436 	ASSERT(MUTEX_HELD(&pd->pd_mutex));
4437 
4438 	fp_els_init(cmd, port->fp_port_id.port_id, pd->pd_port_id.port_id,
4439 	    fp_rnid_intr, job);
4440 
4441 	cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
4442 	pkt->pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
4443 	pkt->pkt_tran_type = FC_PKT_EXCHANGE;
4444 
4445 	payload.ls_code.ls_code = LA_ELS_RNID;
4446 	payload.ls_code.mbz = 0;
4447 	payload.data_format = flag;
4448 
4449 	ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&payload,
4450 	    (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
4451 }
4452 
4453 /*
4454  * Initialize RLS ELS request
4455  */
4456 static void
4457 fp_rls_init(fp_cmd_t *cmd, job_request_t *job)
4458 {
4459 	fc_local_port_t	*port;
4460 	fc_packet_t	*pkt;
4461 	la_els_rls_t 	payload;
4462 	fc_remote_port_t	*pd;
4463 
4464 	pkt = &cmd->cmd_pkt;
4465 	pd = pkt->pkt_pd;
4466 	port = pd->pd_port;
4467 
4468 	ASSERT(MUTEX_HELD(&port->fp_mutex));
4469 	ASSERT(MUTEX_HELD(&pd->pd_mutex));
4470 
4471 	fp_els_init(cmd, port->fp_port_id.port_id, pd->pd_port_id.port_id,
4472 	    fp_rls_intr, job);
4473 
4474 	cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
4475 	pkt->pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
4476 	pkt->pkt_tran_type = FC_PKT_EXCHANGE;
4477 
4478 	payload.ls_code.ls_code = LA_ELS_RLS;
4479 	payload.ls_code.mbz = 0;
4480 	payload.rls_portid = port->fp_port_id;
4481 
4482 	ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&payload,
4483 	    (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
4484 }
4485 
4486 
4487 /*
4488  * Initialize an ADISC ELS request
4489  */
4490 static void
4491 fp_adisc_init(fp_cmd_t *cmd, job_request_t *job)
4492 {
4493 	fc_local_port_t *port;
4494 	fc_packet_t	*pkt;
4495 	la_els_adisc_t 	payload;
4496 	fc_remote_port_t	*pd;
4497 
4498 	pkt = &cmd->cmd_pkt;
4499 	pd = pkt->pkt_pd;
4500 	port = pd->pd_port;
4501 
4502 	ASSERT(MUTEX_HELD(&pd->pd_mutex));
4503 	ASSERT(MUTEX_HELD(&pd->pd_port->fp_mutex));
4504 
4505 	fp_els_init(cmd, port->fp_port_id.port_id, pd->pd_port_id.port_id,
4506 	    fp_adisc_intr, job);
4507 
4508 	cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
4509 	pkt->pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
4510 	pkt->pkt_tran_type = FC_PKT_EXCHANGE;
4511 
4512 	payload.ls_code.ls_code = LA_ELS_ADISC;
4513 	payload.ls_code.mbz = 0;
4514 	payload.nport_id = port->fp_port_id;
4515 	payload.port_wwn = port->fp_service_params.nport_ww_name;
4516 	payload.node_wwn = port->fp_service_params.node_ww_name;
4517 	payload.hard_addr = port->fp_hard_addr;
4518 
4519 	ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&payload,
4520 	    (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
4521 }
4522 
4523 
4524 /*
4525  * Send up a state change notification to ULPs.
4526  * Spawns a call to fctl_ulp_statec_cb in a taskq thread.
4527  */
4528 static int
4529 fp_ulp_statec_cb(fc_local_port_t *port, uint32_t state,
4530     fc_portmap_t *changelist, uint32_t listlen, uint32_t alloc_len, int sleep)
4531 {
4532 	fc_port_clist_t		*clist;
4533 	fc_remote_port_t	*pd;
4534 	int 			count;
4535 
4536 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
4537 
4538 	clist = kmem_zalloc(sizeof (*clist), sleep);
4539 	if (clist == NULL) {
4540 		kmem_free(changelist, alloc_len * sizeof (*changelist));
4541 		return (FC_NOMEM);
4542 	}
4543 
4544 	clist->clist_state = state;
4545 
4546 	mutex_enter(&port->fp_mutex);
4547 	clist->clist_flags = port->fp_topology;
4548 	mutex_exit(&port->fp_mutex);
4549 
4550 	clist->clist_port = (opaque_t)port;
4551 	clist->clist_len = listlen;
4552 	clist->clist_size = alloc_len;
4553 	clist->clist_map = changelist;
4554 
4555 	/*
4556 	 * Bump the reference count of each fc_remote_port_t in this changelist.
4557 	 * This is necessary since these devices will be sitting in a taskq
4558 	 * and referenced later.  When the state change notification is
4559 	 * complete, the reference counts will be decremented.
4560 	 */
4561 	for (count = 0; count < clist->clist_len; count++) {
4562 		pd = clist->clist_map[count].map_pd;
4563 
4564 		if (pd != NULL) {
4565 			mutex_enter(&pd->pd_mutex);
4566 			ASSERT((pd->pd_ref_count >= 0) ||
4567 			    (pd->pd_aux_flags & PD_GIVEN_TO_ULPS));
4568 			pd->pd_ref_count++;
4569 
4570 			if (clist->clist_map[count].map_state !=
4571 			    PORT_DEVICE_INVALID) {
4572 				pd->pd_aux_flags |= PD_GIVEN_TO_ULPS;
4573 			}
4574 
4575 			mutex_exit(&pd->pd_mutex);
4576 		}
4577 	}
4578 
4579 #ifdef	DEBUG
4580 	/*
4581 	 * Sanity check for presence of OLD devices in the hash lists
4582 	 */
4583 	if (clist->clist_size) {
4584 		ASSERT(clist->clist_map != NULL);
4585 		for (count = 0; count < clist->clist_len; count++) {
4586 			if (clist->clist_map[count].map_state ==
4587 			    PORT_DEVICE_INVALID) {
4588 				la_wwn_t 	pwwn;
4589 				fc_portid_t 	d_id;
4590 
4591 				pd = clist->clist_map[count].map_pd;
4592 				ASSERT(pd != NULL);
4593 
4594 				mutex_enter(&pd->pd_mutex);
4595 				pwwn = pd->pd_port_name;
4596 				d_id = pd->pd_port_id;
4597 				mutex_exit(&pd->pd_mutex);
4598 
4599 				pd = fctl_get_remote_port_by_pwwn(port, &pwwn);
4600 				ASSERT(pd != clist->clist_map[count].map_pd);
4601 
4602 				pd = fctl_get_remote_port_by_did(port,
4603 				    d_id.port_id);
4604 				ASSERT(pd != clist->clist_map[count].map_pd);
4605 			}
4606 		}
4607 	}
4608 #endif
4609 
4610 	mutex_enter(&port->fp_mutex);
4611 
4612 	if (state == FC_STATE_ONLINE) {
4613 		if (--port->fp_statec_busy == 0) {
4614 			port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
4615 		}
4616 	}
4617 	mutex_exit(&port->fp_mutex);
4618 
4619 	(void) taskq_dispatch(port->fp_taskq, fctl_ulp_statec_cb,
4620 	    clist, KM_SLEEP);
4621 
4622 	FP_TRACE(FP_NHEAD1(4, 0), "fp_ulp_statec fired; Port=%p,"
4623 	    "state=%x, len=%d", port, state, listlen);
4624 
4625 	return (FC_SUCCESS);
4626 }
4627 
4628 
4629 /*
4630  * Send up a FC_STATE_DEVICE_CHANGE state notification to ULPs
4631  */
4632 static int
4633 fp_ulp_devc_cb(fc_local_port_t *port, fc_portmap_t *changelist,
4634     uint32_t listlen, uint32_t alloc_len, int sleep, int sync)
4635 {
4636 	int		ret;
4637 	fc_port_clist_t *clist;
4638 
4639 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
4640 
4641 	clist = kmem_zalloc(sizeof (*clist), sleep);
4642 	if (clist == NULL) {
4643 		kmem_free(changelist, alloc_len * sizeof (*changelist));
4644 		return (FC_NOMEM);
4645 	}
4646 
4647 	clist->clist_state = FC_STATE_DEVICE_CHANGE;
4648 
4649 	mutex_enter(&port->fp_mutex);
4650 	clist->clist_flags = port->fp_topology;
4651 	mutex_exit(&port->fp_mutex);
4652 
4653 	clist->clist_port = (opaque_t)port;
4654 	clist->clist_len = listlen;
4655 	clist->clist_size = alloc_len;
4656 	clist->clist_map = changelist;
4657 
4658 	/* Send sysevents for target state changes */
4659 
4660 	if (clist->clist_size) {
4661 		int 			count;
4662 		fc_remote_port_t	*pd;
4663 
4664 		ASSERT(clist->clist_map != NULL);
4665 		for (count = 0; count < clist->clist_len; count++) {
4666 			pd = clist->clist_map[count].map_pd;
4667 
4668 			/*
4669 			 * Bump reference counts on all fc_remote_port_t
4670 			 * structs in this list.  We don't know when the task
4671 			 * will fire, and we don't need these fc_remote_port_t
4672 			 * structs going away behind our back.
4673 			 */
4674 			if (pd) {
4675 				mutex_enter(&pd->pd_mutex);
4676 				ASSERT((pd->pd_ref_count >= 0) ||
4677 				    (pd->pd_aux_flags & PD_GIVEN_TO_ULPS));
4678 				pd->pd_ref_count++;
4679 				mutex_exit(&pd->pd_mutex);
4680 			}
4681 
4682 			if (clist->clist_map[count].map_state ==
4683 			    PORT_DEVICE_VALID) {
4684 				if (clist->clist_map[count].map_type ==
4685 				    PORT_DEVICE_NEW) {
4686 					/* Update our state change counter */
4687 					mutex_enter(&port->fp_mutex);
4688 					port->fp_last_change++;
4689 					mutex_exit(&port->fp_mutex);
4690 
4691 					/* Additions */
4692 					fp_log_target_event(port,
4693 					    ESC_SUNFC_TARGET_ADD,
4694 					    clist->clist_map[count].map_pwwn,
4695 					    clist->clist_map[count].map_did.
4696 					    port_id);
4697 				}
4698 
4699 			} else if ((clist->clist_map[count].map_type ==
4700 			    PORT_DEVICE_OLD) &&
4701 			    (clist->clist_map[count].map_state ==
4702 			    PORT_DEVICE_INVALID)) {
4703 				/* Update our state change counter */
4704 				mutex_enter(&port->fp_mutex);
4705 				port->fp_last_change++;
4706 				mutex_exit(&port->fp_mutex);
4707 
4708 				/*
4709 				 * For removals, we don't decrement
4710 				 * pd_ref_count until after the ULP's
4711 				 * state change callback function has
4712 				 * completed.
4713 				 */
4714 
4715 				/* Removals */
4716 				fp_log_target_event(port,
4717 				    ESC_SUNFC_TARGET_REMOVE,
4718 				    clist->clist_map[count].map_pwwn,
4719 				    clist->clist_map[count].map_did.port_id);
4720 			}
4721 
4722 			if (clist->clist_map[count].map_state !=
4723 			    PORT_DEVICE_INVALID) {
4724 				/*
4725 				 * Indicate that the ULPs are now aware of
4726 				 * this device.
4727 				 */
4728 
4729 				mutex_enter(&pd->pd_mutex);
4730 				pd->pd_aux_flags |= PD_GIVEN_TO_ULPS;
4731 				mutex_exit(&pd->pd_mutex);
4732 			}
4733 
4734 #ifdef	DEBUG
4735 			/*
4736 			 * Sanity check for OLD devices in the hash lists
4737 			 */
4738 			if (pd && clist->clist_map[count].map_state ==
4739 			    PORT_DEVICE_INVALID) {
4740 				la_wwn_t 	pwwn;
4741 				fc_portid_t 	d_id;
4742 
4743 				mutex_enter(&pd->pd_mutex);
4744 				pwwn = pd->pd_port_name;
4745 				d_id = pd->pd_port_id;
4746 				mutex_exit(&pd->pd_mutex);
4747 
4748 				/*
4749 				 * This overwrites the 'pd' local variable.
4750 				 * Beware of this if 'pd' ever gets
4751 				 * referenced below this block.
4752 				 */
4753 				pd = fctl_get_remote_port_by_pwwn(port, &pwwn);
4754 				ASSERT(pd != clist->clist_map[count].map_pd);
4755 
4756 				pd = fctl_get_remote_port_by_did(port,
4757 				    d_id.port_id);
4758 				ASSERT(pd != clist->clist_map[count].map_pd);
4759 			}
4760 #endif
4761 		}
4762 	}
4763 
4764 	if (sync) {
4765 		clist->clist_wait = 1;
4766 		mutex_init(&clist->clist_mutex, NULL, MUTEX_DRIVER, NULL);
4767 		cv_init(&clist->clist_cv, NULL, CV_DRIVER, NULL);
4768 	}
4769 
4770 	ret = taskq_dispatch(port->fp_taskq, fctl_ulp_statec_cb, clist, sleep);
4771 	if (sync && ret) {
4772 		mutex_enter(&clist->clist_mutex);
4773 		while (clist->clist_wait) {
4774 			cv_wait(&clist->clist_cv, &clist->clist_mutex);
4775 		}
4776 		mutex_exit(&clist->clist_mutex);
4777 
4778 		mutex_destroy(&clist->clist_mutex);
4779 		cv_destroy(&clist->clist_cv);
4780 		kmem_free(clist, sizeof (*clist));
4781 	}
4782 
4783 	if (!ret) {
4784 		FP_TRACE(FP_NHEAD1(4, 0), "fp_ulp_devc dispatch failed; "
4785 		    "port=%p", port);
4786 		kmem_free(clist->clist_map,
4787 		    sizeof (*(clist->clist_map)) * clist->clist_size);
4788 		kmem_free(clist, sizeof (*clist));
4789 	} else {
4790 		FP_TRACE(FP_NHEAD1(4, 0), "fp_ulp_devc fired; port=%p, len=%d",
4791 		    port, listlen);
4792 	}
4793 
4794 	return (FC_SUCCESS);
4795 }
4796 
4797 
4798 /*
4799  * Perform PLOGI to the group of devices for ULPs
4800  */
4801 static void
4802 fp_plogi_group(fc_local_port_t *port, job_request_t *job)
4803 {
4804 	int			offline;
4805 	int 			count;
4806 	int			rval;
4807 	uint32_t		listlen;
4808 	uint32_t		done;
4809 	uint32_t		d_id;
4810 	fc_remote_node_t	*node;
4811 	fc_remote_port_t 	*pd;
4812 	fc_remote_port_t	*tmp_pd;
4813 	fc_packet_t		*ulp_pkt;
4814 	la_els_logi_t		*els_data;
4815 	ls_code_t		ls_code;
4816 
4817 	FP_TRACE(FP_NHEAD1(1, 0), "fp_plogi_group begin; port=%p, job=%p",
4818 	    port, job);
4819 
4820 	done = 0;
4821 	listlen = job->job_ulp_listlen;
4822 	job->job_counter = job->job_ulp_listlen;
4823 
4824 	mutex_enter(&port->fp_mutex);
4825 	offline = (port->fp_statec_busy ||
4826 	    FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) ? 1 : 0;
4827 	mutex_exit(&port->fp_mutex);
4828 
4829 	for (count = 0; count < listlen; count++) {
4830 		ASSERT(job->job_ulp_pkts[count]->pkt_rsplen >=
4831 		    sizeof (la_els_logi_t));
4832 
4833 		ulp_pkt = job->job_ulp_pkts[count];
4834 		pd = ulp_pkt->pkt_pd;
4835 		d_id = ulp_pkt->pkt_cmd_fhdr.d_id;
4836 
4837 		if (offline) {
4838 			done++;
4839 
4840 			ulp_pkt->pkt_state = FC_PKT_PORT_OFFLINE;
4841 			ulp_pkt->pkt_reason = FC_REASON_OFFLINE;
4842 			ulp_pkt->pkt_pd = NULL;
4843 			ulp_pkt->pkt_comp(ulp_pkt);
4844 
4845 			job->job_ulp_pkts[count] = NULL;
4846 
4847 			fp_jobdone(job);
4848 			continue;
4849 		}
4850 
4851 		if (pd == NULL) {
4852 			pd = fctl_get_remote_port_by_did(port, d_id);
4853 			if (pd == NULL) { /* reset later */
4854 				ulp_pkt->pkt_state = FC_PKT_FAILURE;
4855 				continue;
4856 			}
4857 			mutex_enter(&pd->pd_mutex);
4858 			if (pd->pd_flags == PD_ELS_IN_PROGRESS) {
4859 				mutex_exit(&pd->pd_mutex);
4860 				ulp_pkt->pkt_state = FC_PKT_ELS_IN_PROGRESS;
4861 				done++;
4862 				ulp_pkt->pkt_comp(ulp_pkt);
4863 				job->job_ulp_pkts[count] = NULL;
4864 				fp_jobdone(job);
4865 			} else {
4866 				ulp_pkt->pkt_state = FC_PKT_FAILURE;
4867 				mutex_exit(&pd->pd_mutex);
4868 			}
4869 			continue;
4870 		}
4871 
4872 		switch (ulp_pkt->pkt_state) {
4873 		case FC_PKT_ELS_IN_PROGRESS:
4874 			ulp_pkt->pkt_reason = FC_REASON_OFFLINE;
4875 			/* FALLTHRU */
4876 		case FC_PKT_LOCAL_RJT:
4877 			done++;
4878 			ulp_pkt->pkt_comp(ulp_pkt);
4879 			job->job_ulp_pkts[count] = NULL;
4880 			fp_jobdone(job);
4881 			continue;
4882 		default:
4883 			break;
4884 		}
4885 
4886 		/*
4887 		 * Validate the pd corresponding to the d_id passed
4888 		 * by the ULPs
4889 		 */
4890 		tmp_pd = fctl_get_remote_port_by_did(port, d_id);
4891 		if ((tmp_pd == NULL) || (pd != tmp_pd)) {
4892 			done++;
4893 			ulp_pkt->pkt_state = FC_PKT_FAILURE;
4894 			ulp_pkt->pkt_reason = FC_REASON_NO_CONNECTION;
4895 			ulp_pkt->pkt_pd = NULL;
4896 			ulp_pkt->pkt_comp(ulp_pkt);
4897 			job->job_ulp_pkts[count] = NULL;
4898 			fp_jobdone(job);
4899 			continue;
4900 		}
4901 
4902 		FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_group contd; "
4903 		    "port=%p, pd=%p", port, pd);
4904 
4905 		mutex_enter(&pd->pd_mutex);
4906 
4907 		if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
4908 			done++;
4909 			els_data = (la_els_logi_t *)ulp_pkt->pkt_resp;
4910 
4911 			ls_code.ls_code = LA_ELS_ACC;
4912 			ls_code.mbz = 0;
4913 
4914 			ddi_rep_put8(ulp_pkt->pkt_resp_acc,
4915 			    (uint8_t *)&ls_code, (uint8_t *)&els_data->ls_code,
4916 			    sizeof (ls_code_t), DDI_DEV_AUTOINCR);
4917 
4918 			ddi_rep_put8(ulp_pkt->pkt_resp_acc,
4919 			    (uint8_t *)&pd->pd_csp,
4920 			    (uint8_t *)&els_data->common_service,
4921 			    sizeof (pd->pd_csp), DDI_DEV_AUTOINCR);
4922 
4923 			ddi_rep_put8(ulp_pkt->pkt_resp_acc,
4924 			    (uint8_t *)&pd->pd_port_name,
4925 			    (uint8_t *)&els_data->nport_ww_name,
4926 			    sizeof (pd->pd_port_name), DDI_DEV_AUTOINCR);
4927 
4928 			ddi_rep_put8(ulp_pkt->pkt_resp_acc,
4929 			    (uint8_t *)&pd->pd_clsp1,
4930 			    (uint8_t *)&els_data->class_1,
4931 			    sizeof (pd->pd_clsp1), DDI_DEV_AUTOINCR);
4932 
4933 			ddi_rep_put8(ulp_pkt->pkt_resp_acc,
4934 			    (uint8_t *)&pd->pd_clsp2,
4935 			    (uint8_t *)&els_data->class_2,
4936 			    sizeof (pd->pd_clsp2), DDI_DEV_AUTOINCR);
4937 
4938 			ddi_rep_put8(ulp_pkt->pkt_resp_acc,
4939 			    (uint8_t *)&pd->pd_clsp3,
4940 			    (uint8_t *)&els_data->class_3,
4941 			    sizeof (pd->pd_clsp3), DDI_DEV_AUTOINCR);
4942 
4943 			node = pd->pd_remote_nodep;
4944 			pd->pd_login_count++;
4945 			pd->pd_flags = PD_IDLE;
4946 			ulp_pkt->pkt_pd = pd;
4947 			mutex_exit(&pd->pd_mutex);
4948 
4949 			mutex_enter(&node->fd_mutex);
4950 			ddi_rep_put8(ulp_pkt->pkt_resp_acc,
4951 			    (uint8_t *)&node->fd_node_name,
4952 			    (uint8_t *)(&els_data->node_ww_name),
4953 			    sizeof (node->fd_node_name), DDI_DEV_AUTOINCR);
4954 
4955 
4956 			ddi_rep_put8(ulp_pkt->pkt_resp_acc,
4957 			    (uint8_t *)&node->fd_vv,
4958 			    (uint8_t *)(&els_data->vendor_version),
4959 			    sizeof (node->fd_vv), DDI_DEV_AUTOINCR);
4960 
4961 			mutex_exit(&node->fd_mutex);
4962 			ulp_pkt->pkt_state = FC_PKT_SUCCESS;
4963 		} else {
4964 
4965 			ulp_pkt->pkt_state = FC_PKT_FAILURE; /* reset later */
4966 			mutex_exit(&pd->pd_mutex);
4967 		}
4968 
4969 		if (ulp_pkt->pkt_state != FC_PKT_FAILURE) {
4970 			ulp_pkt->pkt_comp(ulp_pkt);
4971 			job->job_ulp_pkts[count] = NULL;
4972 			fp_jobdone(job);
4973 		}
4974 	}
4975 
4976 	if (done == listlen) {
4977 		fp_jobwait(job);
4978 		fctl_jobdone(job);
4979 		return;
4980 	}
4981 
4982 	job->job_counter = listlen - done;
4983 
4984 	for (count = 0; count < listlen; count++) {
4985 		int cmd_flags;
4986 
4987 		if ((ulp_pkt = job->job_ulp_pkts[count]) == NULL) {
4988 			continue;
4989 		}
4990 
4991 		ASSERT(ulp_pkt->pkt_state == FC_PKT_FAILURE);
4992 
4993 		cmd_flags = FP_CMD_PLOGI_RETAIN;
4994 
4995 		d_id = ulp_pkt->pkt_cmd_fhdr.d_id;
4996 		ASSERT(d_id != 0);
4997 
4998 		pd = fctl_get_remote_port_by_did(port, d_id);
4999 		ulp_pkt->pkt_pd = pd;
5000 
5001 		if (pd != NULL) {
5002 			mutex_enter(&pd->pd_mutex);
5003 			d_id = pd->pd_port_id.port_id;
5004 			pd->pd_flags = PD_ELS_IN_PROGRESS;
5005 			mutex_exit(&pd->pd_mutex);
5006 		} else {
5007 			d_id = ulp_pkt->pkt_cmd_fhdr.d_id;
5008 #ifdef	DEBUG
5009 			pd = fctl_get_remote_port_by_did(port, d_id);
5010 			ASSERT(pd == NULL);
5011 #endif
5012 			/*
5013 			 * In the Fabric topology, use NS to create
5014 			 * port device, and if that fails still try
5015 			 * with PLOGI - which will make yet another
5016 			 * attempt to create after successful PLOGI
5017 			 */
5018 			mutex_enter(&port->fp_mutex);
5019 			if (FC_IS_TOP_SWITCH(port->fp_topology)) {
5020 				mutex_exit(&port->fp_mutex);
5021 				pd = fp_create_remote_port_by_ns(port,
5022 				    d_id, KM_SLEEP);
5023 				if (pd) {
5024 					cmd_flags |= FP_CMD_DELDEV_ON_ERROR;
5025 
5026 					mutex_enter(&pd->pd_mutex);
5027 					pd->pd_flags = PD_ELS_IN_PROGRESS;
5028 					mutex_exit(&pd->pd_mutex);
5029 
5030 					FP_TRACE(FP_NHEAD1(3, 0),
5031 					    "fp_plogi_group;"
5032 					    " NS created PD port=%p, job=%p,"
5033 					    " pd=%p", port, job, pd);
5034 				}
5035 			} else {
5036 				mutex_exit(&port->fp_mutex);
5037 			}
5038 			if ((ulp_pkt->pkt_pd == NULL) && (pd != NULL)) {
5039 				FP_TRACE(FP_NHEAD1(3, 0),
5040 				    "fp_plogi_group;"
5041 				    "ulp_pkt's pd is NULL, get a pd %p",
5042 				    pd);
5043 				mutex_enter(&pd->pd_mutex);
5044 				pd->pd_ref_count++;
5045 				mutex_exit(&pd->pd_mutex);
5046 			}
5047 			ulp_pkt->pkt_pd = pd;
5048 		}
5049 
5050 		rval = fp_port_login(port, d_id, job, cmd_flags,
5051 		    KM_SLEEP, pd, ulp_pkt);
5052 
5053 		if (rval == FC_SUCCESS) {
5054 			continue;
5055 		}
5056 
5057 		if (rval == FC_STATEC_BUSY) {
5058 			ulp_pkt->pkt_state = FC_PKT_PORT_OFFLINE;
5059 			ulp_pkt->pkt_reason = FC_REASON_OFFLINE;
5060 		} else {
5061 			ulp_pkt->pkt_state = FC_PKT_FAILURE;
5062 		}
5063 
5064 		if (pd) {
5065 			mutex_enter(&pd->pd_mutex);
5066 			pd->pd_flags = PD_IDLE;
5067 			mutex_exit(&pd->pd_mutex);
5068 		}
5069 
5070 		if (cmd_flags & FP_CMD_DELDEV_ON_ERROR) {
5071 			ASSERT(pd != NULL);
5072 
5073 			FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_group: NS created,"
5074 			    " PD removed; port=%p, job=%p", port, job);
5075 
5076 			mutex_enter(&pd->pd_mutex);
5077 			pd->pd_ref_count--;
5078 			node = pd->pd_remote_nodep;
5079 			mutex_exit(&pd->pd_mutex);
5080 
5081 			ASSERT(node != NULL);
5082 
5083 			if (fctl_destroy_remote_port(port, pd) == 0) {
5084 				fctl_destroy_remote_node(node);
5085 			}
5086 			ulp_pkt->pkt_pd = NULL;
5087 		}
5088 		ulp_pkt->pkt_comp(ulp_pkt);
5089 		fp_jobdone(job);
5090 	}
5091 
5092 	fp_jobwait(job);
5093 	fctl_jobdone(job);
5094 
5095 	FP_TRACE(FP_NHEAD1(1, 0), "fp_plogi_group end: port=%p, job=%p",
5096 	    port, job);
5097 }
5098 
5099 
5100 /*
5101  * Name server request initialization
5102  */
5103 static void
5104 fp_ns_init(fc_local_port_t *port, job_request_t *job, int sleep)
5105 {
5106 	int rval;
5107 	int count;
5108 	int size;
5109 
5110 	ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
5111 
5112 	job->job_counter = 1;
5113 	job->job_result = FC_SUCCESS;
5114 
5115 	rval = fp_port_login(port, 0xFFFFFC, job, FP_CMD_PLOGI_RETAIN,
5116 	    KM_SLEEP, NULL, NULL);
5117 
5118 	if (rval != FC_SUCCESS) {
5119 		mutex_enter(&port->fp_mutex);
5120 		port->fp_topology = FC_TOP_NO_NS;
5121 		mutex_exit(&port->fp_mutex);
5122 		return;
5123 	}
5124 
5125 	fp_jobwait(job);
5126 
5127 	if (job->job_result != FC_SUCCESS) {
5128 		mutex_enter(&port->fp_mutex);
5129 		port->fp_topology = FC_TOP_NO_NS;
5130 		mutex_exit(&port->fp_mutex);
5131 		return;
5132 	}
5133 
5134 	/*
5135 	 * At this time, we'll do NS registration for objects in the
5136 	 * ns_reg_cmds (see top of this file) array.
5137 	 *
5138 	 * Each time a ULP module registers with the transport, the
5139 	 * appropriate fc4 bit is set fc4 types and registered with
5140 	 * the NS for this support. Also, ULPs and FC admin utilities
5141 	 * may do registration for objects like IP address, symbolic
5142 	 * port/node name, Initial process associator at run time.
5143 	 */
5144 	size = sizeof (ns_reg_cmds) / sizeof (ns_reg_cmds[0]);
5145 	job->job_counter = size;
5146 	job->job_result = FC_SUCCESS;
5147 
5148 	for (count = 0; count < size; count++) {
5149 		if (fp_ns_reg(port, NULL, ns_reg_cmds[count],
5150 		    job, 0, sleep) != FC_SUCCESS) {
5151 			fp_jobdone(job);
5152 		}
5153 	}
5154 	if (size) {
5155 		fp_jobwait(job);
5156 	}
5157 
5158 	job->job_result = FC_SUCCESS;
5159 
5160 	(void) fp_ns_get_devcount(port, job, 0, KM_SLEEP);
5161 
5162 	if (port->fp_dev_count < FP_MAX_DEVICES) {
5163 		(void) fp_ns_get_devcount(port, job, 1, KM_SLEEP);
5164 	}
5165 
5166 	job->job_counter = 1;
5167 
5168 	if (fp_ns_scr(port, job, FC_SCR_FULL_REGISTRATION,
5169 	    sleep) == FC_SUCCESS) {
5170 		fp_jobwait(job);
5171 	}
5172 }
5173 
5174 
5175 /*
5176  * Name server finish:
5177  *	Unregister for RSCNs
5178  * 	Unregister all the host port objects in the Name Server
5179  * 	Perform LOGO with the NS;
5180  */
5181 static void
5182 fp_ns_fini(fc_local_port_t *port, job_request_t *job)
5183 {
5184 	fp_cmd_t 	*cmd;
5185 	uchar_t		class;
5186 	uint32_t	s_id;
5187 	fc_packet_t	*pkt;
5188 	la_els_logo_t 	payload;
5189 
5190 	ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
5191 
5192 	job->job_counter = 1;
5193 
5194 	if (fp_ns_scr(port, job, FC_SCR_CLEAR_REGISTRATION, KM_SLEEP) !=
5195 	    FC_SUCCESS) {
5196 		fp_jobdone(job);
5197 	}
5198 	fp_jobwait(job);
5199 
5200 	job->job_counter = 1;
5201 
5202 	if (fp_ns_reg(port, NULL, NS_DA_ID, job, 0, KM_SLEEP) != FC_SUCCESS) {
5203 		fp_jobdone(job);
5204 	}
5205 	fp_jobwait(job);
5206 
5207 	job->job_counter = 1;
5208 
5209 	cmd = fp_alloc_pkt(port, sizeof (la_els_logo_t),
5210 		FP_PORT_IDENTIFIER_LEN, KM_SLEEP, NULL);
5211 	pkt = &cmd->cmd_pkt;
5212 
5213 	mutex_enter(&port->fp_mutex);
5214 	class = port->fp_ns_login_class;
5215 	s_id = port->fp_port_id.port_id;
5216 	payload.nport_id = port->fp_port_id;
5217 	mutex_exit(&port->fp_mutex);
5218 
5219 	cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class;
5220 	cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
5221 	cmd->cmd_flags = FP_CMD_PLOGI_DONT_CARE;
5222 	cmd->cmd_retry_count = 1;
5223 	cmd->cmd_ulp_pkt = NULL;
5224 
5225 	if (port->fp_npiv_type == FC_NPIV_PORT) {
5226 		fp_els_init(cmd, s_id, 0xFFFFFE, fp_logo_intr, job);
5227 	} else {
5228 		fp_els_init(cmd, s_id, 0xFFFFFC, fp_logo_intr, job);
5229 	}
5230 
5231 	cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
5232 
5233 	payload.ls_code.ls_code = LA_ELS_LOGO;
5234 	payload.ls_code.mbz = 0;
5235 	payload.nport_ww_name = port->fp_service_params.nport_ww_name;
5236 
5237 	ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&payload,
5238 	    (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
5239 
5240 	if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
5241 		fp_iodone(cmd);
5242 	}
5243 	fp_jobwait(job);
5244 }
5245 
5246 
5247 /*
5248  * NS Registration function.
5249  *
5250  *	It should be seriously noted that FC-GS-2 currently doesn't support
5251  *	an Object Registration by a D_ID other than the owner of the object.
5252  *	What we are aiming at currently is to at least allow Symbolic Node/Port
5253  *	Name registration for any N_Port Identifier by the host software.
5254  *
5255  *	Anyway, if the second argument (fc_remote_port_t *) is NULL, this
5256  *	function treats the request as Host NS Object.
5257  */
5258 static int
5259 fp_ns_reg(fc_local_port_t *port, fc_remote_port_t *pd, uint16_t cmd_code,
5260     job_request_t *job, int polled, int sleep)
5261 {
5262 	int 		rval;
5263 	fc_portid_t	s_id;
5264 	fc_packet_t 	*pkt;
5265 	fp_cmd_t 	*cmd;
5266 
5267 	if (pd == NULL) {
5268 		mutex_enter(&port->fp_mutex);
5269 		s_id = port->fp_port_id;
5270 		mutex_exit(&port->fp_mutex);
5271 	} else {
5272 		mutex_enter(&pd->pd_mutex);
5273 		s_id = pd->pd_port_id;
5274 		mutex_exit(&pd->pd_mutex);
5275 	}
5276 
5277 	if (polled) {
5278 		job->job_counter = 1;
5279 	}
5280 
5281 	switch (cmd_code) {
5282 	case NS_RPN_ID:
5283 	case NS_RNN_ID: {
5284 		ns_rxn_req_t rxn;
5285 
5286 		cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
5287 		    sizeof (ns_rxn_req_t), sizeof (fc_reg_resp_t), sleep, NULL);
5288 		if (cmd == NULL) {
5289 			return (FC_NOMEM);
5290 		}
5291 		fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5292 		pkt = &cmd->cmd_pkt;
5293 
5294 		if (pd == NULL) {
5295 			rxn.rxn_xname = (cmd_code == NS_RPN_ID) ?
5296 			    (port->fp_service_params.nport_ww_name) :
5297 			    (port->fp_service_params.node_ww_name);
5298 		} else {
5299 			if (cmd_code == NS_RPN_ID) {
5300 				mutex_enter(&pd->pd_mutex);
5301 				rxn.rxn_xname = pd->pd_port_name;
5302 				mutex_exit(&pd->pd_mutex);
5303 			} else {
5304 				fc_remote_node_t *node;
5305 
5306 				mutex_enter(&pd->pd_mutex);
5307 				node = pd->pd_remote_nodep;
5308 				mutex_exit(&pd->pd_mutex);
5309 
5310 				mutex_enter(&node->fd_mutex);
5311 				rxn.rxn_xname = node->fd_node_name;
5312 				mutex_exit(&node->fd_mutex);
5313 			}
5314 		}
5315 		rxn.rxn_port_id = s_id;
5316 
5317 		ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&rxn,
5318 		    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
5319 		    sizeof (rxn), DDI_DEV_AUTOINCR);
5320 
5321 		break;
5322 	}
5323 
5324 	case NS_RCS_ID: {
5325 		ns_rcos_t rcos;
5326 
5327 		cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
5328 		    sizeof (ns_rcos_t), sizeof (fc_reg_resp_t), sleep, NULL);
5329 		if (cmd == NULL) {
5330 			return (FC_NOMEM);
5331 		}
5332 		fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5333 		pkt = &cmd->cmd_pkt;
5334 
5335 		if (pd == NULL) {
5336 			rcos.rcos_cos = port->fp_cos;
5337 		} else {
5338 			mutex_enter(&pd->pd_mutex);
5339 			rcos.rcos_cos = pd->pd_cos;
5340 			mutex_exit(&pd->pd_mutex);
5341 		}
5342 		rcos.rcos_port_id = s_id;
5343 
5344 		ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&rcos,
5345 		    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
5346 		    sizeof (rcos), DDI_DEV_AUTOINCR);
5347 
5348 		break;
5349 	}
5350 
5351 	case NS_RFT_ID: {
5352 		ns_rfc_type_t rfc;
5353 
5354 		cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
5355 		    sizeof (ns_rfc_type_t), sizeof (fc_reg_resp_t), sleep,
5356 		    NULL);
5357 		if (cmd == NULL) {
5358 			return (FC_NOMEM);
5359 		}
5360 		fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5361 		pkt = &cmd->cmd_pkt;
5362 
5363 		if (pd == NULL) {
5364 			mutex_enter(&port->fp_mutex);
5365 			bcopy(port->fp_fc4_types, rfc.rfc_types,
5366 			    sizeof (port->fp_fc4_types));
5367 			mutex_exit(&port->fp_mutex);
5368 		} else {
5369 			mutex_enter(&pd->pd_mutex);
5370 			bcopy(pd->pd_fc4types, rfc.rfc_types,
5371 			    sizeof (pd->pd_fc4types));
5372 			mutex_exit(&pd->pd_mutex);
5373 		}
5374 		rfc.rfc_port_id = s_id;
5375 
5376 		ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&rfc,
5377 		    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
5378 		    sizeof (rfc), DDI_DEV_AUTOINCR);
5379 
5380 		break;
5381 	}
5382 
5383 	case NS_RSPN_ID: {
5384 		uchar_t 	name_len;
5385 		int 		pl_size;
5386 		fc_portid_t 	spn;
5387 
5388 		if (pd == NULL) {
5389 			mutex_enter(&port->fp_mutex);
5390 			name_len = port->fp_sym_port_namelen;
5391 			mutex_exit(&port->fp_mutex);
5392 		} else {
5393 			mutex_enter(&pd->pd_mutex);
5394 			name_len = pd->pd_spn_len;
5395 			mutex_exit(&pd->pd_mutex);
5396 		}
5397 
5398 		pl_size = sizeof (fc_portid_t) + name_len + 1;
5399 
5400 		cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) + pl_size,
5401 			sizeof (fc_reg_resp_t), sleep, NULL);
5402 		if (cmd == NULL) {
5403 			return (FC_NOMEM);
5404 		}
5405 
5406 		fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5407 
5408 		pkt = &cmd->cmd_pkt;
5409 
5410 		spn = s_id;
5411 
5412 		ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&spn, (uint8_t *)
5413 		    (pkt->pkt_cmd + sizeof (fc_ct_header_t)), sizeof (spn),
5414 		    DDI_DEV_AUTOINCR);
5415 		ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&name_len,
5416 		    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)
5417 		    + sizeof (fc_portid_t)), 1, DDI_DEV_AUTOINCR);
5418 
5419 		if (pd == NULL) {
5420 			mutex_enter(&port->fp_mutex);
5421 			ddi_rep_put8(pkt->pkt_cmd_acc,
5422 			    (uint8_t *)port->fp_sym_port_name, (uint8_t *)
5423 			    (pkt->pkt_cmd + sizeof (fc_ct_header_t) +
5424 			    sizeof (spn) + 1), name_len, DDI_DEV_AUTOINCR);
5425 			mutex_exit(&port->fp_mutex);
5426 		} else {
5427 			mutex_enter(&pd->pd_mutex);
5428 			ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)pd->pd_spn,
5429 			    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t) +
5430 			    sizeof (spn) + 1), name_len, DDI_DEV_AUTOINCR);
5431 			mutex_exit(&pd->pd_mutex);
5432 		}
5433 		break;
5434 	}
5435 
5436 	case NS_RPT_ID: {
5437 		ns_rpt_t rpt;
5438 
5439 		cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
5440 		    sizeof (ns_rpt_t), sizeof (fc_reg_resp_t), sleep, NULL);
5441 		if (cmd == NULL) {
5442 			return (FC_NOMEM);
5443 		}
5444 		fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5445 		pkt = &cmd->cmd_pkt;
5446 
5447 		if (pd == NULL) {
5448 			rpt.rpt_type = port->fp_port_type;
5449 		} else {
5450 			mutex_enter(&pd->pd_mutex);
5451 			rpt.rpt_type = pd->pd_porttype;
5452 			mutex_exit(&pd->pd_mutex);
5453 		}
5454 		rpt.rpt_port_id = s_id;
5455 
5456 		ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&rpt,
5457 		    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
5458 		    sizeof (rpt), DDI_DEV_AUTOINCR);
5459 
5460 		break;
5461 	}
5462 
5463 	case NS_RIP_NN: {
5464 		ns_rip_t rip;
5465 
5466 		cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
5467 		    sizeof (ns_rip_t), sizeof (fc_reg_resp_t), sleep, NULL);
5468 		if (cmd == NULL) {
5469 			return (FC_NOMEM);
5470 		}
5471 		fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5472 		pkt = &cmd->cmd_pkt;
5473 
5474 		if (pd == NULL) {
5475 			rip.rip_node_name =
5476 			    port->fp_service_params.node_ww_name;
5477 			bcopy(port->fp_ip_addr, rip.rip_ip_addr,
5478 			    sizeof (port->fp_ip_addr));
5479 		} else {
5480 			fc_remote_node_t *node;
5481 
5482 			/*
5483 			 * The most correct implementation should have the IP
5484 			 * address in the fc_remote_node_t structure; I believe
5485 			 * Node WWN and IP address should have one to one
5486 			 * correlation (but guess what this is changing in
5487 			 * FC-GS-2 latest draft)
5488 			 */
5489 			mutex_enter(&pd->pd_mutex);
5490 			node = pd->pd_remote_nodep;
5491 			bcopy(pd->pd_ip_addr, rip.rip_ip_addr,
5492 			    sizeof (pd->pd_ip_addr));
5493 			mutex_exit(&pd->pd_mutex);
5494 
5495 			mutex_enter(&node->fd_mutex);
5496 			rip.rip_node_name = node->fd_node_name;
5497 			mutex_exit(&node->fd_mutex);
5498 		}
5499 
5500 		ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&rip,
5501 		    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
5502 		    sizeof (rip), DDI_DEV_AUTOINCR);
5503 
5504 		break;
5505 	}
5506 
5507 	case NS_RIPA_NN: {
5508 		ns_ipa_t ipa;
5509 
5510 		cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
5511 		    sizeof (ns_ipa_t), sizeof (fc_reg_resp_t), sleep, NULL);
5512 		if (cmd == NULL) {
5513 			return (FC_NOMEM);
5514 		}
5515 		fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5516 		pkt = &cmd->cmd_pkt;
5517 
5518 		if (pd == NULL) {
5519 			ipa.ipa_node_name =
5520 			    port->fp_service_params.node_ww_name;
5521 			bcopy(port->fp_ipa, ipa.ipa_value,
5522 			    sizeof (port->fp_ipa));
5523 		} else {
5524 			fc_remote_node_t *node;
5525 
5526 			mutex_enter(&pd->pd_mutex);
5527 			node = pd->pd_remote_nodep;
5528 			mutex_exit(&pd->pd_mutex);
5529 
5530 			mutex_enter(&node->fd_mutex);
5531 			ipa.ipa_node_name = node->fd_node_name;
5532 			bcopy(node->fd_ipa, ipa.ipa_value,
5533 			    sizeof (node->fd_ipa));
5534 			mutex_exit(&node->fd_mutex);
5535 		}
5536 
5537 		ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&ipa,
5538 		    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
5539 		    sizeof (ipa), DDI_DEV_AUTOINCR);
5540 
5541 		break;
5542 	}
5543 
5544 	case NS_RSNN_NN: {
5545 		uchar_t 		name_len;
5546 		int 			pl_size;
5547 		la_wwn_t 		snn;
5548 		fc_remote_node_t	*node = NULL;
5549 
5550 		if (pd == NULL) {
5551 			mutex_enter(&port->fp_mutex);
5552 			name_len = port->fp_sym_node_namelen;
5553 			mutex_exit(&port->fp_mutex);
5554 		} else {
5555 			mutex_enter(&pd->pd_mutex);
5556 			node = pd->pd_remote_nodep;
5557 			mutex_exit(&pd->pd_mutex);
5558 
5559 			mutex_enter(&node->fd_mutex);
5560 			name_len = node->fd_snn_len;
5561 			mutex_exit(&node->fd_mutex);
5562 		}
5563 
5564 		pl_size = sizeof (la_wwn_t) + name_len + 1;
5565 
5566 		cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
5567 			pl_size, sizeof (fc_reg_resp_t), sleep, NULL);
5568 		if (cmd == NULL) {
5569 			return (FC_NOMEM);
5570 		}
5571 		fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5572 
5573 		pkt = &cmd->cmd_pkt;
5574 
5575 		bcopy(&port->fp_service_params.node_ww_name,
5576 		    &snn, sizeof (la_wwn_t));
5577 
5578 		if (pd == NULL) {
5579 			mutex_enter(&port->fp_mutex);
5580 			ddi_rep_put8(pkt->pkt_cmd_acc,
5581 			    (uint8_t *)port->fp_sym_node_name, (uint8_t *)
5582 			    (pkt->pkt_cmd + sizeof (fc_ct_header_t) +
5583 			    sizeof (snn) + 1), name_len, DDI_DEV_AUTOINCR);
5584 			mutex_exit(&port->fp_mutex);
5585 		} else {
5586 			ASSERT(node != NULL);
5587 			mutex_enter(&node->fd_mutex);
5588 			ddi_rep_put8(pkt->pkt_cmd_acc,
5589 			    (uint8_t *)node->fd_snn,
5590 			    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t) +
5591 			    sizeof (snn) + 1), name_len, DDI_DEV_AUTOINCR);
5592 			mutex_exit(&node->fd_mutex);
5593 		}
5594 
5595 		ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&snn,
5596 		    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
5597 		    sizeof (snn), DDI_DEV_AUTOINCR);
5598 		ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&name_len,
5599 		    (uint8_t *)(pkt->pkt_cmd
5600 		    + sizeof (fc_ct_header_t) + sizeof (snn)),
5601 		    1, DDI_DEV_AUTOINCR);
5602 
5603 		break;
5604 	}
5605 
5606 	case NS_DA_ID: {
5607 		ns_remall_t rall;
5608 		char tmp[4] = {0};
5609 		char *ptr;
5610 
5611 		cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
5612 		    sizeof (ns_remall_t), sizeof (fc_reg_resp_t), sleep, NULL);
5613 
5614 		if (cmd == NULL) {
5615 			return (FC_NOMEM);
5616 		}
5617 
5618 		fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5619 		pkt = &cmd->cmd_pkt;
5620 
5621 		ptr = (char *)(&s_id);
5622 		tmp[3] = *ptr++;
5623 		tmp[2] = *ptr++;
5624 		tmp[1] = *ptr++;
5625 		tmp[0] = *ptr;
5626 #if defined(_BIT_FIELDS_LTOH)
5627 		bcopy((caddr_t)tmp, (caddr_t)(&rall.rem_port_id), 4);
5628 #else
5629 		rall.rem_port_id = s_id;
5630 #endif
5631 		ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&rall,
5632 		    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
5633 		    sizeof (rall), DDI_DEV_AUTOINCR);
5634 
5635 		break;
5636 	}
5637 
5638 	default:
5639 		return (FC_FAILURE);
5640 	}
5641 
5642 	rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
5643 
5644 	if (rval != FC_SUCCESS) {
5645 		job->job_result = rval;
5646 		fp_iodone(cmd);
5647 	}
5648 
5649 	if (polled) {
5650 		ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
5651 		fp_jobwait(job);
5652 	} else {
5653 		rval = FC_SUCCESS;
5654 	}
5655 
5656 	return (rval);
5657 }
5658 
5659 
5660 /*
5661  * Common interrupt handler
5662  */
5663 static int
5664 fp_common_intr(fc_packet_t *pkt, int iodone)
5665 {
5666 	int		rval = FC_FAILURE;
5667 	fp_cmd_t 	*cmd;
5668 	fc_local_port_t	*port;
5669 
5670 	cmd = pkt->pkt_ulp_private;
5671 	port = cmd->cmd_port;
5672 
5673 	/*
5674 	 * Fail fast the upper layer requests if
5675 	 * a state change has occurred amidst.
5676 	 */
5677 	mutex_enter(&port->fp_mutex);
5678 	if (cmd->cmd_ulp_pkt != NULL && port->fp_statec_busy) {
5679 		mutex_exit(&port->fp_mutex);
5680 		cmd->cmd_ulp_pkt->pkt_state = FC_PKT_PORT_OFFLINE;
5681 		cmd->cmd_ulp_pkt->pkt_reason = FC_REASON_OFFLINE;
5682 	} else if (!(port->fp_soft_state &
5683 	    (FP_SOFT_IN_DETACH | FP_DETACH_INPROGRESS))) {
5684 		mutex_exit(&port->fp_mutex);
5685 
5686 		switch (pkt->pkt_state) {
5687 		case FC_PKT_LOCAL_BSY:
5688 		case FC_PKT_FABRIC_BSY:
5689 		case FC_PKT_NPORT_BSY:
5690 		case FC_PKT_TIMEOUT:
5691 			cmd->cmd_retry_interval = (pkt->pkt_state ==
5692 			    FC_PKT_TIMEOUT) ? 0 : fp_retry_delay;
5693 			rval = fp_retry_cmd(pkt);
5694 			break;
5695 
5696 		case FC_PKT_FABRIC_RJT:
5697 		case FC_PKT_NPORT_RJT:
5698 		case FC_PKT_LOCAL_RJT:
5699 		case FC_PKT_LS_RJT:
5700 		case FC_PKT_FS_RJT:
5701 		case FC_PKT_BA_RJT:
5702 			rval = fp_handle_reject(pkt);
5703 			break;
5704 
5705 		default:
5706 			if (pkt->pkt_resp_resid) {
5707 				cmd->cmd_retry_interval = 0;
5708 				rval = fp_retry_cmd(pkt);
5709 			}
5710 			break;
5711 		}
5712 	} else {
5713 		mutex_exit(&port->fp_mutex);
5714 	}
5715 
5716 	if (rval != FC_SUCCESS && iodone) {
5717 		fp_iodone(cmd);
5718 		rval = FC_SUCCESS;
5719 	}
5720 
5721 	return (rval);
5722 }
5723 
5724 
5725 /*
5726  * Some not so long winding theory on point to point topology:
5727  *
5728  *	In the ACC payload, if the D_ID is ZERO and the common service
5729  *	parameters indicate N_Port, then the topology is POINT TO POINT.
5730  *
5731  *	In a point to point topology with an N_Port, during Fabric Login,
5732  *	the destination N_Port will check with our WWN and decide if it
5733  * 	needs to issue PLOGI or not. That means, FLOGI could potentially
5734  *	trigger an unsolicited PLOGI from an N_Port. The Unsolicited
5735  *	PLOGI creates the device handles.
5736  *
5737  *	Assuming that the host port WWN is greater than the other N_Port
5738  *	WWN, then we become the master (be aware that this isn't the word
5739  *	used in the FC standards) and initiate the PLOGI.
5740  *
5741  */
5742 static void
5743 fp_flogi_intr(fc_packet_t *pkt)
5744 {
5745 	int			state;
5746 	int			f_port;
5747 	uint32_t		s_id;
5748 	uint32_t		d_id;
5749 	fp_cmd_t 		*cmd;
5750 	fc_local_port_t 	*port;
5751 	la_wwn_t		*swwn;
5752 	la_wwn_t		dwwn;
5753 	la_wwn_t		nwwn;
5754 	fc_remote_port_t	*pd;
5755 	la_els_logi_t 		*acc;
5756 	com_svc_t		csp;
5757 	ls_code_t		resp;
5758 
5759 	cmd = pkt->pkt_ulp_private;
5760 	port = cmd->cmd_port;
5761 
5762 	FP_TRACE(FP_NHEAD1(1, 0), "fp_flogi_intr; port=%p, pkt=%p, state=%x",
5763 	    port, pkt, pkt->pkt_state);
5764 
5765 	if (FP_IS_PKT_ERROR(pkt)) {
5766 		(void) fp_common_intr(pkt, 1);
5767 		return;
5768 	}
5769 
5770 	/*
5771 	 * Currently, we don't need to swap bytes here because qlc is faking the
5772 	 * response for us and so endianness is getting taken care of. But we
5773 	 * have to fix this and generalize this at some point
5774 	 */
5775 	acc = (la_els_logi_t *)pkt->pkt_resp;
5776 
5777 	ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&resp, (uint8_t *)acc,
5778 	    sizeof (resp), DDI_DEV_AUTOINCR);
5779 
5780 	ASSERT(resp.ls_code == LA_ELS_ACC);
5781 	if (resp.ls_code != LA_ELS_ACC) {
5782 		(void) fp_common_intr(pkt, 1);
5783 		return;
5784 	}
5785 
5786 	ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&csp,
5787 	    (uint8_t *)&acc->common_service, sizeof (csp), DDI_DEV_AUTOINCR);
5788 
5789 	f_port = FP_IS_F_PORT(csp.cmn_features) ? 1 : 0;
5790 
5791 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
5792 
5793 	mutex_enter(&port->fp_mutex);
5794 	state = FC_PORT_STATE_MASK(port->fp_state);
5795 	mutex_exit(&port->fp_mutex);
5796 
5797 	if (pkt->pkt_resp_fhdr.d_id == 0) {
5798 		if (f_port == 0 && state != FC_STATE_LOOP) {
5799 			swwn = &port->fp_service_params.nport_ww_name;
5800 
5801 			ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&dwwn,
5802 			    (uint8_t *)&acc->nport_ww_name, sizeof (la_wwn_t),
5803 			    DDI_DEV_AUTOINCR);
5804 
5805 			ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&nwwn,
5806 			    (uint8_t *)&acc->node_ww_name, sizeof (la_wwn_t),
5807 			    DDI_DEV_AUTOINCR);
5808 
5809 			mutex_enter(&port->fp_mutex);
5810 
5811 			port->fp_topology = FC_TOP_PT_PT;
5812 			port->fp_total_devices = 1;
5813 			if (fctl_wwn_cmp(swwn, &dwwn) >= 0) {
5814 				port->fp_ptpt_master = 1;
5815 				/*
5816 				 * Let us choose 'X' as S_ID and 'Y'
5817 				 * as D_ID and that'll work; hopefully
5818 				 * If not, it will get changed.
5819 				 */
5820 				s_id = port->fp_instance + FP_DEFAULT_SID;
5821 				d_id = port->fp_instance + FP_DEFAULT_DID;
5822 				port->fp_port_id.port_id = s_id;
5823 				mutex_exit(&port->fp_mutex);
5824 
5825 				pd = fctl_create_remote_port(port,
5826 				    &nwwn, &dwwn, d_id, PD_PLOGI_INITIATOR,
5827 				    KM_NOSLEEP);
5828 				if (pd == NULL) {
5829 					fp_printf(port, CE_NOTE, FP_LOG_ONLY,
5830 					    0, NULL, "couldn't create device"
5831 					    " d_id=%X", d_id);
5832 					fp_iodone(cmd);
5833 					return;
5834 				}
5835 
5836 				cmd->cmd_pkt.pkt_tran_flags =
5837 				    pkt->pkt_tran_flags;
5838 				cmd->cmd_pkt.pkt_tran_type = pkt->pkt_tran_type;
5839 				cmd->cmd_flags = FP_CMD_PLOGI_RETAIN;
5840 				cmd->cmd_retry_count = fp_retry_count;
5841 
5842 				fp_xlogi_init(port, cmd, s_id, d_id,
5843 				    fp_plogi_intr, cmd->cmd_job, LA_ELS_PLOGI);
5844 
5845 				(&cmd->cmd_pkt)->pkt_pd = pd;
5846 
5847 				/*
5848 				 * We've just created this fc_remote_port_t, and
5849 				 * we're about to use it to send a PLOGI, so
5850 				 * bump the reference count right now.  When
5851 				 * the packet is freed, the reference count will
5852 				 * be decremented.  The ULP may also start using
5853 				 * it, so mark it as given away as well.
5854 				 */
5855 				pd->pd_ref_count++;
5856 				pd->pd_aux_flags |= PD_GIVEN_TO_ULPS;
5857 
5858 				if (fp_sendcmd(port, cmd,
5859 				    port->fp_fca_handle) == FC_SUCCESS) {
5860 					return;
5861 				}
5862 			} else {
5863 				/*
5864 				 * The device handles will be created when the
5865 				 * unsolicited PLOGI is completed successfully
5866 				 */
5867 				port->fp_ptpt_master = 0;
5868 				mutex_exit(&port->fp_mutex);
5869 			}
5870 		}
5871 		pkt->pkt_state = FC_PKT_FAILURE;
5872 	} else {
5873 		if (f_port) {
5874 			mutex_enter(&port->fp_mutex);
5875 			if (state == FC_STATE_LOOP) {
5876 				port->fp_topology = FC_TOP_PUBLIC_LOOP;
5877 			} else {
5878 				port->fp_topology = FC_TOP_FABRIC;
5879 
5880 				ddi_rep_get8(pkt->pkt_resp_acc,
5881 				    (uint8_t *)&port->fp_fabric_name,
5882 				    (uint8_t *)&acc->node_ww_name,
5883 				    sizeof (la_wwn_t),
5884 				    DDI_DEV_AUTOINCR);
5885 			}
5886 			port->fp_port_id.port_id = pkt->pkt_resp_fhdr.d_id;
5887 			mutex_exit(&port->fp_mutex);
5888 		} else {
5889 			pkt->pkt_state = FC_PKT_FAILURE;
5890 		}
5891 	}
5892 	fp_iodone(cmd);
5893 }
5894 
5895 
5896 /*
5897  * Handle solicited PLOGI response
5898  */
5899 static void
5900 fp_plogi_intr(fc_packet_t *pkt)
5901 {
5902 	int			nl_port;
5903 	int			bailout;
5904 	uint32_t		d_id;
5905 	fp_cmd_t 		*cmd;
5906 	la_els_logi_t		*acc;
5907 	fc_local_port_t		*port;
5908 	fc_remote_port_t 	*pd;
5909 	la_wwn_t		nwwn;
5910 	la_wwn_t		pwwn;
5911 	ls_code_t		resp;
5912 
5913 	nl_port = 0;
5914 	cmd = pkt->pkt_ulp_private;
5915 	port = cmd->cmd_port;
5916 	d_id = pkt->pkt_cmd_fhdr.d_id;
5917 
5918 #ifndef	__lock_lint
5919 	ASSERT(cmd->cmd_job && cmd->cmd_job->job_counter);
5920 #endif
5921 
5922 	FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_intr: port=%p, job=%p, d_id=%x,"
5923 	    " jcount=%d pkt=%p, state=%x", port, cmd->cmd_job, d_id,
5924 	    cmd->cmd_job->job_counter, pkt, pkt->pkt_state);
5925 
5926 	/*
5927 	 * Bail out early on ULP initiated requests if the
5928 	 * state change has occurred
5929 	 */
5930 	mutex_enter(&port->fp_mutex);
5931 	bailout = ((port->fp_statec_busy ||
5932 	    FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) &&
5933 	    cmd->cmd_ulp_pkt) ? 1 : 0;
5934 	mutex_exit(&port->fp_mutex);
5935 
5936 	if (FP_IS_PKT_ERROR(pkt) || bailout) {
5937 		int skip_msg = 0;
5938 		int giveup = 0;
5939 
5940 		if (cmd->cmd_ulp_pkt) {
5941 			cmd->cmd_ulp_pkt->pkt_state = pkt->pkt_state;
5942 			cmd->cmd_ulp_pkt->pkt_reason = pkt->pkt_reason;
5943 			cmd->cmd_ulp_pkt->pkt_action = pkt->pkt_action;
5944 			cmd->cmd_ulp_pkt->pkt_expln = pkt->pkt_expln;
5945 		}
5946 
5947 		/*
5948 		 * If an unsolicited cross login already created
5949 		 * a device speed up the discovery by not retrying
5950 		 * the command mindlessly.
5951 		 */
5952 		if (pkt->pkt_pd == NULL &&
5953 		    fctl_get_remote_port_by_did(port, d_id) != NULL) {
5954 			fp_iodone(cmd);
5955 			return;
5956 		}
5957 
5958 		if (pkt->pkt_pd != NULL) {
5959 			giveup = (pkt->pkt_pd->pd_recepient ==
5960 			    PD_PLOGI_RECEPIENT) ? 1 : 0;
5961 			if (giveup) {
5962 				/*
5963 				 * This pd is marked as plogi
5964 				 * recipient, stop retrying
5965 				 */
5966 				FP_TRACE(FP_NHEAD1(3, 0),
5967 				    "fp_plogi_intr: stop retry as"
5968 				    " a cross login was accepted"
5969 				    " from d_id=%x, port=%p.",
5970 				    d_id, port);
5971 				fp_iodone(cmd);
5972 				return;
5973 			}
5974 		}
5975 
5976 		if (fp_common_intr(pkt, 0) == FC_SUCCESS) {
5977 			return;
5978 		}
5979 
5980 		if ((pd = fctl_get_remote_port_by_did(port, d_id)) != NULL) {
5981 			mutex_enter(&pd->pd_mutex);
5982 			if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
5983 				skip_msg++;
5984 			}
5985 			mutex_exit(&pd->pd_mutex);
5986 		}
5987 
5988 		mutex_enter(&port->fp_mutex);
5989 		if (!bailout && !(skip_msg && port->fp_statec_busy) &&
5990 		    port->fp_statec_busy <= 1 &&
5991 		    pkt->pkt_reason != FC_REASON_FCAL_OPN_FAIL) {
5992 			mutex_exit(&port->fp_mutex);
5993 			/*
5994 			 * In case of Login Collisions, JNI HBAs returns the
5995 			 * FC pkt back to the Initiator with the state set to
5996 			 * FC_PKT_LS_RJT and reason to FC_REASON_LOGICAL_ERROR.
5997 			 * QLC HBAs handles such cases in the FW and doesnot
5998 			 * return the LS_RJT with Logical error when
5999 			 * login collision happens.
6000 			 */
6001 			if ((pkt->pkt_state != FC_PKT_LS_RJT) ||
6002 			    (pkt->pkt_reason != FC_REASON_LOGICAL_ERROR)) {
6003 				fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, pkt,
6004 				    "PLOGI to %x failed", d_id);
6005 			}
6006 			FP_TRACE(FP_NHEAD2(9, 0),
6007 			    "PLOGI to %x failed. state=%x reason=%x.",
6008 			    d_id, pkt->pkt_state, pkt->pkt_reason);
6009 		} else {
6010 			mutex_exit(&port->fp_mutex);
6011 		}
6012 
6013 		fp_iodone(cmd);
6014 		return;
6015 	}
6016 
6017 	acc = (la_els_logi_t *)pkt->pkt_resp;
6018 
6019 	ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&resp, (uint8_t *)acc,
6020 	    sizeof (resp), DDI_DEV_AUTOINCR);
6021 
6022 	ASSERT(resp.ls_code == LA_ELS_ACC);
6023 	if (resp.ls_code != LA_ELS_ACC) {
6024 		(void) fp_common_intr(pkt, 1);
6025 		return;
6026 	}
6027 
6028 	if (d_id == FS_NAME_SERVER || d_id == FS_FABRIC_CONTROLLER) {
6029 		mutex_enter(&port->fp_mutex);
6030 		port->fp_ns_login_class = FC_TRAN_CLASS(pkt->pkt_tran_flags);
6031 		mutex_exit(&port->fp_mutex);
6032 		fp_iodone(cmd);
6033 		return;
6034 	}
6035 
6036 	ASSERT(acc == (la_els_logi_t *)pkt->pkt_resp);
6037 
6038 	ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&pwwn,
6039 	    (uint8_t *)&acc->nport_ww_name, sizeof (la_wwn_t),
6040 	    DDI_DEV_AUTOINCR);
6041 
6042 	ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&nwwn,
6043 	    (uint8_t *)&acc->node_ww_name, sizeof (la_wwn_t),
6044 	    DDI_DEV_AUTOINCR);
6045 
6046 	ASSERT(fctl_is_wwn_zero(&pwwn) == FC_FAILURE);
6047 	ASSERT(fctl_is_wwn_zero(&nwwn) == FC_FAILURE);
6048 
6049 	if ((pd = pkt->pkt_pd) == NULL) {
6050 		pd = fctl_get_remote_port_by_pwwn(port, &pwwn);
6051 		if (pd == NULL) {
6052 			pd = fctl_create_remote_port(port, &nwwn, &pwwn, d_id,
6053 			    PD_PLOGI_INITIATOR, KM_NOSLEEP);
6054 			if (pd == NULL) {
6055 				fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
6056 				    "couldn't create port device handles"
6057 				    " d_id=%x", d_id);
6058 				fp_iodone(cmd);
6059 				return;
6060 			}
6061 		} else {
6062 			fc_remote_port_t *tmp_pd;
6063 
6064 			tmp_pd = fctl_get_remote_port_by_did(port, d_id);
6065 			if (tmp_pd != NULL) {
6066 				fp_iodone(cmd);
6067 				return;
6068 			}
6069 
6070 			mutex_enter(&port->fp_mutex);
6071 			mutex_enter(&pd->pd_mutex);
6072 			if ((pd->pd_state == PORT_DEVICE_LOGGED_IN) ||
6073 			    (pd->pd_aux_flags & PD_LOGGED_OUT)) {
6074 				cmd->cmd_flags |= FP_CMD_PLOGI_RETAIN;
6075 			}
6076 
6077 			if (pd->pd_type == PORT_DEVICE_OLD) {
6078 				if (pd->pd_port_id.port_id != d_id) {
6079 					fctl_delist_did_table(port, pd);
6080 					pd->pd_type = PORT_DEVICE_CHANGED;
6081 					pd->pd_port_id.port_id = d_id;
6082 				} else {
6083 					pd->pd_type = PORT_DEVICE_NOCHANGE;
6084 				}
6085 			}
6086 
6087 			if (pd->pd_aux_flags & PD_IN_DID_QUEUE) {
6088 				char ww_name[17];
6089 
6090 				fc_wwn_to_str(&pd->pd_port_name, ww_name);
6091 
6092 				mutex_exit(&pd->pd_mutex);
6093 				mutex_exit(&port->fp_mutex);
6094 				FP_TRACE(FP_NHEAD2(9, 0),
6095 				    "Possible Duplicate name or address"
6096 				    " identifiers in the PLOGI response"
6097 				    " D_ID=%x, PWWN=%s: Please check the"
6098 				    " configuration", d_id, ww_name);
6099 				fp_iodone(cmd);
6100 				return;
6101 			}
6102 			fctl_enlist_did_table(port, pd);
6103 			pd->pd_aux_flags &= ~PD_LOGGED_OUT;
6104 			mutex_exit(&pd->pd_mutex);
6105 			mutex_exit(&port->fp_mutex);
6106 		}
6107 	} else {
6108 		fc_remote_port_t *tmp_pd, *new_wwn_pd;
6109 
6110 		tmp_pd = fctl_get_remote_port_by_did(port, d_id);
6111 		new_wwn_pd = fctl_get_remote_port_by_pwwn(port, &pwwn);
6112 
6113 		mutex_enter(&port->fp_mutex);
6114 		mutex_enter(&pd->pd_mutex);
6115 		if (fctl_wwn_cmp(&pd->pd_port_name, &pwwn) == 0) {
6116 			FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_intr: d_id=%x,"
6117 			    " pd_state=%x pd_type=%x", d_id, pd->pd_state,
6118 			    pd->pd_type);
6119 			if ((pd->pd_state == PORT_DEVICE_LOGGED_IN &&
6120 			    pd->pd_type == PORT_DEVICE_OLD) ||
6121 				(pd->pd_aux_flags & PD_LOGGED_OUT)) {
6122 				pd->pd_type = PORT_DEVICE_NOCHANGE;
6123 			} else if (pd->pd_state != PORT_DEVICE_LOGGED_IN) {
6124 				pd->pd_type = PORT_DEVICE_NEW;
6125 			}
6126 		} else {
6127 			char 	old_name[17];
6128 			char 	new_name[17];
6129 
6130 			fc_wwn_to_str(&pd->pd_port_name, old_name);
6131 			fc_wwn_to_str(&pwwn, new_name);
6132 
6133 			FP_TRACE(FP_NHEAD1(9, 0),
6134 			    "fp_plogi_intr: PWWN of a device with D_ID=%x "
6135 			    "changed. New PWWN = %s, OLD PWWN = %s ; tmp_pd:%p "
6136 			    "pd:%p new_wwn_pd:%p, cmd_ulp_pkt:%p, bailout:0x%x",
6137 			    d_id, new_name, old_name, tmp_pd, pd, new_wwn_pd,
6138 			    cmd->cmd_ulp_pkt, bailout);
6139 
6140 			FP_TRACE(FP_NHEAD2(9, 0),
6141 			    "PWWN of a device with D_ID=%x changed."
6142 			    " New PWWN = %s, OLD PWWN = %s", d_id,
6143 			    new_name, old_name);
6144 
6145 			if (cmd->cmd_ulp_pkt && !bailout) {
6146 				fc_remote_node_t	*rnodep;
6147 				fc_portmap_t	*changelist;
6148 				fc_portmap_t	*listptr;
6149 				int		len = 1;
6150 						/* # entries in changelist */
6151 
6152 				fctl_delist_pwwn_table(port, pd);
6153 
6154 				/*
6155 				 * Lets now check if there already is a pd with
6156 				 * this new WWN in the table. If so, we'll mark
6157 				 * it as invalid
6158 				 */
6159 
6160 				if (new_wwn_pd) {
6161 					/*
6162 					 * There is another pd with in the pwwn
6163 					 * table with the same WWN that we got
6164 					 * in the PLOGI payload. We have to get
6165 					 * it out of the pwwn table, update the
6166 					 * pd's state (fp_fillout_old_map does
6167 					 * this for us) and add it to the
6168 					 * changelist that goes up to ULPs.
6169 					 *
6170 					 * len is length of changelist and so
6171 					 * increment it.
6172 					 */
6173 					len++;
6174 
6175 					if (tmp_pd != pd) {
6176 						/*
6177 						 * Odd case where pwwn and did
6178 						 * tables are out of sync but
6179 						 * we will handle that too. See
6180 						 * more comments below.
6181 						 *
6182 						 * One more device that ULPs
6183 						 * should know about and so len
6184 						 * gets incremented again.
6185 						 */
6186 						len++;
6187 					}
6188 
6189 					listptr = changelist = kmem_zalloc(len *
6190 					    sizeof (*changelist), KM_SLEEP);
6191 
6192 					mutex_enter(&new_wwn_pd->pd_mutex);
6193 					rnodep = new_wwn_pd->pd_remote_nodep;
6194 					mutex_exit(&new_wwn_pd->pd_mutex);
6195 
6196 					/*
6197 					 * Hold the fd_mutex since
6198 					 * fctl_copy_portmap_held expects it.
6199 					 * Preserve lock hierarchy by grabbing
6200 					 * fd_mutex before pd_mutex
6201 					 */
6202 					if (rnodep) {
6203 						mutex_enter(&rnodep->fd_mutex);
6204 					}
6205 					mutex_enter(&new_wwn_pd->pd_mutex);
6206 					fp_fillout_old_map_held(listptr++,
6207 					    new_wwn_pd, 0);
6208 					mutex_exit(&new_wwn_pd->pd_mutex);
6209 					if (rnodep) {
6210 						mutex_exit(&rnodep->fd_mutex);
6211 					}
6212 
6213 					/*
6214 					 * Safety check :
6215 					 * Lets ensure that the pwwn and did
6216 					 * tables are in sync. Ideally, we
6217 					 * should not find that these two pd's
6218 					 * are different.
6219 					 */
6220 					if (tmp_pd != pd) {
6221 						mutex_enter(&tmp_pd->pd_mutex);
6222 						rnodep =
6223 						    tmp_pd->pd_remote_nodep;
6224 						mutex_exit(&tmp_pd->pd_mutex);
6225 
6226 						/* As above grab fd_mutex */
6227 						if (rnodep) {
6228 							mutex_enter(&rnodep->
6229 							    fd_mutex);
6230 						}
6231 						mutex_enter(&tmp_pd->pd_mutex);
6232 
6233 						fp_fillout_old_map_held(
6234 						    listptr++, tmp_pd, 0);
6235 
6236 						mutex_exit(&tmp_pd->pd_mutex);
6237 						if (rnodep) {
6238 							mutex_exit(&rnodep->
6239 							    fd_mutex);
6240 						}
6241 
6242 						/*
6243 						 * Now add "pd" (not tmp_pd)
6244 						 * to fp_did_table to sync it up
6245 						 * with fp_pwwn_table
6246 						 *
6247 						 * pd->pd_mutex is already held
6248 						 * at this point
6249 						 */
6250 						fctl_enlist_did_table(port, pd);
6251 					}
6252 				} else {
6253 					listptr = changelist = kmem_zalloc(
6254 					    sizeof (*changelist), KM_SLEEP);
6255 				}
6256 
6257 				ASSERT(changelist != NULL);
6258 
6259 				fp_fillout_changed_map(listptr, pd, &d_id,
6260 					&pwwn);
6261 				fctl_enlist_pwwn_table(port, pd);
6262 
6263 				mutex_exit(&pd->pd_mutex);
6264 				mutex_exit(&port->fp_mutex);
6265 
6266 				fp_iodone(cmd);
6267 
6268 				(void) fp_ulp_devc_cb(port, changelist, len,
6269 						len, KM_NOSLEEP, 0);
6270 
6271 				return;
6272 			}
6273 		}
6274 
6275 		if (pd->pd_porttype.port_type == FC_NS_PORT_NL) {
6276 			nl_port = 1;
6277 		}
6278 		if (pd->pd_aux_flags & PD_DISABLE_RELOGIN)
6279 			pd->pd_aux_flags &= ~PD_LOGGED_OUT;
6280 
6281 		mutex_exit(&pd->pd_mutex);
6282 		mutex_exit(&port->fp_mutex);
6283 
6284 		if (tmp_pd == NULL) {
6285 			mutex_enter(&port->fp_mutex);
6286 			mutex_enter(&pd->pd_mutex);
6287 			if (pd->pd_aux_flags & PD_IN_DID_QUEUE) {
6288 				char ww_name[17];
6289 
6290 				fc_wwn_to_str(&pd->pd_port_name, ww_name);
6291 				mutex_exit(&pd->pd_mutex);
6292 				mutex_exit(&port->fp_mutex);
6293 				FP_TRACE(FP_NHEAD2(9, 0),
6294 				    "Possible Duplicate name or address"
6295 				    " identifiers in the PLOGI response"
6296 				    " D_ID=%x, PWWN=%s: Please check the"
6297 				    " configuration", d_id, ww_name);
6298 				fp_iodone(cmd);
6299 				return;
6300 			}
6301 			fctl_enlist_did_table(port, pd);
6302 			pd->pd_aux_flags &= ~PD_LOGGED_OUT;
6303 			mutex_exit(&pd->pd_mutex);
6304 			mutex_exit(&port->fp_mutex);
6305 		}
6306 	}
6307 	fp_register_login(&pkt->pkt_resp_acc, pd, acc,
6308 	    FC_TRAN_CLASS(pkt->pkt_tran_flags));
6309 
6310 	if (cmd->cmd_ulp_pkt) {
6311 		cmd->cmd_ulp_pkt->pkt_state = pkt->pkt_state;
6312 		cmd->cmd_ulp_pkt->pkt_action = pkt->pkt_action;
6313 		cmd->cmd_ulp_pkt->pkt_expln = pkt->pkt_expln;
6314 		if (cmd->cmd_ulp_pkt->pkt_pd == NULL) {
6315 			if (pd != NULL) {
6316 				FP_TRACE(FP_NHEAD1(9, 0),
6317 				    "fp_plogi_intr;"
6318 				    "ulp_pkt's pd is NULL, get a pd %p",
6319 				    pd);
6320 				mutex_enter(&pd->pd_mutex);
6321 				pd->pd_ref_count++;
6322 				mutex_exit(&pd->pd_mutex);
6323 			}
6324 			cmd->cmd_ulp_pkt->pkt_pd = pd;
6325 		}
6326 		bcopy((caddr_t)&pkt->pkt_resp_fhdr,
6327 		    (caddr_t)&cmd->cmd_ulp_pkt->pkt_resp_fhdr,
6328 		    sizeof (fc_frame_hdr_t));
6329 		bcopy((caddr_t)pkt->pkt_resp,
6330 		    (caddr_t)cmd->cmd_ulp_pkt->pkt_resp,
6331 		    sizeof (la_els_logi_t));
6332 	}
6333 
6334 	mutex_enter(&port->fp_mutex);
6335 	if (port->fp_topology == FC_TOP_PRIVATE_LOOP || nl_port) {
6336 		mutex_enter(&pd->pd_mutex);
6337 
6338 		cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
6339 		cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
6340 		cmd->cmd_retry_count = fp_retry_count;
6341 
6342 		/*
6343 		 * If the fc_remote_port_t pointer is not set in the given
6344 		 * fc_packet_t, then this fc_remote_port_t must have just
6345 		 * been created.  Save the pointer and also increment the
6346 		 * fc_remote_port_t reference count.
6347 		 */
6348 		if (pkt->pkt_pd == NULL) {
6349 			pkt->pkt_pd = pd;
6350 			pd->pd_ref_count++;	/* It's in use! */
6351 		}
6352 
6353 		fp_adisc_init(cmd, cmd->cmd_job);
6354 
6355 		pkt->pkt_cmdlen = sizeof (la_els_adisc_t);
6356 		pkt->pkt_rsplen = sizeof (la_els_adisc_t);
6357 
6358 		mutex_exit(&pd->pd_mutex);
6359 		mutex_exit(&port->fp_mutex);
6360 
6361 		if (fp_sendcmd(port, cmd, port->fp_fca_handle) == FC_SUCCESS) {
6362 			return;
6363 		}
6364 	} else {
6365 		mutex_exit(&port->fp_mutex);
6366 	}
6367 
6368 	if ((cmd->cmd_flags & FP_CMD_PLOGI_RETAIN) == 0) {
6369 		mutex_enter(&port->fp_mutex);
6370 		mutex_enter(&pd->pd_mutex);
6371 
6372 		cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
6373 		cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
6374 		cmd->cmd_retry_count = fp_retry_count;
6375 
6376 		fp_logo_init(pd, cmd, cmd->cmd_job);
6377 
6378 		pkt->pkt_cmdlen = sizeof (la_els_logo_t);
6379 		pkt->pkt_rsplen = FP_PORT_IDENTIFIER_LEN;
6380 
6381 		mutex_exit(&pd->pd_mutex);
6382 		mutex_exit(&port->fp_mutex);
6383 
6384 		if (fp_sendcmd(port, cmd, port->fp_fca_handle) == FC_SUCCESS) {
6385 			return;
6386 		}
6387 
6388 	}
6389 	fp_iodone(cmd);
6390 }
6391 
6392 
6393 /*
6394  * Handle solicited ADISC response
6395  */
6396 static void
6397 fp_adisc_intr(fc_packet_t *pkt)
6398 {
6399 	int			rval;
6400 	int			bailout;
6401 	fp_cmd_t		*cmd;
6402 	fc_local_port_t		*port;
6403 	fc_remote_port_t	*pd;
6404 	la_els_adisc_t 		*acc;
6405 	ls_code_t		resp;
6406 	fc_hardaddr_t		ha;
6407 	fc_portmap_t		*changelist;
6408 	int			initiator, adiscfail = 0;
6409 
6410 	pd = pkt->pkt_pd;
6411 	cmd = pkt->pkt_ulp_private;
6412 	port = cmd->cmd_port;
6413 
6414 #ifndef	__lock_lint
6415 	ASSERT(cmd->cmd_job && cmd->cmd_job->job_counter);
6416 #endif
6417 
6418 	ASSERT(pd != NULL && port != NULL && cmd != NULL);
6419 
6420 	mutex_enter(&port->fp_mutex);
6421 	bailout = ((port->fp_statec_busy ||
6422 	    FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) &&
6423 	    cmd->cmd_ulp_pkt) ? 1 : 0;
6424 	mutex_exit(&port->fp_mutex);
6425 
6426 	if (bailout) {
6427 		fp_iodone(cmd);
6428 		return;
6429 	}
6430 
6431 	if (pkt->pkt_state == FC_PKT_SUCCESS && pkt->pkt_resp_resid == 0) {
6432 		acc = (la_els_adisc_t *)pkt->pkt_resp;
6433 
6434 		ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&resp,
6435 		    (uint8_t *)acc, sizeof (resp), DDI_DEV_AUTOINCR);
6436 
6437 		if (resp.ls_code == LA_ELS_ACC) {
6438 			int	is_private;
6439 
6440 			ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&ha,
6441 			    (uint8_t *)&acc->hard_addr, sizeof (ha),
6442 			    DDI_DEV_AUTOINCR);
6443 
6444 			mutex_enter(&port->fp_mutex);
6445 
6446 			is_private =
6447 			    (port->fp_topology == FC_TOP_PRIVATE_LOOP) ? 1 : 0;
6448 
6449 			mutex_enter(&pd->pd_mutex);
6450 			if ((pd->pd_aux_flags & PD_IN_DID_QUEUE) == 0) {
6451 				fctl_enlist_did_table(port, pd);
6452 			}
6453 			mutex_exit(&pd->pd_mutex);
6454 
6455 			mutex_exit(&port->fp_mutex);
6456 
6457 			mutex_enter(&pd->pd_mutex);
6458 			if (pd->pd_type != PORT_DEVICE_NEW) {
6459 				if (is_private && (pd->pd_hard_addr.hard_addr !=
6460 				    ha.hard_addr)) {
6461 					pd->pd_type = PORT_DEVICE_CHANGED;
6462 				} else {
6463 					pd->pd_type = PORT_DEVICE_NOCHANGE;
6464 				}
6465 			}
6466 
6467 			if (is_private && (ha.hard_addr &&
6468 			    pd->pd_port_id.port_id != ha.hard_addr)) {
6469 				char ww_name[17];
6470 
6471 				fc_wwn_to_str(&pd->pd_port_name, ww_name);
6472 
6473 				fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
6474 				    "NL_Port Identifier %x doesn't match"
6475 				    " with Hard Address %x, Will use Port"
6476 				    " WWN %s", pd->pd_port_id.port_id,
6477 				    ha.hard_addr, ww_name);
6478 
6479 				pd->pd_hard_addr.hard_addr = 0;
6480 			} else {
6481 				pd->pd_hard_addr.hard_addr = ha.hard_addr;
6482 			}
6483 			mutex_exit(&pd->pd_mutex);
6484 		} else {
6485 			if (fp_common_intr(pkt, 0) == FC_SUCCESS) {
6486 				return;
6487 			}
6488 		}
6489 	} else {
6490 		if (fp_common_intr(pkt, 0) == FC_SUCCESS) {
6491 			return;
6492 		}
6493 
6494 		mutex_enter(&port->fp_mutex);
6495 		if (port->fp_statec_busy <= 1) {
6496 			mutex_exit(&port->fp_mutex);
6497 			fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, pkt,
6498 			    "ADISC to %x failed, cmd_flags=%x",
6499 			    pkt->pkt_cmd_fhdr.d_id, cmd->cmd_flags);
6500 			cmd->cmd_flags &= ~FP_CMD_PLOGI_RETAIN;
6501 			adiscfail = 1;
6502 		} else {
6503 			mutex_exit(&port->fp_mutex);
6504 		}
6505 	}
6506 
6507 	if (cmd->cmd_ulp_pkt) {
6508 		cmd->cmd_ulp_pkt->pkt_state = pkt->pkt_state;
6509 		cmd->cmd_ulp_pkt->pkt_action = pkt->pkt_action;
6510 		cmd->cmd_ulp_pkt->pkt_expln = pkt->pkt_expln;
6511 		if (cmd->cmd_ulp_pkt->pkt_pd == NULL) {
6512 			cmd->cmd_ulp_pkt->pkt_pd = pd;
6513 			FP_TRACE(FP_NHEAD1(9, 0),
6514 			    "fp_adisc__intr;"
6515 			    "ulp_pkt's pd is NULL, get a pd %p",
6516 			    pd);
6517 
6518 		}
6519 		bcopy((caddr_t)&pkt->pkt_resp_fhdr,
6520 		    (caddr_t)&cmd->cmd_ulp_pkt->pkt_resp_fhdr,
6521 		    sizeof (fc_frame_hdr_t));
6522 		bcopy((caddr_t)pkt->pkt_resp,
6523 		    (caddr_t)cmd->cmd_ulp_pkt->pkt_resp,
6524 		    sizeof (la_els_logi_t));
6525 	}
6526 
6527 	if ((cmd->cmd_flags & FP_CMD_PLOGI_RETAIN) == 0) {
6528 		FP_TRACE(FP_NHEAD1(9, 0),
6529 		    "fp_adisc_intr: Perform LOGO.cmd_flags=%x, "
6530 		    "fp_retry_count=%x, ulp_pkt=%p",
6531 		    cmd->cmd_flags, fp_retry_count, cmd->cmd_ulp_pkt);
6532 
6533 		mutex_enter(&port->fp_mutex);
6534 		mutex_enter(&pd->pd_mutex);
6535 
6536 		cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
6537 		cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
6538 		cmd->cmd_retry_count = fp_retry_count;
6539 
6540 		fp_logo_init(pd, cmd, cmd->cmd_job);
6541 
6542 		pkt->pkt_cmdlen = sizeof (la_els_logo_t);
6543 		pkt->pkt_rsplen = FP_PORT_IDENTIFIER_LEN;
6544 
6545 		mutex_exit(&pd->pd_mutex);
6546 		mutex_exit(&port->fp_mutex);
6547 
6548 		rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
6549 		if (adiscfail) {
6550 			mutex_enter(&pd->pd_mutex);
6551 			initiator =
6552 			    (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0;
6553 			pd->pd_state = PORT_DEVICE_VALID;
6554 			pd->pd_aux_flags |= PD_LOGGED_OUT;
6555 			if (pd->pd_aux_flags & PD_DISABLE_RELOGIN)
6556 				pd->pd_type = PORT_DEVICE_NEW;
6557 			else
6558 				pd->pd_type = PORT_DEVICE_NOCHANGE;
6559 			mutex_exit(&pd->pd_mutex);
6560 
6561 			changelist =
6562 			    kmem_zalloc(sizeof (*changelist), KM_SLEEP);
6563 
6564 			if (initiator) {
6565 				fp_unregister_login(pd);
6566 				fctl_copy_portmap(changelist, pd);
6567 			} else {
6568 				fp_fillout_old_map(changelist, pd, 0);
6569 			}
6570 
6571 			FP_TRACE(FP_NHEAD1(9, 0),
6572 			    "fp_adisc_intr: Dev change notification "
6573 			    "to ULP port=%p, pd=%p, map_type=%x map_state=%x "
6574 			    "map_flags=%x initiator=%d", port, pd,
6575 			    changelist->map_type, changelist->map_state,
6576 			    changelist->map_flags, initiator);
6577 
6578 			(void) fp_ulp_devc_cb(port, changelist,
6579 			    1, 1, KM_SLEEP, 0);
6580 		}
6581 		if (rval == FC_SUCCESS) {
6582 			return;
6583 		}
6584 	}
6585 	fp_iodone(cmd);
6586 }
6587 
6588 
6589 /*
6590  * Handle solicited LOGO response
6591  */
6592 static void
6593 fp_logo_intr(fc_packet_t *pkt)
6594 {
6595 	ls_code_t	resp;
6596 
6597 	ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&resp,
6598 	    (uint8_t *)pkt->pkt_resp, sizeof (resp), DDI_DEV_AUTOINCR);
6599 
6600 	if (FP_IS_PKT_ERROR(pkt)) {
6601 		(void) fp_common_intr(pkt, 1);
6602 		return;
6603 	}
6604 
6605 	ASSERT(resp.ls_code == LA_ELS_ACC);
6606 	if (resp.ls_code != LA_ELS_ACC) {
6607 		(void) fp_common_intr(pkt, 1);
6608 		return;
6609 	}
6610 
6611 	if (pkt->pkt_pd != NULL) {
6612 		fp_unregister_login(pkt->pkt_pd);
6613 	}
6614 	fp_iodone(pkt->pkt_ulp_private);
6615 }
6616 
6617 
6618 /*
6619  * Handle solicited RNID response
6620  */
6621 static void
6622 fp_rnid_intr(fc_packet_t *pkt)
6623 {
6624 	ls_code_t		resp;
6625 	job_request_t		*job;
6626 	fp_cmd_t		*cmd;
6627 	la_els_rnid_acc_t	*acc;
6628 
6629 	ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&resp,
6630 	    (uint8_t *)pkt->pkt_resp, sizeof (resp), DDI_DEV_AUTOINCR);
6631 
6632 	cmd = pkt->pkt_ulp_private;
6633 	job = cmd->cmd_job;
6634 	ASSERT(job->job_private != NULL);
6635 
6636 	/* If failure or LS_RJT then retry the packet, if needed */
6637 	if (pkt->pkt_state != FC_PKT_SUCCESS || resp.ls_code != LA_ELS_ACC) {
6638 		(void) fp_common_intr(pkt, 1);
6639 		return;
6640 	}
6641 
6642 	/* Save node_id memory allocated in ioctl code */
6643 	acc = (la_els_rnid_acc_t *)pkt->pkt_resp;
6644 
6645 	ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)job->job_private,
6646 	    (uint8_t *)acc, sizeof (la_els_rnid_acc_t), DDI_DEV_AUTOINCR);
6647 
6648 	/* wakeup the ioctl thread and free the pkt */
6649 	fp_iodone(cmd);
6650 }
6651 
6652 
6653 /*
6654  * Handle solicited RLS response
6655  */
6656 static void
6657 fp_rls_intr(fc_packet_t *pkt)
6658 {
6659 	ls_code_t		resp;
6660 	job_request_t		*job;
6661 	fp_cmd_t		*cmd;
6662 	la_els_rls_acc_t	*acc;
6663 
6664 	ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&resp,
6665 	    (uint8_t *)pkt->pkt_resp, sizeof (resp), DDI_DEV_AUTOINCR);
6666 
6667 	cmd = pkt->pkt_ulp_private;
6668 	job = cmd->cmd_job;
6669 	ASSERT(job->job_private != NULL);
6670 
6671 	/* If failure or LS_RJT then retry the packet, if needed */
6672 	if (FP_IS_PKT_ERROR(pkt) || resp.ls_code != LA_ELS_ACC) {
6673 		(void) fp_common_intr(pkt, 1);
6674 		return;
6675 	}
6676 
6677 	/* Save link error status block in memory allocated in ioctl code */
6678 	acc = (la_els_rls_acc_t *)pkt->pkt_resp;
6679 
6680 	ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)job->job_private,
6681 	    (uint8_t *)&acc->rls_link_params, sizeof (fc_rls_acc_t),
6682 	    DDI_DEV_AUTOINCR);
6683 
6684 	/* wakeup the ioctl thread and free the pkt */
6685 	fp_iodone(cmd);
6686 }
6687 
6688 
6689 /*
6690  * A solicited command completion interrupt (mostly for commands
6691  * that require almost no post processing such as SCR ELS)
6692  */
6693 static void
6694 fp_intr(fc_packet_t *pkt)
6695 {
6696 	if (FP_IS_PKT_ERROR(pkt)) {
6697 		(void) fp_common_intr(pkt, 1);
6698 		return;
6699 	}
6700 	fp_iodone(pkt->pkt_ulp_private);
6701 }
6702 
6703 
6704 /*
6705  * Handle the underlying port's state change
6706  */
6707 static void
6708 fp_statec_cb(opaque_t port_handle, uint32_t state)
6709 {
6710 	fc_local_port_t *port = port_handle;
6711 	job_request_t 	*job;
6712 
6713 	/*
6714 	 * If it is not possible to process the callbacks
6715 	 * just drop the callback on the floor; Don't bother
6716 	 * to do something that isn't safe at this time
6717 	 */
6718 	mutex_enter(&port->fp_mutex);
6719 	if ((port->fp_soft_state &
6720 	    (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN)) ||
6721 	    (FC_PORT_STATE_MASK(port->fp_state) == FC_PORT_STATE_MASK(state))) {
6722 		mutex_exit(&port->fp_mutex);
6723 		return;
6724 	}
6725 
6726 	if (port->fp_statec_busy == 0) {
6727 		port->fp_soft_state |= FP_SOFT_IN_STATEC_CB;
6728 #ifdef	DEBUG
6729 	} else {
6730 		ASSERT(port->fp_soft_state & FP_SOFT_IN_STATEC_CB);
6731 #endif
6732 	}
6733 
6734 	port->fp_statec_busy++;
6735 
6736 	/*
6737 	 * For now, force the trusted method of device authentication (by
6738 	 * PLOGI) when LIPs do not involve OFFLINE to ONLINE transition.
6739 	 */
6740 	if (FC_PORT_STATE_MASK(state) == FC_STATE_LIP ||
6741 	    FC_PORT_STATE_MASK(state) == FC_STATE_LIP_LBIT_SET) {
6742 		state = FC_PORT_SPEED_MASK(port->fp_state) | FC_STATE_LOOP;
6743 		fp_port_offline(port, 0);
6744 	}
6745 	mutex_exit(&port->fp_mutex);
6746 
6747 	switch (FC_PORT_STATE_MASK(state)) {
6748 	case FC_STATE_OFFLINE:
6749 		job = fctl_alloc_job(JOB_PORT_OFFLINE,
6750 		    JOB_TYPE_FCTL_ASYNC, NULL, NULL, KM_NOSLEEP);
6751 		if (job == NULL) {
6752 			fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
6753 			    " fp_statec_cb() couldn't submit a job "
6754 			    " to the thread: failing..");
6755 			mutex_enter(&port->fp_mutex);
6756 			if (--port->fp_statec_busy == 0) {
6757 				port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
6758 			}
6759 			mutex_exit(&port->fp_mutex);
6760 			return;
6761 		}
6762 		mutex_enter(&port->fp_mutex);
6763 		/*
6764 		 * Zero out this field so that we do not retain
6765 		 * the fabric name as its no longer valid
6766 		 */
6767 		bzero(&port->fp_fabric_name, sizeof (la_wwn_t));
6768 		port->fp_state = state;
6769 		mutex_exit(&port->fp_mutex);
6770 
6771 		fctl_enque_job(port, job);
6772 		break;
6773 
6774 	case FC_STATE_ONLINE:
6775 	case FC_STATE_LOOP:
6776 		mutex_enter(&port->fp_mutex);
6777 		port->fp_state = state;
6778 
6779 		if (port->fp_offline_tid) {
6780 			timeout_id_t tid;
6781 
6782 			tid = port->fp_offline_tid;
6783 			port->fp_offline_tid = NULL;
6784 			mutex_exit(&port->fp_mutex);
6785 			(void) untimeout(tid);
6786 		} else {
6787 			mutex_exit(&port->fp_mutex);
6788 		}
6789 
6790 		job = fctl_alloc_job(JOB_PORT_ONLINE,
6791 		    JOB_TYPE_FCTL_ASYNC, NULL, NULL, KM_NOSLEEP);
6792 		if (job == NULL) {
6793 			fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
6794 			    "fp_statec_cb() couldn't submit a job "
6795 			    "to the thread: failing..");
6796 
6797 			mutex_enter(&port->fp_mutex);
6798 			if (--port->fp_statec_busy == 0) {
6799 				port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
6800 			}
6801 			mutex_exit(&port->fp_mutex);
6802 			return;
6803 		}
6804 		fctl_enque_job(port, job);
6805 		break;
6806 
6807 	case FC_STATE_RESET_REQUESTED:
6808 		mutex_enter(&port->fp_mutex);
6809 		port->fp_state = FC_STATE_OFFLINE;
6810 		port->fp_soft_state |= FP_SOFT_IN_FCA_RESET;
6811 		mutex_exit(&port->fp_mutex);
6812 		/* FALLTHROUGH */
6813 
6814 	case FC_STATE_RESET:
6815 		job = fctl_alloc_job(JOB_ULP_NOTIFY,
6816 		    JOB_TYPE_FCTL_ASYNC, NULL, NULL, KM_NOSLEEP);
6817 		if (job == NULL) {
6818 			fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
6819 			    "fp_statec_cb() couldn't submit a job"
6820 			    " to the thread: failing..");
6821 
6822 			mutex_enter(&port->fp_mutex);
6823 			if (--port->fp_statec_busy == 0) {
6824 				port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
6825 			}
6826 			mutex_exit(&port->fp_mutex);
6827 			return;
6828 		}
6829 
6830 		/* squeeze into some field in the job structure */
6831 		job->job_ulp_listlen = FC_PORT_STATE_MASK(state);
6832 		fctl_enque_job(port, job);
6833 		break;
6834 
6835 	case FC_STATE_TARGET_PORT_RESET:
6836 		(void) fp_ulp_notify(port, state, KM_NOSLEEP);
6837 		/* FALLTHROUGH */
6838 
6839 	case FC_STATE_NAMESERVICE:
6840 		/* FALLTHROUGH */
6841 
6842 	default:
6843 		mutex_enter(&port->fp_mutex);
6844 		if (--port->fp_statec_busy == 0) {
6845 			port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
6846 		}
6847 		mutex_exit(&port->fp_mutex);
6848 		break;
6849 	}
6850 }
6851 
6852 
6853 /*
6854  * Register with the Name Server for RSCNs
6855  */
6856 static int
6857 fp_ns_scr(fc_local_port_t *port, job_request_t *job, uchar_t scr_func,
6858     int sleep)
6859 {
6860 	uint32_t	s_id;
6861 	uchar_t		class;
6862 	fc_scr_req_t 	payload;
6863 	fp_cmd_t 	*cmd;
6864 	fc_packet_t 	*pkt;
6865 
6866 	mutex_enter(&port->fp_mutex);
6867 	s_id = port->fp_port_id.port_id;
6868 	class = port->fp_ns_login_class;
6869 	mutex_exit(&port->fp_mutex);
6870 
6871 	cmd = fp_alloc_pkt(port, sizeof (fc_scr_req_t),
6872 	    sizeof (fc_scr_resp_t), sleep, NULL);
6873 	if (cmd == NULL) {
6874 		return (FC_NOMEM);
6875 	}
6876 
6877 	cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class;
6878 	cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
6879 	cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
6880 	cmd->cmd_retry_count = fp_retry_count;
6881 	cmd->cmd_ulp_pkt = NULL;
6882 
6883 	pkt = &cmd->cmd_pkt;
6884 	cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
6885 
6886 	fp_els_init(cmd, s_id, 0xFFFFFD, fp_intr, job);
6887 
6888 	payload.ls_code.ls_code = LA_ELS_SCR;
6889 	payload.ls_code.mbz = 0;
6890 	payload.scr_rsvd = 0;
6891 	payload.scr_func = scr_func;
6892 
6893 	ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&payload,
6894 	    (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
6895 
6896 	job->job_counter = 1;
6897 
6898 	if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
6899 		fp_iodone(cmd);
6900 	}
6901 
6902 	return (FC_SUCCESS);
6903 }
6904 
6905 
6906 /*
6907  * There are basically two methods to determine the total number of
6908  * devices out in the NS database; Reading the details of the two
6909  * methods described below, it shouldn't be hard to identify which
6910  * of the two methods is better.
6911  *
6912  *	Method 1.
6913  *		Iteratively issue GANs until all ports identifiers are walked
6914  *
6915  *	Method 2.
6916  *		Issue GID_PT (get port Identifiers) with Maximum residual
6917  *		field in the request CT HEADER set to accommodate only the
6918  *		CT HEADER in the response frame. And if FC-GS2 has been
6919  *		carefully read, the NS here has a chance to FS_ACC the
6920  *		request and indicate the residual size in the FS_ACC.
6921  *
6922  *	Method 2 is wonderful, although it's not mandatory for the NS
6923  *	to update the Maximum/Residual Field as can be seen in 4.3.1.6
6924  *	(note with particular care the use of the auxiliary verb 'may')
6925  *
6926  */
6927 static int
6928 fp_ns_get_devcount(fc_local_port_t *port, job_request_t *job, int create,
6929     int sleep)
6930 {
6931 	int		flags;
6932 	int		rval;
6933 	uint32_t	src_id;
6934 	fctl_ns_req_t	*ns_cmd;
6935 
6936 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
6937 
6938 	mutex_enter(&port->fp_mutex);
6939 	src_id = port->fp_port_id.port_id;
6940 	mutex_exit(&port->fp_mutex);
6941 
6942 	if (!create && (port->fp_options & FP_NS_SMART_COUNT)) {
6943 		ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pt_t),
6944 		    sizeof (ns_resp_gid_pt_t), 0,
6945 		    (FCTL_NS_GET_DEV_COUNT | FCTL_NS_NO_DATA_BUF), sleep);
6946 
6947 		if (ns_cmd == NULL) {
6948 			return (FC_NOMEM);
6949 		}
6950 
6951 		ns_cmd->ns_cmd_code = NS_GID_PT;
6952 		((ns_req_gid_pt_t *)(ns_cmd->ns_cmd_buf))->port_type.port_type
6953 		    = FC_NS_PORT_NX;	/* All port types */
6954 		((ns_req_gid_pt_t *)(ns_cmd->ns_cmd_buf))->port_type.rsvd = 0;
6955 
6956 	} else {
6957 		uint32_t ns_flags;
6958 
6959 		ns_flags = FCTL_NS_GET_DEV_COUNT | FCTL_NS_NO_DATA_BUF;
6960 		if (create) {
6961 			ns_flags |= FCTL_NS_CREATE_DEVICE;
6962 		}
6963 		ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t),
6964 		    sizeof (ns_resp_gan_t), sizeof (int), ns_flags, sleep);
6965 
6966 		if (ns_cmd == NULL) {
6967 			return (FC_NOMEM);
6968 		}
6969 		ns_cmd->ns_gan_index = 0;
6970 		ns_cmd->ns_gan_sid = FCTL_GAN_START_ID;
6971 		ns_cmd->ns_cmd_code = NS_GA_NXT;
6972 		ns_cmd->ns_gan_max = 0xFFFF;
6973 
6974 		((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.port_id = src_id;
6975 		((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.priv_lilp_posit = 0;
6976 	}
6977 
6978 	flags = job->job_flags;
6979 	job->job_flags &= ~JOB_TYPE_FP_ASYNC;
6980 	job->job_counter = 1;
6981 
6982 	rval = fp_ns_query(port, ns_cmd, job, 1, sleep);
6983 	job->job_flags = flags;
6984 
6985 	if (!create && (port->fp_options & FP_NS_SMART_COUNT)) {
6986 		uint16_t max_resid;
6987 
6988 		/*
6989 		 * Revert to scanning the NS if NS_GID_PT isn't
6990 		 * helping us figure out total number of devices.
6991 		 */
6992 		if (job->job_result != FC_SUCCESS ||
6993 		    ns_cmd->ns_resp_hdr.ct_cmdrsp != FS_ACC_IU) {
6994 			mutex_enter(&port->fp_mutex);
6995 			port->fp_options &= ~FP_NS_SMART_COUNT;
6996 			mutex_exit(&port->fp_mutex);
6997 
6998 			fctl_free_ns_cmd(ns_cmd);
6999 			return (fp_ns_get_devcount(port, job, create, sleep));
7000 		}
7001 
7002 		mutex_enter(&port->fp_mutex);
7003 		port->fp_total_devices = 1;
7004 		max_resid = ns_cmd->ns_resp_hdr.ct_aiusize;
7005 		if (max_resid) {
7006 			/*
7007 			 * Since port identifier is 4 bytes and max_resid
7008 			 * is also in WORDS, max_resid simply indicates
7009 			 * the total number of port identifiers	not
7010 			 * transferred
7011 			 */
7012 			port->fp_total_devices += max_resid;
7013 		}
7014 		mutex_exit(&port->fp_mutex);
7015 	}
7016 	mutex_enter(&port->fp_mutex);
7017 	port->fp_total_devices = *((int *)ns_cmd->ns_data_buf);
7018 	mutex_exit(&port->fp_mutex);
7019 	fctl_free_ns_cmd(ns_cmd);
7020 
7021 	return (rval);
7022 }
7023 
7024 /*
7025  * One heck of a function to serve userland.
7026  */
7027 static int
7028 fp_fciocmd(fc_local_port_t *port, intptr_t data, int mode, fcio_t *fcio)
7029 {
7030 	int 		rval = 0;
7031 	int		jcode;
7032 	uint32_t	ret;
7033 	uchar_t		open_flag;
7034 	fcio_t		*kfcio;
7035 	job_request_t 	*job;
7036 	boolean_t	use32 = B_FALSE;
7037 
7038 #ifdef _MULTI_DATAMODEL
7039 	switch (ddi_model_convert_from(mode & FMODELS)) {
7040 	case DDI_MODEL_ILP32:
7041 		use32 = B_TRUE;
7042 		break;
7043 
7044 	case DDI_MODEL_NONE:
7045 	default:
7046 		break;
7047 	}
7048 #endif
7049 
7050 	mutex_enter(&port->fp_mutex);
7051 	if (port->fp_soft_state & (FP_SOFT_IN_STATEC_CB |
7052 	    FP_SOFT_IN_UNSOL_CB)) {
7053 		fcio->fcio_errno = FC_STATEC_BUSY;
7054 		mutex_exit(&port->fp_mutex);
7055 		rval = EAGAIN;
7056 		if (fp_fcio_copyout(fcio, data, mode)) {
7057 			rval = EFAULT;
7058 		}
7059 		return (rval);
7060 	}
7061 	open_flag = port->fp_flag;
7062 	mutex_exit(&port->fp_mutex);
7063 
7064 	if (fp_check_perms(open_flag, fcio->fcio_cmd) != FC_SUCCESS) {
7065 		fcio->fcio_errno = FC_FAILURE;
7066 		rval = EACCES;
7067 		if (fp_fcio_copyout(fcio, data, mode)) {
7068 			rval = EFAULT;
7069 		}
7070 		return (rval);
7071 	}
7072 
7073 	/*
7074 	 * If an exclusive open was demanded during open, don't let
7075 	 * either innocuous or devil threads to share the file
7076 	 * descriptor and fire down exclusive access commands
7077 	 */
7078 	mutex_enter(&port->fp_mutex);
7079 	if (port->fp_flag & FP_EXCL) {
7080 		if (port->fp_flag & FP_EXCL_BUSY) {
7081 			mutex_exit(&port->fp_mutex);
7082 			fcio->fcio_errno = FC_FAILURE;
7083 			return (EBUSY);
7084 		}
7085 		port->fp_flag |= FP_EXCL_BUSY;
7086 	}
7087 	mutex_exit(&port->fp_mutex);
7088 
7089 	switch (fcio->fcio_cmd) {
7090 	case FCIO_GET_HOST_PARAMS: {
7091 		fc_port_dev_t	*val;
7092 		fc_port_dev32_t	*val32;
7093 		int		index;
7094 		int		lilp_device_count;
7095 		fc_lilpmap_t	*lilp_map;
7096 		uchar_t		*alpa_list;
7097 
7098 		if (use32 == B_TRUE) {
7099 			if (fcio->fcio_olen != sizeof (*val32) ||
7100 			    fcio->fcio_xfer != FCIO_XFER_READ) {
7101 				rval = EINVAL;
7102 				break;
7103 			}
7104 		} else {
7105 			if (fcio->fcio_olen != sizeof (*val) ||
7106 			    fcio->fcio_xfer != FCIO_XFER_READ) {
7107 				rval = EINVAL;
7108 				break;
7109 			}
7110 		}
7111 
7112 		val = kmem_zalloc(sizeof (*val), KM_SLEEP);
7113 
7114 		mutex_enter(&port->fp_mutex);
7115 		val->dev_did = port->fp_port_id;
7116 		val->dev_hard_addr = port->fp_hard_addr;
7117 		val->dev_pwwn = port->fp_service_params.nport_ww_name;
7118 		val->dev_nwwn = port->fp_service_params.node_ww_name;
7119 		val->dev_state = port->fp_state;
7120 
7121 		lilp_map = &port->fp_lilp_map;
7122 		alpa_list = &lilp_map->lilp_alpalist[0];
7123 		lilp_device_count = lilp_map->lilp_length;
7124 		for (index = 0; index < lilp_device_count; index++) {
7125 			uint32_t d_id;
7126 
7127 			d_id = alpa_list[index];
7128 			if (d_id == port->fp_port_id.port_id) {
7129 				break;
7130 			}
7131 		}
7132 		val->dev_did.priv_lilp_posit = (uint8_t)(index & 0xff);
7133 
7134 		bcopy(port->fp_fc4_types, val->dev_type,
7135 		    sizeof (port->fp_fc4_types));
7136 		mutex_exit(&port->fp_mutex);
7137 
7138 		if (use32 == B_TRUE) {
7139 			val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP);
7140 
7141 			val32->dev_did = val->dev_did;
7142 			val32->dev_hard_addr = val->dev_hard_addr;
7143 			val32->dev_pwwn = val->dev_pwwn;
7144 			val32->dev_nwwn = val->dev_nwwn;
7145 			val32->dev_state = val->dev_state;
7146 			val32->dev_did.priv_lilp_posit =
7147 			    val->dev_did.priv_lilp_posit;
7148 
7149 			bcopy(val->dev_type, val32->dev_type,
7150 			    sizeof (port->fp_fc4_types));
7151 
7152 			if (fp_copyout((void *)val32, (void *)fcio->fcio_obuf,
7153 			    fcio->fcio_olen, mode) == 0) {
7154 				if (fp_fcio_copyout(fcio, data, mode)) {
7155 					rval = EFAULT;
7156 				}
7157 			} else {
7158 				rval = EFAULT;
7159 			}
7160 
7161 			kmem_free(val32, sizeof (*val32));
7162 		} else {
7163 			if (fp_copyout((void *)val, (void *)fcio->fcio_obuf,
7164 			    fcio->fcio_olen, mode) == 0) {
7165 				if (fp_fcio_copyout(fcio, data, mode)) {
7166 					rval = EFAULT;
7167 				}
7168 			} else {
7169 				rval = EFAULT;
7170 			}
7171 		}
7172 
7173 		/* need to free "val" here */
7174 		kmem_free(val, sizeof (*val));
7175 		break;
7176 	}
7177 
7178 	case FCIO_GET_OTHER_ADAPTER_PORTS: {
7179 		uint32_t    index;
7180 		char	    *tmpPath;
7181 		fc_local_port_t   *tmpPort;
7182 
7183 		if (fcio->fcio_olen < MAXPATHLEN ||
7184 		    fcio->fcio_ilen != sizeof (uint32_t)) {
7185 			rval = EINVAL;
7186 			break;
7187 		}
7188 		if (ddi_copyin(fcio->fcio_ibuf, &index, sizeof (index), mode)) {
7189 			rval = EFAULT;
7190 			break;
7191 		}
7192 
7193 		tmpPort = fctl_get_adapter_port_by_index(port, index);
7194 		if (tmpPort == NULL) {
7195 			FP_TRACE(FP_NHEAD1(9, 0),
7196 			    "User supplied index out of range");
7197 			fcio->fcio_errno = FC_BADPORT;
7198 			rval = EFAULT;
7199 			if (fp_fcio_copyout(fcio, data, mode)) {
7200 				rval = EFAULT;
7201 			}
7202 			break;
7203 		}
7204 
7205 		tmpPath = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
7206 		(void) ddi_pathname(tmpPort->fp_port_dip, tmpPath);
7207 		if (fp_copyout((void *)tmpPath, (void *)fcio->fcio_obuf,
7208 		    MAXPATHLEN, mode) == 0) {
7209 			if (fp_fcio_copyout(fcio, data, mode)) {
7210 				rval = EFAULT;
7211 			}
7212 		} else {
7213 			rval = EFAULT;
7214 		}
7215 		kmem_free(tmpPath, MAXPATHLEN);
7216 		break;
7217 	}
7218 
7219 	case FCIO_NPIV_GET_ADAPTER_ATTRIBUTES:
7220 	case FCIO_GET_ADAPTER_ATTRIBUTES: {
7221 		fc_hba_adapter_attributes_t	*val;
7222 		fc_hba_adapter_attributes32_t	*val32;
7223 
7224 		if (use32 == B_TRUE) {
7225 			if (fcio->fcio_olen < sizeof (*val32) ||
7226 			    fcio->fcio_xfer != FCIO_XFER_READ) {
7227 				rval = EINVAL;
7228 				break;
7229 			}
7230 		} else {
7231 			if (fcio->fcio_olen < sizeof (*val) ||
7232 			    fcio->fcio_xfer != FCIO_XFER_READ) {
7233 				rval = EINVAL;
7234 				break;
7235 			}
7236 		}
7237 
7238 		val = kmem_zalloc(sizeof (*val), KM_SLEEP);
7239 		val->version = FC_HBA_ADAPTER_ATTRIBUTES_VERSION;
7240 		mutex_enter(&port->fp_mutex);
7241 		bcopy(port->fp_hba_port_attrs.manufacturer,
7242 			val->Manufacturer,
7243 			sizeof (val->Manufacturer));
7244 		bcopy(port->fp_hba_port_attrs.serial_number,
7245 			val->SerialNumber,
7246 			sizeof (val->SerialNumber));
7247 		bcopy(port->fp_hba_port_attrs.model,
7248 			val->Model,
7249 			sizeof (val->Model));
7250 		bcopy(port->fp_hba_port_attrs.model_description,
7251 			val->ModelDescription,
7252 			sizeof (val->ModelDescription));
7253 		bcopy(port->fp_sym_node_name, val->NodeSymbolicName,
7254 		    sizeof (val->NodeSymbolicName));
7255 		bcopy(port->fp_hba_port_attrs.hardware_version,
7256 			val->HardwareVersion,
7257 			sizeof (val->HardwareVersion));
7258 		bcopy(port->fp_hba_port_attrs.option_rom_version,
7259 			val->OptionROMVersion,
7260 			sizeof (val->OptionROMVersion));
7261 		bcopy(port->fp_hba_port_attrs.firmware_version,
7262 			val->FirmwareVersion,
7263 			sizeof (val->FirmwareVersion));
7264 		val->VendorSpecificID =
7265 			port->fp_hba_port_attrs.vendor_specific_id;
7266 		bcopy(&port->fp_service_params.node_ww_name.raw_wwn,
7267 			&val->NodeWWN.raw_wwn,
7268 			sizeof (val->NodeWWN.raw_wwn));
7269 
7270 
7271 		bcopy(port->fp_hba_port_attrs.driver_name,
7272 			val->DriverName,
7273 			sizeof (val->DriverName));
7274 		bcopy(port->fp_hba_port_attrs.driver_version,
7275 			val->DriverVersion,
7276 			sizeof (val->DriverVersion));
7277 		mutex_exit(&port->fp_mutex);
7278 
7279 		if (fcio->fcio_cmd == FCIO_GET_ADAPTER_ATTRIBUTES) {
7280 			val->NumberOfPorts = fctl_count_fru_ports(port, 0);
7281 		} else {
7282 			val->NumberOfPorts = fctl_count_fru_ports(port, 1);
7283 		}
7284 
7285 		if (use32 == B_TRUE) {
7286 			val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP);
7287 			val32->version = val->version;
7288 			bcopy(val->Manufacturer, val32->Manufacturer,
7289 				sizeof (val->Manufacturer));
7290 			bcopy(val->SerialNumber, val32->SerialNumber,
7291 				sizeof (val->SerialNumber));
7292 			bcopy(val->Model, val32->Model,
7293 				sizeof (val->Model));
7294 			bcopy(val->ModelDescription, val32->ModelDescription,
7295 				sizeof (val->ModelDescription));
7296 			bcopy(val->NodeSymbolicName, val32->NodeSymbolicName,
7297 			    sizeof (val->NodeSymbolicName));
7298 			bcopy(val->HardwareVersion, val32->HardwareVersion,
7299 				sizeof (val->HardwareVersion));
7300 			bcopy(val->OptionROMVersion, val32->OptionROMVersion,
7301 				sizeof (val->OptionROMVersion));
7302 			bcopy(val->FirmwareVersion, val32->FirmwareVersion,
7303 				sizeof (val->FirmwareVersion));
7304 			val32->VendorSpecificID = val->VendorSpecificID;
7305 			bcopy(&val->NodeWWN.raw_wwn, &val32->NodeWWN.raw_wwn,
7306 				sizeof (val->NodeWWN.raw_wwn));
7307 			bcopy(val->DriverName, val32->DriverName,
7308 				sizeof (val->DriverName));
7309 			bcopy(val->DriverVersion, val32->DriverVersion,
7310 				sizeof (val->DriverVersion));
7311 
7312 			val32->NumberOfPorts = val->NumberOfPorts;
7313 
7314 			if (fp_copyout((void *)val32, (void *)fcio->fcio_obuf,
7315 			    fcio->fcio_olen, mode) == 0) {
7316 				if (fp_fcio_copyout(fcio, data, mode)) {
7317 					rval = EFAULT;
7318 				}
7319 			} else {
7320 				rval = EFAULT;
7321 			}
7322 
7323 			kmem_free(val32, sizeof (*val32));
7324 		} else {
7325 			if (fp_copyout((void *)val, (void *)fcio->fcio_obuf,
7326 			    fcio->fcio_olen, mode) == 0) {
7327 				if (fp_fcio_copyout(fcio, data, mode)) {
7328 					rval = EFAULT;
7329 				}
7330 			} else {
7331 				rval = EFAULT;
7332 			}
7333 		}
7334 
7335 		kmem_free(val, sizeof (*val));
7336 		break;
7337 	}
7338 
7339 	case FCIO_GET_NPIV_ATTRIBUTES: {
7340 		fc_hba_npiv_attributes_t *attrs;
7341 
7342 		attrs = kmem_zalloc(sizeof (*attrs), KM_SLEEP);
7343 		mutex_enter(&port->fp_mutex);
7344 		bcopy(&port->fp_service_params.node_ww_name.raw_wwn,
7345 		    &attrs->NodeWWN.raw_wwn,
7346 		    sizeof (attrs->NodeWWN.raw_wwn));
7347 		bcopy(&port->fp_service_params.nport_ww_name.raw_wwn,
7348 		    &attrs->PortWWN.raw_wwn,
7349 		    sizeof (attrs->PortWWN.raw_wwn));
7350 		mutex_exit(&port->fp_mutex);
7351 		if (fp_copyout((void *)attrs, (void *)fcio->fcio_obuf,
7352 		    fcio->fcio_olen, mode) == 0) {
7353 			if (fp_fcio_copyout(fcio, data, mode)) {
7354 				rval = EFAULT;
7355 			}
7356 		} else {
7357 			rval = EFAULT;
7358 		}
7359 		kmem_free(attrs, sizeof (*attrs));
7360 		break;
7361 	}
7362 
7363 	case FCIO_DELETE_NPIV_PORT: {
7364 		fc_local_port_t *tmpport;
7365 		char	ww_pname[17];
7366 		la_wwn_t	vwwn[1];
7367 
7368 		FP_TRACE(FP_NHEAD1(1, 0), "Delete NPIV Port");
7369 		if (ddi_copyin(fcio->fcio_ibuf,
7370 		    &vwwn, sizeof (la_wwn_t), mode)) {
7371 			rval = EFAULT;
7372 			break;
7373 		}
7374 
7375 		fc_wwn_to_str(&vwwn[0], ww_pname);
7376 		FP_TRACE(FP_NHEAD1(3, 0),
7377 		    "Delete NPIV Port %s", ww_pname);
7378 		tmpport = fc_delete_npiv_port(port, &vwwn[0]);
7379 		if (tmpport == NULL) {
7380 			FP_TRACE(FP_NHEAD1(3, 0),
7381 			    "Delete NPIV Port : no found");
7382 			rval = EFAULT;
7383 		} else {
7384 			fc_local_port_t *nextport = tmpport->fp_port_next;
7385 			fc_local_port_t *prevport = tmpport->fp_port_prev;
7386 			int portlen, portindex, ret;
7387 
7388 			portlen = sizeof (portindex);
7389 			ret = ddi_prop_op(DDI_DEV_T_ANY,
7390 			    tmpport->fp_port_dip, PROP_LEN_AND_VAL_BUF,
7391 			    DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "port",
7392 			    (caddr_t)&portindex, &portlen);
7393 			if (ret != DDI_SUCCESS) {
7394 				rval = EFAULT;
7395 				break;
7396 			}
7397 			if (ndi_devi_offline(tmpport->fp_port_dip,
7398 			    NDI_DEVI_REMOVE) != DDI_SUCCESS) {
7399 				FP_TRACE(FP_NHEAD1(1, 0),
7400 				    "Delete NPIV Port failed");
7401 				mutex_enter(&port->fp_mutex);
7402 				tmpport->fp_npiv_state = 0;
7403 				mutex_exit(&port->fp_mutex);
7404 				rval = EFAULT;
7405 			} else {
7406 				mutex_enter(&port->fp_mutex);
7407 				nextport->fp_port_prev = prevport;
7408 				prevport->fp_port_next = nextport;
7409 				if (port == port->fp_port_next) {
7410 					port->fp_port_next =
7411 					    port->fp_port_prev = NULL;
7412 				}
7413 				port->fp_npiv_portnum--;
7414 				FP_TRACE(FP_NHEAD1(3, 0),
7415 				    "Delete NPIV Port %d", portindex);
7416 				port->fp_npiv_portindex[portindex-1] = 0;
7417 				mutex_exit(&port->fp_mutex);
7418 			}
7419 		}
7420 		break;
7421 	}
7422 
7423 	case FCIO_CREATE_NPIV_PORT: {
7424 		char ww_nname[17], ww_pname[17];
7425 		la_npiv_create_entry_t entrybuf;
7426 		uint32_t vportindex = 0;
7427 		int npiv_ret = 0;
7428 		char *portname, *fcaname;
7429 
7430 		portname = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
7431 		(void) ddi_pathname(port->fp_port_dip, portname);
7432 		fcaname = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
7433 		(void) ddi_pathname(port->fp_fca_dip, fcaname);
7434 		FP_TRACE(FP_NHEAD1(1, 0),
7435 		    "Create NPIV port %s %s %s", portname, fcaname,
7436 		    ddi_driver_name(port->fp_fca_dip));
7437 		kmem_free(portname, MAXPATHLEN);
7438 		kmem_free(fcaname, MAXPATHLEN);
7439 		if (ddi_copyin(fcio->fcio_ibuf,
7440 		    &entrybuf, sizeof (la_npiv_create_entry_t), mode)) {
7441 			rval = EFAULT;
7442 			break;
7443 		}
7444 
7445 		fc_wwn_to_str(&entrybuf.VNodeWWN, ww_nname);
7446 		fc_wwn_to_str(&entrybuf.VPortWWN, ww_pname);
7447 		vportindex = entrybuf.vindex;
7448 		FP_TRACE(FP_NHEAD1(3, 0),
7449 		    "Create NPIV Port %s %s %d",
7450 		    ww_nname, ww_pname, vportindex);
7451 
7452 		if (fc_get_npiv_port(port, &entrybuf.VPortWWN)) {
7453 			rval = EFAULT;
7454 			break;
7455 		}
7456 		npiv_ret = fctl_fca_create_npivport(port->fp_fca_dip,
7457 		    port->fp_port_dip, ww_nname, ww_pname, &vportindex);
7458 		if (npiv_ret == NDI_SUCCESS) {
7459 			mutex_enter(&port->fp_mutex);
7460 			port->fp_npiv_portnum++;
7461 			mutex_exit(&port->fp_mutex);
7462 			if (fp_copyout((void *)&vportindex,
7463 			    (void *)fcio->fcio_obuf,
7464 			    fcio->fcio_olen, mode) == 0) {
7465 				if (fp_fcio_copyout(fcio, data, mode)) {
7466 					rval = EFAULT;
7467 				}
7468 			} else {
7469 				rval = EFAULT;
7470 			}
7471 		} else {
7472 			rval = EFAULT;
7473 		}
7474 		FP_TRACE(FP_NHEAD1(3, 0),
7475 		    "Create NPIV Port %d %d", npiv_ret, vportindex);
7476 		break;
7477 	}
7478 
7479 	case FCIO_GET_NPIV_PORT_LIST: {
7480 		fc_hba_npiv_port_list_t *list;
7481 		int count;
7482 
7483 		if ((fcio->fcio_xfer != FCIO_XFER_READ) ||
7484 		    (fcio->fcio_olen == 0) || (fcio->fcio_obuf == 0)) {
7485 			rval = EINVAL;
7486 			break;
7487 		}
7488 
7489 		list = kmem_zalloc(fcio->fcio_olen, KM_SLEEP);
7490 		list->version = FC_HBA_LIST_VERSION;
7491 		/* build npiv port list */
7492 		count = fc_ulp_get_npiv_port_list(port, (char *)list->hbaPaths);
7493 		if (count < 0) {
7494 			rval = ENXIO;
7495 			FP_TRACE(FP_NHEAD1(1, 0), "Build NPIV Port List error");
7496 			kmem_free(list, fcio->fcio_olen);
7497 			break;
7498 		}
7499 		list->numAdapters = count;
7500 
7501 		if (fp_copyout((void *)list, (void *)fcio->fcio_obuf,
7502 		    fcio->fcio_olen, mode) == 0) {
7503 			if (fp_fcio_copyout(fcio, data, mode)) {
7504 				FP_TRACE(FP_NHEAD1(1, 0),
7505 				    "Copy NPIV Port data error");
7506 				rval = EFAULT;
7507 			}
7508 		} else {
7509 			FP_TRACE(FP_NHEAD1(1, 0), "Copy NPIV Port List error");
7510 			rval = EFAULT;
7511 		}
7512 		kmem_free(list, fcio->fcio_olen);
7513 		break;
7514 	}
7515 
7516 	case FCIO_GET_ADAPTER_PORT_NPIV_ATTRIBUTES: {
7517 		fc_hba_port_npiv_attributes_t   *val;
7518 
7519 		val = kmem_zalloc(sizeof (*val), KM_SLEEP);
7520 		val->version = FC_HBA_PORT_NPIV_ATTRIBUTES_VERSION;
7521 
7522 		mutex_enter(&port->fp_mutex);
7523 		val->npivflag = port->fp_npiv_flag;
7524 		val->lastChange = port->fp_last_change;
7525 		bcopy(&port->fp_service_params.nport_ww_name.raw_wwn,
7526 		    &val->PortWWN.raw_wwn,
7527 		    sizeof (val->PortWWN.raw_wwn));
7528 		bcopy(&port->fp_service_params.node_ww_name.raw_wwn,
7529 		    &val->NodeWWN.raw_wwn,
7530 		    sizeof (val->NodeWWN.raw_wwn));
7531 		mutex_exit(&port->fp_mutex);
7532 
7533 		val->NumberOfNPIVPorts = fc_ulp_get_npiv_port_num(port);
7534 		if (port->fp_npiv_type != FC_NPIV_PORT) {
7535 			val->MaxNumberOfNPIVPorts =
7536 			    port->fp_fca_tran->fca_num_npivports;
7537 		} else {
7538 			val->MaxNumberOfNPIVPorts = 0;
7539 		}
7540 
7541 		if (fp_copyout((void *)val, (void *)fcio->fcio_obuf,
7542 		    fcio->fcio_olen, mode) == 0) {
7543 			if (fp_fcio_copyout(fcio, data, mode)) {
7544 				rval = EFAULT;
7545 			}
7546 		} else {
7547 			rval = EFAULT;
7548 		}
7549 		kmem_free(val, sizeof (*val));
7550 		break;
7551 	}
7552 
7553 	case FCIO_GET_ADAPTER_PORT_ATTRIBUTES: {
7554 		fc_hba_port_attributes_t	*val;
7555 		fc_hba_port_attributes32_t	*val32;
7556 
7557 		if (use32 == B_TRUE) {
7558 			if (fcio->fcio_olen < sizeof (*val32) ||
7559 			    fcio->fcio_xfer != FCIO_XFER_READ) {
7560 				rval = EINVAL;
7561 				break;
7562 			}
7563 		} else {
7564 			if (fcio->fcio_olen < sizeof (*val) ||
7565 			    fcio->fcio_xfer != FCIO_XFER_READ) {
7566 				rval = EINVAL;
7567 				break;
7568 			}
7569 		}
7570 
7571 		val = kmem_zalloc(sizeof (*val), KM_SLEEP);
7572 		val->version = FC_HBA_PORT_ATTRIBUTES_VERSION;
7573 		mutex_enter(&port->fp_mutex);
7574 		val->lastChange = port->fp_last_change;
7575 		val->fp_minor = port->fp_instance;
7576 
7577 		bcopy(&port->fp_service_params.nport_ww_name.raw_wwn,
7578 		    &val->PortWWN.raw_wwn,
7579 		    sizeof (val->PortWWN.raw_wwn));
7580 		bcopy(&port->fp_service_params.node_ww_name.raw_wwn,
7581 		    &val->NodeWWN.raw_wwn,
7582 		    sizeof (val->NodeWWN.raw_wwn));
7583 		bcopy(&port->fp_fabric_name, &val->FabricName.raw_wwn,
7584 		    sizeof (val->FabricName.raw_wwn));
7585 
7586 		val->PortFcId = port->fp_port_id.port_id;
7587 
7588 		switch (FC_PORT_STATE_MASK(port->fp_state)) {
7589 		case FC_STATE_OFFLINE:
7590 		    val->PortState = FC_HBA_PORTSTATE_OFFLINE;
7591 		    break;
7592 		case FC_STATE_ONLINE:
7593 		case FC_STATE_LOOP:
7594 		case FC_STATE_NAMESERVICE:
7595 		    val->PortState = FC_HBA_PORTSTATE_ONLINE;
7596 		    break;
7597 		default:
7598 		    val->PortState = FC_HBA_PORTSTATE_UNKNOWN;
7599 		    break;
7600 		}
7601 
7602 		/* Translate from LV to FC-HBA port type codes */
7603 		switch (port->fp_port_type.port_type) {
7604 		case FC_NS_PORT_N:
7605 		    val->PortType = FC_HBA_PORTTYPE_NPORT;
7606 		    break;
7607 		case FC_NS_PORT_NL: /* Actually means loop for us */
7608 		    val->PortType = FC_HBA_PORTTYPE_LPORT;
7609 		    break;
7610 		case FC_NS_PORT_F:
7611 		    val->PortType = FC_HBA_PORTTYPE_FPORT;
7612 		    break;
7613 		case FC_NS_PORT_FL:
7614 		    val->PortType = FC_HBA_PORTTYPE_FLPORT;
7615 		    break;
7616 		case FC_NS_PORT_E:
7617 		    val->PortType = FC_HBA_PORTTYPE_EPORT;
7618 		    break;
7619 		default:
7620 		    val->PortType = FC_HBA_PORTTYPE_OTHER;
7621 		    break;
7622 		}
7623 
7624 
7625 		/*
7626 		 * If fp has decided that the topology is public loop,
7627 		 * we will indicate that using the appropriate
7628 		 * FC HBA API constant.
7629 		 */
7630 		switch (port->fp_topology) {
7631 		case FC_TOP_PUBLIC_LOOP:
7632 			val->PortType = FC_HBA_PORTTYPE_NLPORT;
7633 			break;
7634 
7635 		case FC_TOP_PT_PT:
7636 			val->PortType = FC_HBA_PORTTYPE_PTP;
7637 			break;
7638 
7639 		case FC_TOP_UNKNOWN:
7640 			/*
7641 			 * This should cover the case where nothing is connected
7642 			 * to the port. Crystal+ is p'bly an exception here.
7643 			 * For Crystal+, port 0 will come up as private loop
7644 			 * (i.e fp_bind_state will be FC_STATE_LOOP) even when
7645 			 * nothing is connected to it.
7646 			 * Current plan is to let userland handle this.
7647 			 */
7648 			if (port->fp_bind_state == FC_STATE_OFFLINE)
7649 				val->PortType = FC_HBA_PORTTYPE_UNKNOWN;
7650 			break;
7651 
7652 		default:
7653 			/*
7654 			 * Do Nothing.
7655 			 * Unused:
7656 			 *   val->PortType = FC_HBA_PORTTYPE_GPORT;
7657 			 */
7658 			break;
7659 		}
7660 
7661 		val->PortSupportedClassofService =
7662 			port->fp_hba_port_attrs.supported_cos;
7663 		val->PortSupportedFc4Types[0] = 0;
7664 		bcopy(port->fp_fc4_types, val->PortActiveFc4Types,
7665 		    sizeof (val->PortActiveFc4Types));
7666 		bcopy(port->fp_sym_port_name, val->PortSymbolicName,
7667 		    sizeof (val->PortSymbolicName));
7668 		val->PortSupportedSpeed =
7669 			port->fp_hba_port_attrs.supported_speed;
7670 
7671 		switch (FC_PORT_SPEED_MASK(port->fp_state)) {
7672 		case FC_STATE_1GBIT_SPEED:
7673 		    val->PortSpeed = FC_HBA_PORTSPEED_1GBIT;
7674 		    break;
7675 		case FC_STATE_2GBIT_SPEED:
7676 		    val->PortSpeed = FC_HBA_PORTSPEED_2GBIT;
7677 		    break;
7678 		case FC_STATE_4GBIT_SPEED:
7679 		    val->PortSpeed = FC_HBA_PORTSPEED_4GBIT;
7680 		    break;
7681 		case FC_STATE_8GBIT_SPEED:
7682 		    val->PortSpeed = FC_HBA_PORTSPEED_8GBIT;
7683 		    break;
7684 		case FC_STATE_10GBIT_SPEED:
7685 		    val->PortSpeed = FC_HBA_PORTSPEED_10GBIT;
7686 		    break;
7687 		case FC_STATE_16GBIT_SPEED:
7688 		    val->PortSpeed = FC_HBA_PORTSPEED_16GBIT;
7689 		    break;
7690 		default:
7691 		    val->PortSpeed = FC_HBA_PORTSPEED_UNKNOWN;
7692 		    break;
7693 		}
7694 		val->PortMaxFrameSize = port->fp_hba_port_attrs.max_frame_size;
7695 		val->NumberofDiscoveredPorts = port->fp_dev_count;
7696 		mutex_exit(&port->fp_mutex);
7697 
7698 		if (use32 == B_TRUE) {
7699 			val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP);
7700 			val32->version = val->version;
7701 			val32->lastChange = val->lastChange;
7702 			val32->fp_minor = val->fp_minor;
7703 
7704 			bcopy(&val->PortWWN.raw_wwn, &val32->PortWWN.raw_wwn,
7705 				sizeof (val->PortWWN.raw_wwn));
7706 			bcopy(&val->NodeWWN.raw_wwn, &val32->NodeWWN.raw_wwn,
7707 				sizeof (val->NodeWWN.raw_wwn));
7708 			val32->PortFcId = val->PortFcId;
7709 			val32->PortState = val->PortState;
7710 			val32->PortType = val->PortType;
7711 
7712 			val32->PortSupportedClassofService =
7713 			    val->PortSupportedClassofService;
7714 			bcopy(val->PortActiveFc4Types,
7715 			    val32->PortActiveFc4Types,
7716 			    sizeof (val->PortActiveFc4Types));
7717 			bcopy(val->PortSymbolicName, val32->PortSymbolicName,
7718 			    sizeof (val->PortSymbolicName));
7719 			bcopy(&val->FabricName, &val32->FabricName,
7720 			    sizeof (val->FabricName.raw_wwn));
7721 			val32->PortSupportedSpeed = val->PortSupportedSpeed;
7722 			val32->PortSpeed = val->PortSpeed;
7723 
7724 			val32->PortMaxFrameSize = val->PortMaxFrameSize;
7725 			val32->NumberofDiscoveredPorts =
7726 			    val->NumberofDiscoveredPorts;
7727 
7728 			if (fp_copyout((void *)val32, (void *)fcio->fcio_obuf,
7729 			    fcio->fcio_olen, mode) == 0) {
7730 				if (fp_fcio_copyout(fcio, data, mode)) {
7731 					rval = EFAULT;
7732 				}
7733 			} else {
7734 				rval = EFAULT;
7735 			}
7736 
7737 			kmem_free(val32, sizeof (*val32));
7738 		} else {
7739 			if (fp_copyout((void *)val, (void *)fcio->fcio_obuf,
7740 			    fcio->fcio_olen, mode) == 0) {
7741 				if (fp_fcio_copyout(fcio, data, mode)) {
7742 					rval = EFAULT;
7743 				}
7744 			} else {
7745 				rval = EFAULT;
7746 			}
7747 		}
7748 
7749 		kmem_free(val, sizeof (*val));
7750 		break;
7751 	}
7752 
7753 	case FCIO_GET_DISCOVERED_PORT_ATTRIBUTES: {
7754 		fc_hba_port_attributes_t	*val;
7755 		fc_hba_port_attributes32_t	*val32;
7756 		uint32_t	index = 0;
7757 		fc_remote_port_t *tmp_pd;
7758 
7759 		if (use32 == B_TRUE) {
7760 			if (fcio->fcio_olen < sizeof (*val32) ||
7761 			    fcio->fcio_xfer != FCIO_XFER_READ) {
7762 				rval = EINVAL;
7763 				break;
7764 			}
7765 		} else {
7766 			if (fcio->fcio_olen < sizeof (*val) ||
7767 			    fcio->fcio_xfer != FCIO_XFER_READ) {
7768 				rval = EINVAL;
7769 				break;
7770 			}
7771 		}
7772 
7773 		if (ddi_copyin(fcio->fcio_ibuf, &index, sizeof (index), mode)) {
7774 			rval = EFAULT;
7775 			break;
7776 		}
7777 
7778 		if (index >= port->fp_dev_count) {
7779 			FP_TRACE(FP_NHEAD1(9, 0),
7780 			    "User supplied index out of range");
7781 			fcio->fcio_errno = FC_OUTOFBOUNDS;
7782 			rval = EINVAL;
7783 			if (fp_fcio_copyout(fcio, data, mode)) {
7784 				rval = EFAULT;
7785 			}
7786 			break;
7787 		}
7788 
7789 		val = kmem_zalloc(sizeof (*val), KM_SLEEP);
7790 		val->version = FC_HBA_PORT_ATTRIBUTES_VERSION;
7791 
7792 		mutex_enter(&port->fp_mutex);
7793 		tmp_pd = fctl_lookup_pd_by_index(port, index);
7794 
7795 		if (tmp_pd == NULL) {
7796 			fcio->fcio_errno = FC_BADPORT;
7797 			rval = EINVAL;
7798 		} else {
7799 			val->lastChange = port->fp_last_change;
7800 			val->fp_minor = port->fp_instance;
7801 
7802 			mutex_enter(&tmp_pd->pd_mutex);
7803 			bcopy(&tmp_pd->pd_port_name.raw_wwn,
7804 			    &val->PortWWN.raw_wwn,
7805 			    sizeof (val->PortWWN.raw_wwn));
7806 			bcopy(&tmp_pd->pd_remote_nodep->fd_node_name.raw_wwn,
7807 			    &val->NodeWWN.raw_wwn,
7808 			    sizeof (val->NodeWWN.raw_wwn));
7809 			val->PortFcId = tmp_pd->pd_port_id.port_id;
7810 			bcopy(tmp_pd->pd_spn, val->PortSymbolicName,
7811 			    sizeof (val->PortSymbolicName));
7812 			val->PortSupportedClassofService = tmp_pd->pd_cos;
7813 			/*
7814 			 * we will assume the sizeof these pd_fc4types and
7815 			 * portActiveFc4Types will remain the same.  we could
7816 			 * add in a check for it, but we decided it was unneeded
7817 			 */
7818 			bcopy((caddr_t)tmp_pd->pd_fc4types,
7819 			    val->PortActiveFc4Types,
7820 			    sizeof (tmp_pd->pd_fc4types));
7821 			val->PortState =
7822 			    fp_map_remote_port_state(tmp_pd->pd_state);
7823 			mutex_exit(&tmp_pd->pd_mutex);
7824 
7825 			val->PortType = FC_HBA_PORTTYPE_UNKNOWN;
7826 			val->PortSupportedFc4Types[0] = 0;
7827 			val->PortSupportedSpeed = FC_HBA_PORTSPEED_UNKNOWN;
7828 			val->PortSpeed = FC_HBA_PORTSPEED_UNKNOWN;
7829 			val->PortMaxFrameSize = 0;
7830 			val->NumberofDiscoveredPorts = 0;
7831 
7832 			if (use32 == B_TRUE) {
7833 				val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP);
7834 				val32->version = val->version;
7835 				val32->lastChange = val->lastChange;
7836 				val32->fp_minor = val->fp_minor;
7837 
7838 				bcopy(&val->PortWWN.raw_wwn,
7839 				    &val32->PortWWN.raw_wwn,
7840 				    sizeof (val->PortWWN.raw_wwn));
7841 				bcopy(&val->NodeWWN.raw_wwn,
7842 				    &val32->NodeWWN.raw_wwn,
7843 				    sizeof (val->NodeWWN.raw_wwn));
7844 				val32->PortFcId = val->PortFcId;
7845 				bcopy(val->PortSymbolicName,
7846 				    val32->PortSymbolicName,
7847 				    sizeof (val->PortSymbolicName));
7848 				val32->PortSupportedClassofService =
7849 				    val->PortSupportedClassofService;
7850 				bcopy(val->PortActiveFc4Types,
7851 				    val32->PortActiveFc4Types,
7852 				    sizeof (tmp_pd->pd_fc4types));
7853 
7854 				val32->PortType = val->PortType;
7855 				val32->PortState = val->PortState;
7856 				val32->PortSupportedFc4Types[0] =
7857 				    val->PortSupportedFc4Types[0];
7858 				val32->PortSupportedSpeed =
7859 				    val->PortSupportedSpeed;
7860 				val32->PortSpeed = val->PortSpeed;
7861 				val32->PortMaxFrameSize =
7862 				    val->PortMaxFrameSize;
7863 				val32->NumberofDiscoveredPorts =
7864 				    val->NumberofDiscoveredPorts;
7865 
7866 				if (fp_copyout((void *)val32,
7867 				    (void *)fcio->fcio_obuf,
7868 				    fcio->fcio_olen, mode) == 0) {
7869 					    if (fp_fcio_copyout(fcio,
7870 						data, mode)) {
7871 						    rval = EFAULT;
7872 					    }
7873 				} else {
7874 					rval = EFAULT;
7875 				}
7876 
7877 				kmem_free(val32, sizeof (*val32));
7878 			} else {
7879 				if (fp_copyout((void *)val,
7880 				    (void *)fcio->fcio_obuf,
7881 				    fcio->fcio_olen, mode) == 0) {
7882 					if (fp_fcio_copyout(fcio, data, mode)) {
7883 						rval = EFAULT;
7884 					}
7885 				} else {
7886 					rval = EFAULT;
7887 				}
7888 			}
7889 		}
7890 
7891 		mutex_exit(&port->fp_mutex);
7892 		kmem_free(val, sizeof (*val));
7893 		break;
7894 	}
7895 
7896 	case FCIO_GET_PORT_ATTRIBUTES: {
7897 		fc_hba_port_attributes_t    *val;
7898 		fc_hba_port_attributes32_t  *val32;
7899 		la_wwn_t		    wwn;
7900 		fc_remote_port_t	    *tmp_pd;
7901 
7902 		if (use32 == B_TRUE) {
7903 			if (fcio->fcio_olen < sizeof (*val32) ||
7904 			    fcio->fcio_xfer != FCIO_XFER_READ) {
7905 				rval = EINVAL;
7906 				break;
7907 			}
7908 		} else {
7909 			if (fcio->fcio_olen < sizeof (*val) ||
7910 			    fcio->fcio_xfer != FCIO_XFER_READ) {
7911 				rval = EINVAL;
7912 				break;
7913 			}
7914 		}
7915 
7916 		if (ddi_copyin(fcio->fcio_ibuf, &wwn, sizeof (wwn), mode)) {
7917 			rval = EFAULT;
7918 			break;
7919 		}
7920 
7921 		val = kmem_zalloc(sizeof (*val), KM_SLEEP);
7922 		val->version = FC_HBA_PORT_ATTRIBUTES_VERSION;
7923 
7924 		mutex_enter(&port->fp_mutex);
7925 		tmp_pd = fctl_lookup_pd_by_wwn(port, wwn);
7926 		val->lastChange = port->fp_last_change;
7927 		val->fp_minor = port->fp_instance;
7928 		mutex_exit(&port->fp_mutex);
7929 
7930 		if (tmp_pd == NULL) {
7931 			fcio->fcio_errno = FC_BADWWN;
7932 			rval = EINVAL;
7933 		} else {
7934 			mutex_enter(&tmp_pd->pd_mutex);
7935 			bcopy(&tmp_pd->pd_port_name.raw_wwn,
7936 			    &val->PortWWN.raw_wwn,
7937 			    sizeof (val->PortWWN.raw_wwn));
7938 			bcopy(&tmp_pd->pd_remote_nodep->fd_node_name.raw_wwn,
7939 			    &val->NodeWWN.raw_wwn,
7940 			    sizeof (val->NodeWWN.raw_wwn));
7941 			val->PortFcId = tmp_pd->pd_port_id.port_id;
7942 			bcopy(tmp_pd->pd_spn, val->PortSymbolicName,
7943 			    sizeof (val->PortSymbolicName));
7944 			val->PortSupportedClassofService = tmp_pd->pd_cos;
7945 			val->PortType = FC_HBA_PORTTYPE_UNKNOWN;
7946 			val->PortState =
7947 			    fp_map_remote_port_state(tmp_pd->pd_state);
7948 			val->PortSupportedFc4Types[0] = 0;
7949 			/*
7950 			 * we will assume the sizeof these pd_fc4types and
7951 			 * portActiveFc4Types will remain the same.  we could
7952 			 * add in a check for it, but we decided it was unneeded
7953 			 */
7954 			bcopy((caddr_t)tmp_pd->pd_fc4types,
7955 			    val->PortActiveFc4Types,
7956 			    sizeof (tmp_pd->pd_fc4types));
7957 			val->PortSupportedSpeed = FC_HBA_PORTSPEED_UNKNOWN;
7958 			val->PortSpeed = FC_HBA_PORTSPEED_UNKNOWN;
7959 			val->PortMaxFrameSize = 0;
7960 			val->NumberofDiscoveredPorts = 0;
7961 			mutex_exit(&tmp_pd->pd_mutex);
7962 
7963 			if (use32 == B_TRUE) {
7964 				val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP);
7965 				val32->version = val->version;
7966 				val32->lastChange = val->lastChange;
7967 				val32->fp_minor = val->fp_minor;
7968 				bcopy(&val->PortWWN.raw_wwn,
7969 				    &val32->PortWWN.raw_wwn,
7970 				    sizeof (val->PortWWN.raw_wwn));
7971 				bcopy(&val->NodeWWN.raw_wwn,
7972 				    &val32->NodeWWN.raw_wwn,
7973 				    sizeof (val->NodeWWN.raw_wwn));
7974 				val32->PortFcId = val->PortFcId;
7975 				bcopy(val->PortSymbolicName,
7976 				    val32->PortSymbolicName,
7977 				    sizeof (val->PortSymbolicName));
7978 				val32->PortSupportedClassofService =
7979 				    val->PortSupportedClassofService;
7980 				val32->PortType = val->PortType;
7981 				val32->PortState = val->PortState;
7982 				val32->PortSupportedFc4Types[0] =
7983 				    val->PortSupportedFc4Types[0];
7984 				bcopy(val->PortActiveFc4Types,
7985 				    val32->PortActiveFc4Types,
7986 				    sizeof (tmp_pd->pd_fc4types));
7987 				val32->PortSupportedSpeed =
7988 				    val->PortSupportedSpeed;
7989 				val32->PortSpeed = val->PortSpeed;
7990 				val32->PortMaxFrameSize = val->PortMaxFrameSize;
7991 				val32->NumberofDiscoveredPorts =
7992 				    val->NumberofDiscoveredPorts;
7993 
7994 				if (fp_copyout((void *)val32,
7995 				    (void *)fcio->fcio_obuf,
7996 				    fcio->fcio_olen, mode) == 0) {
7997 					if (fp_fcio_copyout(fcio, data, mode)) {
7998 						rval = EFAULT;
7999 					}
8000 				} else {
8001 					rval = EFAULT;
8002 				}
8003 
8004 				kmem_free(val32, sizeof (*val32));
8005 			} else {
8006 				if (fp_copyout((void *)val,
8007 				    (void *)fcio->fcio_obuf,
8008 				    fcio->fcio_olen, mode) == 0) {
8009 					if (fp_fcio_copyout(fcio, data, mode)) {
8010 						rval = EFAULT;
8011 					}
8012 				} else {
8013 					rval = EFAULT;
8014 				}
8015 			}
8016 		}
8017 		kmem_free(val, sizeof (*val));
8018 		break;
8019 	}
8020 
8021 	case FCIO_GET_NUM_DEVS: {
8022 		int num_devices;
8023 
8024 		if (fcio->fcio_olen != sizeof (num_devices) ||
8025 		    fcio->fcio_xfer != FCIO_XFER_READ) {
8026 			rval = EINVAL;
8027 			break;
8028 		}
8029 
8030 		mutex_enter(&port->fp_mutex);
8031 		switch (port->fp_topology) {
8032 		case FC_TOP_PRIVATE_LOOP:
8033 		case FC_TOP_PT_PT:
8034 			num_devices = port->fp_total_devices;
8035 			fcio->fcio_errno = FC_SUCCESS;
8036 			break;
8037 
8038 		case FC_TOP_PUBLIC_LOOP:
8039 		case FC_TOP_FABRIC:
8040 			mutex_exit(&port->fp_mutex);
8041 			job = fctl_alloc_job(JOB_NS_CMD, 0, NULL,
8042 			    NULL, KM_SLEEP);
8043 			ASSERT(job != NULL);
8044 
8045 			/*
8046 			 * In FC-GS-2 the Name Server doesn't send out
8047 			 * RSCNs for any Name Server Database updates
8048 			 * When it is finally fixed there is no need
8049 			 * to probe as below and should be removed.
8050 			 */
8051 			(void) fp_ns_get_devcount(port, job, 0, KM_SLEEP);
8052 			fctl_dealloc_job(job);
8053 
8054 			mutex_enter(&port->fp_mutex);
8055 			num_devices = port->fp_total_devices;
8056 			fcio->fcio_errno = FC_SUCCESS;
8057 			break;
8058 
8059 		case FC_TOP_NO_NS:
8060 			/* FALLTHROUGH */
8061 		case FC_TOP_UNKNOWN:
8062 			/* FALLTHROUGH */
8063 		default:
8064 			num_devices = 0;
8065 			fcio->fcio_errno = FC_SUCCESS;
8066 			break;
8067 		}
8068 		mutex_exit(&port->fp_mutex);
8069 
8070 		if (fp_copyout((void *)&num_devices,
8071 		    (void *)fcio->fcio_obuf, fcio->fcio_olen,
8072 		    mode) == 0) {
8073 			if (fp_fcio_copyout(fcio, data, mode)) {
8074 				rval = EFAULT;
8075 			}
8076 		} else {
8077 			rval = EFAULT;
8078 		}
8079 		break;
8080 	}
8081 
8082 	case FCIO_GET_DEV_LIST: {
8083 		int num_devices;
8084 		int new_count;
8085 		int map_size;
8086 
8087 		if (fcio->fcio_xfer != FCIO_XFER_READ ||
8088 		    fcio->fcio_alen != sizeof (new_count)) {
8089 			rval = EINVAL;
8090 			break;
8091 		}
8092 
8093 		num_devices = fcio->fcio_olen / sizeof (fc_port_dev_t);
8094 
8095 		mutex_enter(&port->fp_mutex);
8096 		if (num_devices < port->fp_total_devices) {
8097 			fcio->fcio_errno = FC_TOOMANY;
8098 			new_count = port->fp_total_devices;
8099 			mutex_exit(&port->fp_mutex);
8100 
8101 			if (fp_copyout((void *)&new_count,
8102 			    (void *)fcio->fcio_abuf,
8103 			    sizeof (new_count), mode)) {
8104 				rval = EFAULT;
8105 				break;
8106 			}
8107 
8108 			if (fp_fcio_copyout(fcio, data, mode)) {
8109 				rval = EFAULT;
8110 				break;
8111 			}
8112 			rval = EINVAL;
8113 			break;
8114 		}
8115 
8116 		if (port->fp_total_devices <= 0) {
8117 			fcio->fcio_errno = FC_NO_MAP;
8118 			new_count = port->fp_total_devices;
8119 			mutex_exit(&port->fp_mutex);
8120 
8121 			if (fp_copyout((void *)&new_count,
8122 			    (void *)fcio->fcio_abuf,
8123 			    sizeof (new_count), mode)) {
8124 				rval = EFAULT;
8125 				break;
8126 			}
8127 
8128 			if (fp_fcio_copyout(fcio, data, mode)) {
8129 				rval = EFAULT;
8130 				break;
8131 			}
8132 			rval = EINVAL;
8133 			break;
8134 		}
8135 
8136 		switch (port->fp_topology) {
8137 		case FC_TOP_PRIVATE_LOOP:
8138 			if (fp_fillout_loopmap(port, fcio,
8139 			    mode) != FC_SUCCESS) {
8140 				rval = EFAULT;
8141 				break;
8142 			}
8143 			if (fp_fcio_copyout(fcio, data, mode)) {
8144 				rval = EFAULT;
8145 			}
8146 			break;
8147 
8148 		case FC_TOP_PT_PT:
8149 			if (fp_fillout_p2pmap(port, fcio,
8150 			    mode) != FC_SUCCESS) {
8151 				rval = EFAULT;
8152 				break;
8153 			}
8154 			if (fp_fcio_copyout(fcio, data, mode)) {
8155 				rval = EFAULT;
8156 			}
8157 			break;
8158 
8159 		case FC_TOP_PUBLIC_LOOP:
8160 		case FC_TOP_FABRIC: {
8161 			fctl_ns_req_t *ns_cmd;
8162 
8163 			map_size =
8164 			    sizeof (fc_port_dev_t) * port->fp_total_devices;
8165 
8166 			mutex_exit(&port->fp_mutex);
8167 
8168 			ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t),
8169 			    sizeof (ns_resp_gan_t), map_size,
8170 			    (FCTL_NS_FILL_NS_MAP | FCTL_NS_BUF_IS_USERLAND),
8171 			    KM_SLEEP);
8172 			ASSERT(ns_cmd != NULL);
8173 
8174 			ns_cmd->ns_gan_index = 0;
8175 			ns_cmd->ns_gan_sid = FCTL_GAN_START_ID;
8176 			ns_cmd->ns_cmd_code = NS_GA_NXT;
8177 			ns_cmd->ns_gan_max = map_size / sizeof (fc_port_dev_t);
8178 
8179 			job = fctl_alloc_job(JOB_PORT_GETMAP, 0, NULL,
8180 			    NULL, KM_SLEEP);
8181 			ASSERT(job != NULL);
8182 
8183 			ret = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP);
8184 
8185 			if (ret != FC_SUCCESS ||
8186 			    job->job_result != FC_SUCCESS) {
8187 				fctl_free_ns_cmd(ns_cmd);
8188 
8189 				fcio->fcio_errno = job->job_result;
8190 				new_count = 0;
8191 				if (fp_copyout((void *)&new_count,
8192 				    (void *)fcio->fcio_abuf,
8193 				    sizeof (new_count), mode)) {
8194 					fctl_dealloc_job(job);
8195 					mutex_enter(&port->fp_mutex);
8196 					rval = EFAULT;
8197 					break;
8198 				}
8199 
8200 				if (fp_fcio_copyout(fcio, data, mode)) {
8201 					fctl_dealloc_job(job);
8202 					mutex_enter(&port->fp_mutex);
8203 					rval = EFAULT;
8204 					break;
8205 				}
8206 				rval = EIO;
8207 				mutex_enter(&port->fp_mutex);
8208 				break;
8209 			}
8210 			fctl_dealloc_job(job);
8211 
8212 			new_count = ns_cmd->ns_gan_index;
8213 			if (fp_copyout((void *)&new_count,
8214 			    (void *)fcio->fcio_abuf, sizeof (new_count),
8215 			    mode)) {
8216 				rval = EFAULT;
8217 				fctl_free_ns_cmd(ns_cmd);
8218 				mutex_enter(&port->fp_mutex);
8219 				break;
8220 			}
8221 
8222 			if (fp_copyout((void *)ns_cmd->ns_data_buf,
8223 			    (void *)fcio->fcio_obuf, sizeof (fc_port_dev_t) *
8224 			    ns_cmd->ns_gan_index, mode)) {
8225 				rval = EFAULT;
8226 				fctl_free_ns_cmd(ns_cmd);
8227 				mutex_enter(&port->fp_mutex);
8228 				break;
8229 			}
8230 			fctl_free_ns_cmd(ns_cmd);
8231 
8232 			if (fp_fcio_copyout(fcio, data, mode)) {
8233 				rval = EFAULT;
8234 			}
8235 			mutex_enter(&port->fp_mutex);
8236 			break;
8237 		}
8238 
8239 		case FC_TOP_NO_NS:
8240 			/* FALLTHROUGH */
8241 		case FC_TOP_UNKNOWN:
8242 			/* FALLTHROUGH */
8243 		default:
8244 			fcio->fcio_errno = FC_NO_MAP;
8245 			num_devices = port->fp_total_devices;
8246 
8247 			if (fp_copyout((void *)&new_count,
8248 			    (void *)fcio->fcio_abuf,
8249 			    sizeof (new_count), mode)) {
8250 				rval = EFAULT;
8251 				break;
8252 			}
8253 
8254 			if (fp_fcio_copyout(fcio, data, mode)) {
8255 				rval = EFAULT;
8256 				break;
8257 			}
8258 			rval = EINVAL;
8259 			break;
8260 		}
8261 		mutex_exit(&port->fp_mutex);
8262 		break;
8263 	}
8264 
8265 	case FCIO_GET_SYM_PNAME: {
8266 		rval = ENOTSUP;
8267 		break;
8268 	}
8269 
8270 	case FCIO_GET_SYM_NNAME: {
8271 		rval = ENOTSUP;
8272 		break;
8273 	}
8274 
8275 	case FCIO_SET_SYM_PNAME: {
8276 		rval = ENOTSUP;
8277 		break;
8278 	}
8279 
8280 	case FCIO_SET_SYM_NNAME: {
8281 		rval = ENOTSUP;
8282 		break;
8283 	}
8284 
8285 	case FCIO_GET_LOGI_PARAMS: {
8286 		la_wwn_t		pwwn;
8287 		la_wwn_t		*my_pwwn;
8288 		la_els_logi_t		*params;
8289 		la_els_logi32_t		*params32;
8290 		fc_remote_node_t	*node;
8291 		fc_remote_port_t	*pd;
8292 
8293 		if (fcio->fcio_ilen != sizeof (la_wwn_t) ||
8294 		    (fcio->fcio_xfer & FCIO_XFER_READ) == 0 ||
8295 		    (fcio->fcio_xfer & FCIO_XFER_WRITE) == 0) {
8296 			rval = EINVAL;
8297 			break;
8298 		}
8299 
8300 		if (use32 == B_TRUE) {
8301 			if (fcio->fcio_olen != sizeof (la_els_logi32_t)) {
8302 				rval = EINVAL;
8303 				break;
8304 			}
8305 		} else {
8306 			if (fcio->fcio_olen != sizeof (la_els_logi_t)) {
8307 				rval = EINVAL;
8308 				break;
8309 			}
8310 		}
8311 
8312 		if (ddi_copyin(fcio->fcio_ibuf, &pwwn, sizeof (pwwn), mode)) {
8313 			rval = EFAULT;
8314 			break;
8315 		}
8316 
8317 		pd = fctl_hold_remote_port_by_pwwn(port, &pwwn);
8318 		if (pd == NULL) {
8319 			mutex_enter(&port->fp_mutex);
8320 			my_pwwn = &port->fp_service_params.nport_ww_name;
8321 			mutex_exit(&port->fp_mutex);
8322 
8323 			if (fctl_wwn_cmp(&pwwn, my_pwwn) != 0) {
8324 				rval = ENXIO;
8325 				break;
8326 			}
8327 
8328 			params = kmem_zalloc(sizeof (*params), KM_SLEEP);
8329 			mutex_enter(&port->fp_mutex);
8330 			*params = port->fp_service_params;
8331 			mutex_exit(&port->fp_mutex);
8332 		} else {
8333 			params = kmem_zalloc(sizeof (*params), KM_SLEEP);
8334 
8335 			mutex_enter(&pd->pd_mutex);
8336 			params->ls_code.mbz = params->ls_code.ls_code = 0;
8337 			params->common_service = pd->pd_csp;
8338 			params->nport_ww_name = pd->pd_port_name;
8339 			params->class_1 = pd->pd_clsp1;
8340 			params->class_2 = pd->pd_clsp2;
8341 			params->class_3 = pd->pd_clsp3;
8342 			node = pd->pd_remote_nodep;
8343 			mutex_exit(&pd->pd_mutex);
8344 
8345 			bzero(params->reserved, sizeof (params->reserved));
8346 
8347 			mutex_enter(&node->fd_mutex);
8348 			bcopy(node->fd_vv, params->vendor_version,
8349 			    sizeof (node->fd_vv));
8350 			params->node_ww_name = node->fd_node_name;
8351 			mutex_exit(&node->fd_mutex);
8352 
8353 			fctl_release_remote_port(pd);
8354 		}
8355 
8356 		if (use32 == B_TRUE) {
8357 			params32 = kmem_zalloc(sizeof (*params32), KM_SLEEP);
8358 
8359 			params32->ls_code.mbz = params->ls_code.mbz;
8360 			params32->common_service = params->common_service;
8361 			params32->nport_ww_name = params->nport_ww_name;
8362 			params32->class_1 = params->class_1;
8363 			params32->class_2 = params->class_2;
8364 			params32->class_3 = params->class_3;
8365 			bzero(params32->reserved, sizeof (params32->reserved));
8366 			bcopy(params->vendor_version, params32->vendor_version,
8367 			    sizeof (node->fd_vv));
8368 			params32->node_ww_name = params->node_ww_name;
8369 
8370 			if (ddi_copyout((void *)params32,
8371 			    (void *)fcio->fcio_obuf,
8372 			    sizeof (*params32), mode)) {
8373 				rval = EFAULT;
8374 			}
8375 
8376 			kmem_free(params32, sizeof (*params32));
8377 		} else {
8378 			if (ddi_copyout((void *)params, (void *)fcio->fcio_obuf,
8379 			    sizeof (*params), mode)) {
8380 				rval = EFAULT;
8381 			}
8382 		}
8383 
8384 		kmem_free(params, sizeof (*params));
8385 		if (fp_fcio_copyout(fcio, data, mode)) {
8386 			rval = EFAULT;
8387 		}
8388 		break;
8389 	}
8390 
8391 	case FCIO_DEV_LOGOUT:
8392 	case FCIO_DEV_LOGIN:
8393 		if (fcio->fcio_ilen != sizeof (la_wwn_t) ||
8394 		    fcio->fcio_xfer != FCIO_XFER_WRITE) {
8395 			rval = EINVAL;
8396 
8397 			if (fp_fcio_copyout(fcio, data, mode)) {
8398 				rval = EFAULT;
8399 			}
8400 			break;
8401 		}
8402 
8403 		if (fcio->fcio_cmd == FCIO_DEV_LOGIN) {
8404 			jcode = JOB_FCIO_LOGIN;
8405 		} else {
8406 			jcode = JOB_FCIO_LOGOUT;
8407 		}
8408 
8409 		kfcio = kmem_zalloc(sizeof (*kfcio), KM_SLEEP);
8410 		bcopy(fcio, kfcio, sizeof (*fcio));
8411 
8412 		if (kfcio->fcio_ilen) {
8413 			kfcio->fcio_ibuf = kmem_zalloc(kfcio->fcio_ilen,
8414 			    KM_SLEEP);
8415 
8416 			if (ddi_copyin((void *)fcio->fcio_ibuf,
8417 			    (void *)kfcio->fcio_ibuf, kfcio->fcio_ilen,
8418 			    mode)) {
8419 				rval = EFAULT;
8420 
8421 				kmem_free(kfcio->fcio_ibuf, kfcio->fcio_ilen);
8422 				kmem_free(kfcio, sizeof (*kfcio));
8423 				fcio->fcio_errno = job->job_result;
8424 				if (fp_fcio_copyout(fcio, data, mode)) {
8425 					rval = EFAULT;
8426 				}
8427 				break;
8428 			}
8429 		}
8430 
8431 		job = fctl_alloc_job(jcode, 0, NULL, NULL, KM_SLEEP);
8432 		job->job_private = kfcio;
8433 
8434 		fctl_enque_job(port, job);
8435 		fctl_jobwait(job);
8436 
8437 		rval = job->job_result;
8438 
8439 		fcio->fcio_errno = kfcio->fcio_errno;
8440 		if (fp_fcio_copyout(fcio, data, mode)) {
8441 			rval = EFAULT;
8442 		}
8443 
8444 		kmem_free(kfcio->fcio_ibuf, kfcio->fcio_ilen);
8445 		kmem_free(kfcio, sizeof (*kfcio));
8446 		fctl_dealloc_job(job);
8447 		break;
8448 
8449 	case FCIO_GET_STATE: {
8450 		la_wwn_t		pwwn;
8451 		uint32_t		state;
8452 		fc_remote_port_t 	*pd;
8453 		fctl_ns_req_t		*ns_cmd;
8454 
8455 		if (fcio->fcio_ilen != sizeof (la_wwn_t) ||
8456 		    fcio->fcio_olen != sizeof (state) ||
8457 		    (fcio->fcio_xfer & FCIO_XFER_WRITE) == 0 ||
8458 		    (fcio->fcio_xfer & FCIO_XFER_READ) == 0) {
8459 			rval = EINVAL;
8460 			break;
8461 		}
8462 
8463 		if (ddi_copyin(fcio->fcio_ibuf, &pwwn, sizeof (pwwn), mode)) {
8464 			rval = EFAULT;
8465 			break;
8466 		}
8467 		fcio->fcio_errno = 0;
8468 
8469 		pd = fctl_hold_remote_port_by_pwwn(port, &pwwn);
8470 		if (pd == NULL) {
8471 			mutex_enter(&port->fp_mutex);
8472 			if (FC_IS_TOP_SWITCH(port->fp_topology)) {
8473 				mutex_exit(&port->fp_mutex);
8474 				job = fctl_alloc_job(JOB_PLOGI_ONE, 0,
8475 				    NULL, NULL, KM_SLEEP);
8476 
8477 				job->job_counter = 1;
8478 				job->job_result = FC_SUCCESS;
8479 
8480 				ns_cmd = fctl_alloc_ns_cmd(
8481 				    sizeof (ns_req_gid_pn_t),
8482 				    sizeof (ns_resp_gid_pn_t),
8483 				    sizeof (ns_resp_gid_pn_t),
8484 				    FCTL_NS_BUF_IS_USERLAND, KM_SLEEP);
8485 				ASSERT(ns_cmd != NULL);
8486 
8487 				ns_cmd->ns_cmd_code = NS_GID_PN;
8488 				((ns_req_gid_pn_t *)
8489 				    (ns_cmd->ns_cmd_buf))->pwwn = pwwn;
8490 
8491 				ret = fp_ns_query(port, ns_cmd, job,
8492 				    1, KM_SLEEP);
8493 
8494 				if (ret != FC_SUCCESS || job->job_result !=
8495 				    FC_SUCCESS) {
8496 					if (ret != FC_SUCCESS) {
8497 						fcio->fcio_errno = ret;
8498 					} else {
8499 						fcio->fcio_errno =
8500 						    job->job_result;
8501 					}
8502 					rval = EIO;
8503 				} else {
8504 					state = PORT_DEVICE_INVALID;
8505 				}
8506 				fctl_free_ns_cmd(ns_cmd);
8507 				fctl_dealloc_job(job);
8508 			} else {
8509 				mutex_exit(&port->fp_mutex);
8510 				fcio->fcio_errno = FC_BADWWN;
8511 				rval = ENXIO;
8512 			}
8513 		} else {
8514 			mutex_enter(&pd->pd_mutex);
8515 			state = pd->pd_state;
8516 			mutex_exit(&pd->pd_mutex);
8517 
8518 			fctl_release_remote_port(pd);
8519 		}
8520 
8521 		if (!rval) {
8522 			if (ddi_copyout((void *)&state,
8523 			    (void *)fcio->fcio_obuf, sizeof (state),
8524 			    mode)) {
8525 				rval = EFAULT;
8526 			}
8527 		}
8528 		if (fp_fcio_copyout(fcio, data, mode)) {
8529 			rval = EFAULT;
8530 		}
8531 		break;
8532 	}
8533 
8534 	case FCIO_DEV_REMOVE: {
8535 		la_wwn_t	pwwn;
8536 		fc_portmap_t	*changelist;
8537 		fc_remote_port_t *pd;
8538 
8539 		if (fcio->fcio_ilen != sizeof (la_wwn_t) ||
8540 		    fcio->fcio_xfer != FCIO_XFER_WRITE) {
8541 			rval = EINVAL;
8542 			break;
8543 		}
8544 
8545 		if (ddi_copyin(fcio->fcio_ibuf, &pwwn, sizeof (pwwn), mode)) {
8546 			rval = EFAULT;
8547 			break;
8548 		}
8549 
8550 		pd = fctl_hold_remote_port_by_pwwn(port, &pwwn);
8551 		if (pd == NULL) {
8552 			rval = ENXIO;
8553 			fcio->fcio_errno = FC_BADWWN;
8554 			if (fp_fcio_copyout(fcio, data, mode)) {
8555 				rval = EFAULT;
8556 			}
8557 			break;
8558 		}
8559 
8560 		mutex_enter(&pd->pd_mutex);
8561 		if (pd->pd_ref_count > 1) {
8562 			mutex_exit(&pd->pd_mutex);
8563 
8564 			rval = EBUSY;
8565 			fcio->fcio_errno = FC_FAILURE;
8566 			fctl_release_remote_port(pd);
8567 
8568 			if (fp_fcio_copyout(fcio, data, mode)) {
8569 				rval = EFAULT;
8570 			}
8571 			break;
8572 		}
8573 		mutex_exit(&pd->pd_mutex);
8574 
8575 		changelist = kmem_zalloc(sizeof (*changelist), KM_SLEEP);
8576 
8577 		fctl_copy_portmap(changelist, pd);
8578 		changelist->map_type = PORT_DEVICE_USER_LOGOUT;
8579 		(void) fp_ulp_devc_cb(port, changelist, 1, 1, KM_SLEEP, 1);
8580 
8581 		fctl_release_remote_port(pd);
8582 		break;
8583 	}
8584 
8585 	case FCIO_GET_FCODE_REV: {
8586 		caddr_t 	fcode_rev;
8587 		fc_fca_pm_t	pm;
8588 
8589 		if (fcio->fcio_olen < FC_FCODE_REV_SIZE ||
8590 		    fcio->fcio_xfer != FCIO_XFER_READ) {
8591 			rval = EINVAL;
8592 			break;
8593 		}
8594 		bzero((caddr_t)&pm, sizeof (pm));
8595 
8596 		fcode_rev = kmem_zalloc(fcio->fcio_olen, KM_SLEEP);
8597 
8598 		pm.pm_cmd_flags = FC_FCA_PM_READ;
8599 		pm.pm_cmd_code = FC_PORT_GET_FCODE_REV;
8600 		pm.pm_data_len = fcio->fcio_olen;
8601 		pm.pm_data_buf = fcode_rev;
8602 
8603 		ret = port->fp_fca_tran->fca_port_manage(
8604 		    port->fp_fca_handle, &pm);
8605 
8606 		if (ret == FC_SUCCESS) {
8607 			if (ddi_copyout((void *)fcode_rev,
8608 			    (void *)fcio->fcio_obuf,
8609 			    fcio->fcio_olen, mode) == 0) {
8610 				if (fp_fcio_copyout(fcio, data, mode)) {
8611 					rval = EFAULT;
8612 				}
8613 			} else {
8614 				rval = EFAULT;
8615 			}
8616 		} else {
8617 			/*
8618 			 * check if buffer was not large enough to obtain
8619 			 * FCODE version.
8620 			 */
8621 			if (pm.pm_data_len > fcio->fcio_olen) {
8622 				rval = ENOMEM;
8623 			} else {
8624 				rval = EIO;
8625 			}
8626 			fcio->fcio_errno = ret;
8627 			if (fp_fcio_copyout(fcio, data, mode)) {
8628 				rval = EFAULT;
8629 			}
8630 		}
8631 		kmem_free(fcode_rev, fcio->fcio_olen);
8632 		break;
8633 	}
8634 
8635 	case FCIO_GET_FW_REV: {
8636 		caddr_t 	fw_rev;
8637 		fc_fca_pm_t	pm;
8638 
8639 		if (fcio->fcio_olen < FC_FW_REV_SIZE ||
8640 		    fcio->fcio_xfer != FCIO_XFER_READ) {
8641 			rval = EINVAL;
8642 			break;
8643 		}
8644 		bzero((caddr_t)&pm, sizeof (pm));
8645 
8646 		fw_rev = kmem_zalloc(fcio->fcio_olen, KM_SLEEP);
8647 
8648 		pm.pm_cmd_flags = FC_FCA_PM_READ;
8649 		pm.pm_cmd_code = FC_PORT_GET_FW_REV;
8650 		pm.pm_data_len = fcio->fcio_olen;
8651 		pm.pm_data_buf = fw_rev;
8652 
8653 		ret = port->fp_fca_tran->fca_port_manage(
8654 		    port->fp_fca_handle, &pm);
8655 
8656 		if (ret == FC_SUCCESS) {
8657 			if (ddi_copyout((void *)fw_rev,
8658 			    (void *)fcio->fcio_obuf,
8659 			    fcio->fcio_olen, mode) == 0) {
8660 				if (fp_fcio_copyout(fcio, data, mode)) {
8661 					rval = EFAULT;
8662 				}
8663 			} else {
8664 				rval = EFAULT;
8665 			}
8666 		} else {
8667 			if (fp_fcio_copyout(fcio, data, mode)) {
8668 				rval = EFAULT;
8669 			}
8670 			rval = EIO;
8671 		}
8672 		kmem_free(fw_rev, fcio->fcio_olen);
8673 		break;
8674 	}
8675 
8676 	case FCIO_GET_DUMP_SIZE: {
8677 		uint32_t 	dump_size;
8678 		fc_fca_pm_t	pm;
8679 
8680 		if (fcio->fcio_olen != sizeof (dump_size) ||
8681 		    fcio->fcio_xfer != FCIO_XFER_READ) {
8682 			rval = EINVAL;
8683 			break;
8684 		}
8685 		bzero((caddr_t)&pm, sizeof (pm));
8686 		pm.pm_cmd_flags = FC_FCA_PM_READ;
8687 		pm.pm_cmd_code = FC_PORT_GET_DUMP_SIZE;
8688 		pm.pm_data_len = sizeof (dump_size);
8689 		pm.pm_data_buf = (caddr_t)&dump_size;
8690 
8691 		ret = port->fp_fca_tran->fca_port_manage(
8692 		    port->fp_fca_handle, &pm);
8693 
8694 		if (ret == FC_SUCCESS) {
8695 			if (ddi_copyout((void *)&dump_size,
8696 			    (void *)fcio->fcio_obuf, sizeof (dump_size),
8697 			    mode) == 0) {
8698 				if (fp_fcio_copyout(fcio, data, mode)) {
8699 					rval = EFAULT;
8700 				}
8701 			} else {
8702 				rval = EFAULT;
8703 			}
8704 		} else {
8705 			fcio->fcio_errno = ret;
8706 			rval = EIO;
8707 			if (fp_fcio_copyout(fcio, data, mode)) {
8708 				rval = EFAULT;
8709 			}
8710 		}
8711 		break;
8712 	}
8713 
8714 	case FCIO_DOWNLOAD_FW: {
8715 		caddr_t		firmware;
8716 		fc_fca_pm_t	pm;
8717 
8718 		if (fcio->fcio_ilen <= 0 ||
8719 		    fcio->fcio_xfer != FCIO_XFER_WRITE) {
8720 			rval = EINVAL;
8721 			break;
8722 		}
8723 
8724 		firmware = kmem_zalloc(fcio->fcio_ilen, KM_SLEEP);
8725 		if (ddi_copyin(fcio->fcio_ibuf, firmware,
8726 		    fcio->fcio_ilen, mode)) {
8727 			rval = EFAULT;
8728 			kmem_free(firmware, fcio->fcio_ilen);
8729 			break;
8730 		}
8731 
8732 		bzero((caddr_t)&pm, sizeof (pm));
8733 		pm.pm_cmd_flags = FC_FCA_PM_WRITE;
8734 		pm.pm_cmd_code = FC_PORT_DOWNLOAD_FW;
8735 		pm.pm_data_len = fcio->fcio_ilen;
8736 		pm.pm_data_buf = firmware;
8737 
8738 		ret = port->fp_fca_tran->fca_port_manage(
8739 		    port->fp_fca_handle, &pm);
8740 
8741 		kmem_free(firmware, fcio->fcio_ilen);
8742 
8743 		if (ret != FC_SUCCESS) {
8744 			fcio->fcio_errno = ret;
8745 			rval = EIO;
8746 			if (fp_fcio_copyout(fcio, data, mode)) {
8747 				rval = EFAULT;
8748 			}
8749 		}
8750 		break;
8751 	}
8752 
8753 	case FCIO_DOWNLOAD_FCODE: {
8754 		caddr_t		fcode;
8755 		fc_fca_pm_t	pm;
8756 
8757 		if (fcio->fcio_ilen <= 0 ||
8758 		    fcio->fcio_xfer != FCIO_XFER_WRITE) {
8759 			rval = EINVAL;
8760 			break;
8761 		}
8762 
8763 		fcode = kmem_zalloc(fcio->fcio_ilen, KM_SLEEP);
8764 		if (ddi_copyin(fcio->fcio_ibuf, fcode,
8765 		    fcio->fcio_ilen, mode)) {
8766 			rval = EFAULT;
8767 			kmem_free(fcode, fcio->fcio_ilen);
8768 			break;
8769 		}
8770 
8771 		bzero((caddr_t)&pm, sizeof (pm));
8772 		pm.pm_cmd_flags = FC_FCA_PM_WRITE;
8773 		pm.pm_cmd_code = FC_PORT_DOWNLOAD_FCODE;
8774 		pm.pm_data_len = fcio->fcio_ilen;
8775 		pm.pm_data_buf = fcode;
8776 
8777 		ret = port->fp_fca_tran->fca_port_manage(
8778 		    port->fp_fca_handle, &pm);
8779 
8780 		kmem_free(fcode, fcio->fcio_ilen);
8781 
8782 		if (ret != FC_SUCCESS) {
8783 			fcio->fcio_errno = ret;
8784 			rval = EIO;
8785 			if (fp_fcio_copyout(fcio, data, mode)) {
8786 				rval = EFAULT;
8787 			}
8788 		}
8789 		break;
8790 	}
8791 
8792 	case FCIO_FORCE_DUMP:
8793 		ret = port->fp_fca_tran->fca_reset(
8794 		    port->fp_fca_handle, FC_FCA_CORE);
8795 
8796 		if (ret != FC_SUCCESS) {
8797 			fcio->fcio_errno = ret;
8798 			rval = EIO;
8799 			if (fp_fcio_copyout(fcio, data, mode)) {
8800 				rval = EFAULT;
8801 			}
8802 		}
8803 		break;
8804 
8805 	case FCIO_GET_DUMP: {
8806 		caddr_t		dump;
8807 		uint32_t 	dump_size;
8808 		fc_fca_pm_t	pm;
8809 
8810 		if (fcio->fcio_xfer != FCIO_XFER_READ) {
8811 			rval = EINVAL;
8812 			break;
8813 		}
8814 		bzero((caddr_t)&pm, sizeof (pm));
8815 
8816 		pm.pm_cmd_flags = FC_FCA_PM_READ;
8817 		pm.pm_cmd_code = FC_PORT_GET_DUMP_SIZE;
8818 		pm.pm_data_len = sizeof (dump_size);
8819 		pm.pm_data_buf = (caddr_t)&dump_size;
8820 
8821 		ret = port->fp_fca_tran->fca_port_manage(
8822 		    port->fp_fca_handle, &pm);
8823 
8824 		if (ret != FC_SUCCESS) {
8825 			fcio->fcio_errno = ret;
8826 			rval = EIO;
8827 			if (fp_fcio_copyout(fcio, data, mode)) {
8828 				rval = EFAULT;
8829 			}
8830 			break;
8831 		}
8832 		if (fcio->fcio_olen != dump_size) {
8833 			fcio->fcio_errno = FC_NOMEM;
8834 			rval = EINVAL;
8835 			if (fp_fcio_copyout(fcio, data, mode)) {
8836 				rval = EFAULT;
8837 			}
8838 			break;
8839 		}
8840 
8841 		dump = kmem_zalloc(dump_size, KM_SLEEP);
8842 
8843 		bzero((caddr_t)&pm, sizeof (pm));
8844 		pm.pm_cmd_flags = FC_FCA_PM_READ;
8845 		pm.pm_cmd_code = FC_PORT_GET_DUMP;
8846 		pm.pm_data_len = dump_size;
8847 		pm.pm_data_buf = dump;
8848 
8849 		ret = port->fp_fca_tran->fca_port_manage(
8850 		    port->fp_fca_handle, &pm);
8851 
8852 		if (ret == FC_SUCCESS) {
8853 			if (ddi_copyout((void *)dump, (void *)fcio->fcio_obuf,
8854 			    dump_size, mode) == 0) {
8855 				if (fp_fcio_copyout(fcio, data, mode)) {
8856 					rval = EFAULT;
8857 				}
8858 			} else {
8859 				rval = EFAULT;
8860 			}
8861 		} else {
8862 			fcio->fcio_errno = ret;
8863 			rval = EIO;
8864 			if (fp_fcio_copyout(fcio, data, mode)) {
8865 				rval = EFAULT;
8866 			}
8867 		}
8868 		kmem_free(dump, dump_size);
8869 		break;
8870 	}
8871 
8872 	case FCIO_GET_TOPOLOGY: {
8873 		uint32_t user_topology;
8874 
8875 		if (fcio->fcio_xfer != FCIO_XFER_READ ||
8876 		    fcio->fcio_olen != sizeof (user_topology)) {
8877 			rval = EINVAL;
8878 			break;
8879 		}
8880 
8881 		mutex_enter(&port->fp_mutex);
8882 		if (FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) {
8883 			user_topology = FC_TOP_UNKNOWN;
8884 		} else {
8885 			user_topology = port->fp_topology;
8886 		}
8887 		mutex_exit(&port->fp_mutex);
8888 
8889 		if (ddi_copyout((void *)&user_topology,
8890 		    (void *)fcio->fcio_obuf, sizeof (user_topology),
8891 		    mode)) {
8892 			rval = EFAULT;
8893 		}
8894 		break;
8895 	}
8896 
8897 	case FCIO_RESET_LINK: {
8898 		la_wwn_t pwwn;
8899 
8900 		/*
8901 		 * Look at the output buffer field; if this field has zero
8902 		 * bytes then attempt to reset the local link/loop. If the
8903 		 * fcio_ibuf field points to a WWN, see if it's an NL_Port,
8904 		 * and if yes, determine the LFA and reset the remote LIP
8905 		 * by LINIT ELS.
8906 		 */
8907 
8908 		if (fcio->fcio_xfer != FCIO_XFER_WRITE ||
8909 		    fcio->fcio_ilen != sizeof (pwwn)) {
8910 			rval = EINVAL;
8911 			break;
8912 		}
8913 
8914 		if (ddi_copyin(fcio->fcio_ibuf, &pwwn,
8915 		    sizeof (pwwn), mode)) {
8916 			rval = EFAULT;
8917 			break;
8918 		}
8919 
8920 		mutex_enter(&port->fp_mutex);
8921 		if (port->fp_soft_state & FP_SOFT_IN_LINK_RESET) {
8922 			mutex_exit(&port->fp_mutex);
8923 			break;
8924 		}
8925 		port->fp_soft_state |= FP_SOFT_IN_LINK_RESET;
8926 		mutex_exit(&port->fp_mutex);
8927 
8928 		job = fctl_alloc_job(JOB_LINK_RESET, 0, NULL, NULL, KM_SLEEP);
8929 		if (job == NULL) {
8930 			rval = ENOMEM;
8931 			break;
8932 		}
8933 		job->job_counter = 1;
8934 		job->job_private = (void *)&pwwn;
8935 
8936 		fctl_enque_job(port, job);
8937 		fctl_jobwait(job);
8938 
8939 		mutex_enter(&port->fp_mutex);
8940 		port->fp_soft_state &= ~FP_SOFT_IN_LINK_RESET;
8941 		mutex_exit(&port->fp_mutex);
8942 
8943 		if (job->job_result != FC_SUCCESS) {
8944 			fcio->fcio_errno = job->job_result;
8945 			rval = EIO;
8946 			if (fp_fcio_copyout(fcio, data, mode)) {
8947 				rval = EFAULT;
8948 			}
8949 		}
8950 		fctl_dealloc_job(job);
8951 		break;
8952 	}
8953 
8954 	case FCIO_RESET_HARD:
8955 		ret = port->fp_fca_tran->fca_reset(
8956 		    port->fp_fca_handle, FC_FCA_RESET);
8957 		if (ret != FC_SUCCESS) {
8958 			fcio->fcio_errno = ret;
8959 			rval = EIO;
8960 			if (fp_fcio_copyout(fcio, data, mode)) {
8961 				rval = EFAULT;
8962 			}
8963 		}
8964 		break;
8965 
8966 	case FCIO_RESET_HARD_CORE:
8967 		ret = port->fp_fca_tran->fca_reset(
8968 		    port->fp_fca_handle, FC_FCA_RESET_CORE);
8969 		if (ret != FC_SUCCESS) {
8970 			rval = EIO;
8971 			fcio->fcio_errno = ret;
8972 			if (fp_fcio_copyout(fcio, data, mode)) {
8973 				rval = EFAULT;
8974 			}
8975 		}
8976 		break;
8977 
8978 	case FCIO_DIAG: {
8979 		fc_fca_pm_t pm;
8980 
8981 		bzero((caddr_t)&pm, sizeof (fc_fca_pm_t));
8982 
8983 		/* Validate user buffer from ioctl call. */
8984 		if (((fcio->fcio_ilen > 0) && (fcio->fcio_ibuf == NULL)) ||
8985 		    ((fcio->fcio_ilen <= 0) && (fcio->fcio_ibuf != NULL)) ||
8986 		    ((fcio->fcio_alen > 0) && (fcio->fcio_abuf == NULL)) ||
8987 		    ((fcio->fcio_alen <= 0) && (fcio->fcio_abuf != NULL)) ||
8988 		    ((fcio->fcio_olen > 0) && (fcio->fcio_obuf == NULL)) ||
8989 		    ((fcio->fcio_olen <= 0) && (fcio->fcio_obuf != NULL))) {
8990 			rval = EFAULT;
8991 			break;
8992 		}
8993 
8994 		if ((pm.pm_cmd_len = fcio->fcio_ilen) > 0) {
8995 			pm.pm_cmd_buf = kmem_zalloc(fcio->fcio_ilen, KM_SLEEP);
8996 			if (ddi_copyin(fcio->fcio_ibuf, pm.pm_cmd_buf,
8997 			    fcio->fcio_ilen, mode)) {
8998 				rval = EFAULT;
8999 				goto fp_fcio_diag_cleanup;
9000 			}
9001 		}
9002 
9003 		if ((pm.pm_data_len = fcio->fcio_alen) > 0) {
9004 			pm.pm_data_buf = kmem_zalloc(fcio->fcio_alen, KM_SLEEP);
9005 			if (ddi_copyin(fcio->fcio_abuf, pm.pm_data_buf,
9006 			    fcio->fcio_alen, mode)) {
9007 				rval = EFAULT;
9008 				goto fp_fcio_diag_cleanup;
9009 			}
9010 		}
9011 
9012 		if ((pm.pm_stat_len = fcio->fcio_olen) > 0) {
9013 			pm.pm_stat_buf = kmem_zalloc(fcio->fcio_olen, KM_SLEEP);
9014 		}
9015 
9016 		pm.pm_cmd_code = FC_PORT_DIAG;
9017 		pm.pm_cmd_flags = fcio->fcio_cmd_flags;
9018 
9019 		ret = port->fp_fca_tran->fca_port_manage(
9020 		    port->fp_fca_handle, &pm);
9021 
9022 		if (ret != FC_SUCCESS) {
9023 			if (ret == FC_INVALID_REQUEST) {
9024 				rval = ENOTTY;
9025 			} else {
9026 				rval = EIO;
9027 			}
9028 
9029 			fcio->fcio_errno = ret;
9030 			if (fp_fcio_copyout(fcio, data, mode)) {
9031 				rval = EFAULT;
9032 			}
9033 			goto fp_fcio_diag_cleanup;
9034 		}
9035 
9036 		/*
9037 		 * pm_stat_len will contain the number of status bytes
9038 		 * an FCA driver requires to return the complete status
9039 		 * of the requested diag operation. If the user buffer
9040 		 * is not large enough to hold the entire status, We
9041 		 * copy only the portion of data the fits in the buffer and
9042 		 * return a ENOMEM to the user application.
9043 		 */
9044 		if (pm.pm_stat_len > fcio->fcio_olen) {
9045 			fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
9046 			    "fp:FCIO_DIAG:status buffer too small\n");
9047 
9048 			rval = ENOMEM;
9049 			if (ddi_copyout(pm.pm_stat_buf, fcio->fcio_obuf,
9050 			    fcio->fcio_olen, mode)) {
9051 				rval = EFAULT;
9052 				goto fp_fcio_diag_cleanup;
9053 			}
9054 		} else {
9055 			/*
9056 			 * Copy only data pm_stat_len bytes of data
9057 			 */
9058 			if (ddi_copyout(pm.pm_stat_buf, fcio->fcio_obuf,
9059 			    pm.pm_stat_len, mode)) {
9060 				rval = EFAULT;
9061 				goto fp_fcio_diag_cleanup;
9062 			}
9063 		}
9064 
9065 		if (fp_fcio_copyout(fcio, data, mode)) {
9066 			rval = EFAULT;
9067 		}
9068 
9069 fp_fcio_diag_cleanup:
9070 		if (pm.pm_cmd_buf != NULL) {
9071 			kmem_free(pm.pm_cmd_buf, fcio->fcio_ilen);
9072 		}
9073 		if (pm.pm_data_buf != NULL) {
9074 			kmem_free(pm.pm_data_buf, fcio->fcio_alen);
9075 		}
9076 		if (pm.pm_stat_buf != NULL) {
9077 			kmem_free(pm.pm_stat_buf, fcio->fcio_olen);
9078 		}
9079 
9080 		break;
9081 	}
9082 
9083 	case FCIO_GET_NODE_ID: {
9084 		/* validate parameters */
9085 		if (fcio->fcio_xfer != FCIO_XFER_READ ||
9086 		    fcio->fcio_olen < sizeof (fc_rnid_t)) {
9087 			rval = EINVAL;
9088 			break;
9089 		}
9090 
9091 		rval = fp_get_rnid(port, data, mode, fcio);
9092 
9093 		/* ioctl handling is over */
9094 		break;
9095 	}
9096 
9097 	case FCIO_SEND_NODE_ID: {
9098 		la_wwn_t 		pwwn;
9099 
9100 		/* validate parameters */
9101 		if (fcio->fcio_ilen != sizeof (la_wwn_t) ||
9102 		    fcio->fcio_xfer != FCIO_XFER_READ) {
9103 			rval = EINVAL;
9104 			break;
9105 		}
9106 
9107 		if (ddi_copyin(fcio->fcio_ibuf, &pwwn,
9108 		    sizeof (la_wwn_t), mode)) {
9109 			rval = EFAULT;
9110 			break;
9111 		}
9112 
9113 		rval = fp_send_rnid(port, data, mode, fcio, &pwwn);
9114 
9115 		/* ioctl handling is over */
9116 		break;
9117 	}
9118 
9119 	case FCIO_SET_NODE_ID: {
9120 		if (fcio->fcio_ilen != sizeof (fc_rnid_t) ||
9121 		    (fcio->fcio_xfer != FCIO_XFER_WRITE)) {
9122 			rval = EINVAL;
9123 			break;
9124 		}
9125 
9126 		rval = fp_set_rnid(port, data, mode, fcio);
9127 		break;
9128 	}
9129 
9130 	case FCIO_LINK_STATUS: {
9131 		fc_portid_t		rls_req;
9132 		fc_rls_acc_t		*rls_acc;
9133 		fc_fca_pm_t		pm;
9134 		uint32_t		dest, src_id;
9135 		fp_cmd_t		*cmd;
9136 		fc_remote_port_t	*pd;
9137 		uchar_t			pd_flags;
9138 
9139 		/* validate parameters */
9140 		if (fcio->fcio_ilen != sizeof (fc_portid_t) ||
9141 		    fcio->fcio_olen != sizeof (fc_rls_acc_t) ||
9142 		    fcio->fcio_xfer != FCIO_XFER_RW) {
9143 			rval = EINVAL;
9144 			break;
9145 		}
9146 
9147 		if ((fcio->fcio_cmd_flags != FCIO_CFLAGS_RLS_DEST_FPORT) &&
9148 		    (fcio->fcio_cmd_flags != FCIO_CFLAGS_RLS_DEST_NPORT)) {
9149 			rval = EINVAL;
9150 			break;
9151 		}
9152 
9153 		if (ddi_copyin((void *)fcio->fcio_ibuf, (void *)&rls_req,
9154 		    sizeof (fc_portid_t), mode)) {
9155 			rval = EFAULT;
9156 			break;
9157 		}
9158 
9159 
9160 		/* Determine the destination of the RLS frame */
9161 		if (fcio->fcio_cmd_flags == FCIO_CFLAGS_RLS_DEST_FPORT) {
9162 			dest = FS_FABRIC_F_PORT;
9163 		} else {
9164 			dest = rls_req.port_id;
9165 		}
9166 
9167 		mutex_enter(&port->fp_mutex);
9168 		src_id = port->fp_port_id.port_id;
9169 		mutex_exit(&port->fp_mutex);
9170 
9171 		/* If dest is zero OR same as FCA ID, then use port_manage() */
9172 		if (dest == 0 || dest == src_id) {
9173 
9174 			/* Allocate memory for link error status block */
9175 			rls_acc = kmem_zalloc(sizeof (*rls_acc), KM_SLEEP);
9176 			ASSERT(rls_acc != NULL);
9177 
9178 			/* Prepare the port management structure */
9179 			bzero((caddr_t)&pm, sizeof (pm));
9180 
9181 			pm.pm_cmd_flags = FC_FCA_PM_READ;
9182 			pm.pm_cmd_code  = FC_PORT_RLS;
9183 			pm.pm_data_len  = sizeof (*rls_acc);
9184 			pm.pm_data_buf  = (caddr_t)rls_acc;
9185 
9186 			/* Get the adapter's link error status block */
9187 			ret = port->fp_fca_tran->fca_port_manage(
9188 			    port->fp_fca_handle, &pm);
9189 
9190 			if (ret == FC_SUCCESS) {
9191 				/* xfer link status block to userland */
9192 				if (ddi_copyout((void *)rls_acc,
9193 				    (void *)fcio->fcio_obuf,
9194 				    sizeof (*rls_acc), mode) == 0) {
9195 					if (fp_fcio_copyout(fcio, data,
9196 					    mode)) {
9197 						rval = EFAULT;
9198 					}
9199 				} else {
9200 					rval = EFAULT;
9201 				}
9202 			} else {
9203 				rval = EIO;
9204 				fcio->fcio_errno = ret;
9205 				if (fp_fcio_copyout(fcio, data, mode)) {
9206 					rval = EFAULT;
9207 				}
9208 			}
9209 
9210 			kmem_free(rls_acc, sizeof (*rls_acc));
9211 
9212 			/* ioctl handling is over */
9213 			break;
9214 		}
9215 
9216 		/*
9217 		 * Send RLS to the destination port.
9218 		 * Having RLS frame destination is as FPORT is not yet
9219 		 * supported and will be implemented in future, if needed.
9220 		 * Following call to get "pd" will fail if dest is FPORT
9221 		 */
9222 		pd = fctl_hold_remote_port_by_did(port, dest);
9223 		if (pd == NULL) {
9224 			fcio->fcio_errno = FC_BADOBJECT;
9225 			rval = ENXIO;
9226 			if (fp_fcio_copyout(fcio, data, mode)) {
9227 				rval = EFAULT;
9228 			}
9229 			break;
9230 		}
9231 
9232 		mutex_enter(&pd->pd_mutex);
9233 		if (pd->pd_state != PORT_DEVICE_LOGGED_IN) {
9234 			mutex_exit(&pd->pd_mutex);
9235 			fctl_release_remote_port(pd);
9236 
9237 			fcio->fcio_errno = FC_LOGINREQ;
9238 			rval = EINVAL;
9239 			if (fp_fcio_copyout(fcio, data, mode)) {
9240 				rval = EFAULT;
9241 			}
9242 			break;
9243 		}
9244 		ASSERT(pd->pd_login_count >= 1);
9245 		mutex_exit(&pd->pd_mutex);
9246 
9247 		/*
9248 		 * Allocate job structure and set job_code as DUMMY,
9249 		 * because we will not go through the job thread.
9250 		 * Instead fp_sendcmd() is called directly here.
9251 		 */
9252 		job = fctl_alloc_job(JOB_DUMMY, JOB_TYPE_FP_ASYNC,
9253 		    NULL, NULL, KM_SLEEP);
9254 		ASSERT(job != NULL);
9255 
9256 		job->job_counter = 1;
9257 
9258 		cmd = fp_alloc_pkt(port, sizeof (la_els_rls_t),
9259 		    sizeof (la_els_rls_acc_t), KM_SLEEP, pd);
9260 		if (cmd == NULL) {
9261 			fcio->fcio_errno = FC_NOMEM;
9262 			rval = ENOMEM;
9263 
9264 			fctl_release_remote_port(pd);
9265 
9266 			fctl_dealloc_job(job);
9267 			if (fp_fcio_copyout(fcio, data, mode)) {
9268 				rval = EFAULT;
9269 			}
9270 			break;
9271 		}
9272 
9273 		/* Allocate memory for link error status block */
9274 		rls_acc = kmem_zalloc(sizeof (*rls_acc), KM_SLEEP);
9275 
9276 		mutex_enter(&port->fp_mutex);
9277 		mutex_enter(&pd->pd_mutex);
9278 
9279 		cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
9280 		cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
9281 		cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
9282 		cmd->cmd_retry_count = 1;
9283 		cmd->cmd_ulp_pkt = NULL;
9284 
9285 		fp_rls_init(cmd, job);
9286 
9287 		job->job_private = (void *)rls_acc;
9288 
9289 		pd_flags = pd->pd_flags;
9290 		pd->pd_flags = PD_ELS_IN_PROGRESS;
9291 
9292 		mutex_exit(&pd->pd_mutex);
9293 		mutex_exit(&port->fp_mutex);
9294 
9295 		if (fp_sendcmd(port, cmd, port->fp_fca_handle) == FC_SUCCESS) {
9296 			fctl_jobwait(job);
9297 
9298 			fcio->fcio_errno = job->job_result;
9299 			if (job->job_result == FC_SUCCESS) {
9300 				ASSERT(pd != NULL);
9301 				/*
9302 				 * link error status block is now available.
9303 				 * Copy it to userland
9304 				 */
9305 				ASSERT(job->job_private == (void *)rls_acc);
9306 				if (ddi_copyout((void *)rls_acc,
9307 				    (void *)fcio->fcio_obuf,
9308 				    sizeof (*rls_acc), mode) == 0) {
9309 					if (fp_fcio_copyout(fcio, data,
9310 					    mode)) {
9311 						rval = EFAULT;
9312 					}
9313 				} else {
9314 					rval = EFAULT;
9315 				}
9316 			} else {
9317 				rval = EIO;
9318 			}
9319 		} else {
9320 			rval = EIO;
9321 			fp_free_pkt(cmd);
9322 		}
9323 
9324 		if (rval) {
9325 			mutex_enter(&port->fp_mutex);
9326 			mutex_enter(&pd->pd_mutex);
9327 			if (pd->pd_flags == PD_ELS_IN_PROGRESS) {
9328 				pd->pd_flags = pd_flags;
9329 			}
9330 			mutex_exit(&pd->pd_mutex);
9331 			mutex_exit(&port->fp_mutex);
9332 		}
9333 
9334 		fctl_release_remote_port(pd);
9335 		fctl_dealloc_job(job);
9336 		kmem_free(rls_acc, sizeof (*rls_acc));
9337 
9338 		if (fp_fcio_copyout(fcio, data, mode)) {
9339 			rval = EFAULT;
9340 		}
9341 		break;
9342 	}
9343 
9344 	case FCIO_NS: {
9345 		fc_ns_cmd_t 	*ns_req;
9346 		fc_ns_cmd32_t 	*ns_req32;
9347 		fctl_ns_req_t 	*ns_cmd;
9348 
9349 		if (use32 == B_TRUE) {
9350 			if (fcio->fcio_ilen != sizeof (*ns_req32)) {
9351 				rval = EINVAL;
9352 				break;
9353 			}
9354 
9355 			ns_req = kmem_zalloc(sizeof (*ns_req), KM_SLEEP);
9356 			ns_req32 = kmem_zalloc(sizeof (*ns_req32), KM_SLEEP);
9357 
9358 			if (ddi_copyin(fcio->fcio_ibuf, ns_req32,
9359 			    sizeof (*ns_req32), mode)) {
9360 				rval = EFAULT;
9361 				kmem_free(ns_req, sizeof (*ns_req));
9362 				kmem_free(ns_req32, sizeof (*ns_req32));
9363 				break;
9364 			}
9365 
9366 			ns_req->ns_flags = ns_req32->ns_flags;
9367 			ns_req->ns_cmd = ns_req32->ns_cmd;
9368 			ns_req->ns_req_len = ns_req32->ns_req_len;
9369 			ns_req->ns_req_payload = ns_req32->ns_req_payload;
9370 			ns_req->ns_resp_len = ns_req32->ns_resp_len;
9371 			ns_req->ns_resp_payload = ns_req32->ns_resp_payload;
9372 			ns_req->ns_fctl_private = ns_req32->ns_fctl_private;
9373 			ns_req->ns_resp_hdr = ns_req32->ns_resp_hdr;
9374 
9375 			kmem_free(ns_req32, sizeof (*ns_req32));
9376 		} else {
9377 			if (fcio->fcio_ilen != sizeof (*ns_req)) {
9378 				rval = EINVAL;
9379 				break;
9380 			}
9381 
9382 			ns_req = kmem_zalloc(sizeof (*ns_req), KM_SLEEP);
9383 
9384 			if (ddi_copyin(fcio->fcio_ibuf, ns_req,
9385 			    sizeof (fc_ns_cmd_t), mode)) {
9386 				rval = EFAULT;
9387 				kmem_free(ns_req, sizeof (*ns_req));
9388 				break;
9389 			}
9390 		}
9391 
9392 		if (ns_req->ns_req_len <= 0) {
9393 			rval = EINVAL;
9394 			kmem_free(ns_req, sizeof (*ns_req));
9395 			break;
9396 		}
9397 
9398 		job = fctl_alloc_job(JOB_NS_CMD, 0, NULL, NULL, KM_SLEEP);
9399 		ASSERT(job != NULL);
9400 
9401 		ns_cmd = fctl_alloc_ns_cmd(ns_req->ns_req_len,
9402 		    ns_req->ns_resp_len, ns_req->ns_resp_len,
9403 		    FCTL_NS_FILL_NS_MAP, KM_SLEEP);
9404 		ASSERT(ns_cmd != NULL);
9405 		ns_cmd->ns_cmd_code = ns_req->ns_cmd;
9406 
9407 		if (ns_cmd->ns_cmd_code == NS_GA_NXT) {
9408 			ns_cmd->ns_gan_max = 1;
9409 			ns_cmd->ns_gan_index = 0;
9410 			ns_cmd->ns_gan_sid = FCTL_GAN_START_ID;
9411 		}
9412 
9413 		if (ddi_copyin(ns_req->ns_req_payload,
9414 		    ns_cmd->ns_cmd_buf, ns_req->ns_req_len, mode)) {
9415 			rval = EFAULT;
9416 			fctl_free_ns_cmd(ns_cmd);
9417 			fctl_dealloc_job(job);
9418 			kmem_free(ns_req, sizeof (*ns_req));
9419 			break;
9420 		}
9421 
9422 		job->job_private = (void *)ns_cmd;
9423 		fctl_enque_job(port, job);
9424 		fctl_jobwait(job);
9425 		rval = job->job_result;
9426 
9427 		if (rval == FC_SUCCESS) {
9428 			if (ns_req->ns_resp_len) {
9429 				if (ddi_copyout(ns_cmd->ns_data_buf,
9430 				    ns_req->ns_resp_payload,
9431 				    ns_cmd->ns_data_len, mode)) {
9432 					rval = EFAULT;
9433 					fctl_free_ns_cmd(ns_cmd);
9434 					fctl_dealloc_job(job);
9435 					kmem_free(ns_req, sizeof (*ns_req));
9436 					break;
9437 				}
9438 			}
9439 		} else {
9440 			rval = EIO;
9441 		}
9442 		ns_req->ns_resp_hdr = ns_cmd->ns_resp_hdr;
9443 		fctl_free_ns_cmd(ns_cmd);
9444 		fctl_dealloc_job(job);
9445 		kmem_free(ns_req, sizeof (*ns_req));
9446 
9447 		if (fp_fcio_copyout(fcio, data, mode)) {
9448 			rval = EFAULT;
9449 		}
9450 		break;
9451 	}
9452 
9453 	default:
9454 		rval = ENOTTY;
9455 		break;
9456 	}
9457 
9458 	/*
9459 	 * If set, reset the EXCL busy bit to
9460 	 * receive other exclusive access commands
9461 	 */
9462 	mutex_enter(&port->fp_mutex);
9463 	if (port->fp_flag & FP_EXCL_BUSY) {
9464 		port->fp_flag &= ~FP_EXCL_BUSY;
9465 	}
9466 	mutex_exit(&port->fp_mutex);
9467 
9468 	return (rval);
9469 }
9470 
9471 
9472 /*
9473  * This function assumes that the response length
9474  * is same regardless of data model (LP32 or LP64)
9475  * which is true for all the ioctls currently
9476  * supported.
9477  */
9478 static int
9479 fp_copyout(void *from, void *to, size_t len, int mode)
9480 {
9481 	return (ddi_copyout(from, to, len, mode));
9482 }
9483 
9484 /*
9485  * This function does the set rnid
9486  */
9487 static int
9488 fp_set_rnid(fc_local_port_t *port, intptr_t data, int mode, fcio_t *fcio)
9489 {
9490 	int 		rval = 0;
9491 	fc_rnid_t	*rnid;
9492 	fc_fca_pm_t	pm;
9493 
9494 	/* Allocate memory for node id block */
9495 	rnid = kmem_zalloc(sizeof (fc_rnid_t), KM_SLEEP);
9496 
9497 	if (ddi_copyin(fcio->fcio_ibuf, rnid, sizeof (fc_rnid_t), mode)) {
9498 		FP_TRACE(FP_NHEAD1(3, 0), "fp_set_rnid: failed = %d", EFAULT);
9499 		kmem_free(rnid, sizeof (fc_rnid_t));
9500 		return (EFAULT);
9501 	}
9502 
9503 	/* Prepare the port management structure */
9504 	bzero((caddr_t)&pm, sizeof (pm));
9505 
9506 	pm.pm_cmd_flags = FC_FCA_PM_WRITE;
9507 	pm.pm_cmd_code  = FC_PORT_SET_NODE_ID;
9508 	pm.pm_data_len  = sizeof (*rnid);
9509 	pm.pm_data_buf  = (caddr_t)rnid;
9510 
9511 	/* Get the adapter's node data */
9512 	rval = port->fp_fca_tran->fca_port_manage(
9513 	    port->fp_fca_handle, &pm);
9514 
9515 	if (rval != FC_SUCCESS) {
9516 		fcio->fcio_errno = rval;
9517 		rval = EIO;
9518 		if (fp_fcio_copyout(fcio, data, mode)) {
9519 			rval = EFAULT;
9520 		}
9521 	} else {
9522 		mutex_enter(&port->fp_mutex);
9523 		/* copy to the port structure */
9524 		bcopy(rnid, &port->fp_rnid_params,
9525 			sizeof (port->fp_rnid_params));
9526 		mutex_exit(&port->fp_mutex);
9527 	}
9528 
9529 	kmem_free(rnid, sizeof (fc_rnid_t));
9530 
9531 	if (rval != FC_SUCCESS) {
9532 		FP_TRACE(FP_NHEAD1(3, 0), "fp_set_rnid: failed = %d", rval);
9533 	}
9534 
9535 	return (rval);
9536 }
9537 
9538 /*
9539  * This function does the local pwwn get rnid
9540  */
9541 static int
9542 fp_get_rnid(fc_local_port_t *port, intptr_t data, int mode, fcio_t *fcio)
9543 {
9544 	fc_rnid_t		*rnid;
9545 	fc_fca_pm_t		pm;
9546 	int 			rval = 0;
9547 	uint32_t		ret;
9548 
9549 	/* Allocate memory for rnid data block */
9550 	rnid = kmem_zalloc(sizeof (fc_rnid_t), KM_SLEEP);
9551 
9552 	mutex_enter(&port->fp_mutex);
9553 	if (port->fp_rnid_init == 1) {
9554 		bcopy(&port->fp_rnid_params, rnid, sizeof (fc_rnid_t));
9555 		mutex_exit(&port->fp_mutex);
9556 		/* xfer node info to userland */
9557 		if (ddi_copyout((void *)rnid, (void *)fcio->fcio_obuf,
9558 		    sizeof (*rnid), mode) == 0) {
9559 			if (fp_fcio_copyout(fcio, data, mode)) {
9560 				rval = EFAULT;
9561 			}
9562 		} else {
9563 			rval = EFAULT;
9564 		}
9565 
9566 		kmem_free(rnid, sizeof (fc_rnid_t));
9567 
9568 		if (rval != FC_SUCCESS) {
9569 			FP_TRACE(FP_NHEAD1(3, 0), "fp_get_rnid: failed = %d",
9570 			rval);
9571 		}
9572 
9573 		return (rval);
9574 	}
9575 	mutex_exit(&port->fp_mutex);
9576 
9577 	/* Prepare the port management structure */
9578 	bzero((caddr_t)&pm, sizeof (pm));
9579 
9580 	pm.pm_cmd_flags = FC_FCA_PM_READ;
9581 	pm.pm_cmd_code  = FC_PORT_GET_NODE_ID;
9582 	pm.pm_data_len  = sizeof (fc_rnid_t);
9583 	pm.pm_data_buf  = (caddr_t)rnid;
9584 
9585 	/* Get the adapter's node data */
9586 	ret = port->fp_fca_tran->fca_port_manage(
9587 			port->fp_fca_handle,
9588 			&pm);
9589 
9590 	if (ret == FC_SUCCESS) {
9591 		/* initialize in the port_info */
9592 		mutex_enter(&port->fp_mutex);
9593 		port->fp_rnid_init = 1;
9594 		bcopy(rnid, &port->fp_rnid_params, sizeof (*rnid));
9595 		mutex_exit(&port->fp_mutex);
9596 
9597 		/* xfer node info to userland */
9598 		if (ddi_copyout((void *)rnid,
9599 				(void *)fcio->fcio_obuf,
9600 				sizeof (*rnid), mode) == 0) {
9601 			if (fp_fcio_copyout(fcio, data,
9602 					mode)) {
9603 				rval = EFAULT;
9604 			}
9605 		} else {
9606 			rval = EFAULT;
9607 		}
9608 	} else {
9609 		rval = EIO;
9610 		fcio->fcio_errno = ret;
9611 		if (fp_fcio_copyout(fcio, data, mode)) {
9612 			rval = EFAULT;
9613 		}
9614 	}
9615 
9616 	kmem_free(rnid, sizeof (fc_rnid_t));
9617 
9618 	if (rval != FC_SUCCESS) {
9619 		FP_TRACE(FP_NHEAD1(3, 0), "fp_get_rnid: failed = %d", rval);
9620 	}
9621 
9622 	return (rval);
9623 }
9624 
9625 static int
9626 fp_send_rnid(fc_local_port_t *port, intptr_t data, int mode, fcio_t *fcio,
9627 	la_wwn_t *pwwn)
9628 {
9629 	int 			rval = 0;
9630 	fc_remote_port_t	*pd;
9631 	fp_cmd_t		*cmd;
9632 	job_request_t 		*job;
9633 	la_els_rnid_acc_t	*rnid_acc;
9634 
9635 	pd = fctl_get_remote_port_by_pwwn(port, pwwn);
9636 	if (pd == NULL) {
9637 		/*
9638 		 * We can safely assume that the destination port
9639 		 * is logged in. Either the user land will explicitly
9640 		 * login before issuing RNID ioctl or the device would
9641 		 * have been configured, meaning already logged in.
9642 		 */
9643 
9644 		FP_TRACE(FP_NHEAD1(3, 0), "fp_send_rnid: failed = %d", ENXIO);
9645 
9646 		return (ENXIO);
9647 	}
9648 	/*
9649 	 * Allocate job structure and set job_code as DUMMY,
9650 	 * because we will not go thorugh the job thread.
9651 	 * Instead fp_sendcmd() is called directly here.
9652 	 */
9653 	job = fctl_alloc_job(JOB_DUMMY, JOB_TYPE_FP_ASYNC,
9654 	    NULL, NULL, KM_SLEEP);
9655 
9656 	ASSERT(job != NULL);
9657 
9658 	job->job_counter = 1;
9659 
9660 	cmd = fp_alloc_pkt(port, sizeof (la_els_rnid_t),
9661 	    sizeof (la_els_rnid_acc_t), KM_SLEEP, pd);
9662 	if (cmd == NULL) {
9663 		fcio->fcio_errno = FC_NOMEM;
9664 		rval = ENOMEM;
9665 
9666 		fctl_dealloc_job(job);
9667 		if (fp_fcio_copyout(fcio, data, mode)) {
9668 			rval = EFAULT;
9669 		}
9670 
9671 		FP_TRACE(FP_NHEAD1(3, 0), "fp_send_rnid: failed = %d", rval);
9672 
9673 		return (rval);
9674 	}
9675 
9676 	/* Allocate memory for node id accept block */
9677 	rnid_acc = kmem_zalloc(sizeof (la_els_rnid_acc_t), KM_SLEEP);
9678 
9679 	mutex_enter(&port->fp_mutex);
9680 	mutex_enter(&pd->pd_mutex);
9681 
9682 	cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
9683 	cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
9684 	cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
9685 	cmd->cmd_retry_count = 1;
9686 	cmd->cmd_ulp_pkt = NULL;
9687 
9688 	fp_rnid_init(cmd, fcio->fcio_cmd_flags, job);
9689 
9690 	job->job_private = (void *)rnid_acc;
9691 
9692 	pd->pd_flags = PD_ELS_IN_PROGRESS;
9693 
9694 	mutex_exit(&pd->pd_mutex);
9695 	mutex_exit(&port->fp_mutex);
9696 
9697 	if (fp_sendcmd(port, cmd, port->fp_fca_handle) == FC_SUCCESS) {
9698 		fctl_jobwait(job);
9699 		fcio->fcio_errno = job->job_result;
9700 		if (job->job_result == FC_SUCCESS) {
9701 			int rnid_cnt;
9702 			ASSERT(pd != NULL);
9703 			/*
9704 			 * node id block is now available.
9705 			 * Copy it to userland
9706 			 */
9707 			ASSERT(job->job_private == (void *)rnid_acc);
9708 
9709 			/* get the response length */
9710 			rnid_cnt = sizeof (ls_code_t) + sizeof (fc_rnid_hdr_t) +
9711 					rnid_acc->hdr.cmn_len +
9712 					rnid_acc->hdr.specific_len;
9713 
9714 			if (fcio->fcio_olen < rnid_cnt) {
9715 				rval = EINVAL;
9716 			} else if (ddi_copyout((void *)rnid_acc,
9717 				(void *)fcio->fcio_obuf,
9718 				rnid_cnt, mode) == 0) {
9719 				if (fp_fcio_copyout(fcio, data,
9720 					mode)) {
9721 					rval = EFAULT;
9722 				}
9723 			} else {
9724 				rval = EFAULT;
9725 			}
9726 		} else {
9727 			rval = EIO;
9728 		}
9729 	} else {
9730 		rval = EIO;
9731 		if (pd) {
9732 			mutex_enter(&pd->pd_mutex);
9733 			pd->pd_flags = PD_IDLE;
9734 			mutex_exit(&pd->pd_mutex);
9735 		}
9736 		fp_free_pkt(cmd);
9737 	}
9738 
9739 	fctl_dealloc_job(job);
9740 	kmem_free(rnid_acc, sizeof (la_els_rnid_acc_t));
9741 
9742 	if (fp_fcio_copyout(fcio, data, mode)) {
9743 		rval = EFAULT;
9744 	}
9745 
9746 	if (rval != FC_SUCCESS) {
9747 		FP_TRACE(FP_NHEAD1(3, 0), "fp_send_rnid: failed = %d", rval);
9748 	}
9749 
9750 	return (rval);
9751 }
9752 
9753 /*
9754  * Copy out to userland
9755  */
9756 static int
9757 fp_fcio_copyout(fcio_t *fcio, intptr_t data, int mode)
9758 {
9759 	int rval;
9760 
9761 #ifdef	_MULTI_DATAMODEL
9762 	switch (ddi_model_convert_from(mode & FMODELS)) {
9763 	case DDI_MODEL_ILP32: {
9764 		struct fcio32 fcio32;
9765 
9766 		fcio32.fcio_xfer = fcio->fcio_xfer;
9767 		fcio32.fcio_cmd = fcio->fcio_cmd;
9768 		fcio32.fcio_flags = fcio->fcio_flags;
9769 		fcio32.fcio_cmd_flags = fcio->fcio_cmd_flags;
9770 		fcio32.fcio_ilen = fcio->fcio_ilen;
9771 		fcio32.fcio_ibuf =
9772 			(caddr32_t)(uintptr_t)fcio->fcio_ibuf;
9773 		fcio32.fcio_olen = fcio->fcio_olen;
9774 		fcio32.fcio_obuf =
9775 			(caddr32_t)(uintptr_t)fcio->fcio_obuf;
9776 		fcio32.fcio_alen = fcio->fcio_alen;
9777 		fcio32.fcio_abuf =
9778 			(caddr32_t)(uintptr_t)fcio->fcio_abuf;
9779 		fcio32.fcio_errno = fcio->fcio_errno;
9780 
9781 		rval = ddi_copyout((void *)&fcio32, (void *)data,
9782 		    sizeof (struct fcio32), mode);
9783 		break;
9784 	}
9785 	case DDI_MODEL_NONE:
9786 		rval = ddi_copyout((void *)fcio, (void *)data,
9787 		    sizeof (fcio_t), mode);
9788 		break;
9789 	}
9790 #else
9791 	rval = ddi_copyout((void *)fcio, (void *)data, sizeof (fcio_t), mode);
9792 #endif
9793 
9794 	return (rval);
9795 }
9796 
9797 
9798 static void
9799 fp_p2p_online(fc_local_port_t *port, job_request_t *job)
9800 {
9801 	uint32_t		listlen;
9802 	fc_portmap_t		*changelist;
9803 
9804 	ASSERT(MUTEX_HELD(&port->fp_mutex));
9805 	ASSERT(port->fp_topology == FC_TOP_PT_PT);
9806 	ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
9807 
9808 	listlen = 0;
9809 	changelist = NULL;
9810 
9811 	if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) {
9812 		if (port->fp_statec_busy > 1) {
9813 			job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION;
9814 		}
9815 	}
9816 	mutex_exit(&port->fp_mutex);
9817 
9818 	if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) {
9819 		fctl_fillout_map(port, &changelist, &listlen, 1, 0, 0);
9820 		(void) fp_ulp_statec_cb(port, FC_STATE_ONLINE, changelist,
9821 		    listlen, listlen, KM_SLEEP);
9822 
9823 		mutex_enter(&port->fp_mutex);
9824 	} else {
9825 		ASSERT(changelist == NULL && listlen == 0);
9826 		mutex_enter(&port->fp_mutex);
9827 		if (--port->fp_statec_busy == 0) {
9828 			port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
9829 		}
9830 	}
9831 }
9832 
9833 static int
9834 fp_fillout_p2pmap(fc_local_port_t *port, fcio_t *fcio, int mode)
9835 {
9836 	int			rval;
9837 	int			count;
9838 	int			index;
9839 	int			num_devices;
9840 	fc_remote_node_t	*node;
9841 	fc_port_dev_t 		*devlist;
9842 	struct pwwn_hash 	*head;
9843 	fc_remote_port_t 	*pd;
9844 
9845 	ASSERT(MUTEX_HELD(&port->fp_mutex));
9846 
9847 	num_devices = fcio->fcio_olen / sizeof (fc_port_dev_t);
9848 
9849 	devlist = kmem_zalloc(sizeof (fc_port_dev_t) * num_devices, KM_SLEEP);
9850 
9851 	for (count = index = 0; index < pwwn_table_size; index++) {
9852 		head = &port->fp_pwwn_table[index];
9853 		pd = head->pwwn_head;
9854 		while (pd != NULL) {
9855 			mutex_enter(&pd->pd_mutex);
9856 			if (pd->pd_state == PORT_DEVICE_INVALID) {
9857 				mutex_exit(&pd->pd_mutex);
9858 				pd = pd->pd_wwn_hnext;
9859 				continue;
9860 			}
9861 
9862 			devlist[count].dev_state = pd->pd_state;
9863 			devlist[count].dev_hard_addr = pd->pd_hard_addr;
9864 			devlist[count].dev_did = pd->pd_port_id;
9865 			devlist[count].dev_did.priv_lilp_posit =
9866 			    (uint8_t)(index & 0xff);
9867 			bcopy((caddr_t)pd->pd_fc4types,
9868 			    (caddr_t)devlist[count].dev_type,
9869 			    sizeof (pd->pd_fc4types));
9870 
9871 			bcopy((caddr_t)&pd->pd_port_name,
9872 			    (caddr_t)&devlist[count].dev_pwwn,
9873 			    sizeof (la_wwn_t));
9874 
9875 			node = pd->pd_remote_nodep;
9876 			mutex_exit(&pd->pd_mutex);
9877 
9878 			if (node) {
9879 				mutex_enter(&node->fd_mutex);
9880 				bcopy((caddr_t)&node->fd_node_name,
9881 				    (caddr_t)&devlist[count].dev_nwwn,
9882 				    sizeof (la_wwn_t));
9883 				mutex_exit(&node->fd_mutex);
9884 			}
9885 			count++;
9886 			if (count >= num_devices) {
9887 				goto found;
9888 			}
9889 		}
9890 	}
9891 found:
9892 	if (fp_copyout((void *)&count, (void *)fcio->fcio_abuf,
9893 	    sizeof (count), mode)) {
9894 		rval = FC_FAILURE;
9895 	} else if (fp_copyout((void *)devlist, (void *)fcio->fcio_obuf,
9896 	    sizeof (fc_port_dev_t) * num_devices, mode)) {
9897 		rval = FC_FAILURE;
9898 	} else {
9899 		rval = FC_SUCCESS;
9900 	}
9901 
9902 	kmem_free(devlist, sizeof (fc_port_dev_t) * num_devices);
9903 
9904 	return (rval);
9905 }
9906 
9907 
9908 /*
9909  * Handle Fabric ONLINE
9910  */
9911 static void
9912 fp_fabric_online(fc_local_port_t *port, job_request_t *job)
9913 {
9914 	int			index;
9915 	int			rval;
9916 	int			dbg_count;
9917 	int			count = 0;
9918 	char 			ww_name[17];
9919 	uint32_t		d_id;
9920 	uint32_t		listlen;
9921 	fctl_ns_req_t		*ns_cmd;
9922 	struct pwwn_hash	*head;
9923 	fc_remote_port_t	*pd;
9924 	fc_remote_port_t	*npd;
9925 	fc_portmap_t		*changelist;
9926 
9927 	ASSERT(MUTEX_HELD(&port->fp_mutex));
9928 	ASSERT(FC_IS_TOP_SWITCH(port->fp_topology));
9929 	ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
9930 
9931 	ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t),
9932 	    sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t),
9933 	    0, KM_SLEEP);
9934 
9935 	ASSERT(ns_cmd != NULL);
9936 
9937 	ns_cmd->ns_cmd_code = NS_GID_PN;
9938 
9939 	/*
9940 	 * Check if orphans are showing up now
9941 	 */
9942 	if (port->fp_orphan_count) {
9943 		fc_orphan_t 	*orp;
9944 		fc_orphan_t	*norp = NULL;
9945 		fc_orphan_t	*prev = NULL;
9946 
9947 		for (orp = port->fp_orphan_list; orp; orp = norp) {
9948 			norp = orp->orp_next;
9949 			mutex_exit(&port->fp_mutex);
9950 			orp->orp_nscan++;
9951 
9952 			job->job_counter = 1;
9953 			job->job_result = FC_SUCCESS;
9954 
9955 			((ns_req_gid_pn_t *)
9956 			    (ns_cmd->ns_cmd_buf))->pwwn = orp->orp_pwwn;
9957 			((ns_resp_gid_pn_t *)
9958 			    ns_cmd->ns_data_buf)->pid.port_id = 0;
9959 			((ns_resp_gid_pn_t *)
9960 			    ns_cmd->ns_data_buf)->pid.priv_lilp_posit = 0;
9961 
9962 			rval = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP);
9963 			if (rval == FC_SUCCESS) {
9964 				d_id =
9965 				    BE_32(*((uint32_t *)ns_cmd->ns_data_buf));
9966 				pd = fp_create_remote_port_by_ns(port,
9967 				    d_id, KM_SLEEP);
9968 
9969 				if (pd != NULL) {
9970 					fc_wwn_to_str(&orp->orp_pwwn, ww_name);
9971 
9972 					fp_printf(port, CE_WARN, FP_LOG_ONLY,
9973 					    0, NULL, "N_x Port with D_ID=%x,"
9974 					    " PWWN=%s reappeared in fabric",
9975 					    d_id, ww_name);
9976 
9977 					mutex_enter(&port->fp_mutex);
9978 					if (prev) {
9979 						prev->orp_next = orp->orp_next;
9980 					} else {
9981 						ASSERT(orp ==
9982 						    port->fp_orphan_list);
9983 						port->fp_orphan_list =
9984 						    orp->orp_next;
9985 					}
9986 					port->fp_orphan_count--;
9987 					mutex_exit(&port->fp_mutex);
9988 					kmem_free(orp, sizeof (*orp));
9989 					count++;
9990 
9991 					mutex_enter(&pd->pd_mutex);
9992 					pd->pd_flags = PD_ELS_MARK;
9993 
9994 					mutex_exit(&pd->pd_mutex);
9995 				} else {
9996 					prev = orp;
9997 				}
9998 			} else {
9999 				if (orp->orp_nscan == FC_ORPHAN_SCAN_LIMIT) {
10000 					fc_wwn_to_str(&orp->orp_pwwn, ww_name);
10001 
10002 					fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0,
10003 					    NULL,
10004 					    " Port WWN %s removed from orphan"
10005 					    " list after %d scans", ww_name,
10006 					    orp->orp_nscan);
10007 
10008 					mutex_enter(&port->fp_mutex);
10009 					if (prev) {
10010 						prev->orp_next = orp->orp_next;
10011 					} else {
10012 						ASSERT(orp ==
10013 						    port->fp_orphan_list);
10014 						port->fp_orphan_list =
10015 						    orp->orp_next;
10016 					}
10017 					port->fp_orphan_count--;
10018 					mutex_exit(&port->fp_mutex);
10019 
10020 					kmem_free(orp, sizeof (*orp));
10021 				} else {
10022 					prev = orp;
10023 				}
10024 			}
10025 			mutex_enter(&port->fp_mutex);
10026 		}
10027 	}
10028 
10029 	/*
10030 	 * Walk the Port WWN hash table, reestablish LOGIN
10031 	 * if a LOGIN is already performed on a particular
10032 	 * device; Any failure to LOGIN should mark the
10033 	 * port device OLD.
10034 	 */
10035 	for (index = 0; index < pwwn_table_size; index++) {
10036 		head = &port->fp_pwwn_table[index];
10037 		npd = head->pwwn_head;
10038 
10039 		while ((pd = npd) != NULL) {
10040 			la_wwn_t 	*pwwn;
10041 
10042 			npd = pd->pd_wwn_hnext;
10043 
10044 			/*
10045 			 * Don't count in the port devices that are new
10046 			 * unless the total number of devices visible
10047 			 * through this port is less than FP_MAX_DEVICES
10048 			 */
10049 			mutex_enter(&pd->pd_mutex);
10050 			if (port->fp_dev_count >= FP_MAX_DEVICES ||
10051 			    (port->fp_options & FP_TARGET_MODE)) {
10052 				if (pd->pd_type == PORT_DEVICE_NEW ||
10053 				    pd->pd_flags == PD_ELS_MARK ||
10054 				    pd->pd_recepient != PD_PLOGI_INITIATOR) {
10055 					mutex_exit(&pd->pd_mutex);
10056 					continue;
10057 				}
10058 			} else {
10059 				if (pd->pd_flags == PD_ELS_MARK ||
10060 				    pd->pd_recepient != PD_PLOGI_INITIATOR) {
10061 					mutex_exit(&pd->pd_mutex);
10062 					continue;
10063 				}
10064 				pd->pd_type = PORT_DEVICE_OLD;
10065 			}
10066 			count++;
10067 
10068 			/*
10069 			 * Consult with the name server about D_ID changes
10070 			 */
10071 			job->job_counter = 1;
10072 			job->job_result = FC_SUCCESS;
10073 
10074 			((ns_req_gid_pn_t *)
10075 			    (ns_cmd->ns_cmd_buf))->pwwn = pd->pd_port_name;
10076 			((ns_resp_gid_pn_t *)
10077 			    ns_cmd->ns_data_buf)->pid.port_id = 0;
10078 
10079 			((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->
10080 			    pid.priv_lilp_posit = 0;
10081 
10082 			pwwn = &pd->pd_port_name;
10083 			pd->pd_flags = PD_ELS_MARK;
10084 
10085 			mutex_exit(&pd->pd_mutex);
10086 			mutex_exit(&port->fp_mutex);
10087 
10088 			rval = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP);
10089 			if (rval != FC_SUCCESS) {
10090 				fc_wwn_to_str(pwwn, ww_name);
10091 
10092 				mutex_enter(&pd->pd_mutex);
10093 				d_id = pd->pd_port_id.port_id;
10094 				pd->pd_type = PORT_DEVICE_DELETE;
10095 				mutex_exit(&pd->pd_mutex);
10096 
10097 				FP_TRACE(FP_NHEAD1(3, 0),
10098 				    "fp_fabric_online: PD "
10099 				    "disappeared; d_id=%x, PWWN=%s",
10100 				    d_id, ww_name);
10101 
10102 				FP_TRACE(FP_NHEAD2(9, 0),
10103 				    "N_x Port with D_ID=%x, PWWN=%s"
10104 				    " disappeared from fabric", d_id,
10105 				    ww_name);
10106 
10107 				mutex_enter(&port->fp_mutex);
10108 				continue;
10109 			}
10110 
10111 			d_id = BE_32(*((uint32_t *)ns_cmd->ns_data_buf));
10112 
10113 			mutex_enter(&port->fp_mutex);
10114 			mutex_enter(&pd->pd_mutex);
10115 			if (d_id != pd->pd_port_id.port_id) {
10116 				fctl_delist_did_table(port, pd);
10117 				fc_wwn_to_str(pwwn, ww_name);
10118 
10119 				FP_TRACE(FP_NHEAD2(9, 0),
10120 				    "D_ID of a device with PWWN %s changed."
10121 				    " New D_ID = %x, OLD D_ID = %x", ww_name,
10122 				    d_id, pd->pd_port_id.port_id);
10123 
10124 				pd->pd_port_id.port_id = BE_32(d_id);
10125 				pd->pd_type = PORT_DEVICE_CHANGED;
10126 				fctl_enlist_did_table(port, pd);
10127 			}
10128 			mutex_exit(&pd->pd_mutex);
10129 
10130 		}
10131 	}
10132 
10133 	if (ns_cmd) {
10134 		fctl_free_ns_cmd(ns_cmd);
10135 	}
10136 
10137 	listlen = 0;
10138 	changelist = NULL;
10139 	if (count) {
10140 		if (port->fp_soft_state & FP_SOFT_IN_FCA_RESET) {
10141 			port->fp_soft_state &= ~FP_SOFT_IN_FCA_RESET;
10142 			mutex_exit(&port->fp_mutex);
10143 			delay(drv_usectohz(FLA_RR_TOV * 1000 * 1000));
10144 			mutex_enter(&port->fp_mutex);
10145 		}
10146 
10147 		dbg_count = 0;
10148 
10149 		job->job_counter = count;
10150 
10151 		for (index = 0; index < pwwn_table_size; index++) {
10152 			head = &port->fp_pwwn_table[index];
10153 			npd = head->pwwn_head;
10154 
10155 			while ((pd = npd) != NULL) {
10156 				npd = pd->pd_wwn_hnext;
10157 
10158 				mutex_enter(&pd->pd_mutex);
10159 				if (pd->pd_flags != PD_ELS_MARK) {
10160 					mutex_exit(&pd->pd_mutex);
10161 					continue;
10162 				}
10163 
10164 				dbg_count++;
10165 
10166 				/*
10167 				 * If it is already marked deletion, nothing
10168 				 * else to do.
10169 				 */
10170 				if (pd->pd_type == PORT_DEVICE_DELETE) {
10171 					pd->pd_type = PORT_DEVICE_OLD;
10172 
10173 					mutex_exit(&pd->pd_mutex);
10174 					mutex_exit(&port->fp_mutex);
10175 					fp_jobdone(job);
10176 					mutex_enter(&port->fp_mutex);
10177 
10178 					continue;
10179 				}
10180 
10181 				/*
10182 				 * If it is freshly discovered out of
10183 				 * the orphan list, nothing else to do
10184 				 */
10185 				if (pd->pd_type == PORT_DEVICE_NEW) {
10186 					pd->pd_flags = PD_IDLE;
10187 
10188 					mutex_exit(&pd->pd_mutex);
10189 					mutex_exit(&port->fp_mutex);
10190 					fp_jobdone(job);
10191 					mutex_enter(&port->fp_mutex);
10192 
10193 					continue;
10194 				}
10195 
10196 				pd->pd_flags = PD_IDLE;
10197 				d_id = pd->pd_port_id.port_id;
10198 
10199 				/*
10200 				 * Explicitly mark all devices OLD; successful
10201 				 * PLOGI should reset this to either NO_CHANGE
10202 				 * or CHANGED.
10203 				 */
10204 				if (pd->pd_type != PORT_DEVICE_CHANGED) {
10205 					pd->pd_type = PORT_DEVICE_OLD;
10206 				}
10207 
10208 				mutex_exit(&pd->pd_mutex);
10209 				mutex_exit(&port->fp_mutex);
10210 
10211 				rval = fp_port_login(port, d_id, job,
10212 				    FP_CMD_PLOGI_RETAIN, KM_SLEEP, pd, NULL);
10213 
10214 				if (rval != FC_SUCCESS) {
10215 					fp_jobdone(job);
10216 				}
10217 				mutex_enter(&port->fp_mutex);
10218 			}
10219 		}
10220 		mutex_exit(&port->fp_mutex);
10221 
10222 		ASSERT(dbg_count == count);
10223 		fp_jobwait(job);
10224 
10225 		mutex_enter(&port->fp_mutex);
10226 
10227 		ASSERT(port->fp_statec_busy > 0);
10228 		if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) {
10229 			if (port->fp_statec_busy > 1) {
10230 				job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION;
10231 			}
10232 		}
10233 		mutex_exit(&port->fp_mutex);
10234 	} else {
10235 		ASSERT(port->fp_statec_busy > 0);
10236 		if (port->fp_statec_busy > 1) {
10237 			job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION;
10238 		}
10239 		mutex_exit(&port->fp_mutex);
10240 	}
10241 
10242 	if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) {
10243 		fctl_fillout_map(port, &changelist, &listlen, 1, 0, 0);
10244 
10245 		(void) fp_ulp_statec_cb(port, FC_STATE_ONLINE, changelist,
10246 		    listlen, listlen, KM_SLEEP);
10247 
10248 		mutex_enter(&port->fp_mutex);
10249 	} else {
10250 		ASSERT(changelist == NULL && listlen == 0);
10251 		mutex_enter(&port->fp_mutex);
10252 		if (--port->fp_statec_busy == 0) {
10253 			port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
10254 		}
10255 	}
10256 }
10257 
10258 
10259 /*
10260  * Fill out device list for userland ioctl in private loop
10261  */
10262 static int
10263 fp_fillout_loopmap(fc_local_port_t *port, fcio_t *fcio, int mode)
10264 {
10265 	int			rval;
10266 	int			count;
10267 	int			index;
10268 	int			num_devices;
10269 	fc_remote_node_t	*node;
10270 	fc_port_dev_t 		*devlist;
10271 	int			lilp_device_count;
10272 	fc_lilpmap_t		*lilp_map;
10273 	uchar_t			*alpa_list;
10274 
10275 	ASSERT(MUTEX_HELD(&port->fp_mutex));
10276 
10277 	num_devices = fcio->fcio_olen / sizeof (fc_port_dev_t);
10278 	if (port->fp_total_devices > port->fp_dev_count &&
10279 	    num_devices >= port->fp_total_devices) {
10280 		job_request_t 	*job;
10281 
10282 		mutex_exit(&port->fp_mutex);
10283 		job = fctl_alloc_job(JOB_PORT_GETMAP, 0, NULL, NULL, KM_SLEEP);
10284 		job->job_counter = 1;
10285 
10286 		mutex_enter(&port->fp_mutex);
10287 		fp_get_loopmap(port, job);
10288 		mutex_exit(&port->fp_mutex);
10289 
10290 		fp_jobwait(job);
10291 		fctl_dealloc_job(job);
10292 	} else {
10293 		mutex_exit(&port->fp_mutex);
10294 	}
10295 	devlist = kmem_zalloc(sizeof (*devlist) * num_devices, KM_SLEEP);
10296 
10297 	mutex_enter(&port->fp_mutex);
10298 
10299 	/*
10300 	 * Applications are accustomed to getting the device list in
10301 	 * LILP map order. The HBA firmware usually returns the device
10302 	 * map in the LILP map order and diagnostic applications would
10303 	 * prefer to receive in the device list in that order too
10304 	 */
10305 	lilp_map = &port->fp_lilp_map;
10306 	alpa_list = &lilp_map->lilp_alpalist[0];
10307 
10308 	/*
10309 	 * the length field corresponds to the offset in the LILP frame
10310 	 * which begins with 1. The thing to note here is that the
10311 	 * lilp_device_count is 1 more than fp->fp_total_devices since
10312 	 * the host adapter's alpa also shows up in the lilp map. We
10313 	 * don't however return details of the host adapter since
10314 	 * fctl_get_remote_port_by_did fails for the host adapter's ALPA
10315 	 * and applications are required to issue the FCIO_GET_HOST_PARAMS
10316 	 * ioctl to obtain details about the host adapter port.
10317 	 */
10318 	lilp_device_count = lilp_map->lilp_length;
10319 
10320 	for (count = index = 0; index < lilp_device_count &&
10321 	    count < num_devices; index++) {
10322 		uint32_t d_id;
10323 		fc_remote_port_t *pd;
10324 
10325 		d_id = alpa_list[index];
10326 
10327 		mutex_exit(&port->fp_mutex);
10328 		pd = fctl_get_remote_port_by_did(port, d_id);
10329 		mutex_enter(&port->fp_mutex);
10330 
10331 		if (pd != NULL) {
10332 			mutex_enter(&pd->pd_mutex);
10333 
10334 			if (pd->pd_state == PORT_DEVICE_INVALID) {
10335 				mutex_exit(&pd->pd_mutex);
10336 				continue;
10337 			}
10338 
10339 			devlist[count].dev_state = pd->pd_state;
10340 			devlist[count].dev_hard_addr = pd->pd_hard_addr;
10341 			devlist[count].dev_did = pd->pd_port_id;
10342 			devlist[count].dev_did.priv_lilp_posit =
10343 						(uint8_t)(index & 0xff);
10344 			bcopy((caddr_t)pd->pd_fc4types,
10345 			    (caddr_t)devlist[count].dev_type,
10346 			    sizeof (pd->pd_fc4types));
10347 
10348 			bcopy((caddr_t)&pd->pd_port_name,
10349 			    (caddr_t)&devlist[count].dev_pwwn,
10350 			    sizeof (la_wwn_t));
10351 
10352 			node = pd->pd_remote_nodep;
10353 			mutex_exit(&pd->pd_mutex);
10354 
10355 			if (node) {
10356 				mutex_enter(&node->fd_mutex);
10357 				bcopy((caddr_t)&node->fd_node_name,
10358 				    (caddr_t)&devlist[count].dev_nwwn,
10359 				    sizeof (la_wwn_t));
10360 				mutex_exit(&node->fd_mutex);
10361 			}
10362 			count++;
10363 		}
10364 	}
10365 
10366 	if (fp_copyout((void *)&count, (void *)fcio->fcio_abuf,
10367 	    sizeof (count), mode)) {
10368 		rval = FC_FAILURE;
10369 	}
10370 
10371 	if (fp_copyout((void *)devlist, (void *)fcio->fcio_obuf,
10372 	    sizeof (fc_port_dev_t) * num_devices, mode)) {
10373 		rval = FC_FAILURE;
10374 	} else {
10375 		rval = FC_SUCCESS;
10376 	}
10377 
10378 	kmem_free(devlist, sizeof (*devlist) * num_devices);
10379 	ASSERT(MUTEX_HELD(&port->fp_mutex));
10380 
10381 	return (rval);
10382 }
10383 
10384 
10385 /*
10386  * Completion function for responses to unsolicited commands
10387  */
10388 static void
10389 fp_unsol_intr(fc_packet_t *pkt)
10390 {
10391 	fp_cmd_t 	*cmd;
10392 	fc_local_port_t *port;
10393 
10394 	cmd = pkt->pkt_ulp_private;
10395 	port = cmd->cmd_port;
10396 
10397 	if (pkt->pkt_state != FC_PKT_SUCCESS) {
10398 		fp_printf(port, CE_WARN, FP_LOG_ONLY, 0, pkt,
10399 		    "couldn't post response to unsolicited request;"
10400 		    " ox_id=%x rx_id=%x", pkt->pkt_cmd_fhdr.ox_id,
10401 		    pkt->pkt_resp_fhdr.rx_id);
10402 	}
10403 
10404 	if (cmd == port->fp_els_resp_pkt) {
10405 		mutex_enter(&port->fp_mutex);
10406 		port->fp_els_resp_pkt_busy = 0;
10407 		mutex_exit(&port->fp_mutex);
10408 		return;
10409 	}
10410 
10411 	fp_free_pkt(cmd);
10412 }
10413 
10414 
10415 /*
10416  * solicited LINIT ELS completion function
10417  */
10418 static void
10419 fp_linit_intr(fc_packet_t *pkt)
10420 {
10421 	fp_cmd_t		*cmd;
10422 	job_request_t		*job;
10423 	fc_linit_resp_t		acc;
10424 
10425 	if (FP_IS_PKT_ERROR(pkt)) {
10426 		(void) fp_common_intr(pkt, 1);
10427 		return;
10428 	}
10429 
10430 	cmd = pkt->pkt_ulp_private;
10431 	job = cmd->cmd_job;
10432 
10433 	ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&acc,
10434 	    (uint8_t *)pkt->pkt_resp, sizeof (acc), DDI_DEV_AUTOINCR);
10435 
10436 	if (acc.status != FC_LINIT_SUCCESS) {
10437 		job->job_result = FC_FAILURE;
10438 	} else {
10439 		job->job_result = FC_SUCCESS;
10440 	}
10441 	fp_iodone(cmd);
10442 }
10443 
10444 
10445 /*
10446  * Decode the unsolicited request; For FC-4 Device and Link data frames
10447  * notify the registered ULP of this FC-4 type right here. For Unsolicited
10448  * ELS requests, submit a request to the job_handler thread to work on it.
10449  * The intent is to act quickly on the FC-4 unsolicited link and data frames
10450  * and save much of the interrupt time processing of unsolicited ELS requests
10451  * and hand it off to the job_handler thread.
10452  */
10453 static void
10454 fp_unsol_cb(opaque_t port_handle, fc_unsol_buf_t *buf, uint32_t type)
10455 {
10456 	uchar_t		r_ctl;
10457 	uchar_t		ls_code;
10458 	uint32_t	s_id;
10459 	uint32_t	rscn_count = FC_INVALID_RSCN_COUNT;
10460 	uint32_t	cb_arg;
10461 	fp_cmd_t	*cmd;
10462 	fc_local_port_t *port;
10463 	job_request_t	*job;
10464 	fc_remote_port_t 	*pd;
10465 
10466 	port = port_handle;
10467 
10468 	FP_TRACE(FP_NHEAD1(1, 0), "fp_unsol_cb: s_id=%x,"
10469 	    " d_id=%x, type=%x, r_ctl=%x, f_ctl=%x"
10470 	    " seq_id=%x, df_ctl=%x, seq_cnt=%x, ox_id=%x, rx_id=%x"
10471 	    " ro=%x, buffer[0]:%x", buf->ub_frame.s_id, buf->ub_frame.d_id,
10472 	    buf->ub_frame.type, buf->ub_frame.r_ctl, buf->ub_frame.f_ctl,
10473 	    buf->ub_frame.seq_id, buf->ub_frame.df_ctl, buf->ub_frame.seq_cnt,
10474 	    buf->ub_frame.ox_id, buf->ub_frame.rx_id, buf->ub_frame.ro,
10475 	    buf->ub_buffer[0]);
10476 
10477 	if (type & 0x80000000) {
10478 		/*
10479 		 * Huh ? Nothing much can be done without
10480 		 * a valid buffer. So just exit.
10481 		 */
10482 		return;
10483 	}
10484 	/*
10485 	 * If the unsolicited interrupts arrive while it isn't
10486 	 * safe to handle unsolicited callbacks; Drop them, yes,
10487 	 * drop them on the floor
10488 	 */
10489 	mutex_enter(&port->fp_mutex);
10490 	port->fp_active_ubs++;
10491 	if ((port->fp_soft_state &
10492 	    (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN)) ||
10493 	    FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) {
10494 
10495 		FP_TRACE(FP_NHEAD1(3, 0), "fp_unsol_cb: port state is "
10496 		    "not ONLINE. s_id=%x, d_id=%x, type=%x, "
10497 		    "seq_id=%x, ox_id=%x, rx_id=%x"
10498 		    "ro=%x", buf->ub_frame.s_id, buf->ub_frame.d_id,
10499 		    buf->ub_frame.type, buf->ub_frame.seq_id,
10500 		    buf->ub_frame.ox_id, buf->ub_frame.rx_id, buf->ub_frame.ro);
10501 
10502 		ASSERT(port->fp_active_ubs > 0);
10503 		if (--(port->fp_active_ubs) == 0) {
10504 			port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB;
10505 		}
10506 
10507 		mutex_exit(&port->fp_mutex);
10508 
10509 		port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
10510 		    1, &buf->ub_token);
10511 
10512 		return;
10513 	}
10514 
10515 	r_ctl = buf->ub_frame.r_ctl;
10516 	s_id = buf->ub_frame.s_id;
10517 	if (port->fp_active_ubs == 1) {
10518 		port->fp_soft_state |= FP_SOFT_IN_UNSOL_CB;
10519 	}
10520 
10521 	if (r_ctl == R_CTL_ELS_REQ && buf->ub_buffer[0] == LA_ELS_LOGO &&
10522 	    port->fp_statec_busy) {
10523 		mutex_exit(&port->fp_mutex);
10524 		pd = fctl_get_remote_port_by_did(port, s_id);
10525 		if (pd) {
10526 			mutex_enter(&pd->pd_mutex);
10527 			if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
10528 				FP_TRACE(FP_NHEAD1(3, 0),
10529 				    "LOGO for LOGGED IN D_ID %x",
10530 				    buf->ub_frame.s_id);
10531 				pd->pd_state = PORT_DEVICE_VALID;
10532 			}
10533 			mutex_exit(&pd->pd_mutex);
10534 		}
10535 
10536 		mutex_enter(&port->fp_mutex);
10537 		ASSERT(port->fp_active_ubs > 0);
10538 		if (--(port->fp_active_ubs) == 0) {
10539 			port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB;
10540 		}
10541 		mutex_exit(&port->fp_mutex);
10542 
10543 		port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
10544 		    1, &buf->ub_token);
10545 
10546 		FP_TRACE(FP_NHEAD1(3, 0),
10547 		    "fp_unsol_cb() bailing out LOGO for D_ID %x",
10548 		    buf->ub_frame.s_id);
10549 		return;
10550 	}
10551 
10552 	if (port->fp_els_resp_pkt_busy == 0) {
10553 		if (r_ctl == R_CTL_ELS_REQ) {
10554 			ls_code = buf->ub_buffer[0];
10555 
10556 			switch (ls_code) {
10557 			case LA_ELS_PLOGI:
10558 			case LA_ELS_FLOGI:
10559 				port->fp_els_resp_pkt_busy = 1;
10560 				mutex_exit(&port->fp_mutex);
10561 				fp_i_handle_unsol_els(port, buf);
10562 
10563 				mutex_enter(&port->fp_mutex);
10564 				ASSERT(port->fp_active_ubs > 0);
10565 				if (--(port->fp_active_ubs) == 0) {
10566 					port->fp_soft_state &=
10567 					    ~FP_SOFT_IN_UNSOL_CB;
10568 				}
10569 				mutex_exit(&port->fp_mutex);
10570 				port->fp_fca_tran->fca_ub_release(
10571 				    port->fp_fca_handle, 1, &buf->ub_token);
10572 
10573 				return;
10574 			case LA_ELS_RSCN:
10575 				if (++(port)->fp_rscn_count ==
10576 				    FC_INVALID_RSCN_COUNT) {
10577 					++(port)->fp_rscn_count;
10578 				}
10579 				rscn_count = port->fp_rscn_count;
10580 				break;
10581 
10582 			default:
10583 				break;
10584 			}
10585 		}
10586 	} else if ((r_ctl == R_CTL_ELS_REQ) &&
10587 	    (buf->ub_buffer[0] == LA_ELS_RSCN)) {
10588 		if (++port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
10589 			++port->fp_rscn_count;
10590 		}
10591 		rscn_count = port->fp_rscn_count;
10592 	}
10593 
10594 	mutex_exit(&port->fp_mutex);
10595 
10596 	switch (r_ctl & R_CTL_ROUTING) {
10597 	case R_CTL_DEVICE_DATA:
10598 		/*
10599 		 * If the unsolicited buffer is a CT IU,
10600 		 * have the job_handler thread work on it.
10601 		 */
10602 		if (buf->ub_frame.type == FC_TYPE_FC_SERVICES) {
10603 			break;
10604 		}
10605 		/* FALLTHROUGH */
10606 
10607 	case R_CTL_FC4_SVC: {
10608 		int sendup = 0;
10609 
10610 		/*
10611 		 * If a LOGIN isn't performed before this request
10612 		 * shut the door on this port with a reply that a
10613 		 * LOGIN is required. We make an exception however
10614 		 * for IP broadcast packets and pass them through
10615 		 * to the IP ULP(s) to handle broadcast requests.
10616 		 * This is not a problem for private loop devices
10617 		 * but for fabric topologies we don't log into the
10618 		 * remote ports during port initialization and
10619 		 * the ULPs need to log into requesting ports on
10620 		 * demand.
10621 		 */
10622 		pd = fctl_get_remote_port_by_did(port, s_id);
10623 		if (pd) {
10624 			mutex_enter(&pd->pd_mutex);
10625 			if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
10626 				sendup++;
10627 			}
10628 			mutex_exit(&pd->pd_mutex);
10629 		} else if ((pd == NULL) &&
10630 		    (buf->ub_frame.type == FC_TYPE_IS8802_SNAP) &&
10631 		    (buf->ub_frame.d_id == 0xffffff ||
10632 		    buf->ub_frame.d_id == 0x00)) {
10633 			/* brodacst IP frame - so sendup via job thread */
10634 			break;
10635 		}
10636 
10637 		/*
10638 		 * Send all FC4 services via job thread too
10639 		 */
10640 		if ((r_ctl & R_CTL_ROUTING) == R_CTL_FC4_SVC) {
10641 			break;
10642 		}
10643 
10644 		if (sendup || !FC_IS_REAL_DEVICE(s_id)) {
10645 			fctl_ulp_unsol_cb(port, buf, buf->ub_frame.type);
10646 			return;
10647 		}
10648 
10649 		if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
10650 			cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t),
10651 			    0, KM_NOSLEEP, pd);
10652 			if (cmd != NULL) {
10653 				fp_els_rjt_init(port, cmd, buf,
10654 				    FC_ACTION_NON_RETRYABLE,
10655 				    FC_REASON_LOGIN_REQUIRED, NULL);
10656 
10657 				if (fp_sendcmd(port, cmd,
10658 				    port->fp_fca_handle) != FC_SUCCESS) {
10659 					fp_free_pkt(cmd);
10660 				}
10661 			}
10662 		}
10663 
10664 		mutex_enter(&port->fp_mutex);
10665 		ASSERT(port->fp_active_ubs > 0);
10666 		if (--(port->fp_active_ubs) == 0) {
10667 			port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB;
10668 		}
10669 		mutex_exit(&port->fp_mutex);
10670 		port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
10671 		    1, &buf->ub_token);
10672 
10673 		return;
10674 	}
10675 
10676 	default:
10677 		break;
10678 	}
10679 
10680 	/*
10681 	 * Submit a Request to the job_handler thread to work
10682 	 * on the unsolicited request. The potential side effect
10683 	 * of this is that the unsolicited buffer takes a little
10684 	 * longer to get released but we save interrupt time in
10685 	 * the bargain.
10686 	 */
10687 	cb_arg = (rscn_count == FC_INVALID_RSCN_COUNT) ? NULL : rscn_count;
10688 
10689 	/*
10690 	 * One way that the rscn_count will get used is described below :
10691 	 *
10692 	 * 1. fp_unsol_cb() gets an RSCN and updates fp_rscn_count.
10693 	 * 2. Before mutex is released, a copy of it is stored in rscn_count.
10694 	 * 3. The count is passed to job thread as JOB_UNSOL_REQUEST (below)
10695 	 *    by overloading the job_cb_arg to pass the rscn_count
10696 	 * 4. When one of the routines processing the RSCN picks it up (ex:
10697 	 *    fp_validate_rscn_page()), it passes this count in the map
10698 	 *    structure (as part of the map_rscn_info structure member) to the
10699 	 *    ULPs.
10700 	 * 5. When ULPs make calls back to the transport (example interfaces for
10701 	 *    this are fc_ulp_transport(), fc_ulp_login(), fc_issue_els()), they
10702 	 *    can now pass back this count as part of the fc_packet's
10703 	 *    pkt_ulp_rscn_count member. fcp does this currently.
10704 	 * 6. When transport gets a call to transport a command on the wire, it
10705 	 *    will check to see if there is a valid pkt_ulp_rsvd1 field in the
10706 	 *    fc_packet. If there is, it will match that info with the current
10707 	 *    rscn_count on that instance of the port. If they don't match up
10708 	 *    then there was a newer RSCN. The ULP gets back an error code which
10709 	 *    informs it about it - FC_DEVICE_BUSY_NEW_RSCN.
10710 	 * 7. At this point the ULP is free to make up its own mind as to how to
10711 	 *    handle this. Currently, fcp will reset its retry counters and keep
10712 	 *    retrying the operation it was doing in anticipation of getting a
10713 	 *    new state change call back for the new RSCN.
10714 	 */
10715 	job = fctl_alloc_job(JOB_UNSOL_REQUEST, 0, NULL,
10716 	    (opaque_t)(uintptr_t)cb_arg, KM_NOSLEEP);
10717 	if (job == NULL) {
10718 		fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, "fp_unsol_cb() "
10719 		    "couldn't submit a job to the thread, failing..");
10720 
10721 		mutex_enter(&port->fp_mutex);
10722 
10723 		if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
10724 			--port->fp_rscn_count;
10725 		}
10726 
10727 		ASSERT(port->fp_active_ubs > 0);
10728 		if (--(port->fp_active_ubs) == 0) {
10729 			port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB;
10730 		}
10731 
10732 		mutex_exit(&port->fp_mutex);
10733 		port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
10734 		    1, &buf->ub_token);
10735 
10736 		return;
10737 	}
10738 	job->job_private = (void *)buf;
10739 	fctl_enque_job(port, job);
10740 }
10741 
10742 
10743 /*
10744  * Handle unsolicited requests
10745  */
10746 static void
10747 fp_handle_unsol_buf(fc_local_port_t *port, fc_unsol_buf_t *buf,
10748     job_request_t *job)
10749 {
10750 	uchar_t			r_ctl;
10751 	uchar_t			ls_code;
10752 	uint32_t		s_id;
10753 	fp_cmd_t		*cmd;
10754 	fc_remote_port_t 	*pd;
10755 	fp_unsol_spec_t		*ub_spec;
10756 
10757 	r_ctl = buf->ub_frame.r_ctl;
10758 	s_id = buf->ub_frame.s_id;
10759 
10760 	switch (r_ctl & R_CTL_ROUTING) {
10761 	case R_CTL_EXTENDED_SVC:
10762 		if (r_ctl != R_CTL_ELS_REQ) {
10763 			break;
10764 		}
10765 
10766 		ls_code = buf->ub_buffer[0];
10767 		switch (ls_code) {
10768 		case LA_ELS_LOGO:
10769 		case LA_ELS_ADISC:
10770 		case LA_ELS_PRLO:
10771 			pd = fctl_get_remote_port_by_did(port, s_id);
10772 			if (pd == NULL) {
10773 				if (!FC_IS_REAL_DEVICE(s_id)) {
10774 					break;
10775 				}
10776 				if (!FP_IS_CLASS_1_OR_2(buf->ub_class)) {
10777 					break;
10778 				}
10779 				if ((cmd = fp_alloc_pkt(port,
10780 				    sizeof (la_els_rjt_t), 0, KM_SLEEP,
10781 				    NULL)) == NULL) {
10782 					/*
10783 					 * Can this actually fail when
10784 					 * given KM_SLEEP?  (Could be used
10785 					 * this way in a number of places.)
10786 					 */
10787 					break;
10788 				}
10789 
10790 				fp_els_rjt_init(port, cmd, buf,
10791 				    FC_ACTION_NON_RETRYABLE,
10792 				    FC_REASON_INVALID_LINK_CTRL, job);
10793 
10794 				if (fp_sendcmd(port, cmd,
10795 				    port->fp_fca_handle) != FC_SUCCESS) {
10796 					fp_free_pkt(cmd);
10797 				}
10798 
10799 				break;
10800 			}
10801 			if (ls_code == LA_ELS_LOGO) {
10802 				fp_handle_unsol_logo(port, buf, pd, job);
10803 			} else if (ls_code == LA_ELS_ADISC) {
10804 				fp_handle_unsol_adisc(port, buf, pd, job);
10805 			} else {
10806 				fp_handle_unsol_prlo(port, buf, pd, job);
10807 			}
10808 			break;
10809 
10810 		case LA_ELS_PLOGI:
10811 			fp_handle_unsol_plogi(port, buf, job, KM_SLEEP);
10812 			break;
10813 
10814 		case LA_ELS_FLOGI:
10815 			fp_handle_unsol_flogi(port, buf, job, KM_SLEEP);
10816 			break;
10817 
10818 		case LA_ELS_RSCN:
10819 			fp_handle_unsol_rscn(port, buf, job, KM_SLEEP);
10820 			break;
10821 
10822 		default:
10823 			ub_spec = kmem_zalloc(sizeof (*ub_spec), KM_SLEEP);
10824 			ub_spec->port = port;
10825 			ub_spec->buf = buf;
10826 
10827 			(void) taskq_dispatch(port->fp_taskq,
10828 			    fp_ulp_unsol_cb, ub_spec, KM_SLEEP);
10829 			return;
10830 		}
10831 		break;
10832 
10833 	case R_CTL_BASIC_SVC:
10834 		/*
10835 		 * The unsolicited basic link services could be ABTS
10836 		 * and RMC (Or even a NOP). Just BA_RJT them until
10837 		 * such time there arises a need to handle them more
10838 		 * carefully.
10839 		 */
10840 		if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
10841 			cmd = fp_alloc_pkt(port, sizeof (la_ba_rjt_t),
10842 			    0, KM_SLEEP, NULL);
10843 			if (cmd != NULL) {
10844 				fp_ba_rjt_init(port, cmd, buf, job);
10845 				if (fp_sendcmd(port, cmd,
10846 				    port->fp_fca_handle) != FC_SUCCESS) {
10847 					fp_free_pkt(cmd);
10848 				}
10849 			}
10850 		}
10851 		break;
10852 
10853 	case R_CTL_DEVICE_DATA:
10854 		if (buf->ub_frame.type == FC_TYPE_FC_SERVICES) {
10855 			/*
10856 			 * Mostly this is of type FC_TYPE_FC_SERVICES.
10857 			 * As we don't like any Unsolicited FC services
10858 			 * requests, we would do well to RJT them as
10859 			 * well.
10860 			 */
10861 			if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
10862 				cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t),
10863 				    0, KM_SLEEP, NULL);
10864 				if (cmd != NULL) {
10865 					fp_els_rjt_init(port, cmd, buf,
10866 					    FC_ACTION_NON_RETRYABLE,
10867 					    FC_REASON_INVALID_LINK_CTRL, job);
10868 
10869 					if (fp_sendcmd(port, cmd,
10870 					    port->fp_fca_handle) !=
10871 					    FC_SUCCESS) {
10872 						fp_free_pkt(cmd);
10873 					}
10874 				}
10875 			}
10876 			break;
10877 		}
10878 		/* FALLTHROUGH */
10879 
10880 	case R_CTL_FC4_SVC:
10881 		ub_spec = kmem_zalloc(sizeof (*ub_spec), KM_SLEEP);
10882 		ub_spec->port = port;
10883 		ub_spec->buf = buf;
10884 
10885 		(void) taskq_dispatch(port->fp_taskq,
10886 		    fp_ulp_unsol_cb, ub_spec, KM_SLEEP);
10887 		return;
10888 
10889 	case R_CTL_LINK_CTL:
10890 		/*
10891 		 * Turn deaf ear on unsolicited link control frames.
10892 		 * Typical unsolicited link control Frame is an LCR
10893 		 * (to reset End to End credit to the default login
10894 		 * value and abort current sequences for all classes)
10895 		 * An intelligent microcode/firmware should handle
10896 		 * this transparently at its level and not pass all
10897 		 * the way up here.
10898 		 *
10899 		 * Possible responses to LCR are R_RDY, F_RJT, P_RJT
10900 		 * or F_BSY. P_RJT is chosen to be the most appropriate
10901 		 * at this time.
10902 		 */
10903 		/* FALLTHROUGH */
10904 
10905 	default:
10906 		/*
10907 		 * Just reject everything else as an invalid request.
10908 		 */
10909 		if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
10910 			cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t),
10911 			    0, KM_SLEEP, NULL);
10912 			if (cmd != NULL) {
10913 				fp_els_rjt_init(port, cmd, buf,
10914 				    FC_ACTION_NON_RETRYABLE,
10915 				    FC_REASON_INVALID_LINK_CTRL, job);
10916 
10917 				if (fp_sendcmd(port, cmd,
10918 				    port->fp_fca_handle) != FC_SUCCESS) {
10919 					fp_free_pkt(cmd);
10920 				}
10921 			}
10922 		}
10923 		break;
10924 	}
10925 
10926 	mutex_enter(&port->fp_mutex);
10927 	ASSERT(port->fp_active_ubs > 0);
10928 	if (--(port->fp_active_ubs) == 0) {
10929 		port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB;
10930 	}
10931 	mutex_exit(&port->fp_mutex);
10932 	port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
10933 	    1, &buf->ub_token);
10934 }
10935 
10936 
10937 /*
10938  * Prepare a BA_RJT and send it over.
10939  */
10940 static void
10941 fp_ba_rjt_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf,
10942     job_request_t *job)
10943 {
10944 	fc_packet_t	*pkt;
10945 	la_ba_rjt_t 	payload;
10946 
10947 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
10948 
10949 	cmd->cmd_pkt.pkt_tran_flags = buf->ub_class;
10950 	cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND;
10951 	cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
10952 	cmd->cmd_retry_count = 1;
10953 	cmd->cmd_ulp_pkt = NULL;
10954 
10955 	cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
10956 	cmd->cmd_job = job;
10957 
10958 	pkt = &cmd->cmd_pkt;
10959 
10960 	fp_unsol_resp_init(pkt, buf, R_CTL_LS_BA_RJT, FC_TYPE_BASIC_LS);
10961 
10962 	payload.reserved = 0;
10963 	payload.reason_code = FC_REASON_CMD_UNSUPPORTED;
10964 	payload.explanation = FC_EXPLN_NONE;
10965 	payload.vendor = 0;
10966 
10967 	ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&payload,
10968 	    (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
10969 }
10970 
10971 
10972 /*
10973  * Prepare an LS_RJT and send it over
10974  */
10975 static void
10976 fp_els_rjt_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf,
10977     uchar_t action, uchar_t reason, job_request_t *job)
10978 {
10979 	fc_packet_t	*pkt;
10980 	la_els_rjt_t 	payload;
10981 
10982 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
10983 
10984 	cmd->cmd_pkt.pkt_tran_flags = buf->ub_class;
10985 	cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND;
10986 	cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
10987 	cmd->cmd_retry_count = 1;
10988 	cmd->cmd_ulp_pkt = NULL;
10989 
10990 	cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
10991 	cmd->cmd_job = job;
10992 
10993 	pkt = &cmd->cmd_pkt;
10994 
10995 	fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP, FC_TYPE_EXTENDED_LS);
10996 
10997 	payload.ls_code.ls_code = LA_ELS_RJT;
10998 	payload.ls_code.mbz = 0;
10999 	payload.action = action;
11000 	payload.reason = reason;
11001 	payload.reserved = 0;
11002 	payload.vu = 0;
11003 
11004 	ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&payload,
11005 	    (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
11006 }
11007 
11008 /*
11009  *     Function: fp_prlo_acc_init
11010  *
11011  *  Description: Initializes an Link Service Accept for a PRLO.
11012  *
11013  *    Arguments: *port		Local port through which the PRLO was
11014  *				received.
11015  *		 cmd		Command that will carry the accept.
11016  *		 *buf		Unsolicited buffer containing the PRLO
11017  *				request.
11018  *		 job		Job request.
11019  *		 sleep		Allocation mode.
11020  *
11021  * Return Value: *cmd		Command containing the response.
11022  *
11023  *      Context: Depends on the parameter sleep.
11024  */
11025 fp_cmd_t *
11026 fp_prlo_acc_init(fc_local_port_t *port, fc_remote_port_t *pd,
11027     fc_unsol_buf_t *buf, job_request_t *job, int sleep)
11028 {
11029 	fp_cmd_t	*cmd;
11030 	fc_packet_t	*pkt;
11031 	la_els_prlo_t	*req;
11032 	size_t		len;
11033 	uint16_t	flags;
11034 
11035 	req = (la_els_prlo_t *)buf->ub_buffer;
11036 	len = (size_t)ntohs(req->payload_length);
11037 
11038 	/*
11039 	 * The payload of the accept to a PRLO has to be the exact match of
11040 	 * the payload of the request (at the exception of the code).
11041 	 */
11042 	cmd = fp_alloc_pkt(port, (int)len, 0, sleep, pd);
11043 
11044 	if (cmd) {
11045 		/*
11046 		 * The fp command was successfully allocated.
11047 		 */
11048 		cmd->cmd_pkt.pkt_tran_flags = buf->ub_class;
11049 		cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND;
11050 		cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
11051 		cmd->cmd_retry_count = 1;
11052 		cmd->cmd_ulp_pkt = NULL;
11053 
11054 		cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
11055 		cmd->cmd_job = job;
11056 
11057 		pkt = &cmd->cmd_pkt;
11058 
11059 		fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP,
11060 		    FC_TYPE_EXTENDED_LS);
11061 
11062 		/* The code is overwritten for the copy. */
11063 		req->ls_code = LA_ELS_ACC;
11064 		/* Response code is set. */
11065 		flags = ntohs(req->flags);
11066 		flags &= ~SP_RESP_CODE_MASK;
11067 		flags |= SP_RESP_CODE_REQ_EXECUTED;
11068 		req->flags = htons(flags);
11069 
11070 		ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)req,
11071 		    (uint8_t *)pkt->pkt_cmd, len, DDI_DEV_AUTOINCR);
11072 	}
11073 	return (cmd);
11074 }
11075 
11076 /*
11077  * Prepare an ACC response to an ELS request
11078  */
11079 static void
11080 fp_els_acc_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf,
11081     job_request_t *job)
11082 {
11083 	fc_packet_t	*pkt;
11084 	ls_code_t	payload;
11085 
11086 	cmd->cmd_pkt.pkt_tran_flags = buf->ub_class;
11087 	cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND;
11088 	cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
11089 	cmd->cmd_retry_count = 1;
11090 	cmd->cmd_ulp_pkt = NULL;
11091 
11092 	cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
11093 	cmd->cmd_job = job;
11094 
11095 	pkt = &cmd->cmd_pkt;
11096 
11097 	fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP, FC_TYPE_EXTENDED_LS);
11098 
11099 	payload.ls_code = LA_ELS_ACC;
11100 	payload.mbz = 0;
11101 
11102 	ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&payload,
11103 	    (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
11104 }
11105 
11106 /*
11107  * Unsolicited PRLO handler
11108  *
11109  * A Process Logout should be handled by the ULP that established it.  However,
11110  * some devices send a PRLO to trigger a PLOGI followed by a PRLI.  This happens
11111  * when a device implicitly logs out an initiator (for whatever reason) and
11112  * tries to get that initiator to restablish the connection (PLOGI and PRLI).
11113  * The logical thing to do for the device would be to send a LOGO in response
11114  * to any FC4 frame sent by the initiator. Some devices choose, however, to send
11115  * a PRLO instead.
11116  *
11117  * From a Fibre Channel standpoint a PRLO calls for a PRLI. There's no reason to
11118  * think that the Port Login has been lost.  If we follow the Fibre Channel
11119  * protocol to the letter a PRLI should be sent after accepting the PRLO.  If
11120  * the Port Login has also been lost, the remote port will reject the PRLI
11121  * indicating that we must PLOGI first.  The initiator will then turn around and
11122  * send a PLOGI.  The way Leadville is layered and the way the ULP interface
11123  * is defined doesn't allow this scenario to be followed easily.  If FCP were to
11124  * handle the PRLO and attempt the PRLI, the reject indicating that a PLOGI is
11125  * needed would be received by FCP. FCP would have, then, to tell the transport
11126  * (fp) to PLOGI.  The problem is, the transport would still think the Port
11127  * Login is valid and there is no way for FCP to tell the transport: "PLOGI even
11128  * if you think it's not necessary".  To work around that difficulty, the PRLO
11129  * is treated by the transport as a LOGO.  The downside to it is a Port Login
11130  * may be disrupted (if a PLOGI wasn't actually needed) and another ULP (that
11131  * has nothing to do with the PRLO) may be impacted.  However, this is a
11132  * scenario very unlikely to happen.  As of today the only ULP in Leadville
11133  * using PRLI/PRLOs is FCP.  For a PRLO to disrupt another ULP (that would be
11134  * FCIP), a SCSI target would have to be running FCP and FCIP (which is very
11135  * unlikely).
11136  */
11137 static void
11138 fp_handle_unsol_prlo(fc_local_port_t *port, fc_unsol_buf_t *buf,
11139     fc_remote_port_t *pd, job_request_t *job)
11140 {
11141 	int		busy;
11142 	int		rval;
11143 	int		retain;
11144 	fp_cmd_t	*cmd;
11145 	fc_portmap_t 	*listptr;
11146 	boolean_t	tolerance;
11147 	la_els_prlo_t	*req;
11148 
11149 	req = (la_els_prlo_t *)buf->ub_buffer;
11150 
11151 	if ((ntohs(req->payload_length) !=
11152 	    (sizeof (service_parameter_page_t) + sizeof (ls_code_t))) ||
11153 	    (req->page_length != sizeof (service_parameter_page_t))) {
11154 		/*
11155 		 * We are being very restrictive.  Only on page per
11156 		 * payload.  If it is not the case we reject the ELS although
11157 		 * we should reply indicating we handle only single page
11158 		 * per PRLO.
11159 		 */
11160 		goto fp_reject_prlo;
11161 	}
11162 
11163 	if (ntohs(req->payload_length) > buf->ub_bufsize) {
11164 		/*
11165 		 * This is in case the payload advertizes a size bigger than
11166 		 * what it really is.
11167 		 */
11168 		goto fp_reject_prlo;
11169 	}
11170 
11171 	mutex_enter(&port->fp_mutex);
11172 	busy = port->fp_statec_busy;
11173 	mutex_exit(&port->fp_mutex);
11174 
11175 	mutex_enter(&pd->pd_mutex);
11176 	tolerance = fctl_tc_increment(&pd->pd_logo_tc);
11177 	if (!busy) {
11178 		if (pd->pd_state != PORT_DEVICE_LOGGED_IN ||
11179 		    pd->pd_state == PORT_DEVICE_INVALID ||
11180 		    pd->pd_flags == PD_ELS_IN_PROGRESS ||
11181 		    pd->pd_type == PORT_DEVICE_OLD) {
11182 			busy++;
11183 		}
11184 	}
11185 
11186 	if (busy) {
11187 		mutex_exit(&pd->pd_mutex);
11188 
11189 		FP_TRACE(FP_NHEAD1(5, 0), "Logout; D_ID=%x,"
11190 		    "pd=%p - busy",
11191 		    pd->pd_port_id.port_id, pd);
11192 
11193 		if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11194 			goto fp_reject_prlo;
11195 		}
11196 	} else {
11197 		retain = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0;
11198 
11199 		if (tolerance) {
11200 			fctl_tc_reset(&pd->pd_logo_tc);
11201 			retain = 0;
11202 			pd->pd_state = PORT_DEVICE_INVALID;
11203 		}
11204 
11205 		FP_TRACE(FP_NHEAD1(5, 0), "Accepting LOGO; d_id=%x, pd=%p,"
11206 		    " tolerance=%d retain=%d", pd->pd_port_id.port_id, pd,
11207 		    tolerance, retain);
11208 
11209 		pd->pd_aux_flags |= PD_LOGGED_OUT;
11210 		mutex_exit(&pd->pd_mutex);
11211 
11212 		cmd = fp_prlo_acc_init(port, pd, buf, job, KM_SLEEP);
11213 		if (cmd == NULL) {
11214 			return;
11215 		}
11216 
11217 		rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
11218 		if (rval != FC_SUCCESS) {
11219 			fp_free_pkt(cmd);
11220 			return;
11221 		}
11222 
11223 		listptr = kmem_zalloc(sizeof (fc_portmap_t), KM_SLEEP);
11224 
11225 		if (retain) {
11226 			fp_unregister_login(pd);
11227 			fctl_copy_portmap(listptr, pd);
11228 		} else {
11229 			uint32_t 	d_id;
11230 			char 		ww_name[17];
11231 
11232 			mutex_enter(&pd->pd_mutex);
11233 			d_id = pd->pd_port_id.port_id;
11234 			fc_wwn_to_str(&pd->pd_port_name, ww_name);
11235 			mutex_exit(&pd->pd_mutex);
11236 
11237 			FP_TRACE(FP_NHEAD2(9, 0),
11238 			    "N_x Port with D_ID=%x, PWWN=%s logged out"
11239 			    " %d times in %d us; Giving up", d_id, ww_name,
11240 			    FC_LOGO_TOLERANCE_LIMIT,
11241 			    FC_LOGO_TOLERANCE_TIME_LIMIT);
11242 
11243 			fp_fillout_old_map(listptr, pd, 0);
11244 			listptr->map_type = PORT_DEVICE_OLD;
11245 		}
11246 
11247 		(void) fp_ulp_devc_cb(port, listptr, 1, 1, KM_SLEEP, 0);
11248 		return;
11249 	}
11250 
11251 fp_reject_prlo:
11252 
11253 	cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t), 0, KM_SLEEP, pd);
11254 	if (cmd != NULL) {
11255 		fp_els_rjt_init(port, cmd, buf, FC_ACTION_NON_RETRYABLE,
11256 		    FC_REASON_INVALID_LINK_CTRL, job);
11257 
11258 		if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
11259 			fp_free_pkt(cmd);
11260 		}
11261 	}
11262 }
11263 
11264 /*
11265  * Unsolicited LOGO handler
11266  */
11267 static void
11268 fp_handle_unsol_logo(fc_local_port_t *port, fc_unsol_buf_t *buf,
11269     fc_remote_port_t *pd, job_request_t *job)
11270 {
11271 	int		busy;
11272 	int		rval;
11273 	int		retain;
11274 	fp_cmd_t	*cmd;
11275 	fc_portmap_t 	*listptr;
11276 	boolean_t	tolerance;
11277 
11278 	mutex_enter(&port->fp_mutex);
11279 	busy = port->fp_statec_busy;
11280 	mutex_exit(&port->fp_mutex);
11281 
11282 	mutex_enter(&pd->pd_mutex);
11283 	tolerance = fctl_tc_increment(&pd->pd_logo_tc);
11284 	if (!busy) {
11285 		if (pd->pd_state != PORT_DEVICE_LOGGED_IN ||
11286 		    pd->pd_state == PORT_DEVICE_INVALID ||
11287 		    pd->pd_flags == PD_ELS_IN_PROGRESS ||
11288 		    pd->pd_type == PORT_DEVICE_OLD) {
11289 			busy++;
11290 		}
11291 	}
11292 
11293 	if (busy) {
11294 		mutex_exit(&pd->pd_mutex);
11295 
11296 		FP_TRACE(FP_NHEAD1(5, 0), "Logout; D_ID=%x,"
11297 		    "pd=%p - busy",
11298 		    pd->pd_port_id.port_id, pd);
11299 
11300 		if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11301 			cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t),
11302 			    0, KM_SLEEP, pd);
11303 			if (cmd != NULL) {
11304 				fp_els_rjt_init(port, cmd, buf,
11305 				    FC_ACTION_NON_RETRYABLE,
11306 				    FC_REASON_INVALID_LINK_CTRL, job);
11307 
11308 				if (fp_sendcmd(port, cmd,
11309 				    port->fp_fca_handle) != FC_SUCCESS) {
11310 					fp_free_pkt(cmd);
11311 				}
11312 			}
11313 		}
11314 	} else {
11315 		retain = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0;
11316 
11317 		if (tolerance) {
11318 			fctl_tc_reset(&pd->pd_logo_tc);
11319 			retain = 0;
11320 			pd->pd_state = PORT_DEVICE_INVALID;
11321 		}
11322 
11323 		FP_TRACE(FP_NHEAD1(5, 0), "Accepting LOGO; d_id=%x, pd=%p,"
11324 		    " tolerance=%d retain=%d", pd->pd_port_id.port_id, pd,
11325 		    tolerance, retain);
11326 
11327 		pd->pd_aux_flags |= PD_LOGGED_OUT;
11328 		mutex_exit(&pd->pd_mutex);
11329 
11330 		cmd = fp_alloc_pkt(port, FP_PORT_IDENTIFIER_LEN, 0,
11331 		    KM_SLEEP, pd);
11332 		if (cmd == NULL) {
11333 			return;
11334 		}
11335 
11336 		fp_els_acc_init(port, cmd, buf, job);
11337 
11338 		rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
11339 		if (rval != FC_SUCCESS) {
11340 			fp_free_pkt(cmd);
11341 			return;
11342 		}
11343 
11344 		listptr = kmem_zalloc(sizeof (fc_portmap_t), KM_SLEEP);
11345 
11346 		if (retain) {
11347 			job_request_t	*job;
11348 			fctl_ns_req_t	*ns_cmd;
11349 
11350 			/*
11351 			 * when get LOGO, first try to get PID from nameserver
11352 			 * if failed, then we do not need
11353 			 * send PLOGI to that remote port
11354 			 */
11355 			job = fctl_alloc_job(
11356 			    JOB_NS_CMD, 0, NULL, (opaque_t)port, KM_SLEEP);
11357 
11358 			if (job != NULL) {
11359 				ns_cmd = fctl_alloc_ns_cmd(
11360 				    sizeof (ns_req_gid_pn_t),
11361 				    sizeof (ns_resp_gid_pn_t),
11362 				    sizeof (ns_resp_gid_pn_t),
11363 				    0, KM_SLEEP);
11364 				if (ns_cmd != NULL) {
11365 					int ret;
11366 					job->job_result = FC_SUCCESS;
11367 					ns_cmd->ns_cmd_code = NS_GID_PN;
11368 					((ns_req_gid_pn_t *)
11369 					    (ns_cmd->ns_cmd_buf))->pwwn =
11370 					    pd->pd_port_name;
11371 					ret = fp_ns_query(
11372 					    port, ns_cmd, job, 1, KM_SLEEP);
11373 					if ((ret != FC_SUCCESS) ||
11374 					    (job->job_result != FC_SUCCESS)) {
11375 						fctl_free_ns_cmd(ns_cmd);
11376 						fctl_dealloc_job(job);
11377 						FP_TRACE(FP_NHEAD2(9, 0),
11378 						    "NS query failed,",
11379 						    " delete pd");
11380 						goto delete_pd;
11381 					}
11382 					fctl_free_ns_cmd(ns_cmd);
11383 				}
11384 				fctl_dealloc_job(job);
11385 			}
11386 			fp_unregister_login(pd);
11387 			fctl_copy_portmap(listptr, pd);
11388 		} else {
11389 			uint32_t 	d_id;
11390 			char 		ww_name[17];
11391 
11392 delete_pd:
11393 			mutex_enter(&pd->pd_mutex);
11394 			d_id = pd->pd_port_id.port_id;
11395 			fc_wwn_to_str(&pd->pd_port_name, ww_name);
11396 			mutex_exit(&pd->pd_mutex);
11397 
11398 			FP_TRACE(FP_NHEAD2(9, 0),
11399 			    "N_x Port with D_ID=%x, PWWN=%s logged out"
11400 			    " %d times in %d us; Giving up", d_id, ww_name,
11401 			    FC_LOGO_TOLERANCE_LIMIT,
11402 			    FC_LOGO_TOLERANCE_TIME_LIMIT);
11403 
11404 			fp_fillout_old_map(listptr, pd, 0);
11405 			listptr->map_type = PORT_DEVICE_OLD;
11406 		}
11407 
11408 		(void) fp_ulp_devc_cb(port, listptr, 1, 1, KM_SLEEP, 0);
11409 	}
11410 }
11411 
11412 
11413 /*
11414  * Perform general purpose preparation of a response to an unsolicited request
11415  */
11416 static void
11417 fp_unsol_resp_init(fc_packet_t *pkt, fc_unsol_buf_t *buf,
11418     uchar_t r_ctl, uchar_t type)
11419 {
11420 	pkt->pkt_cmd_fhdr.r_ctl = r_ctl;
11421 	pkt->pkt_cmd_fhdr.d_id = buf->ub_frame.s_id;
11422 	pkt->pkt_cmd_fhdr.s_id = buf->ub_frame.d_id;
11423 	pkt->pkt_cmd_fhdr.type = type;
11424 	pkt->pkt_cmd_fhdr.f_ctl = F_CTL_LAST_SEQ | F_CTL_XCHG_CONTEXT;
11425 	pkt->pkt_cmd_fhdr.seq_id = buf->ub_frame.seq_id;
11426 	pkt->pkt_cmd_fhdr.df_ctl  = buf->ub_frame.df_ctl;
11427 	pkt->pkt_cmd_fhdr.seq_cnt = buf->ub_frame.seq_cnt;
11428 	pkt->pkt_cmd_fhdr.ox_id = buf->ub_frame.ox_id;
11429 	pkt->pkt_cmd_fhdr.rx_id = buf->ub_frame.rx_id;
11430 	pkt->pkt_cmd_fhdr.ro = 0;
11431 	pkt->pkt_cmd_fhdr.rsvd = 0;
11432 	pkt->pkt_comp = fp_unsol_intr;
11433 	pkt->pkt_timeout = FP_ELS_TIMEOUT;
11434 }
11435 
11436 /*
11437  * Immediate handling of unsolicited FLOGI and PLOGI requests. In the
11438  * early development days of public loop soc+ firmware, numerous problems
11439  * were encountered (the details are undocumented and history now) which
11440  * led to the birth of this function.
11441  *
11442  * If a pre-allocated unsolicited response packet is free, send out an
11443  * immediate response, otherwise submit the request to the port thread
11444  * to do the deferred processing.
11445  */
11446 static void
11447 fp_i_handle_unsol_els(fc_local_port_t *port, fc_unsol_buf_t *buf)
11448 {
11449 	int			sent;
11450 	int 			f_port;
11451 	int			do_acc;
11452 	fp_cmd_t 		*cmd;
11453 	la_els_logi_t 		*payload;
11454 	fc_remote_port_t	*pd;
11455 	char			dww_name[17];
11456 
11457 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
11458 
11459 	cmd = port->fp_els_resp_pkt;
11460 
11461 	mutex_enter(&port->fp_mutex);
11462 	do_acc = (port->fp_statec_busy == 0) ? 1 : 0;
11463 	mutex_exit(&port->fp_mutex);
11464 
11465 	switch (buf->ub_buffer[0]) {
11466 	case LA_ELS_PLOGI: {
11467 		int small;
11468 
11469 		payload = (la_els_logi_t *)buf->ub_buffer;
11470 
11471 		f_port = FP_IS_F_PORT(payload->
11472 		    common_service.cmn_features) ? 1 : 0;
11473 
11474 		small = fctl_wwn_cmp(&port->fp_service_params.nport_ww_name,
11475 		    &payload->nport_ww_name);
11476 		pd = fctl_get_remote_port_by_pwwn(port,
11477 		    &payload->nport_ww_name);
11478 		if (pd) {
11479 			mutex_enter(&pd->pd_mutex);
11480 			sent = (pd->pd_flags == PD_ELS_IN_PROGRESS) ? 1 : 0;
11481 			/*
11482 			 * Most likely this means a cross login is in
11483 			 * progress or a device about to be yanked out.
11484 			 * Only accept the plogi if my wwn is smaller.
11485 			 */
11486 			if (pd->pd_type == PORT_DEVICE_OLD) {
11487 				sent = 1;
11488 			}
11489 			/*
11490 			 * Stop plogi request (if any)
11491 			 * attempt from local side to speedup
11492 			 * the discovery progress.
11493 			 * Mark the pd as PD_PLOGI_RECEPIENT.
11494 			 */
11495 			if (f_port == 0 && small < 0) {
11496 				pd->pd_recepient = PD_PLOGI_RECEPIENT;
11497 			}
11498 			fc_wwn_to_str(&pd->pd_port_name, dww_name);
11499 
11500 			mutex_exit(&pd->pd_mutex);
11501 
11502 			FP_TRACE(FP_NHEAD1(3, 0), "fp_i_handle_unsol_els: "
11503 			    "Unsol PLOGI received. PD still exists in the "
11504 			    "PWWN list. pd=%p PWWN=%s, sent=%x",
11505 			    pd, dww_name, sent);
11506 
11507 			if (f_port == 0 && small < 0) {
11508 				FP_TRACE(FP_NHEAD1(3, 0),
11509 				    "fp_i_handle_unsol_els: Mark the pd"
11510 				    " as plogi recipient, pd=%p, PWWN=%s"
11511 				    ", sent=%x",
11512 				    pd, dww_name, sent);
11513 			}
11514 		} else {
11515 			sent = 0;
11516 		}
11517 
11518 		/*
11519 		 * To avoid Login collisions, accept only if my WWN
11520 		 * is smaller than the requester (A curious side note
11521 		 * would be that this rule may not satisfy the PLOGIs
11522 		 * initiated by the switch from not-so-well known
11523 		 * ports such as 0xFFFC41)
11524 		 */
11525 		if ((f_port == 0 && small < 0) ||
11526 		    (((small > 0 && do_acc) ||
11527 		    FC_MUST_ACCEPT_D_ID(buf->ub_frame.s_id)) && sent == 0)) {
11528 			if (fp_is_class_supported(port->fp_cos,
11529 			    buf->ub_class) == FC_FAILURE) {
11530 				if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11531 					cmd->cmd_pkt.pkt_cmdlen =
11532 					    sizeof (la_els_rjt_t);
11533 					cmd->cmd_pkt.pkt_rsplen = 0;
11534 					fp_els_rjt_init(port, cmd, buf,
11535 					    FC_ACTION_NON_RETRYABLE,
11536 					    FC_REASON_CLASS_NOT_SUPP, NULL);
11537 					FP_TRACE(FP_NHEAD1(3, 0),
11538 					    "fp_i_handle_unsol_els: "
11539 					    "Unsupported class. "
11540 					    "Rejecting PLOGI");
11541 
11542 				} else {
11543 					mutex_enter(&port->fp_mutex);
11544 					port->fp_els_resp_pkt_busy = 0;
11545 					mutex_exit(&port->fp_mutex);
11546 					return;
11547 				}
11548 			} else {
11549 				cmd->cmd_pkt.pkt_cmdlen =
11550 				    sizeof (la_els_logi_t);
11551 				cmd->cmd_pkt.pkt_rsplen = 0;
11552 
11553 				/*
11554 				 * Sometime later, we should validate
11555 				 * the service parameters instead of
11556 				 * just accepting it.
11557 				 */
11558 				fp_login_acc_init(port, cmd, buf, NULL,
11559 				    KM_NOSLEEP);
11560 				FP_TRACE(FP_NHEAD1(3, 0),
11561 				    "fp_i_handle_unsol_els: Accepting PLOGI,"
11562 				    " f_port=%d, small=%d, do_acc=%d,"
11563 				    " sent=%d.", f_port, small, do_acc,
11564 				    sent);
11565 				/*
11566 				 * If fp_port_id is zero and topology is
11567 				 * Point-to-Point, get the local port id from
11568 				 * the d_id in the PLOGI request.
11569 				 * If the outgoing FLOGI hasn't been accepted,
11570 				 * the topology will be unknown here. But it's
11571 				 * still safe to save the d_id to fp_port_id,
11572 				 * just because it will be overwritten later
11573 				 * if the topology is not Point-to-Point.
11574 				 */
11575 				mutex_enter(&port->fp_mutex);
11576 				if ((port->fp_port_id.port_id == 0) &&
11577 				    (port->fp_topology == FC_TOP_PT_PT ||
11578 				    port->fp_topology == FC_TOP_UNKNOWN)) {
11579 					port->fp_port_id.port_id =
11580 					    buf->ub_frame.d_id;
11581 				}
11582 				mutex_exit(&port->fp_mutex);
11583 			}
11584 		} else {
11585 			if (FP_IS_CLASS_1_OR_2(buf->ub_class) ||
11586 			    port->fp_options & FP_SEND_RJT) {
11587 				cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_rjt_t);
11588 				cmd->cmd_pkt.pkt_rsplen = 0;
11589 				fp_els_rjt_init(port, cmd, buf,
11590 				    FC_ACTION_NON_RETRYABLE,
11591 				    FC_REASON_LOGICAL_BSY, NULL);
11592 				FP_TRACE(FP_NHEAD1(3, 0),
11593 				    "fp_i_handle_unsol_els: "
11594 				    "Rejecting PLOGI with Logical Busy."
11595 				    "Possible Login collision.");
11596 			} else {
11597 				mutex_enter(&port->fp_mutex);
11598 				port->fp_els_resp_pkt_busy = 0;
11599 				mutex_exit(&port->fp_mutex);
11600 				return;
11601 			}
11602 		}
11603 		break;
11604 	}
11605 
11606 	case LA_ELS_FLOGI:
11607 		if (fp_is_class_supported(port->fp_cos,
11608 		    buf->ub_class) == FC_FAILURE) {
11609 			if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11610 				cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_rjt_t);
11611 				cmd->cmd_pkt.pkt_rsplen = 0;
11612 				fp_els_rjt_init(port, cmd, buf,
11613 				    FC_ACTION_NON_RETRYABLE,
11614 				    FC_REASON_CLASS_NOT_SUPP, NULL);
11615 				FP_TRACE(FP_NHEAD1(3, 0),
11616 				    "fp_i_handle_unsol_els: "
11617 				    "Unsupported Class. Rejecting FLOGI.");
11618 			} else {
11619 				mutex_enter(&port->fp_mutex);
11620 				port->fp_els_resp_pkt_busy = 0;
11621 				mutex_exit(&port->fp_mutex);
11622 				return;
11623 			}
11624 		} else {
11625 			mutex_enter(&port->fp_mutex);
11626 			if (FC_PORT_STATE_MASK(port->fp_state) !=
11627 			    FC_STATE_ONLINE || (port->fp_port_id.port_id &&
11628 			    buf->ub_frame.s_id == port->fp_port_id.port_id)) {
11629 				mutex_exit(&port->fp_mutex);
11630 				if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11631 					cmd->cmd_pkt.pkt_cmdlen =
11632 					    sizeof (la_els_rjt_t);
11633 					cmd->cmd_pkt.pkt_rsplen = 0;
11634 					fp_els_rjt_init(port, cmd, buf,
11635 					    FC_ACTION_NON_RETRYABLE,
11636 					    FC_REASON_INVALID_LINK_CTRL,
11637 					    NULL);
11638 					FP_TRACE(FP_NHEAD1(3, 0),
11639 					    "fp_i_handle_unsol_els: "
11640 					    "Invalid Link Ctrl. "
11641 					    "Rejecting FLOGI.");
11642 				} else {
11643 					mutex_enter(&port->fp_mutex);
11644 					port->fp_els_resp_pkt_busy = 0;
11645 					mutex_exit(&port->fp_mutex);
11646 					return;
11647 				}
11648 			} else {
11649 				mutex_exit(&port->fp_mutex);
11650 				cmd->cmd_pkt.pkt_cmdlen =
11651 				    sizeof (la_els_logi_t);
11652 				cmd->cmd_pkt.pkt_rsplen = 0;
11653 				/*
11654 				 * Let's not aggressively validate the N_Port's
11655 				 * service parameters until PLOGI. Suffice it
11656 				 * to give a hint that we are an N_Port and we
11657 				 * are game to some serious stuff here.
11658 				 */
11659 				fp_login_acc_init(port, cmd, buf,
11660 				    NULL, KM_NOSLEEP);
11661 				FP_TRACE(FP_NHEAD1(3, 0),
11662 				    "fp_i_handle_unsol_els: "
11663 				    "Accepting FLOGI.");
11664 			}
11665 		}
11666 		break;
11667 
11668 	default:
11669 		return;
11670 	}
11671 
11672 	if ((fp_sendcmd(port, cmd, port->fp_fca_handle)) != FC_SUCCESS) {
11673 		mutex_enter(&port->fp_mutex);
11674 		port->fp_els_resp_pkt_busy = 0;
11675 		mutex_exit(&port->fp_mutex);
11676 	}
11677 }
11678 
11679 
11680 /*
11681  * Handle unsolicited PLOGI request
11682  */
11683 static void
11684 fp_handle_unsol_plogi(fc_local_port_t *port, fc_unsol_buf_t *buf,
11685     job_request_t *job, int sleep)
11686 {
11687 	int			sent;
11688 	int			small;
11689 	int 			f_port;
11690 	int			do_acc;
11691 	fp_cmd_t		*cmd;
11692 	la_wwn_t 		*swwn;
11693 	la_wwn_t		*dwwn;
11694 	la_els_logi_t 		*payload;
11695 	fc_remote_port_t	*pd;
11696 	char			dww_name[17];
11697 
11698 	payload = (la_els_logi_t *)buf->ub_buffer;
11699 	f_port = FP_IS_F_PORT(payload->common_service.cmn_features) ? 1 : 0;
11700 
11701 	mutex_enter(&port->fp_mutex);
11702 	do_acc = (port->fp_statec_busy == 0) ? 1 : 0;
11703 	mutex_exit(&port->fp_mutex);
11704 
11705 	FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_plogi: s_id=%x, d_id=%x,"
11706 	    "type=%x, f_ctl=%x"
11707 	    " seq_id=%x, ox_id=%x, rx_id=%x"
11708 	    " ro=%x", buf->ub_frame.s_id, buf->ub_frame.d_id,
11709 	    buf->ub_frame.type, buf->ub_frame.f_ctl, buf->ub_frame.seq_id,
11710 	    buf->ub_frame.ox_id, buf->ub_frame.rx_id, buf->ub_frame.ro);
11711 
11712 	swwn = &port->fp_service_params.nport_ww_name;
11713 	dwwn = &payload->nport_ww_name;
11714 	small = fctl_wwn_cmp(swwn, dwwn);
11715 	pd = fctl_get_remote_port_by_pwwn(port, dwwn);
11716 	if (pd) {
11717 		mutex_enter(&pd->pd_mutex);
11718 		sent = (pd->pd_flags == PD_ELS_IN_PROGRESS) ? 1 : 0;
11719 		/*
11720 		 * Most likely this means a cross login is in
11721 		 * progress or a device about to be yanked out.
11722 		 * Only accept the plogi if my wwn is smaller.
11723 		 */
11724 
11725 		if (pd->pd_type == PORT_DEVICE_OLD) {
11726 			sent = 1;
11727 		}
11728 		/*
11729 		 * Stop plogi request (if any)
11730 		 * attempt from local side to speedup
11731 		 * the discovery progress.
11732 		 * Mark the pd as PD_PLOGI_RECEPIENT.
11733 		 */
11734 		if (f_port == 0 && small < 0) {
11735 			pd->pd_recepient = PD_PLOGI_RECEPIENT;
11736 		}
11737 		fc_wwn_to_str(&pd->pd_port_name, dww_name);
11738 
11739 		mutex_exit(&pd->pd_mutex);
11740 
11741 		FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_plogi: Unsol PLOGI"
11742 		    " received. PD still exists in the PWWN list. pd=%p "
11743 		    "PWWN=%s, sent=%x", pd, dww_name, sent);
11744 
11745 		if (f_port == 0 && small < 0) {
11746 			FP_TRACE(FP_NHEAD1(3, 0),
11747 			    "fp_handle_unsol_plogi: Mark the pd"
11748 			    " as plogi recipient, pd=%p, PWWN=%s"
11749 			    ", sent=%x",
11750 			    pd, dww_name, sent);
11751 		}
11752 	} else {
11753 		sent = 0;
11754 	}
11755 
11756 	/*
11757 	 * Avoid Login collisions by accepting only if my WWN is smaller.
11758 	 *
11759 	 * A side note: There is no need to start a PLOGI from this end in
11760 	 *	this context if login isn't going to be accepted for the
11761 	 * 	above reason as either a LIP (in private loop), RSCN (in
11762 	 *	fabric topology), or an FLOGI (in point to point - Huh ?
11763 	 *	check FC-PH) would normally drive the PLOGI from this end.
11764 	 *	At this point of time there is no need for an inbound PLOGI
11765 	 *	to kick an outbound PLOGI when it is going to be rejected
11766 	 *	for the reason of WWN being smaller. However it isn't hard
11767 	 *	to do that either (when such a need arises, start a timer
11768 	 *	for a duration that extends beyond a normal device discovery
11769 	 *	time and check if an outbound PLOGI did go before that, if
11770 	 *	none fire one)
11771 	 *
11772 	 *	Unfortunately, as it turned out, during booting, it is possible
11773 	 *	to miss another initiator in the same loop as port driver
11774 	 * 	instances are serially attached. While preserving the above
11775 	 * 	comments for belly laughs, please kick an outbound PLOGI in
11776 	 *	a non-switch environment (which is a pt pt between N_Ports or
11777 	 *	a private loop)
11778 	 *
11779 	 *	While preserving the above comments for amusement, send an
11780 	 *	ACC if the PLOGI is going to be rejected for WWN being smaller
11781 	 *	when no discovery is in progress at this end. Turn around
11782 	 *	and make the port device as the PLOGI initiator, so that
11783 	 *	during subsequent link/loop initialization, this end drives
11784 	 *	the PLOGI (In fact both ends do in this particular case, but
11785 	 *	only one wins)
11786 	 *
11787 	 * Make sure the PLOGIs initiated by the switch from not-so-well-known
11788 	 * ports (such as 0xFFFC41) are accepted too.
11789 	 */
11790 	if ((f_port == 0 && small < 0) || (((small > 0 && do_acc) ||
11791 	    FC_MUST_ACCEPT_D_ID(buf->ub_frame.s_id)) && sent == 0)) {
11792 		if (fp_is_class_supported(port->fp_cos,
11793 		    buf->ub_class) == FC_FAILURE) {
11794 			if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11795 				cmd = fp_alloc_pkt(port,
11796 				    sizeof (la_els_logi_t), 0, sleep, pd);
11797 				if (cmd == NULL) {
11798 					return;
11799 				}
11800 				cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_rjt_t);
11801 				cmd->cmd_pkt.pkt_rsplen = 0;
11802 				fp_els_rjt_init(port, cmd, buf,
11803 				    FC_ACTION_NON_RETRYABLE,
11804 				    FC_REASON_CLASS_NOT_SUPP, job);
11805 				FP_TRACE(FP_NHEAD1(3, 0),
11806 				    "fp_handle_unsol_plogi: "
11807 				    "Unsupported class. rejecting PLOGI");
11808 			}
11809 		} else {
11810 			cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t),
11811 			    0, sleep, pd);
11812 			if (cmd == NULL) {
11813 				return;
11814 			}
11815 			cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_logi_t);
11816 			cmd->cmd_pkt.pkt_rsplen = 0;
11817 
11818 			/*
11819 			 * Sometime later, we should validate the service
11820 			 * parameters instead of just accepting it.
11821 			 */
11822 			fp_login_acc_init(port, cmd, buf, job, KM_SLEEP);
11823 			FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_plogi: "
11824 			    "Accepting PLOGI, f_port=%d, small=%d, "
11825 			    "do_acc=%d, sent=%d.", f_port, small, do_acc,
11826 			    sent);
11827 
11828 			/*
11829 			 * If fp_port_id is zero and topology is
11830 			 * Point-to-Point, get the local port id from
11831 			 * the d_id in the PLOGI request.
11832 			 * If the outgoing FLOGI hasn't been accepted,
11833 			 * the topology will be unknown here. But it's
11834 			 * still safe to save the d_id to fp_port_id,
11835 			 * just because it will be overwritten later
11836 			 * if the topology is not Point-to-Point.
11837 			 */
11838 			mutex_enter(&port->fp_mutex);
11839 			if ((port->fp_port_id.port_id == 0) &&
11840 			    (port->fp_topology == FC_TOP_PT_PT ||
11841 			    port->fp_topology == FC_TOP_UNKNOWN)) {
11842 				port->fp_port_id.port_id =
11843 				    buf->ub_frame.d_id;
11844 			}
11845 			mutex_exit(&port->fp_mutex);
11846 		}
11847 	} else {
11848 		if (FP_IS_CLASS_1_OR_2(buf->ub_class) ||
11849 		    port->fp_options & FP_SEND_RJT) {
11850 			cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t),
11851 			    0, sleep, pd);
11852 			if (cmd == NULL) {
11853 				return;
11854 			}
11855 			cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_rjt_t);
11856 			cmd->cmd_pkt.pkt_rsplen = 0;
11857 			/*
11858 			 * Send out Logical busy to indicate
11859 			 * the detection of PLOGI collision
11860 			 */
11861 			fp_els_rjt_init(port, cmd, buf,
11862 			    FC_ACTION_NON_RETRYABLE,
11863 			    FC_REASON_LOGICAL_BSY, job);
11864 
11865 			fc_wwn_to_str(dwwn, dww_name);
11866 			FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_plogi: "
11867 			    "Rejecting Unsol PLOGI with Logical Busy."
11868 			    "possible PLOGI collision. PWWN=%s, sent=%x",
11869 			    dww_name, sent);
11870 		} else {
11871 			return;
11872 		}
11873 	}
11874 
11875 	if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
11876 		fp_free_pkt(cmd);
11877 	}
11878 }
11879 
11880 
11881 /*
11882  * Handle mischievous turning over of our own FLOGI requests back to
11883  * us by the SOC+ microcode. In other words, look at the class of such
11884  * bone headed requests, if 1 or 2, bluntly P_RJT them, if 3 drop them
11885  * on the floor
11886  */
11887 static void
11888 fp_handle_unsol_flogi(fc_local_port_t *port, fc_unsol_buf_t *buf,
11889 	job_request_t *job, int sleep)
11890 {
11891 	uint32_t	state;
11892 	uint32_t	s_id;
11893 	fp_cmd_t 	*cmd;
11894 
11895 	if (fp_is_class_supported(port->fp_cos, buf->ub_class) == FC_FAILURE) {
11896 		if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11897 			cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t),
11898 			    0, sleep, NULL);
11899 			if (cmd == NULL) {
11900 				return;
11901 			}
11902 			fp_els_rjt_init(port, cmd, buf,
11903 			    FC_ACTION_NON_RETRYABLE,
11904 			    FC_REASON_CLASS_NOT_SUPP, job);
11905 		} else {
11906 			return;
11907 		}
11908 	} else {
11909 
11910 		FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_flogi:"
11911 		    " s_id=%x, d_id=%x, type=%x, f_ctl=%x"
11912 		    " seq_id=%x, ox_id=%x, rx_id=%x, ro=%x",
11913 		    buf->ub_frame.s_id, buf->ub_frame.d_id,
11914 		    buf->ub_frame.type, buf->ub_frame.f_ctl,
11915 		    buf->ub_frame.seq_id, buf->ub_frame.ox_id,
11916 		    buf->ub_frame.rx_id, buf->ub_frame.ro);
11917 
11918 		mutex_enter(&port->fp_mutex);
11919 		state = FC_PORT_STATE_MASK(port->fp_state);
11920 		s_id = port->fp_port_id.port_id;
11921 		mutex_exit(&port->fp_mutex);
11922 
11923 		if (state != FC_STATE_ONLINE ||
11924 		    (s_id && buf->ub_frame.s_id == s_id)) {
11925 			if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11926 				cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t),
11927 				    0, sleep, NULL);
11928 				if (cmd == NULL) {
11929 					return;
11930 				}
11931 				fp_els_rjt_init(port, cmd, buf,
11932 				    FC_ACTION_NON_RETRYABLE,
11933 				    FC_REASON_INVALID_LINK_CTRL, job);
11934 				FP_TRACE(FP_NHEAD1(3, 0),
11935 				    "fp_handle_unsol_flogi: "
11936 				    "Rejecting PLOGI. Invalid Link CTRL");
11937 			} else {
11938 				return;
11939 			}
11940 		} else {
11941 			cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t),
11942 			    0, sleep, NULL);
11943 			if (cmd == NULL) {
11944 				return;
11945 			}
11946 			/*
11947 			 * Let's not aggressively validate the N_Port's
11948 			 * service parameters until PLOGI. Suffice it
11949 			 * to give a hint that we are an N_Port and we
11950 			 * are game to some serious stuff here.
11951 			 */
11952 			fp_login_acc_init(port, cmd, buf, job, KM_SLEEP);
11953 			FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_flogi: "
11954 			    "Accepting PLOGI");
11955 		}
11956 	}
11957 
11958 	if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
11959 		fp_free_pkt(cmd);
11960 	}
11961 }
11962 
11963 
11964 /*
11965  * Perform PLOGI accept
11966  */
11967 static void
11968 fp_login_acc_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf,
11969     job_request_t *job, int sleep)
11970 {
11971 	fc_packet_t	*pkt;
11972 	fc_portmap_t 	*listptr;
11973 	la_els_logi_t	payload;
11974 
11975 	ASSERT(buf != NULL);
11976 
11977 	/*
11978 	 * If we are sending ACC to PLOGI and we haven't already
11979 	 * create port and node device handles, let's create them
11980 	 * here.
11981 	 */
11982 	if (buf->ub_buffer[0] == LA_ELS_PLOGI &&
11983 	    FC_IS_REAL_DEVICE(buf->ub_frame.s_id)) {
11984 		int			small;
11985 		int			do_acc;
11986 		fc_remote_port_t	*pd;
11987 		la_els_logi_t 		*req;
11988 
11989 		req = (la_els_logi_t *)buf->ub_buffer;
11990 		small = fctl_wwn_cmp(&port->fp_service_params.nport_ww_name,
11991 		    &req->nport_ww_name);
11992 
11993 		mutex_enter(&port->fp_mutex);
11994 		do_acc = (port->fp_statec_busy == 0) ? 1 : 0;
11995 		mutex_exit(&port->fp_mutex);
11996 
11997 		pd = fctl_create_remote_port(port, &req->node_ww_name,
11998 		    &req->nport_ww_name, buf->ub_frame.s_id,
11999 		    PD_PLOGI_RECEPIENT, sleep);
12000 		if (pd == NULL) {
12001 			FP_TRACE(FP_NHEAD1(3, 0), "login_acc_init: "
12002 			    "Couldn't create port device for d_id:0x%x",
12003 			    buf->ub_frame.s_id);
12004 
12005 			fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
12006 			    "couldn't create port device d_id=%x",
12007 			    buf->ub_frame.s_id);
12008 		} else {
12009 			/*
12010 			 * usoc currently returns PLOGIs inline and
12011 			 * the maximum buffer size is 60 bytes or so.
12012 			 * So attempt not to look beyond what is in
12013 			 * the unsolicited buffer
12014 			 *
12015 			 * JNI also traverses this path sometimes
12016 			 */
12017 			if (buf->ub_bufsize >= sizeof (la_els_logi_t)) {
12018 				fp_register_login(NULL, pd, req, buf->ub_class);
12019 			} else {
12020 				mutex_enter(&pd->pd_mutex);
12021 				if (pd->pd_login_count == 0) {
12022 					pd->pd_login_count++;
12023 				}
12024 				pd->pd_state = PORT_DEVICE_LOGGED_IN;
12025 				pd->pd_login_class = buf->ub_class;
12026 				mutex_exit(&pd->pd_mutex);
12027 			}
12028 
12029 			listptr = kmem_zalloc(sizeof (fc_portmap_t), sleep);
12030 			if (listptr != NULL) {
12031 				fctl_copy_portmap(listptr, pd);
12032 				(void) fp_ulp_devc_cb(port, listptr,
12033 				    1, 1, sleep, 0);
12034 			}
12035 
12036 			if (small > 0 && do_acc) {
12037 				mutex_enter(&pd->pd_mutex);
12038 				pd->pd_recepient = PD_PLOGI_INITIATOR;
12039 				mutex_exit(&pd->pd_mutex);
12040 			}
12041 		}
12042 	}
12043 
12044 	cmd->cmd_pkt.pkt_tran_flags = buf->ub_class;
12045 	cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND;
12046 	cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
12047 	cmd->cmd_retry_count = 1;
12048 	cmd->cmd_ulp_pkt = NULL;
12049 
12050 	cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
12051 	cmd->cmd_job = job;
12052 
12053 	pkt = &cmd->cmd_pkt;
12054 
12055 	fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP, FC_TYPE_EXTENDED_LS);
12056 
12057 	payload = port->fp_service_params;
12058 	payload.ls_code.ls_code = LA_ELS_ACC;
12059 
12060 	ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&payload,
12061 	    (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
12062 
12063 	FP_TRACE(FP_NHEAD1(3, 0), "login_acc_init: ELS:0x%x d_id:0x%x "
12064 	    "bufsize:0x%x sizeof(la_els_logi):0x%x "
12065 	    "port's wwn:0x%01x%03x%04x%08x requestor's wwn:0x%01x%03x%04x%08x "
12066 	    "statec_busy:0x%x", buf->ub_buffer[0], buf->ub_frame.s_id,
12067 	    buf->ub_bufsize, sizeof (la_els_logi_t),
12068 	    port->fp_service_params.nport_ww_name.w.naa_id,
12069 	    port->fp_service_params.nport_ww_name.w.nport_id,
12070 	    port->fp_service_params.nport_ww_name.w.wwn_hi,
12071 	    port->fp_service_params.nport_ww_name.w.wwn_lo,
12072 	    ((la_els_logi_t *)buf->ub_buffer)->nport_ww_name.w.naa_id,
12073 	    ((la_els_logi_t *)buf->ub_buffer)->nport_ww_name.w.nport_id,
12074 	    ((la_els_logi_t *)buf->ub_buffer)->nport_ww_name.w.wwn_hi,
12075 	    ((la_els_logi_t *)buf->ub_buffer)->nport_ww_name.w.wwn_lo,
12076 	    port->fp_statec_busy);
12077 }
12078 
12079 
12080 #define	RSCN_EVENT_NAME_LEN	256
12081 
12082 /*
12083  * Handle RSCNs
12084  */
12085 static void
12086 fp_handle_unsol_rscn(fc_local_port_t *port, fc_unsol_buf_t *buf,
12087     job_request_t *job, int sleep)
12088 {
12089 	uint32_t		mask;
12090 	fp_cmd_t		*cmd;
12091 	uint32_t		count;
12092 	int			listindex;
12093 	int16_t			len;
12094 	fc_rscn_t		*payload;
12095 	fc_portmap_t 		*listptr;
12096 	fctl_ns_req_t		*ns_cmd;
12097 	fc_affected_id_t 	*page;
12098 	caddr_t			nvname;
12099 	nvlist_t		*attr_list = NULL;
12100 
12101 	mutex_enter(&port->fp_mutex);
12102 	if (!FC_IS_TOP_SWITCH(port->fp_topology)) {
12103 		if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
12104 			--port->fp_rscn_count;
12105 		}
12106 		mutex_exit(&port->fp_mutex);
12107 		return;
12108 	}
12109 	mutex_exit(&port->fp_mutex);
12110 
12111 	cmd = fp_alloc_pkt(port, FP_PORT_IDENTIFIER_LEN, 0, sleep, NULL);
12112 	if (cmd != NULL) {
12113 		fp_els_acc_init(port, cmd, buf, job);
12114 		if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
12115 			fp_free_pkt(cmd);
12116 		}
12117 	}
12118 
12119 	payload = (fc_rscn_t *)buf->ub_buffer;
12120 	ASSERT(payload->rscn_code == LA_ELS_RSCN);
12121 	ASSERT(payload->rscn_len == FP_PORT_IDENTIFIER_LEN);
12122 
12123 	len = payload->rscn_payload_len - FP_PORT_IDENTIFIER_LEN;
12124 
12125 	if (len <= 0) {
12126 		mutex_enter(&port->fp_mutex);
12127 		if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
12128 			--port->fp_rscn_count;
12129 		}
12130 		mutex_exit(&port->fp_mutex);
12131 
12132 		return;
12133 	}
12134 
12135 	ASSERT((len & 0x3) == 0);	/* Must be power of 4 */
12136 	count = (len >> 2) << 1;	/* number of pages multiplied by 2 */
12137 
12138 	listptr = kmem_zalloc(sizeof (fc_portmap_t) * count, sleep);
12139 	page = (fc_affected_id_t *)(buf->ub_buffer + sizeof (fc_rscn_t));
12140 
12141 	ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
12142 
12143 	ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gpn_id_t),
12144 	    sizeof (ns_resp_gpn_id_t), sizeof (ns_resp_gpn_id_t),
12145 	    0, sleep);
12146 	if (ns_cmd == NULL) {
12147 		kmem_free(listptr, sizeof (fc_portmap_t) * count);
12148 
12149 		mutex_enter(&port->fp_mutex);
12150 		if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
12151 			--port->fp_rscn_count;
12152 		}
12153 		mutex_exit(&port->fp_mutex);
12154 
12155 		return;
12156 	}
12157 
12158 	ns_cmd->ns_cmd_code = NS_GPN_ID;
12159 
12160 	FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_rscn: s_id=%x, d_id=%x,"
12161 	    "type=%x, f_ctl=%x seq_id=%x, ox_id=%x, rx_id=%x"
12162 	    " ro=%x", buf->ub_frame.s_id, buf->ub_frame.d_id,
12163 	    buf->ub_frame.type, buf->ub_frame.f_ctl, buf->ub_frame.seq_id,
12164 	    buf->ub_frame.ox_id, buf->ub_frame.rx_id, buf->ub_frame.ro);
12165 
12166 	/* Only proceed if we can allocate nvname and the nvlist */
12167 	if ((nvname = kmem_zalloc(RSCN_EVENT_NAME_LEN, KM_NOSLEEP)) != NULL &&
12168 		nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE,
12169 		KM_NOSLEEP) == DDI_SUCCESS) {
12170 	    if (!(attr_list && nvlist_add_uint32(attr_list, "instance",
12171 		    port->fp_instance) == DDI_SUCCESS &&
12172 		    nvlist_add_byte_array(attr_list, "port-wwn",
12173 		    port->fp_service_params.nport_ww_name.raw_wwn,
12174 		    sizeof (la_wwn_t)) == DDI_SUCCESS)) {
12175 		nvlist_free(attr_list);
12176 		attr_list = NULL;
12177 	    }
12178 	}
12179 
12180 	for (listindex = 0; len; len -= FP_PORT_IDENTIFIER_LEN, page++) {
12181 		/* Add affected page to the event payload */
12182 		if (attr_list != NULL) {
12183 		    (void) snprintf(nvname, RSCN_EVENT_NAME_LEN,
12184 			    "affected_page_%d", listindex);
12185 		    if (attr_list && nvlist_add_uint32(attr_list, nvname,
12186 			    ntohl(*(uint32_t *)page)) != DDI_SUCCESS) {
12187 			/* We don't want to send a partial event, so dump it */
12188 			nvlist_free(attr_list);
12189 			attr_list = NULL;
12190 		    }
12191 		}
12192 		/*
12193 		 * Query the NS to get the Port WWN for this
12194 		 * affected D_ID.
12195 		 */
12196 		mask = 0;
12197 		switch (page->aff_format & FC_RSCN_ADDRESS_MASK) {
12198 		case FC_RSCN_PORT_ADDRESS:
12199 			fp_validate_rscn_page(port, page, job, ns_cmd,
12200 			    listptr, &listindex, sleep);
12201 
12202 			if (listindex == 0) {
12203 				/*
12204 				 * We essentially did not process this RSCN. So,
12205 				 * ULPs are not going to be called and so we
12206 				 * decrement the rscn_count
12207 				 */
12208 				mutex_enter(&port->fp_mutex);
12209 				if (--port->fp_rscn_count ==
12210 				    FC_INVALID_RSCN_COUNT) {
12211 					--port->fp_rscn_count;
12212 				}
12213 				mutex_exit(&port->fp_mutex);
12214 			}
12215 			break;
12216 
12217 		case FC_RSCN_AREA_ADDRESS:
12218 			mask = 0xFFFF00;
12219 			/* FALLTHROUGH */
12220 
12221 		case FC_RSCN_DOMAIN_ADDRESS:
12222 			if (!mask) {
12223 				mask = 0xFF0000;
12224 			}
12225 			fp_validate_area_domain(port, page->aff_d_id, mask,
12226 			    job, sleep);
12227 			break;
12228 
12229 		case FC_RSCN_FABRIC_ADDRESS:
12230 			/*
12231 			 * We need to discover all the devices on this
12232 			 * port.
12233 			 */
12234 			fp_validate_area_domain(port, 0, 0, job, sleep);
12235 			break;
12236 
12237 		default:
12238 			break;
12239 		}
12240 	}
12241 	if (attr_list != NULL) {
12242 	    (void) ddi_log_sysevent(port->fp_port_dip, DDI_VENDOR_SUNW,
12243 		    EC_SUNFC, ESC_SUNFC_PORT_RSCN, attr_list,
12244 		    NULL, DDI_SLEEP);
12245 	    nvlist_free(attr_list);
12246 	} else {
12247 	    FP_TRACE(FP_NHEAD1(9, 0),
12248 		"RSCN handled, but event not sent to userland");
12249 	}
12250 	if (nvname != NULL) {
12251 	    kmem_free(nvname, RSCN_EVENT_NAME_LEN);
12252 	}
12253 
12254 	if (ns_cmd) {
12255 		fctl_free_ns_cmd(ns_cmd);
12256 	}
12257 
12258 	if (listindex) {
12259 #ifdef	DEBUG
12260 		page = (fc_affected_id_t *)(buf->ub_buffer +
12261 		    sizeof (fc_rscn_t));
12262 
12263 		if (listptr->map_did.port_id != page->aff_d_id) {
12264 			FP_TRACE(FP_NHEAD1(9, 0),
12265 			    "PORT RSCN: processed=%x, reporting=%x",
12266 			    listptr->map_did.port_id, page->aff_d_id);
12267 		}
12268 #endif
12269 
12270 		(void) fp_ulp_devc_cb(port, listptr, listindex, count,
12271 		    sleep, 0);
12272 	} else {
12273 		kmem_free(listptr, sizeof (fc_portmap_t) * count);
12274 	}
12275 }
12276 
12277 
12278 /*
12279  * Fill out old map for ULPs with fp_mutex, fd_mutex and pd_mutex held
12280  */
12281 static void
12282 fp_fillout_old_map_held(fc_portmap_t *map, fc_remote_port_t *pd, uchar_t flag)
12283 {
12284 	int		is_switch;
12285 	int		initiator;
12286 	fc_local_port_t	*port;
12287 
12288 	port = pd->pd_port;
12289 
12290 	/* This function has the following bunch of assumptions */
12291 	ASSERT(port != NULL);
12292 	ASSERT(MUTEX_HELD(&port->fp_mutex));
12293 	ASSERT(MUTEX_HELD(&pd->pd_remote_nodep->fd_mutex));
12294 	ASSERT(MUTEX_HELD(&pd->pd_mutex));
12295 
12296 	pd->pd_state = PORT_DEVICE_INVALID;
12297 	pd->pd_type = PORT_DEVICE_OLD;
12298 	initiator = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0;
12299 	is_switch = FC_IS_TOP_SWITCH(port->fp_topology);
12300 
12301 	fctl_delist_did_table(port, pd);
12302 	fctl_delist_pwwn_table(port, pd);
12303 
12304 	FP_TRACE(FP_NHEAD1(6, 0), "fp_fillout_old_map_held: port=%p, d_id=%x"
12305 	    " removed the PD=%p from DID and PWWN tables",
12306 	    port, pd->pd_port_id.port_id, pd);
12307 
12308 	if ((!flag) && port && initiator && is_switch) {
12309 		(void) fctl_add_orphan_held(port, pd);
12310 	}
12311 	fctl_copy_portmap_held(map, pd);
12312 	map->map_pd = pd;
12313 }
12314 
12315 /*
12316  * Fill out old map for ULPs
12317  */
12318 static void
12319 fp_fillout_old_map(fc_portmap_t *map, fc_remote_port_t *pd, uchar_t flag)
12320 {
12321 	int		is_switch;
12322 	int		initiator;
12323 	fc_local_port_t	*port;
12324 
12325 	mutex_enter(&pd->pd_mutex);
12326 	port = pd->pd_port;
12327 	mutex_exit(&pd->pd_mutex);
12328 
12329 	mutex_enter(&port->fp_mutex);
12330 	mutex_enter(&pd->pd_mutex);
12331 
12332 	pd->pd_state = PORT_DEVICE_INVALID;
12333 	pd->pd_type = PORT_DEVICE_OLD;
12334 	initiator = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0;
12335 	is_switch = FC_IS_TOP_SWITCH(port->fp_topology);
12336 
12337 	fctl_delist_did_table(port, pd);
12338 	fctl_delist_pwwn_table(port, pd);
12339 
12340 	FP_TRACE(FP_NHEAD1(6, 0), "fp_fillout_old_map: port=%p, d_id=%x"
12341 	    " removed the PD=%p from DID and PWWN tables",
12342 	    port, pd->pd_port_id.port_id, pd);
12343 
12344 	mutex_exit(&pd->pd_mutex);
12345 	mutex_exit(&port->fp_mutex);
12346 
12347 	ASSERT(port != NULL);
12348 	if ((!flag) && port && initiator && is_switch) {
12349 		(void) fctl_add_orphan(port, pd, KM_NOSLEEP);
12350 	}
12351 	fctl_copy_portmap(map, pd);
12352 	map->map_pd = pd;
12353 }
12354 
12355 
12356 /*
12357  * Fillout Changed Map for ULPs
12358  */
12359 static void
12360 fp_fillout_changed_map(fc_portmap_t *map, fc_remote_port_t *pd,
12361     uint32_t *new_did, la_wwn_t *new_pwwn)
12362 {
12363 	ASSERT(MUTEX_HELD(&pd->pd_mutex));
12364 
12365 	pd->pd_type = PORT_DEVICE_CHANGED;
12366 	if (new_did) {
12367 		pd->pd_port_id.port_id = *new_did;
12368 	}
12369 	if (new_pwwn) {
12370 		pd->pd_port_name = *new_pwwn;
12371 	}
12372 	mutex_exit(&pd->pd_mutex);
12373 
12374 	fctl_copy_portmap(map, pd);
12375 
12376 	mutex_enter(&pd->pd_mutex);
12377 	pd->pd_type = PORT_DEVICE_NOCHANGE;
12378 }
12379 
12380 
12381 /*
12382  * Fillout New Name Server map
12383  */
12384 static void
12385 fp_fillout_new_nsmap(fc_local_port_t *port, ddi_acc_handle_t *handle,
12386     fc_portmap_t *port_map, ns_resp_gan_t *gan_resp, uint32_t d_id)
12387 {
12388 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
12389 
12390 	if (handle) {
12391 		ddi_rep_get8(*handle, (uint8_t *)&port_map->map_pwwn,
12392 		    (uint8_t *)&gan_resp->gan_pwwn, sizeof (gan_resp->gan_pwwn),
12393 		    DDI_DEV_AUTOINCR);
12394 		ddi_rep_get8(*handle, (uint8_t *)&port_map->map_nwwn,
12395 		    (uint8_t *)&gan_resp->gan_nwwn, sizeof (gan_resp->gan_nwwn),
12396 		    DDI_DEV_AUTOINCR);
12397 		ddi_rep_get8(*handle, (uint8_t *)port_map->map_fc4_types,
12398 		    (uint8_t *)gan_resp->gan_fc4types,
12399 		    sizeof (gan_resp->gan_fc4types), DDI_DEV_AUTOINCR);
12400 	} else {
12401 		bcopy(&gan_resp->gan_pwwn, &port_map->map_pwwn,
12402 		    sizeof (gan_resp->gan_pwwn));
12403 		bcopy(&gan_resp->gan_nwwn, &port_map->map_nwwn,
12404 		    sizeof (gan_resp->gan_nwwn));
12405 		bcopy(gan_resp->gan_fc4types, port_map->map_fc4_types,
12406 		    sizeof (gan_resp->gan_fc4types));
12407 	}
12408 	port_map->map_did.port_id = d_id;
12409 	port_map->map_did.priv_lilp_posit = 0;
12410 	port_map->map_hard_addr.hard_addr = 0;
12411 	port_map->map_hard_addr.rsvd = 0;
12412 	port_map->map_state = PORT_DEVICE_INVALID;
12413 	port_map->map_type = PORT_DEVICE_NEW;
12414 	port_map->map_flags = 0;
12415 	port_map->map_pd = NULL;
12416 
12417 	(void) fctl_remove_if_orphan(port, &port_map->map_pwwn);
12418 
12419 	ASSERT(port != NULL);
12420 }
12421 
12422 
12423 /*
12424  * Perform LINIT ELS
12425  */
12426 static int
12427 fp_remote_lip(fc_local_port_t *port, la_wwn_t *pwwn, int sleep,
12428     job_request_t *job)
12429 {
12430 	int			rval;
12431 	uint32_t		d_id;
12432 	uint32_t		s_id;
12433 	uint32_t		lfa;
12434 	uchar_t			class;
12435 	uint32_t		ret;
12436 	fp_cmd_t		*cmd;
12437 	fc_porttype_t		ptype;
12438 	fc_packet_t		*pkt;
12439 	fc_linit_req_t		payload;
12440 	fc_remote_port_t 	*pd;
12441 
12442 	rval = 0;
12443 
12444 	ASSERT(job != NULL);
12445 	ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
12446 
12447 	pd = fctl_get_remote_port_by_pwwn(port, pwwn);
12448 	if (pd == NULL) {
12449 		fctl_ns_req_t *ns_cmd;
12450 
12451 		ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t),
12452 		    sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t),
12453 		    0, sleep);
12454 
12455 		if (ns_cmd == NULL) {
12456 			return (FC_NOMEM);
12457 		}
12458 		job->job_result = FC_SUCCESS;
12459 		ns_cmd->ns_cmd_code = NS_GID_PN;
12460 		((ns_req_gid_pn_t *)(ns_cmd->ns_cmd_buf))->pwwn = *pwwn;
12461 
12462 		ret = fp_ns_query(port, ns_cmd, job, 1, sleep);
12463 		if (ret != FC_SUCCESS || job->job_result != FC_SUCCESS) {
12464 			fctl_free_ns_cmd(ns_cmd);
12465 			return (FC_FAILURE);
12466 		}
12467 		bcopy(ns_cmd->ns_data_buf, (caddr_t)&d_id, sizeof (d_id));
12468 		d_id = BE_32(*((uint32_t *)ns_cmd->ns_data_buf));
12469 
12470 		fctl_free_ns_cmd(ns_cmd);
12471 		lfa = d_id & 0xFFFF00;
12472 
12473 		/*
12474 		 * Given this D_ID, get the port type to see if
12475 		 * we can do LINIT on the LFA
12476 		 */
12477 		ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gpt_id_t),
12478 		    sizeof (ns_resp_gpt_id_t), sizeof (ns_resp_gpt_id_t),
12479 		    0, sleep);
12480 
12481 		if (ns_cmd == NULL) {
12482 			return (FC_NOMEM);
12483 		}
12484 
12485 		job->job_result = FC_SUCCESS;
12486 		ns_cmd->ns_cmd_code = NS_GPT_ID;
12487 
12488 		((ns_req_gpt_id_t *)(ns_cmd->ns_cmd_buf))->pid.port_id = d_id;
12489 		((ns_req_gpt_id_t *)
12490 		    (ns_cmd->ns_cmd_buf))->pid.priv_lilp_posit = 0;
12491 
12492 		ret = fp_ns_query(port, ns_cmd, job, 1, sleep);
12493 		if (ret != FC_SUCCESS || job->job_result != FC_SUCCESS) {
12494 			fctl_free_ns_cmd(ns_cmd);
12495 			return (FC_FAILURE);
12496 		}
12497 		bcopy(ns_cmd->ns_data_buf, (caddr_t)&ptype, sizeof (ptype));
12498 
12499 		fctl_free_ns_cmd(ns_cmd);
12500 
12501 		switch (ptype.port_type) {
12502 		case FC_NS_PORT_NL:
12503 		case FC_NS_PORT_F_NL:
12504 		case FC_NS_PORT_FL:
12505 			break;
12506 
12507 		default:
12508 			return (FC_FAILURE);
12509 		}
12510 	} else {
12511 		mutex_enter(&pd->pd_mutex);
12512 		ptype = pd->pd_porttype;
12513 
12514 		switch (pd->pd_porttype.port_type) {
12515 		case FC_NS_PORT_NL:
12516 		case FC_NS_PORT_F_NL:
12517 		case FC_NS_PORT_FL:
12518 			lfa = pd->pd_port_id.port_id & 0xFFFF00;
12519 			break;
12520 
12521 		default:
12522 			mutex_exit(&pd->pd_mutex);
12523 			return (FC_FAILURE);
12524 		}
12525 		mutex_exit(&pd->pd_mutex);
12526 	}
12527 
12528 	mutex_enter(&port->fp_mutex);
12529 	s_id = port->fp_port_id.port_id;
12530 	class = port->fp_ns_login_class;
12531 	mutex_exit(&port->fp_mutex);
12532 
12533 	cmd = fp_alloc_pkt(port, sizeof (fc_linit_req_t),
12534 	    sizeof (fc_linit_resp_t), sleep, pd);
12535 	if (cmd == NULL) {
12536 		return (FC_NOMEM);
12537 	}
12538 
12539 	cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class;
12540 	cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
12541 	cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
12542 	cmd->cmd_retry_count = fp_retry_count;
12543 	cmd->cmd_ulp_pkt = NULL;
12544 
12545 	pkt = &cmd->cmd_pkt;
12546 	cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
12547 
12548 	fp_els_init(cmd, s_id, lfa, fp_linit_intr, job);
12549 
12550 	/*
12551 	 * How does LIP work by the way ?
12552 	 * 	If the L_Port receives three consecutive identical ordered
12553 	 *	sets whose first two characters (fully decoded) are equal to
12554 	 *	the values shown in Table 3 of FC-AL-2 then the L_Port shall
12555 	 *	recognize a Loop Initialization Primitive sequence. The
12556 	 *	character 3 determines the type of lip:
12557 	 *		LIP(F7)		Normal LIP
12558 	 *		LIP(F8)		Loop Failure LIP
12559 	 *
12560 	 * The possible combination for the 3rd and 4th bytes are:
12561 	 *	F7, 	F7	Normal Lip 	- No valid AL_PA
12562 	 *	F8, 	F8	Loop Failure	- No valid AL_PA
12563 	 *	F7, 	AL_PS	Normal Lip	- Valid source AL_PA
12564 	 *	F8, 	AL_PS	Loop Failure	- Valid source AL_PA
12565 	 *	AL_PD	AL_PS	Loop reset of AL_PD originated by AL_PS
12566 	 *			And Normal Lip for all other loop members
12567 	 *	0xFF	AL_PS	Vendor specific reset of all loop members
12568 	 *
12569 	 * Now, it may not always be that we, at the source, may have an
12570 	 * AL_PS (AL_PA of source) for 4th character slot, so we decide
12571 	 * to do (Normal Lip, No Valid AL_PA), that means, in the LINIT
12572 	 * payload we are going to set:
12573 	 *	lip_b3 = 0xF7;		Normal LIP
12574 	 *	lip_b4 = 0xF7;		No valid source AL_PA
12575 	 */
12576 	payload.ls_code.ls_code = LA_ELS_LINIT;
12577 	payload.ls_code.mbz = 0;
12578 	payload.rsvd = 0;
12579 	payload.func = 0;		/* Let Fabric determine the best way */
12580 	payload.lip_b3 = 0xF7;		/* Normal LIP */
12581 	payload.lip_b4 = 0xF7;		/* No valid source AL_PA */
12582 
12583 	ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&payload,
12584 	    (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
12585 
12586 	job->job_counter = 1;
12587 
12588 	ret = fp_sendcmd(port, cmd, port->fp_fca_handle);
12589 	if (ret == FC_SUCCESS) {
12590 		fp_jobwait(job);
12591 		rval = job->job_result;
12592 	} else {
12593 		rval = FC_FAILURE;
12594 		fp_free_pkt(cmd);
12595 	}
12596 
12597 	return (rval);
12598 }
12599 
12600 
12601 /*
12602  * Fill out the device handles with GAN response
12603  */
12604 static void
12605 fp_stuff_device_with_gan(ddi_acc_handle_t *handle, fc_remote_port_t *pd,
12606     ns_resp_gan_t *gan_resp)
12607 {
12608 	fc_remote_node_t 	*node;
12609 	fc_porttype_t		type;
12610 	fc_local_port_t		*port;
12611 
12612 	ASSERT(pd != NULL);
12613 	ASSERT(handle != NULL);
12614 
12615 	port = pd->pd_port;
12616 
12617 	FP_TRACE(FP_NHEAD1(1, 0), "GAN PD stuffing; pd=%p,"
12618 	    " port_id=%x, sym_len=%d fc4-type=%x",
12619 	    pd, gan_resp->gan_type_id.rsvd,
12620 	    gan_resp->gan_spnlen, gan_resp->gan_fc4types[0]);
12621 
12622 	mutex_enter(&pd->pd_mutex);
12623 
12624 	ddi_rep_get8(*handle, (uint8_t *)&type,
12625 	    (uint8_t *)&gan_resp->gan_type_id, sizeof (type), DDI_DEV_AUTOINCR);
12626 
12627 	pd->pd_porttype.port_type = type.port_type;
12628 	pd->pd_porttype.rsvd = 0;
12629 
12630 	pd->pd_spn_len = gan_resp->gan_spnlen;
12631 	if (pd->pd_spn_len) {
12632 		ddi_rep_get8(*handle, (uint8_t *)pd->pd_spn,
12633 		    (uint8_t *)gan_resp->gan_spname, pd->pd_spn_len,
12634 		    DDI_DEV_AUTOINCR);
12635 	}
12636 
12637 	ddi_rep_get8(*handle, (uint8_t *)pd->pd_ip_addr,
12638 	    (uint8_t *)gan_resp->gan_ip, sizeof (pd->pd_ip_addr),
12639 	    DDI_DEV_AUTOINCR);
12640 	ddi_rep_get8(*handle, (uint8_t *)&pd->pd_cos,
12641 	    (uint8_t *)&gan_resp->gan_cos, sizeof (pd->pd_cos),
12642 	    DDI_DEV_AUTOINCR);
12643 	ddi_rep_get8(*handle, (uint8_t *)pd->pd_fc4types,
12644 	    (uint8_t *)gan_resp->gan_fc4types, sizeof (pd->pd_fc4types),
12645 	    DDI_DEV_AUTOINCR);
12646 
12647 	node = pd->pd_remote_nodep;
12648 	mutex_exit(&pd->pd_mutex);
12649 
12650 	mutex_enter(&node->fd_mutex);
12651 
12652 	ddi_rep_get8(*handle, (uint8_t *)node->fd_ipa,
12653 	    (uint8_t *)gan_resp->gan_ipa, sizeof (node->fd_ipa),
12654 	    DDI_DEV_AUTOINCR);
12655 
12656 	node->fd_snn_len = gan_resp->gan_snnlen;
12657 	if (node->fd_snn_len) {
12658 		ddi_rep_get8(*handle, (uint8_t *)node->fd_snn,
12659 		    (uint8_t *)gan_resp->gan_snname, node->fd_snn_len,
12660 		    DDI_DEV_AUTOINCR);
12661 	}
12662 
12663 	mutex_exit(&node->fd_mutex);
12664 }
12665 
12666 
12667 /*
12668  * Handles all NS Queries (also means that this function
12669  * doesn't handle NS object registration)
12670  */
12671 static int
12672 fp_ns_query(fc_local_port_t *port, fctl_ns_req_t *ns_cmd, job_request_t *job,
12673     int polled, int sleep)
12674 {
12675 	int 		rval;
12676 	fp_cmd_t 	*cmd;
12677 
12678 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
12679 
12680 	if (ns_cmd->ns_cmd_size == 0) {
12681 		return (FC_FAILURE);
12682 	}
12683 
12684 	cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
12685 	    ns_cmd->ns_cmd_size, sizeof (fc_ct_header_t) +
12686 	    ns_cmd->ns_resp_size, sleep, NULL);
12687 	if (cmd == NULL) {
12688 		return (FC_NOMEM);
12689 	}
12690 
12691 	fp_ct_init(port, cmd, ns_cmd, ns_cmd->ns_cmd_code, ns_cmd->ns_cmd_buf,
12692 	    ns_cmd->ns_cmd_size, ns_cmd->ns_resp_size, job);
12693 
12694 	if (polled) {
12695 		job->job_counter = 1;
12696 		ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
12697 	}
12698 	rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
12699 	if (rval != FC_SUCCESS) {
12700 		job->job_result = rval;
12701 		fp_iodone(cmd);
12702 		if (polled == 0) {
12703 			/*
12704 			 * Return FC_SUCCESS to indicate that
12705 			 * fp_iodone is performed already.
12706 			 */
12707 			rval = FC_SUCCESS;
12708 		}
12709 	}
12710 
12711 	if (polled) {
12712 		fp_jobwait(job);
12713 		rval = job->job_result;
12714 	}
12715 
12716 	return (rval);
12717 }
12718 
12719 
12720 /*
12721  * Initialize Common Transport request
12722  */
12723 static void
12724 fp_ct_init(fc_local_port_t *port, fp_cmd_t *cmd, fctl_ns_req_t *ns_cmd,
12725     uint16_t cmd_code, caddr_t cmd_buf, uint16_t cmd_len,
12726     uint16_t resp_len, job_request_t *job)
12727 {
12728 	uint32_t	s_id;
12729 	uchar_t		class;
12730 	fc_packet_t 	*pkt;
12731 	fc_ct_header_t 	ct;
12732 
12733 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
12734 
12735 	mutex_enter(&port->fp_mutex);
12736 	s_id = port->fp_port_id.port_id;
12737 	class = port->fp_ns_login_class;
12738 	mutex_exit(&port->fp_mutex);
12739 
12740 	cmd->cmd_job = job;
12741 	cmd->cmd_private = ns_cmd;
12742 	pkt = &cmd->cmd_pkt;
12743 
12744 	ct.ct_rev = CT_REV;
12745 	ct.ct_inid = 0;
12746 	ct.ct_fcstype = FCSTYPE_DIRECTORY;
12747 	ct.ct_fcssubtype = FCSSUB_DS_NAME_SERVER;
12748 	ct.ct_options = 0;
12749 	ct.ct_reserved1 = 0;
12750 	ct.ct_cmdrsp = cmd_code;
12751 	ct.ct_aiusize = resp_len >> 2;
12752 	ct.ct_reserved2 = 0;
12753 	ct.ct_reason = 0;
12754 	ct.ct_expln = 0;
12755 	ct.ct_vendor = 0;
12756 
12757 	ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&ct, (uint8_t *)pkt->pkt_cmd,
12758 	    sizeof (ct), DDI_DEV_AUTOINCR);
12759 
12760 	pkt->pkt_cmd_fhdr.r_ctl = R_CTL_UNSOL_CONTROL;
12761 	pkt->pkt_cmd_fhdr.d_id = 0xFFFFFC;
12762 	pkt->pkt_cmd_fhdr.s_id = s_id;
12763 	pkt->pkt_cmd_fhdr.type = FC_TYPE_FC_SERVICES;
12764 	pkt->pkt_cmd_fhdr.f_ctl = F_CTL_SEQ_INITIATIVE |
12765 	    F_CTL_FIRST_SEQ | F_CTL_END_SEQ;
12766 	pkt->pkt_cmd_fhdr.seq_id = 0;
12767 	pkt->pkt_cmd_fhdr.df_ctl  = 0;
12768 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
12769 	pkt->pkt_cmd_fhdr.ox_id = 0xffff;
12770 	pkt->pkt_cmd_fhdr.rx_id = 0xffff;
12771 	pkt->pkt_cmd_fhdr.ro = 0;
12772 	pkt->pkt_cmd_fhdr.rsvd = 0;
12773 
12774 	pkt->pkt_comp = fp_ns_intr;
12775 	pkt->pkt_ulp_private = (opaque_t)cmd;
12776 	pkt->pkt_timeout = FP_NS_TIMEOUT;
12777 
12778 	if (cmd_buf) {
12779 		ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)cmd_buf,
12780 		    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
12781 		    cmd_len, DDI_DEV_AUTOINCR);
12782 	}
12783 
12784 	cmd->cmd_transport = port->fp_fca_tran->fca_transport;
12785 
12786 	cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class;
12787 	cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
12788 	cmd->cmd_flags = FP_CMD_PLOGI_DONT_CARE;
12789 	cmd->cmd_retry_count = fp_retry_count;
12790 	cmd->cmd_ulp_pkt = NULL;
12791 }
12792 
12793 
12794 /*
12795  * Name Server request interrupt routine
12796  */
12797 static void
12798 fp_ns_intr(fc_packet_t *pkt)
12799 {
12800 	fp_cmd_t	*cmd;
12801 	fc_local_port_t	*port;
12802 	fc_ct_header_t 	resp_hdr;
12803 	fc_ct_header_t 	cmd_hdr;
12804 	fctl_ns_req_t	*ns_cmd;
12805 
12806 	cmd = pkt->pkt_ulp_private;
12807 	port = cmd->cmd_port;
12808 
12809 	ddi_rep_get8(pkt->pkt_cmd_acc, (uint8_t *)&cmd_hdr,
12810 	    (uint8_t *)pkt->pkt_cmd, sizeof (cmd_hdr), DDI_DEV_AUTOINCR);
12811 
12812 	ns_cmd = (fctl_ns_req_t *)
12813 	    (((fp_cmd_t *)(pkt->pkt_ulp_private))->cmd_private);
12814 
12815 	if (!FP_IS_PKT_ERROR(pkt)) {
12816 		ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&resp_hdr,
12817 		    (uint8_t *)pkt->pkt_resp, sizeof (resp_hdr),
12818 		    DDI_DEV_AUTOINCR);
12819 
12820 		/*
12821 		 * On x86 architectures, make sure the resp_hdr is big endian.
12822 		 * This macro is a NOP on sparc architectures mainly because
12823 		 * we don't want to end up wasting time since the end result
12824 		 * is going to be the same.
12825 		 */
12826 		MAKE_BE_32(&resp_hdr);
12827 
12828 		if (ns_cmd) {
12829 			/*
12830 			 * Always copy out the response CT_HDR
12831 			 */
12832 			bcopy(&resp_hdr, &ns_cmd->ns_resp_hdr,
12833 			    sizeof (resp_hdr));
12834 		}
12835 
12836 		if (resp_hdr.ct_cmdrsp == FS_RJT_IU) {
12837 			pkt->pkt_state = FC_PKT_FS_RJT;
12838 			pkt->pkt_reason = resp_hdr.ct_reason;
12839 			pkt->pkt_expln = resp_hdr.ct_expln;
12840 		}
12841 	}
12842 
12843 	if (FP_IS_PKT_ERROR(pkt)) {
12844 		if (ns_cmd) {
12845 			if (ns_cmd->ns_flags & FCTL_NS_VALIDATE_PD) {
12846 				ASSERT(ns_cmd->ns_pd != NULL);
12847 
12848 				/* Mark it OLD if not already done */
12849 				mutex_enter(&ns_cmd->ns_pd->pd_mutex);
12850 				ns_cmd->ns_pd->pd_type = PORT_DEVICE_OLD;
12851 				mutex_exit(&ns_cmd->ns_pd->pd_mutex);
12852 			}
12853 
12854 			if (ns_cmd->ns_flags & FCTL_NS_ASYNC_REQUEST) {
12855 				fctl_free_ns_cmd(ns_cmd);
12856 				((fp_cmd_t *)
12857 				    (pkt->pkt_ulp_private))->cmd_private = NULL;
12858 			}
12859 
12860 		}
12861 
12862 		FP_TRACE(FP_NHEAD1(4, 0), "NS failure; pkt state=%x reason=%x",
12863 		    pkt->pkt_state, pkt->pkt_reason);
12864 
12865 		(void) fp_common_intr(pkt, 1);
12866 
12867 		return;
12868 	}
12869 
12870 	if (resp_hdr.ct_cmdrsp != FS_ACC_IU) {
12871 		uint32_t	d_id;
12872 		fc_local_port_t	*port;
12873 		fp_cmd_t	*cmd;
12874 
12875 		d_id = pkt->pkt_cmd_fhdr.d_id;
12876 		cmd = pkt->pkt_ulp_private;
12877 		port = cmd->cmd_port;
12878 		FP_TRACE(FP_NHEAD2(9, 0),
12879 		    "Bogus NS response received for D_ID=%x", d_id);
12880 	}
12881 
12882 	if (cmd_hdr.ct_cmdrsp == NS_GA_NXT) {
12883 		fp_gan_handler(pkt, ns_cmd);
12884 		return;
12885 	}
12886 
12887 	if (cmd_hdr.ct_cmdrsp >= NS_GPN_ID &&
12888 	    cmd_hdr.ct_cmdrsp <= NS_GID_PT) {
12889 		if (ns_cmd) {
12890 			if ((ns_cmd->ns_flags & FCTL_NS_NO_DATA_BUF) == 0) {
12891 				fp_ns_query_handler(pkt, ns_cmd);
12892 				return;
12893 			}
12894 		}
12895 	}
12896 
12897 	fp_iodone(pkt->pkt_ulp_private);
12898 }
12899 
12900 
12901 /*
12902  * Process NS_GAN response
12903  */
12904 static void
12905 fp_gan_handler(fc_packet_t *pkt, fctl_ns_req_t *ns_cmd)
12906 {
12907 	int			my_did;
12908 	fc_portid_t		d_id;
12909 	fp_cmd_t		*cmd;
12910 	fc_local_port_t		*port;
12911 	fc_remote_port_t	*pd;
12912 	ns_req_gan_t		gan_req;
12913 	ns_resp_gan_t		*gan_resp;
12914 
12915 	ASSERT(ns_cmd != NULL);
12916 
12917 	cmd = pkt->pkt_ulp_private;
12918 	port = cmd->cmd_port;
12919 
12920 	gan_resp = (ns_resp_gan_t *)(pkt->pkt_resp + sizeof (fc_ct_header_t));
12921 
12922 	ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&d_id,
12923 	    (uint8_t *)&gan_resp->gan_type_id, sizeof (d_id), DDI_DEV_AUTOINCR);
12924 
12925 	*(uint32_t *)&d_id = BE_32(*(uint32_t *)&d_id);
12926 
12927 	/*
12928 	 * In this case the priv_lilp_posit field  in reality
12929 	 * is actually represents the relative position on a private loop.
12930 	 * So zero it while dealing with Port Identifiers.
12931 	 */
12932 	d_id.priv_lilp_posit = 0;
12933 	pd = fctl_get_remote_port_by_did(port, d_id.port_id);
12934 	if (ns_cmd->ns_gan_sid == d_id.port_id) {
12935 		/*
12936 		 * We've come a full circle; time to get out.
12937 		 */
12938 		fp_iodone(cmd);
12939 		return;
12940 	}
12941 
12942 	if (ns_cmd->ns_gan_sid == FCTL_GAN_START_ID) {
12943 		ns_cmd->ns_gan_sid = d_id.port_id;
12944 	}
12945 
12946 	mutex_enter(&port->fp_mutex);
12947 	my_did = (d_id.port_id == port->fp_port_id.port_id) ? 1 : 0;
12948 	mutex_exit(&port->fp_mutex);
12949 
12950 	FP_TRACE(FP_NHEAD1(1, 0), "GAN response; port=%p, d_id=%x", port,
12951 	    d_id.port_id);
12952 
12953 	if (my_did == 0) {
12954 		la_wwn_t pwwn;
12955 		la_wwn_t nwwn;
12956 
12957 		FP_TRACE(FP_NHEAD1(1, 0), "GAN response details; "
12958 		    "port=%p, d_id=%x, type_id=%x, "
12959 		    "pwwn=%x %x %x %x %x %x %x %x, "
12960 		    "nwwn=%x %x %x %x %x %x %x %x",
12961 		    port, d_id.port_id, gan_resp->gan_type_id,
12962 
12963 		    gan_resp->gan_pwwn.raw_wwn[0],
12964 		    gan_resp->gan_pwwn.raw_wwn[1],
12965 		    gan_resp->gan_pwwn.raw_wwn[2],
12966 		    gan_resp->gan_pwwn.raw_wwn[3],
12967 		    gan_resp->gan_pwwn.raw_wwn[4],
12968 		    gan_resp->gan_pwwn.raw_wwn[5],
12969 		    gan_resp->gan_pwwn.raw_wwn[6],
12970 		    gan_resp->gan_pwwn.raw_wwn[7],
12971 
12972 		    gan_resp->gan_nwwn.raw_wwn[0],
12973 		    gan_resp->gan_nwwn.raw_wwn[1],
12974 		    gan_resp->gan_nwwn.raw_wwn[2],
12975 		    gan_resp->gan_nwwn.raw_wwn[3],
12976 		    gan_resp->gan_nwwn.raw_wwn[4],
12977 		    gan_resp->gan_nwwn.raw_wwn[5],
12978 		    gan_resp->gan_nwwn.raw_wwn[6],
12979 		    gan_resp->gan_nwwn.raw_wwn[7]);
12980 
12981 		ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&nwwn,
12982 		    (uint8_t *)&gan_resp->gan_nwwn, sizeof (nwwn),
12983 		    DDI_DEV_AUTOINCR);
12984 
12985 		ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&pwwn,
12986 		    (uint8_t *)&gan_resp->gan_pwwn, sizeof (pwwn),
12987 		    DDI_DEV_AUTOINCR);
12988 
12989 		if (ns_cmd->ns_flags & FCTL_NS_CREATE_DEVICE && pd == NULL) {
12990 			pd = fctl_create_remote_port(port, &nwwn, &pwwn,
12991 			    d_id.port_id, PD_PLOGI_INITIATOR, KM_NOSLEEP);
12992 		}
12993 		if (pd != NULL) {
12994 			fp_stuff_device_with_gan(&pkt->pkt_resp_acc,
12995 			    pd, gan_resp);
12996 		}
12997 
12998 		if (ns_cmd->ns_flags & FCTL_NS_GET_DEV_COUNT) {
12999 			*((int *)ns_cmd->ns_data_buf) += 1;
13000 		}
13001 
13002 		if (ns_cmd->ns_flags & FCTL_NS_FILL_NS_MAP) {
13003 			ASSERT((ns_cmd->ns_flags & FCTL_NS_NO_DATA_BUF) == 0);
13004 
13005 			if (ns_cmd->ns_flags & FCTL_NS_BUF_IS_USERLAND) {
13006 				fc_port_dev_t *userbuf;
13007 
13008 				userbuf = ((fc_port_dev_t *)
13009 				    ns_cmd->ns_data_buf) +
13010 				    ns_cmd->ns_gan_index++;
13011 
13012 				userbuf->dev_did = d_id;
13013 
13014 				ddi_rep_get8(pkt->pkt_resp_acc,
13015 				    (uint8_t *)userbuf->dev_type,
13016 				    (uint8_t *)gan_resp->gan_fc4types,
13017 				    sizeof (userbuf->dev_type),
13018 				    DDI_DEV_AUTOINCR);
13019 
13020 				userbuf->dev_nwwn = nwwn;
13021 				userbuf->dev_pwwn = pwwn;
13022 
13023 				if (pd != NULL) {
13024 					mutex_enter(&pd->pd_mutex);
13025 					userbuf->dev_state = pd->pd_state;
13026 					userbuf->dev_hard_addr =
13027 					    pd->pd_hard_addr;
13028 					mutex_exit(&pd->pd_mutex);
13029 				} else {
13030 					userbuf->dev_state =
13031 					    PORT_DEVICE_INVALID;
13032 				}
13033 			} else if (ns_cmd->ns_flags &
13034 			    FCTL_NS_BUF_IS_FC_PORTMAP) {
13035 				fc_portmap_t *map;
13036 
13037 				map = ((fc_portmap_t *)
13038 				    ns_cmd->ns_data_buf) +
13039 				    ns_cmd->ns_gan_index++;
13040 
13041 				/*
13042 				 * First fill it like any new map
13043 				 * and update the port device info
13044 				 * below.
13045 				 */
13046 				fp_fillout_new_nsmap(port, &pkt->pkt_resp_acc,
13047 				    map, gan_resp, d_id.port_id);
13048 				if (pd != NULL) {
13049 					fctl_copy_portmap(map, pd);
13050 				} else {
13051 					map->map_state = PORT_DEVICE_INVALID;
13052 					map->map_type = PORT_DEVICE_NOCHANGE;
13053 				}
13054 			} else {
13055 				caddr_t dst_ptr;
13056 
13057 				dst_ptr = ns_cmd->ns_data_buf +
13058 				    (NS_GAN_RESP_LEN) * ns_cmd->ns_gan_index++;
13059 
13060 				ddi_rep_get8(pkt->pkt_resp_acc,
13061 				    (uint8_t *)dst_ptr, (uint8_t *)gan_resp,
13062 				    NS_GAN_RESP_LEN, DDI_DEV_AUTOINCR);
13063 			}
13064 		} else {
13065 			ns_cmd->ns_gan_index++;
13066 		}
13067 		if (ns_cmd->ns_gan_index >= ns_cmd->ns_gan_max) {
13068 			fp_iodone(cmd);
13069 			return;
13070 		}
13071 	}
13072 
13073 	gan_req.pid = d_id;
13074 
13075 	ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&gan_req,
13076 	    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
13077 	    sizeof (gan_req), DDI_DEV_AUTOINCR);
13078 
13079 	if (cmd->cmd_transport(port->fp_fca_handle, pkt) != FC_SUCCESS) {
13080 		pkt->pkt_state = FC_PKT_TRAN_ERROR;
13081 		fp_iodone(cmd);
13082 	}
13083 }
13084 
13085 
13086 /*
13087  * Handle NS Query interrupt
13088  */
13089 static void
13090 fp_ns_query_handler(fc_packet_t *pkt, fctl_ns_req_t *ns_cmd)
13091 {
13092 	fp_cmd_t 	*cmd;
13093 	fc_local_port_t	*port;
13094 	caddr_t 	src_ptr;
13095 	uint32_t 	xfer_len;
13096 
13097 	cmd = pkt->pkt_ulp_private;
13098 	port = cmd->cmd_port;
13099 
13100 	xfer_len = ns_cmd->ns_resp_size;
13101 
13102 	FP_TRACE(FP_NHEAD1(1, 0), "NS Query response, cmd_code=%x, xfer_len=%x",
13103 	    ns_cmd->ns_cmd_code, xfer_len);
13104 
13105 	if (ns_cmd->ns_cmd_code == NS_GPN_ID) {
13106 		src_ptr = (caddr_t)pkt->pkt_resp + sizeof (fc_ct_header_t);
13107 
13108 		FP_TRACE(FP_NHEAD1(6, 0), "GPN_ID results; %x %x %x %x %x",
13109 		    src_ptr[0], src_ptr[1], src_ptr[2], src_ptr[3], src_ptr[4]);
13110 	}
13111 
13112 	if (xfer_len <= ns_cmd->ns_data_len) {
13113 		src_ptr = (caddr_t)pkt->pkt_resp + sizeof (fc_ct_header_t);
13114 		ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)ns_cmd->ns_data_buf,
13115 		    (uint8_t *)src_ptr, xfer_len, DDI_DEV_AUTOINCR);
13116 	}
13117 
13118 	if (ns_cmd->ns_flags & FCTL_NS_VALIDATE_PD) {
13119 		ASSERT(ns_cmd->ns_pd != NULL);
13120 
13121 		mutex_enter(&ns_cmd->ns_pd->pd_mutex);
13122 		if (ns_cmd->ns_pd->pd_type == PORT_DEVICE_OLD) {
13123 			ns_cmd->ns_pd->pd_type = PORT_DEVICE_NOCHANGE;
13124 		}
13125 		mutex_exit(&ns_cmd->ns_pd->pd_mutex);
13126 	}
13127 
13128 	if (ns_cmd->ns_flags & FCTL_NS_ASYNC_REQUEST) {
13129 		fctl_free_ns_cmd(ns_cmd);
13130 		((fp_cmd_t *)(pkt->pkt_ulp_private))->cmd_private = NULL;
13131 	}
13132 	fp_iodone(cmd);
13133 }
13134 
13135 
13136 /*
13137  * Handle unsolicited ADISC ELS request
13138  */
13139 static void
13140 fp_handle_unsol_adisc(fc_local_port_t *port, fc_unsol_buf_t *buf,
13141     fc_remote_port_t *pd, job_request_t *job)
13142 {
13143 	int		rval;
13144 	fp_cmd_t	*cmd;
13145 
13146 	FP_TRACE(FP_NHEAD1(5, 0), "ADISC; port=%p, D_ID=%x state=%x, pd=%p",
13147 	    port, pd->pd_port_id.port_id, pd->pd_state, pd);
13148 	mutex_enter(&pd->pd_mutex);
13149 	if (pd->pd_state != PORT_DEVICE_LOGGED_IN) {
13150 		mutex_exit(&pd->pd_mutex);
13151 		if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
13152 			cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t),
13153 			    0, KM_SLEEP, pd);
13154 			if (cmd != NULL) {
13155 				fp_els_rjt_init(port, cmd, buf,
13156 				    FC_ACTION_NON_RETRYABLE,
13157 				    FC_REASON_INVALID_LINK_CTRL, job);
13158 
13159 				if (fp_sendcmd(port, cmd,
13160 				    port->fp_fca_handle) != FC_SUCCESS) {
13161 					fp_free_pkt(cmd);
13162 				}
13163 			}
13164 		}
13165 	} else {
13166 		mutex_exit(&pd->pd_mutex);
13167 		/*
13168 		 * Yes, yes, we don't have a hard address. But we
13169 		 * we should still respond. Huh ? Visit 21.19.2
13170 		 * of FC-PH-2 which essentially says that if an
13171 		 * NL_Port doesn't have a hard address, or if a port
13172 		 * does not have FC-AL capability, it shall report
13173 		 * zeroes in this field.
13174 		 */
13175 		cmd = fp_alloc_pkt(port, sizeof (la_els_adisc_t),
13176 		    0, KM_SLEEP, pd);
13177 		if (cmd == NULL) {
13178 			return;
13179 		}
13180 		fp_adisc_acc_init(port, cmd, buf, job);
13181 		rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
13182 		if (rval != FC_SUCCESS) {
13183 			fp_free_pkt(cmd);
13184 		}
13185 	}
13186 }
13187 
13188 
13189 /*
13190  * Initialize ADISC response.
13191  */
13192 static void
13193 fp_adisc_acc_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf,
13194     job_request_t *job)
13195 {
13196 	fc_packet_t	*pkt;
13197 	la_els_adisc_t	payload;
13198 
13199 	cmd->cmd_pkt.pkt_tran_flags = buf->ub_class;
13200 	cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND;
13201 	cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
13202 	cmd->cmd_retry_count = 1;
13203 	cmd->cmd_ulp_pkt = NULL;
13204 
13205 	cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
13206 	cmd->cmd_job = job;
13207 
13208 	pkt = &cmd->cmd_pkt;
13209 
13210 	fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP, FC_TYPE_EXTENDED_LS);
13211 
13212 	payload.ls_code.ls_code = LA_ELS_ACC;
13213 	payload.ls_code.mbz = 0;
13214 
13215 	mutex_enter(&port->fp_mutex);
13216 	payload.nport_id = port->fp_port_id;
13217 	payload.hard_addr = port->fp_hard_addr;
13218 	mutex_exit(&port->fp_mutex);
13219 
13220 	payload.port_wwn = port->fp_service_params.nport_ww_name;
13221 	payload.node_wwn = port->fp_service_params.node_ww_name;
13222 
13223 	ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&payload,
13224 	    (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
13225 }
13226 
13227 
13228 /*
13229  * Hold and Install the requested ULP drivers
13230  */
13231 static void
13232 fp_load_ulp_modules(dev_info_t *dip, fc_local_port_t *port)
13233 {
13234 	int		len;
13235 	int		count;
13236 	int		data_len;
13237 	major_t		ulp_major;
13238 	caddr_t		ulp_name;
13239 	caddr_t		data_ptr;
13240 	caddr_t		data_buf;
13241 
13242 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
13243 
13244 	data_buf = NULL;
13245 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
13246 	    DDI_PROP_DONTPASS, "load-ulp-list",
13247 	    (caddr_t)&data_buf, &data_len) != DDI_PROP_SUCCESS) {
13248 		return;
13249 	}
13250 
13251 	len = strlen(data_buf);
13252 	port->fp_ulp_nload = fctl_atoi(data_buf, 10);
13253 
13254 	data_ptr = data_buf + len + 1;
13255 	for (count = 0; count < port->fp_ulp_nload; count++) {
13256 		len = strlen(data_ptr) + 1;
13257 		ulp_name = kmem_zalloc(len, KM_SLEEP);
13258 		bcopy(data_ptr, ulp_name, len);
13259 
13260 		ulp_major = ddi_name_to_major(ulp_name);
13261 
13262 		if (ulp_major != (major_t)-1) {
13263 			if (modload("drv", ulp_name) < 0) {
13264 				fp_printf(port, CE_NOTE, FP_LOG_ONLY,
13265 				    0, NULL, "failed to load %s",
13266 				    ulp_name);
13267 			}
13268 		} else {
13269 			fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
13270 			    "%s isn't a valid driver", ulp_name);
13271 		}
13272 
13273 		kmem_free(ulp_name, len);
13274 		data_ptr += len;	/* Skip to next field */
13275 	}
13276 
13277 	/*
13278 	 * Free the memory allocated by DDI
13279 	 */
13280 	if (data_buf != NULL) {
13281 		kmem_free(data_buf, data_len);
13282 	}
13283 }
13284 
13285 
13286 /*
13287  * Perform LOGO operation
13288  */
13289 static int
13290 fp_logout(fc_local_port_t *port, fc_remote_port_t *pd, job_request_t *job)
13291 {
13292 	int		rval;
13293 	fp_cmd_t 	*cmd;
13294 
13295 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
13296 	ASSERT(!MUTEX_HELD(&pd->pd_mutex));
13297 
13298 	cmd = fp_alloc_pkt(port, sizeof (la_els_logo_t),
13299 	    FP_PORT_IDENTIFIER_LEN, KM_SLEEP, pd);
13300 
13301 	mutex_enter(&port->fp_mutex);
13302 	mutex_enter(&pd->pd_mutex);
13303 
13304 	ASSERT(pd->pd_state == PORT_DEVICE_LOGGED_IN);
13305 	ASSERT(pd->pd_login_count == 1);
13306 
13307 	cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
13308 	cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
13309 	cmd->cmd_flags = 0;
13310 	cmd->cmd_retry_count = 1;
13311 	cmd->cmd_ulp_pkt = NULL;
13312 
13313 	fp_logo_init(pd, cmd, job);
13314 
13315 	mutex_exit(&pd->pd_mutex);
13316 	mutex_exit(&port->fp_mutex);
13317 
13318 	rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
13319 	if (rval != FC_SUCCESS) {
13320 		fp_iodone(cmd);
13321 	}
13322 
13323 	return (rval);
13324 }
13325 
13326 
13327 /*
13328  * Perform Port attach callbacks to registered ULPs
13329  */
13330 static void
13331 fp_attach_ulps(fc_local_port_t *port, fc_attach_cmd_t cmd)
13332 {
13333 	fp_soft_attach_t *att;
13334 
13335 	att = kmem_zalloc(sizeof (*att), KM_SLEEP);
13336 	att->att_cmd = cmd;
13337 	att->att_port = port;
13338 
13339 	/*
13340 	 * We need to remember whether or not fctl_busy_port
13341 	 * succeeded so we know whether or not to call
13342 	 * fctl_idle_port when the task is complete.
13343 	 */
13344 
13345 	if (fctl_busy_port(port) == 0) {
13346 		att->att_need_pm_idle = B_TRUE;
13347 	} else {
13348 		att->att_need_pm_idle = B_FALSE;
13349 	}
13350 
13351 	(void) taskq_dispatch(port->fp_taskq, fp_ulp_port_attach,
13352 	    att, KM_SLEEP);
13353 }
13354 
13355 
13356 /*
13357  * Forward state change notifications on to interested ULPs.
13358  * Spawns a call to fctl_ulp_statec_cb() in a taskq thread to do all the
13359  * real work.
13360  */
13361 static int
13362 fp_ulp_notify(fc_local_port_t *port, uint32_t statec, int sleep)
13363 {
13364 	fc_port_clist_t *clist;
13365 
13366 	clist = kmem_zalloc(sizeof (*clist), sleep);
13367 	if (clist == NULL) {
13368 		return (FC_NOMEM);
13369 	}
13370 
13371 	clist->clist_state = statec;
13372 
13373 	mutex_enter(&port->fp_mutex);
13374 	clist->clist_flags = port->fp_topology;
13375 	mutex_exit(&port->fp_mutex);
13376 
13377 	clist->clist_port = (opaque_t)port;
13378 	clist->clist_len = 0;
13379 	clist->clist_size = 0;
13380 	clist->clist_map = NULL;
13381 
13382 	(void) taskq_dispatch(port->fp_taskq, fctl_ulp_statec_cb,
13383 	    clist, KM_SLEEP);
13384 
13385 	return (FC_SUCCESS);
13386 }
13387 
13388 
13389 /*
13390  * Get name server map
13391  */
13392 static int
13393 fp_ns_getmap(fc_local_port_t *port, job_request_t *job, fc_portmap_t **map,
13394     uint32_t *len, uint32_t sid)
13395 {
13396 	int ret;
13397 	fctl_ns_req_t *ns_cmd;
13398 
13399 	/*
13400 	 * Don't let the allocator do anything for response;
13401 	 * we have have buffer ready to fillout.
13402 	 */
13403 	ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t),
13404 	    sizeof (ns_resp_gan_t), 0, (FCTL_NS_FILL_NS_MAP |
13405 	    FCTL_NS_BUF_IS_FC_PORTMAP), KM_SLEEP);
13406 
13407 	ns_cmd->ns_data_len = sizeof (**map) * (*len);
13408 	ns_cmd->ns_data_buf = (caddr_t)*map;
13409 
13410 	ASSERT(ns_cmd != NULL);
13411 
13412 	ns_cmd->ns_gan_index = 0;
13413 	ns_cmd->ns_gan_sid = sid;
13414 	ns_cmd->ns_cmd_code = NS_GA_NXT;
13415 	ns_cmd->ns_gan_max = *len;
13416 
13417 	ret = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP);
13418 
13419 	if (ns_cmd->ns_gan_index != *len) {
13420 		*len = ns_cmd->ns_gan_index;
13421 	}
13422 	ns_cmd->ns_data_len = 0;
13423 	ns_cmd->ns_data_buf = NULL;
13424 	fctl_free_ns_cmd(ns_cmd);
13425 
13426 	return (ret);
13427 }
13428 
13429 
13430 /*
13431  * Create a remote port in Fabric topology by using NS services
13432  */
13433 static fc_remote_port_t *
13434 fp_create_remote_port_by_ns(fc_local_port_t *port, uint32_t d_id, int sleep)
13435 {
13436 	int			rval;
13437 	job_request_t 		*job;
13438 	fctl_ns_req_t 		*ns_cmd;
13439 	fc_remote_port_t	*pd;
13440 
13441 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
13442 
13443 	FP_TRACE(FP_NHEAD1(1, 0), "PD creation begin; port=%p, d_id=%x",
13444 	    port, d_id);
13445 
13446 #ifdef	DEBUG
13447 	mutex_enter(&port->fp_mutex);
13448 	ASSERT(FC_IS_TOP_SWITCH(port->fp_topology));
13449 	mutex_exit(&port->fp_mutex);
13450 #endif
13451 
13452 	job = fctl_alloc_job(JOB_NS_CMD, 0, NULL, (opaque_t)port, sleep);
13453 	if (job == NULL) {
13454 		return (NULL);
13455 	}
13456 
13457 	ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t),
13458 	    sizeof (ns_resp_gan_t), 0, (FCTL_NS_CREATE_DEVICE |
13459 	    FCTL_NS_NO_DATA_BUF), sleep);
13460 	if (ns_cmd == NULL) {
13461 		return (NULL);
13462 	}
13463 
13464 	job->job_result = FC_SUCCESS;
13465 	ns_cmd->ns_gan_max = 1;
13466 	ns_cmd->ns_cmd_code = NS_GA_NXT;
13467 	ns_cmd->ns_gan_sid = FCTL_GAN_START_ID;
13468 	((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.port_id = d_id - 1;
13469 	((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.priv_lilp_posit = 0;
13470 
13471 	ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
13472 	rval = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP);
13473 	fctl_free_ns_cmd(ns_cmd);
13474 
13475 	if (rval != FC_SUCCESS || job->job_result != FC_SUCCESS) {
13476 		fctl_dealloc_job(job);
13477 		return (NULL);
13478 	}
13479 	fctl_dealloc_job(job);
13480 
13481 	pd = fctl_get_remote_port_by_did(port, d_id);
13482 
13483 	FP_TRACE(FP_NHEAD1(1, 0), "PD creation end; port=%p, d_id=%x, pd=%p",
13484 	    port, d_id, pd);
13485 
13486 	return (pd);
13487 }
13488 
13489 
13490 /*
13491  * Check for the permissions on an ioctl command. If it is required to have an
13492  * EXCLUSIVE open performed, return a FAILURE to just shut the door on it. If
13493  * the ioctl command isn't in one of the list built, shut the door on that too.
13494  *
13495  * 	Certain ioctls perform hardware accesses in FCA drivers, and it needs
13496  *	to be made sure that users open the port for an exclusive access while
13497  *	performing those operations.
13498  *
13499  * 	This can prevent a casual user from inflicting damage on the port by
13500  *	sending these ioctls from multiple processes/threads (there is no good
13501  *	reason why one would need to do that) without actually realizing how
13502  *	expensive such commands could turn out to be.
13503  *
13504  *	It is also important to note that, even with an exclusive access,
13505  *	multiple threads can share the same file descriptor and fire down
13506  *	commands in parallel. To prevent that the driver needs to make sure
13507  *	that such commands aren't in progress already. This is taken care of
13508  *	in the FP_EXCL_BUSY bit of fp_flag.
13509  */
13510 static int
13511 fp_check_perms(uchar_t open_flag, uint16_t ioctl_cmd)
13512 {
13513 	int ret = FC_FAILURE;
13514 	int count;
13515 
13516 	for (count = 0;
13517 	    count < sizeof (fp_perm_list) / sizeof (fp_perm_list[0]);
13518 	    count++) {
13519 		if (fp_perm_list[count].fp_ioctl_cmd == ioctl_cmd) {
13520 			if (fp_perm_list[count].fp_open_flag & open_flag) {
13521 				ret = FC_SUCCESS;
13522 			}
13523 			break;
13524 		}
13525 	}
13526 
13527 	return (ret);
13528 }
13529 
13530 
13531 /*
13532  * Bind Port driver's unsolicited, state change callbacks
13533  */
13534 static int
13535 fp_bind_callbacks(fc_local_port_t *port)
13536 {
13537 	fc_fca_bind_info_t	bind_info = {0};
13538 	fc_fca_port_info_t	*port_info;
13539 	int		rval =  DDI_SUCCESS;
13540 	uint16_t	class;
13541 	int		node_namelen, port_namelen;
13542 	char		*nname = NULL, *pname = NULL;
13543 
13544 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
13545 
13546 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, port->fp_port_dip,
13547 	    DDI_PROP_NOTPROM | DDI_PROP_DONTPASS,
13548 	    "node-name", &nname) != DDI_PROP_SUCCESS) {
13549 		FP_TRACE(FP_NHEAD1(1, 0),
13550 		    "fp_bind_callback fail to get node-name");
13551 	}
13552 	if (nname) {
13553 		fc_str_to_wwn(nname, &(bind_info.port_nwwn));
13554 	}
13555 
13556 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, port->fp_port_dip,
13557 	    DDI_PROP_NOTPROM | DDI_PROP_DONTPASS,
13558 	    "port-name", &pname) != DDI_PROP_SUCCESS) {
13559 		FP_TRACE(FP_NHEAD1(1, 0),
13560 		    "fp_bind_callback fail to get port-name");
13561 	}
13562 	if (pname) {
13563 		fc_str_to_wwn(pname, &(bind_info.port_pwwn));
13564 	}
13565 
13566 	if (port->fp_npiv_type == FC_NPIV_PORT) {
13567 		bind_info.port_npiv = 1;
13568 	}
13569 
13570 	/*
13571 	 * fca_bind_port returns the FCA driver's handle for the local
13572 	 * port instance. If the port number isn't supported it returns NULL.
13573 	 * It also sets up callback in the FCA for various
13574 	 * things like state change, ELS etc..
13575 	 */
13576 	bind_info.port_statec_cb = fp_statec_cb;
13577 	bind_info.port_unsol_cb = fp_unsol_cb;
13578 	bind_info.port_num = port->fp_port_num;
13579 	bind_info.port_handle = (opaque_t)port;
13580 
13581 	port_info = kmem_zalloc(sizeof (*port_info), KM_SLEEP);
13582 
13583 	/*
13584 	 * Hold the port driver mutex as the callbacks are bound until the
13585 	 * service parameters are properly filled in (in order to be able to
13586 	 * properly respond to unsolicited ELS requests)
13587 	 */
13588 	mutex_enter(&port->fp_mutex);
13589 
13590 	port->fp_fca_handle = port->fp_fca_tran->fca_bind_port(
13591 	    port->fp_fca_dip, port_info, &bind_info);
13592 
13593 	if (port->fp_fca_handle == NULL) {
13594 		rval = DDI_FAILURE;
13595 		goto exit;
13596 	}
13597 
13598 	port->fp_bind_state = port->fp_state = port_info->pi_port_state;
13599 	port->fp_service_params = port_info->pi_login_params;
13600 	port->fp_hard_addr = port_info->pi_hard_addr;
13601 
13602 	/* Copy from the FCA structure to the FP structure */
13603 	port->fp_hba_port_attrs = port_info->pi_attrs;
13604 
13605 	if (port_info->pi_rnid_params.status == FC_SUCCESS) {
13606 		port->fp_rnid_init = 1;
13607 		bcopy(&port_info->pi_rnid_params.params,
13608 		    &port->fp_rnid_params,
13609 		    sizeof (port->fp_rnid_params));
13610 	} else {
13611 		port->fp_rnid_init = 0;
13612 	}
13613 
13614 	node_namelen = strlen((char *)&port_info->pi_attrs.sym_node_name);
13615 	if (node_namelen) {
13616 		bcopy(&port_info->pi_attrs.sym_node_name,
13617 		    &port->fp_sym_node_name,
13618 		    node_namelen);
13619 		port->fp_sym_node_namelen = node_namelen;
13620 	}
13621 	port_namelen = strlen((char *)&port_info->pi_attrs.sym_port_name);
13622 	if (port_namelen) {
13623 		bcopy(&port_info->pi_attrs.sym_port_name,
13624 		    &port->fp_sym_port_name,
13625 		    port_namelen);
13626 		port->fp_sym_port_namelen = port_namelen;
13627 	}
13628 
13629 	/* zero out the normally unused fields right away */
13630 	port->fp_service_params.ls_code.mbz = 0;
13631 	port->fp_service_params.ls_code.ls_code = 0;
13632 	bzero(&port->fp_service_params.reserved,
13633 	    sizeof (port->fp_service_params.reserved));
13634 
13635 	class = port_info->pi_login_params.class_1.class_opt;
13636 	port->fp_cos |= (class & 0x8000) ? FC_NS_CLASS1 : 0;
13637 
13638 	class = port_info->pi_login_params.class_2.class_opt;
13639 	port->fp_cos |= (class & 0x8000) ? FC_NS_CLASS2 : 0;
13640 
13641 	class = port_info->pi_login_params.class_3.class_opt;
13642 	port->fp_cos |= (class & 0x8000) ? FC_NS_CLASS3 : 0;
13643 
13644 exit:
13645 	if (nname) {
13646 		ddi_prop_free(nname);
13647 	}
13648 	if (pname) {
13649 		ddi_prop_free(pname);
13650 	}
13651 	mutex_exit(&port->fp_mutex);
13652 	kmem_free(port_info, sizeof (*port_info));
13653 
13654 	return (rval);
13655 }
13656 
13657 
13658 /*
13659  * Retrieve FCA capabilities
13660  */
13661 static void
13662 fp_retrieve_caps(fc_local_port_t *port)
13663 {
13664 	int			rval;
13665 	int 			ub_count;
13666 	fc_fcp_dma_t		fcp_dma;
13667 	fc_reset_action_t	action;
13668 	fc_dma_behavior_t	dma_behavior;
13669 
13670 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
13671 
13672 	rval = port->fp_fca_tran->fca_get_cap(port->fp_fca_handle,
13673 	    FC_CAP_UNSOL_BUF, &ub_count);
13674 
13675 	switch (rval) {
13676 	case FC_CAP_FOUND:
13677 	case FC_CAP_SETTABLE:
13678 		switch (ub_count) {
13679 		case 0:
13680 			break;
13681 
13682 		case -1:
13683 			ub_count = fp_unsol_buf_count;
13684 			break;
13685 
13686 		default:
13687 			/* 1/4th of total buffers is my share */
13688 			ub_count =
13689 			    (ub_count / port->fp_fca_tran->fca_numports) >> 2;
13690 			break;
13691 		}
13692 		break;
13693 
13694 	default:
13695 		ub_count = 0;
13696 		break;
13697 	}
13698 
13699 	mutex_enter(&port->fp_mutex);
13700 	port->fp_ub_count = ub_count;
13701 	mutex_exit(&port->fp_mutex);
13702 
13703 	rval = port->fp_fca_tran->fca_get_cap(port->fp_fca_handle,
13704 	    FC_CAP_POST_RESET_BEHAVIOR, &action);
13705 
13706 	switch (rval) {
13707 	case FC_CAP_FOUND:
13708 	case FC_CAP_SETTABLE:
13709 		switch (action) {
13710 		case FC_RESET_RETURN_NONE:
13711 		case FC_RESET_RETURN_ALL:
13712 		case FC_RESET_RETURN_OUTSTANDING:
13713 			break;
13714 
13715 		default:
13716 			action = FC_RESET_RETURN_NONE;
13717 			break;
13718 		}
13719 		break;
13720 
13721 	default:
13722 		action = FC_RESET_RETURN_NONE;
13723 		break;
13724 	}
13725 	mutex_enter(&port->fp_mutex);
13726 	port->fp_reset_action = action;
13727 	mutex_exit(&port->fp_mutex);
13728 
13729 	rval = port->fp_fca_tran->fca_get_cap(port->fp_fca_handle,
13730 	    FC_CAP_NOSTREAM_ON_UNALIGN_BUF, &dma_behavior);
13731 
13732 	switch (rval) {
13733 	case FC_CAP_FOUND:
13734 		switch (dma_behavior) {
13735 		case FC_ALLOW_STREAMING:
13736 			/* FALLTHROUGH */
13737 		case FC_NO_STREAMING:
13738 			break;
13739 
13740 		default:
13741 			/*
13742 			 * If capability was found and the value
13743 			 * was incorrect assume the worst
13744 			 */
13745 			dma_behavior = FC_NO_STREAMING;
13746 			break;
13747 		}
13748 		break;
13749 
13750 	default:
13751 		/*
13752 		 * If capability was not defined - allow streaming; existing
13753 		 * FCAs should not be affected.
13754 		 */
13755 		dma_behavior = FC_ALLOW_STREAMING;
13756 		break;
13757 	}
13758 	mutex_enter(&port->fp_mutex);
13759 	port->fp_dma_behavior = dma_behavior;
13760 	mutex_exit(&port->fp_mutex);
13761 
13762 	rval = port->fp_fca_tran->fca_get_cap(port->fp_fca_handle,
13763 	    FC_CAP_FCP_DMA, &fcp_dma);
13764 
13765 	if (rval != FC_CAP_FOUND || (fcp_dma != FC_NO_DVMA_SPACE &&
13766 	    fcp_dma != FC_DVMA_SPACE)) {
13767 		fcp_dma = FC_DVMA_SPACE;
13768 	}
13769 
13770 	mutex_enter(&port->fp_mutex);
13771 	port->fp_fcp_dma = fcp_dma;
13772 	mutex_exit(&port->fp_mutex);
13773 }
13774 
13775 
13776 /*
13777  * Handle Domain, Area changes in the Fabric.
13778  */
13779 static void
13780 fp_validate_area_domain(fc_local_port_t *port, uint32_t id, uint32_t mask,
13781     job_request_t *job, int sleep)
13782 {
13783 #ifdef	DEBUG
13784 	uint32_t		dcnt;
13785 #endif
13786 	int			rval;
13787 	int			send;
13788 	int			index;
13789 	int			listindex;
13790 	int			login;
13791 	int			job_flags;
13792 	char 			ww_name[17];
13793 	uint32_t		d_id;
13794 	uint32_t		count;
13795 	fctl_ns_req_t		*ns_cmd;
13796 	fc_portmap_t		*list;
13797 	fc_orphan_t 		*orp;
13798 	fc_orphan_t		*norp;
13799 	fc_orphan_t		*prev;
13800 	fc_remote_port_t 	*pd;
13801 	fc_remote_port_t 	*npd;
13802 	struct pwwn_hash 	*head;
13803 
13804 	ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t),
13805 	    sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t),
13806 	    0, sleep);
13807 	if (ns_cmd == NULL) {
13808 		mutex_enter(&port->fp_mutex);
13809 		if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
13810 			--port->fp_rscn_count;
13811 		}
13812 		mutex_exit(&port->fp_mutex);
13813 
13814 		return;
13815 	}
13816 	ns_cmd->ns_cmd_code = NS_GID_PN;
13817 
13818 	/*
13819 	 * We need to get a new count of devices from the
13820 	 * name server, which will also create any new devices
13821 	 * as needed.
13822 	 */
13823 
13824 	(void) fp_ns_get_devcount(port, job, 1, sleep);
13825 
13826 	FP_TRACE(FP_NHEAD1(3, 0),
13827 	    "fp_validate_area_domain: get_devcount found %d devices",
13828 	    port->fp_total_devices);
13829 
13830 	mutex_enter(&port->fp_mutex);
13831 
13832 	for (count = index = 0; index < pwwn_table_size; index++) {
13833 		head = &port->fp_pwwn_table[index];
13834 		pd = head->pwwn_head;
13835 		while (pd != NULL) {
13836 			mutex_enter(&pd->pd_mutex);
13837 			if (pd->pd_flags != PD_ELS_IN_PROGRESS) {
13838 				if ((pd->pd_port_id.port_id & mask) == id &&
13839 				    pd->pd_recepient == PD_PLOGI_INITIATOR) {
13840 					count++;
13841 					pd->pd_type = PORT_DEVICE_OLD;
13842 					pd->pd_flags = PD_ELS_MARK;
13843 				}
13844 			}
13845 			mutex_exit(&pd->pd_mutex);
13846 			pd = pd->pd_wwn_hnext;
13847 		}
13848 	}
13849 
13850 #ifdef	DEBUG
13851 	dcnt = count;
13852 #endif /* DEBUG */
13853 
13854 	/*
13855 	 * Since port->fp_orphan_count is declared an 'int' it is
13856 	 * theoretically possible that the count could go negative.
13857 	 *
13858 	 * This would be bad and if that happens we really do want
13859 	 * to know.
13860 	 */
13861 
13862 	ASSERT(port->fp_orphan_count >= 0);
13863 
13864 	count += port->fp_orphan_count;
13865 
13866 	/*
13867 	 * We add the port->fp_total_devices value to the count
13868 	 * in the case where our port is newly attached. This is
13869 	 * because we haven't done any discovery and we don't have
13870 	 * any orphans in the port's orphan list. If we do not do
13871 	 * this addition to count then we won't alloc enough kmem
13872 	 * to do discovery with.
13873 	 */
13874 
13875 	if (count == 0) {
13876 		count += port->fp_total_devices;
13877 		FP_TRACE(FP_NHEAD1(3, 0), "fp_validate_area_domain: "
13878 		    "0x%x orphans found, using 0x%x",
13879 		    port->fp_orphan_count, count);
13880 	}
13881 
13882 	mutex_exit(&port->fp_mutex);
13883 
13884 	/*
13885 	 * Allocate the change list
13886 	 */
13887 
13888 	list = kmem_zalloc(sizeof (fc_portmap_t) * count, sleep);
13889 	if (list == NULL) {
13890 		fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
13891 		    " Not enough memory to service RSCNs"
13892 		    " for %d ports, continuing...", count);
13893 
13894 		fctl_free_ns_cmd(ns_cmd);
13895 
13896 		mutex_enter(&port->fp_mutex);
13897 		if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
13898 			--port->fp_rscn_count;
13899 		}
13900 		mutex_exit(&port->fp_mutex);
13901 
13902 		return;
13903 	}
13904 
13905 	/*
13906 	 * Attempt to validate or invalidate the devices that were
13907 	 * already in the pwwn hash table.
13908 	 */
13909 
13910 	mutex_enter(&port->fp_mutex);
13911 	for (listindex = 0, index = 0; index < pwwn_table_size; index++) {
13912 		head = &port->fp_pwwn_table[index];
13913 		npd = head->pwwn_head;
13914 
13915 		while ((pd = npd) != NULL) {
13916 			npd = pd->pd_wwn_hnext;
13917 
13918 			mutex_enter(&pd->pd_mutex);
13919 			if ((pd->pd_port_id.port_id & mask) == id &&
13920 			    pd->pd_flags == PD_ELS_MARK) {
13921 				la_wwn_t *pwwn;
13922 
13923 				job->job_result = FC_SUCCESS;
13924 
13925 				((ns_req_gid_pn_t *)
13926 				    (ns_cmd->ns_cmd_buf))->pwwn =
13927 				    pd->pd_port_name;
13928 
13929 				pwwn = &pd->pd_port_name;
13930 				d_id = pd->pd_port_id.port_id;
13931 
13932 				mutex_exit(&pd->pd_mutex);
13933 				mutex_exit(&port->fp_mutex);
13934 
13935 				rval = fp_ns_query(port, ns_cmd, job, 1,
13936 				    sleep);
13937 				if (rval != FC_SUCCESS) {
13938 					fc_wwn_to_str(pwwn, ww_name);
13939 
13940 					FP_TRACE(FP_NHEAD1(3, 0),
13941 					    "AREA RSCN: PD disappeared; "
13942 					    "d_id=%x, PWWN=%s", d_id, ww_name);
13943 
13944 					FP_TRACE(FP_NHEAD2(9, 0),
13945 					    "N_x Port with D_ID=%x,"
13946 					    " PWWN=%s disappeared from fabric",
13947 					    d_id, ww_name);
13948 
13949 					fp_fillout_old_map(list + listindex++,
13950 					    pd, 1);
13951 				} else {
13952 					fctl_copy_portmap(list + listindex++,
13953 					    pd);
13954 
13955 					mutex_enter(&pd->pd_mutex);
13956 					pd->pd_flags = PD_ELS_IN_PROGRESS;
13957 					mutex_exit(&pd->pd_mutex);
13958 				}
13959 
13960 				mutex_enter(&port->fp_mutex);
13961 			} else {
13962 				mutex_exit(&pd->pd_mutex);
13963 			}
13964 		}
13965 	}
13966 
13967 	mutex_exit(&port->fp_mutex);
13968 
13969 	ASSERT(listindex == dcnt);
13970 
13971 	job->job_counter = listindex;
13972 	job_flags = job->job_flags;
13973 	job->job_flags |= JOB_TYPE_FP_ASYNC;
13974 
13975 	/*
13976 	 * Login (if we were the initiator) or validate devices in the
13977 	 * port map.
13978 	 */
13979 
13980 	for (index = 0; index < listindex; index++) {
13981 		pd = list[index].map_pd;
13982 
13983 		mutex_enter(&pd->pd_mutex);
13984 		ASSERT((pd->pd_port_id.port_id & mask) == id);
13985 
13986 		if (pd->pd_flags != PD_ELS_IN_PROGRESS) {
13987 			ASSERT(pd->pd_type == PORT_DEVICE_OLD);
13988 			mutex_exit(&pd->pd_mutex);
13989 			fp_jobdone(job);
13990 			continue;
13991 		}
13992 
13993 		login = (pd->pd_state == PORT_DEVICE_LOGGED_IN) ? 1 : 0;
13994 		send = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0;
13995 		d_id = pd->pd_port_id.port_id;
13996 		mutex_exit(&pd->pd_mutex);
13997 
13998 		if ((d_id & mask) == id && send) {
13999 			if (login) {
14000 				FP_TRACE(FP_NHEAD1(6, 0),
14001 				    "RSCN and PLOGI request;"
14002 				    " pd=%p, job=%p d_id=%x, index=%d", pd,
14003 				    job, d_id, index);
14004 
14005 				rval = fp_port_login(port, d_id, job,
14006 				    FP_CMD_PLOGI_RETAIN, sleep, pd, NULL);
14007 				if (rval != FC_SUCCESS) {
14008 					mutex_enter(&pd->pd_mutex);
14009 					pd->pd_flags = PD_IDLE;
14010 					mutex_exit(&pd->pd_mutex);
14011 
14012 					job->job_result = rval;
14013 					fp_jobdone(job);
14014 				}
14015 
14016 				FP_TRACE(FP_NHEAD2(4, 0),
14017 				    "PLOGI succeeded:no skip(1) for "
14018 				    "D_ID %x", d_id);
14019 				list[index].map_flags |=
14020 				    PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY;
14021 			} else {
14022 				FP_TRACE(FP_NHEAD1(6, 0), "RSCN and NS request;"
14023 				    " pd=%p, job=%p d_id=%x, index=%d", pd,
14024 				    job, d_id, index);
14025 
14026 				rval = fp_ns_validate_device(port, pd, job,
14027 				    0, sleep);
14028 				if (rval != FC_SUCCESS) {
14029 					fp_jobdone(job);
14030 				}
14031 				mutex_enter(&pd->pd_mutex);
14032 				pd->pd_flags = PD_IDLE;
14033 				mutex_exit(&pd->pd_mutex);
14034 			}
14035 		} else {
14036 			FP_TRACE(FP_NHEAD1(6, 0),
14037 			    "RSCN and NO request sent; pd=%p,"
14038 			    " d_id=%x, index=%d", pd, d_id, index);
14039 
14040 			mutex_enter(&pd->pd_mutex);
14041 			pd->pd_flags = PD_IDLE;
14042 			mutex_exit(&pd->pd_mutex);
14043 
14044 			fp_jobdone(job);
14045 		}
14046 	}
14047 
14048 	if (listindex) {
14049 		fctl_jobwait(job);
14050 	}
14051 	job->job_flags = job_flags;
14052 
14053 	/*
14054 	 * Orphan list validation.
14055 	 */
14056 	mutex_enter(&port->fp_mutex);
14057 	for (prev = NULL, orp = port->fp_orphan_list; port->fp_orphan_count &&
14058 	    orp != NULL; orp = norp) {
14059 		norp = orp->orp_next;
14060 		mutex_exit(&port->fp_mutex);
14061 
14062 		job->job_counter = 1;
14063 		job->job_result = FC_SUCCESS;
14064 		ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
14065 
14066 		((ns_req_gid_pn_t *)ns_cmd->ns_cmd_buf)->pwwn = orp->orp_pwwn;
14067 
14068 		((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->pid.port_id = 0;
14069 		((ns_resp_gid_pn_t *)
14070 		    ns_cmd->ns_data_buf)->pid.priv_lilp_posit = 0;
14071 
14072 		rval = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP);
14073 		if (rval == FC_SUCCESS) {
14074 			d_id = BE_32(*((uint32_t *)ns_cmd->ns_data_buf));
14075 			pd = fp_create_remote_port_by_ns(port, d_id, KM_SLEEP);
14076 			if (pd != NULL) {
14077 				fc_wwn_to_str(&orp->orp_pwwn, ww_name);
14078 
14079 				FP_TRACE(FP_NHEAD1(6, 0),
14080 				    "RSCN and ORPHAN list "
14081 				    "success; d_id=%x, PWWN=%s", d_id, ww_name);
14082 
14083 				FP_TRACE(FP_NHEAD2(6, 0),
14084 				    "N_x Port with D_ID=%x, PWWN=%s reappeared"
14085 				    " in fabric", d_id, ww_name);
14086 
14087 				mutex_enter(&port->fp_mutex);
14088 				if (prev) {
14089 					prev->orp_next = orp->orp_next;
14090 				} else {
14091 					ASSERT(orp == port->fp_orphan_list);
14092 					port->fp_orphan_list = orp->orp_next;
14093 				}
14094 				port->fp_orphan_count--;
14095 				mutex_exit(&port->fp_mutex);
14096 
14097 				kmem_free(orp, sizeof (*orp));
14098 				fctl_copy_portmap(list + listindex++, pd);
14099 			} else {
14100 				prev = orp;
14101 			}
14102 		} else {
14103 			prev = orp;
14104 		}
14105 		mutex_enter(&port->fp_mutex);
14106 	}
14107 	mutex_exit(&port->fp_mutex);
14108 
14109 	/*
14110 	 * One more pass through the list to delist old devices from
14111 	 * the d_id and pwwn tables and possibly add to the orphan list.
14112 	 */
14113 
14114 	for (index = 0; index < listindex; index++) {
14115 		pd = list[index].map_pd;
14116 		ASSERT(pd != NULL);
14117 
14118 		/*
14119 		 * Update PLOGI results; For NS validation
14120 		 * of orphan list, it is redundant
14121 		 *
14122 		 * Take care to preserve PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY if
14123 		 * appropriate as fctl_copy_portmap() will clear map_flags.
14124 		 */
14125 		if (list[index].map_flags &
14126 		    PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY) {
14127 			fctl_copy_portmap(list + index, pd);
14128 			list[index].map_flags |=
14129 			    PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY;
14130 		} else {
14131 			fctl_copy_portmap(list + index, pd);
14132 		}
14133 
14134 		FP_TRACE(FP_NHEAD1(6, 0), "RSCN with Area DOMAIN "
14135 		    "results; pd=%p, d_id=%x pwwn=%x %x %x %x %x %x %x %x",
14136 		    pd, pd->pd_port_id.port_id,
14137 		    pd->pd_port_name.raw_wwn[0],
14138 		    pd->pd_port_name.raw_wwn[1],
14139 		    pd->pd_port_name.raw_wwn[2],
14140 		    pd->pd_port_name.raw_wwn[3],
14141 		    pd->pd_port_name.raw_wwn[4],
14142 		    pd->pd_port_name.raw_wwn[5],
14143 		    pd->pd_port_name.raw_wwn[6],
14144 		    pd->pd_port_name.raw_wwn[7]);
14145 
14146 		FP_TRACE(FP_NHEAD1(6, 0), "RSCN with Area DOMAIN "
14147 		    "results continued, pd=%p type=%x, flags=%x, state=%x",
14148 		    pd, pd->pd_type, pd->pd_flags, pd->pd_state);
14149 
14150 		mutex_enter(&pd->pd_mutex);
14151 		if (pd->pd_type == PORT_DEVICE_OLD) {
14152 			int initiator;
14153 
14154 			pd->pd_flags = PD_IDLE;
14155 			initiator = (pd->pd_recepient ==
14156 			    PD_PLOGI_INITIATOR) ? 1 : 0;
14157 
14158 			mutex_exit(&pd->pd_mutex);
14159 
14160 			mutex_enter(&port->fp_mutex);
14161 			mutex_enter(&pd->pd_mutex);
14162 
14163 			pd->pd_state = PORT_DEVICE_INVALID;
14164 			fctl_delist_did_table(port, pd);
14165 			fctl_delist_pwwn_table(port, pd);
14166 
14167 			mutex_exit(&pd->pd_mutex);
14168 			mutex_exit(&port->fp_mutex);
14169 
14170 			if (initiator) {
14171 				(void) fctl_add_orphan(port, pd, sleep);
14172 			}
14173 			list[index].map_pd = pd;
14174 		} else {
14175 			ASSERT(pd->pd_flags == PD_IDLE);
14176 			if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
14177 				/*
14178 				 * Reset LOGO tolerance to zero
14179 				 */
14180 				fctl_tc_reset(&pd->pd_logo_tc);
14181 			}
14182 			mutex_exit(&pd->pd_mutex);
14183 		}
14184 	}
14185 
14186 	if (ns_cmd) {
14187 		fctl_free_ns_cmd(ns_cmd);
14188 	}
14189 	if (listindex) {
14190 		(void) fp_ulp_devc_cb(port, list, listindex, count,
14191 		    sleep, 0);
14192 	} else {
14193 		kmem_free(list, sizeof (*list) * count);
14194 
14195 		mutex_enter(&port->fp_mutex);
14196 		if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
14197 			--port->fp_rscn_count;
14198 		}
14199 		mutex_exit(&port->fp_mutex);
14200 	}
14201 }
14202 
14203 
14204 /*
14205  * Work hard to make sense out of an RSCN page.
14206  */
14207 static void
14208 fp_validate_rscn_page(fc_local_port_t *port, fc_affected_id_t *page,
14209     job_request_t *job, fctl_ns_req_t *ns_cmd, fc_portmap_t *listptr,
14210     int *listindex, int sleep)
14211 {
14212 	int			rval;
14213 	char 			ww_name[17];
14214 	la_wwn_t		*pwwn;
14215 	fc_remote_port_t	*pwwn_pd;
14216 	fc_remote_port_t	*did_pd;
14217 
14218 	did_pd = fctl_get_remote_port_by_did(port, page->aff_d_id);
14219 
14220 	FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page; "
14221 	    "port=%p, d_id=%x, pd=%p, rscn_count:0x%x", port, page->aff_d_id,
14222 	    did_pd, (uint32_t)(uintptr_t)job->job_cb_arg);
14223 
14224 	if (did_pd != NULL) {
14225 		mutex_enter(&did_pd->pd_mutex);
14226 		if (did_pd->pd_flags != PD_IDLE) {
14227 			mutex_exit(&did_pd->pd_mutex);
14228 			FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page: "
14229 			    "PD is BUSY; port=%p, d_id=%x, pd=%p",
14230 			    port, page->aff_d_id, did_pd);
14231 			return;
14232 		}
14233 		did_pd->pd_flags = PD_ELS_IN_PROGRESS;
14234 		mutex_exit(&did_pd->pd_mutex);
14235 	}
14236 
14237 	job->job_counter = 1;
14238 
14239 	pwwn = &((ns_resp_gpn_id_t *)ns_cmd->ns_data_buf)->pwwn;
14240 
14241 	((ns_req_gpn_id_t *)ns_cmd->ns_cmd_buf)->pid.port_id = page->aff_d_id;
14242 	((ns_req_gpn_id_t *)ns_cmd->ns_cmd_buf)->pid.priv_lilp_posit = 0;
14243 
14244 	bzero(ns_cmd->ns_data_buf, sizeof (la_wwn_t));
14245 	rval = fp_ns_query(port, ns_cmd, job, 1, sleep);
14246 
14247 	FP_TRACE(FP_NHEAD1(1, 0), "NS Query Response for D_ID page; rev=%x,"
14248 	    " in_id=%x, cmdrsp=%x, reason=%x, expln=%x",
14249 	    ns_cmd->ns_resp_hdr.ct_rev, ns_cmd->ns_resp_hdr.ct_inid,
14250 	    ns_cmd->ns_resp_hdr.ct_cmdrsp, ns_cmd->ns_resp_hdr.ct_reason,
14251 	    ns_cmd->ns_resp_hdr.ct_expln);
14252 
14253 	job->job_counter = 1;
14254 
14255 	if (rval != FC_SUCCESS || fctl_is_wwn_zero(pwwn) == FC_SUCCESS) {
14256 		/*
14257 		 * What this means is that the D_ID
14258 		 * disappeared from the Fabric.
14259 		 */
14260 		if (did_pd == NULL) {
14261 			FP_TRACE(FP_NHEAD1(1, 0), "RSCN with D_ID page;"
14262 			    " NULL PD disappeared, rval=%x", rval);
14263 			return;
14264 		}
14265 
14266 		fc_wwn_to_str(&did_pd->pd_port_name, ww_name);
14267 
14268 		(listptr + *listindex)->map_rscn_info.ulp_rscn_count =
14269 		    (uint32_t)(uintptr_t)job->job_cb_arg;
14270 
14271 		fp_fillout_old_map(listptr + (*listindex)++, did_pd, 0);
14272 
14273 		FP_TRACE(FP_NHEAD1(3, 0), "RSCN: PD disappeared; "
14274 		    "d_id=%x, PWWN=%s", page->aff_d_id, ww_name);
14275 
14276 		FP_TRACE(FP_NHEAD2(9, 0),
14277 		    "GPN_ID for D_ID=%x failed", page->aff_d_id);
14278 
14279 		FP_TRACE(FP_NHEAD2(9, 0),
14280 		    "N_x Port with D_ID=%x, PWWN=%s disappeared from"
14281 		    " fabric", page->aff_d_id, ww_name);
14282 
14283 		mutex_enter(&did_pd->pd_mutex);
14284 		did_pd->pd_flags = PD_IDLE;
14285 		mutex_exit(&did_pd->pd_mutex);
14286 
14287 		FP_TRACE(FP_NHEAD1(3, 0), "RSCN with D_ID (%x) page; "
14288 		    "PD disappeared, pd=%p", page->aff_d_id, did_pd);
14289 
14290 		return;
14291 	}
14292 
14293 	pwwn_pd = fctl_get_remote_port_by_pwwn(port, pwwn);
14294 
14295 	if (did_pd != NULL && pwwn_pd != NULL && did_pd == pwwn_pd) {
14296 		/*
14297 		 * There is no change. Do PLOGI again and add it to
14298 		 * ULP portmap baggage and return. Note: When RSCNs
14299 		 * arrive with per page states, the need for PLOGI
14300 		 * can be determined correctly.
14301 		 */
14302 		mutex_enter(&pwwn_pd->pd_mutex);
14303 		pwwn_pd->pd_type = PORT_DEVICE_NOCHANGE;
14304 		mutex_exit(&pwwn_pd->pd_mutex);
14305 
14306 		(listptr + *listindex)->map_rscn_info.ulp_rscn_count =
14307 		    (uint32_t)(uintptr_t)job->job_cb_arg;
14308 
14309 		fctl_copy_portmap(listptr + (*listindex)++, pwwn_pd);
14310 
14311 		mutex_enter(&pwwn_pd->pd_mutex);
14312 		if ((pwwn_pd->pd_state == PORT_DEVICE_LOGGED_IN) ||
14313 			(pwwn_pd->pd_aux_flags & PD_LOGGED_OUT)) {
14314 			fc_wwn_to_str(&pwwn_pd->pd_port_name, ww_name);
14315 			mutex_exit(&pwwn_pd->pd_mutex);
14316 
14317 			rval = fp_port_login(port, page->aff_d_id, job,
14318 			    FP_CMD_PLOGI_RETAIN, sleep, pwwn_pd, NULL);
14319 			if (rval == FC_SUCCESS) {
14320 				fp_jobwait(job);
14321 				rval = job->job_result;
14322 
14323 				/*
14324 				 * Reset LOGO tolerance to zero
14325 				 * Also we are the PLOGI initiator now.
14326 				 */
14327 				mutex_enter(&pwwn_pd->pd_mutex);
14328 				fctl_tc_reset(&pwwn_pd->pd_logo_tc);
14329 				pwwn_pd->pd_recepient = PD_PLOGI_INITIATOR;
14330 				mutex_exit(&pwwn_pd->pd_mutex);
14331 			}
14332 
14333 			if (rval == FC_SUCCESS) {
14334 				struct fc_portmap *map =
14335 				    listptr + *listindex - 1;
14336 
14337 				FP_TRACE(FP_NHEAD2(4, 0),
14338 				    "PLOGI succeeded: no skip(2)"
14339 				    " for D_ID %x", page->aff_d_id);
14340 				map->map_flags |=
14341 				    PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY;
14342 			} else {
14343 				FP_TRACE(FP_NHEAD2(9, rval),
14344 				    "PLOGI to D_ID=%x failed", page->aff_d_id);
14345 
14346 				FP_TRACE(FP_NHEAD2(9, 0),
14347 				    "N_x Port with D_ID=%x, PWWN=%s"
14348 				    " disappeared from fabric",
14349 				    page->aff_d_id, ww_name);
14350 
14351 				fp_fillout_old_map(listptr +
14352 				    *listindex - 1, pwwn_pd, 0);
14353 			}
14354 		} else {
14355 			mutex_exit(&pwwn_pd->pd_mutex);
14356 		}
14357 
14358 		mutex_enter(&did_pd->pd_mutex);
14359 		did_pd->pd_flags = PD_IDLE;
14360 		mutex_exit(&did_pd->pd_mutex);
14361 
14362 		FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID (0x%x) page; "
14363 		    "Case ONE, rval=%x, result=%x pd=%p", page->aff_d_id, rval,
14364 		    job->job_result, pwwn_pd);
14365 
14366 		return;
14367 	}
14368 
14369 	if (did_pd == NULL && pwwn_pd == NULL) {
14370 
14371 		fc_orphan_t	*orp  = NULL;
14372 		fc_orphan_t	*norp = NULL;
14373 		fc_orphan_t	*prev = NULL;
14374 
14375 		/*
14376 		 * Hunt down the orphan list before giving up.
14377 		 */
14378 
14379 		mutex_enter(&port->fp_mutex);
14380 		if (port->fp_orphan_count) {
14381 
14382 			for (orp = port->fp_orphan_list; orp; orp = norp) {
14383 				norp = orp->orp_next;
14384 
14385 				if (fctl_wwn_cmp(&orp->orp_pwwn, pwwn) != 0) {
14386 					prev = orp;
14387 					continue;
14388 				}
14389 
14390 				if (prev) {
14391 					prev->orp_next = orp->orp_next;
14392 				} else {
14393 					ASSERT(orp ==
14394 					    port->fp_orphan_list);
14395 					port->fp_orphan_list =
14396 					    orp->orp_next;
14397 				}
14398 				port->fp_orphan_count--;
14399 				break;
14400 			}
14401 		}
14402 
14403 		mutex_exit(&port->fp_mutex);
14404 		pwwn_pd = fp_create_remote_port_by_ns(port,
14405 		    page->aff_d_id, sleep);
14406 
14407 		if (pwwn_pd != NULL) {
14408 
14409 			if (orp) {
14410 				fc_wwn_to_str(&orp->orp_pwwn,
14411 				    ww_name);
14412 
14413 				FP_TRACE(FP_NHEAD2(9, 0),
14414 				    "N_x Port with D_ID=%x,"
14415 				    " PWWN=%s reappeared in fabric",
14416 				    page->aff_d_id, ww_name);
14417 
14418 				kmem_free(orp, sizeof (*orp));
14419 			}
14420 
14421 			(listptr + *listindex)->
14422 			    map_rscn_info.ulp_rscn_count =
14423 			    (uint32_t)(uintptr_t)job->job_cb_arg;
14424 
14425 			fctl_copy_portmap(listptr +
14426 			    (*listindex)++, pwwn_pd);
14427 		}
14428 
14429 		FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID (0x%x) page; "
14430 		    "Case TWO", page->aff_d_id);
14431 
14432 		return;
14433 	}
14434 
14435 	if (pwwn_pd != NULL && did_pd == NULL) {
14436 		uint32_t old_d_id;
14437 		uint32_t d_id = page->aff_d_id;
14438 
14439 		/*
14440 		 * What this means is there is a new D_ID for this
14441 		 * Port WWN. Take out the port device off D_ID
14442 		 * list and put it back with a new D_ID. Perform
14443 		 * PLOGI if already logged in.
14444 		 */
14445 		mutex_enter(&port->fp_mutex);
14446 		mutex_enter(&pwwn_pd->pd_mutex);
14447 
14448 		old_d_id = pwwn_pd->pd_port_id.port_id;
14449 
14450 		fctl_delist_did_table(port, pwwn_pd);
14451 
14452 		(listptr + *listindex)->map_rscn_info.ulp_rscn_count =
14453 		    (uint32_t)(uintptr_t)job->job_cb_arg;
14454 
14455 		fp_fillout_changed_map(listptr + (*listindex)++, pwwn_pd,
14456 		    &d_id, NULL);
14457 		fctl_enlist_did_table(port, pwwn_pd);
14458 
14459 		FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page;"
14460 		    " Case THREE, pd=%p,"
14461 		    " state=%x", pwwn_pd, pwwn_pd->pd_state);
14462 
14463 		if ((pwwn_pd->pd_state == PORT_DEVICE_LOGGED_IN) ||
14464 			(pwwn_pd->pd_aux_flags & PD_LOGGED_OUT)) {
14465 			fc_wwn_to_str(&pwwn_pd->pd_port_name, ww_name);
14466 
14467 			mutex_exit(&pwwn_pd->pd_mutex);
14468 			mutex_exit(&port->fp_mutex);
14469 
14470 			FP_TRACE(FP_NHEAD2(9, 0),
14471 			    "N_x Port with D_ID=%x, PWWN=%s has a new"
14472 			    " D_ID=%x now", old_d_id, ww_name, d_id);
14473 
14474 			rval = fp_port_login(port, page->aff_d_id, job,
14475 			    FP_CMD_PLOGI_RETAIN, sleep, pwwn_pd, NULL);
14476 			if (rval == FC_SUCCESS) {
14477 				fp_jobwait(job);
14478 				rval = job->job_result;
14479 			}
14480 
14481 			if (rval != FC_SUCCESS) {
14482 				fp_fillout_old_map(listptr +
14483 				    *listindex - 1, pwwn_pd, 0);
14484 			}
14485 		} else {
14486 			mutex_exit(&pwwn_pd->pd_mutex);
14487 			mutex_exit(&port->fp_mutex);
14488 		}
14489 
14490 		return;
14491 	}
14492 
14493 	if (pwwn_pd == NULL && did_pd != NULL) {
14494 		fc_portmap_t	*ptr;
14495 		uint32_t 	len = 1;
14496 		char 		old_ww_name[17];
14497 
14498 		mutex_enter(&did_pd->pd_mutex);
14499 		fc_wwn_to_str(&did_pd->pd_port_name, old_ww_name);
14500 		mutex_exit(&did_pd->pd_mutex);
14501 
14502 		fc_wwn_to_str(pwwn, ww_name);
14503 
14504 		(listptr + *listindex)->map_rscn_info.ulp_rscn_count =
14505 		    (uint32_t)(uintptr_t)job->job_cb_arg;
14506 
14507 		/*
14508 		 * What this means is that there is a new Port WWN for
14509 		 * this D_ID; Mark the Port device as old and provide
14510 		 * the new PWWN and D_ID combination as new.
14511 		 */
14512 		fp_fillout_old_map(listptr + (*listindex)++, did_pd, 0);
14513 
14514 		FP_TRACE(FP_NHEAD2(9, 0),
14515 		    "N_x Port with D_ID=%x, PWWN=%s has a new PWWN=%s now",
14516 		    page->aff_d_id, old_ww_name, ww_name);
14517 
14518 		(listptr + *listindex)->map_rscn_info.ulp_rscn_count =
14519 		    (uint32_t)(uintptr_t)job->job_cb_arg;
14520 
14521 		ptr = listptr + (*listindex)++;
14522 
14523 		job->job_counter = 1;
14524 
14525 		if (fp_ns_getmap(port, job, &ptr, &len,
14526 		    page->aff_d_id - 1) != FC_SUCCESS) {
14527 			(*listindex)--;
14528 		}
14529 
14530 		mutex_enter(&did_pd->pd_mutex);
14531 		did_pd->pd_flags = PD_IDLE;
14532 		mutex_exit(&did_pd->pd_mutex);
14533 
14534 		return;
14535 	}
14536 
14537 	/*
14538 	 * A weird case of Port WWN and D_ID existence but not matching up
14539 	 * between them. Trust your instincts - Take the port device handle
14540 	 * off Port WWN list, fix it with new Port WWN and put it back, In
14541 	 * the mean time mark the port device corresponding to the old port
14542 	 * WWN as OLD.
14543 	 */
14544 	FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page; Case WEIRD, pwwn_pd=%p,"
14545 	    " did_pd=%p", pwwn_pd, did_pd);
14546 
14547 	mutex_enter(&port->fp_mutex);
14548 	mutex_enter(&pwwn_pd->pd_mutex);
14549 
14550 	pwwn_pd->pd_type = PORT_DEVICE_OLD;
14551 	pwwn_pd->pd_state = PORT_DEVICE_INVALID;
14552 	fctl_delist_did_table(port, pwwn_pd);
14553 	fctl_delist_pwwn_table(port, pwwn_pd);
14554 
14555 	FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page; case WEIRD continued,"
14556 	    " pwwn-d_id=%x pwwn-wwn=%x %x %x %x %x %x %x %x",
14557 	    pwwn_pd->pd_port_id.port_id,
14558 
14559 	    pwwn_pd->pd_port_name.raw_wwn[0],
14560 	    pwwn_pd->pd_port_name.raw_wwn[1],
14561 	    pwwn_pd->pd_port_name.raw_wwn[2],
14562 	    pwwn_pd->pd_port_name.raw_wwn[3],
14563 	    pwwn_pd->pd_port_name.raw_wwn[4],
14564 	    pwwn_pd->pd_port_name.raw_wwn[5],
14565 	    pwwn_pd->pd_port_name.raw_wwn[6],
14566 	    pwwn_pd->pd_port_name.raw_wwn[7]);
14567 
14568 	mutex_exit(&pwwn_pd->pd_mutex);
14569 	mutex_exit(&port->fp_mutex);
14570 
14571 	(listptr + *listindex)->map_rscn_info.ulp_rscn_count =
14572 	    (uint32_t)(uintptr_t)job->job_cb_arg;
14573 
14574 	fctl_copy_portmap(listptr + (*listindex)++, pwwn_pd);
14575 
14576 	mutex_enter(&port->fp_mutex);
14577 	mutex_enter(&did_pd->pd_mutex);
14578 
14579 	fctl_delist_pwwn_table(port, did_pd);
14580 
14581 	(listptr + *listindex)->map_rscn_info.ulp_rscn_count =
14582 	    (uint32_t)(uintptr_t)job->job_cb_arg;
14583 
14584 	fp_fillout_changed_map(listptr + (*listindex)++, did_pd, NULL, pwwn);
14585 	fctl_enlist_pwwn_table(port, did_pd);
14586 
14587 	FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page; case WEIRD continued,"
14588 	    " d_id=%x, state=%x, did-wwn=%x %x %x %x %x %x %x %x",
14589 	    did_pd->pd_port_id.port_id, did_pd->pd_state,
14590 
14591 	    did_pd->pd_port_name.raw_wwn[0],
14592 	    did_pd->pd_port_name.raw_wwn[1],
14593 	    did_pd->pd_port_name.raw_wwn[2],
14594 	    did_pd->pd_port_name.raw_wwn[3],
14595 	    did_pd->pd_port_name.raw_wwn[4],
14596 	    did_pd->pd_port_name.raw_wwn[5],
14597 	    did_pd->pd_port_name.raw_wwn[6],
14598 	    did_pd->pd_port_name.raw_wwn[7]);
14599 
14600 	if ((did_pd->pd_state == PORT_DEVICE_LOGGED_IN) ||
14601 		(did_pd->pd_aux_flags & PD_LOGGED_OUT)) {
14602 		mutex_exit(&did_pd->pd_mutex);
14603 		mutex_exit(&port->fp_mutex);
14604 
14605 		rval = fp_port_login(port, page->aff_d_id, job,
14606 		    FP_CMD_PLOGI_RETAIN, sleep, did_pd, NULL);
14607 		if (rval == FC_SUCCESS) {
14608 			fp_jobwait(job);
14609 			if (job->job_result != FC_SUCCESS) {
14610 				fp_fillout_old_map(listptr +
14611 				    *listindex - 1, did_pd, 0);
14612 			}
14613 		} else {
14614 			fp_fillout_old_map(listptr + *listindex - 1, did_pd, 0);
14615 		}
14616 	} else {
14617 		mutex_exit(&did_pd->pd_mutex);
14618 		mutex_exit(&port->fp_mutex);
14619 	}
14620 
14621 	mutex_enter(&did_pd->pd_mutex);
14622 	did_pd->pd_flags = PD_IDLE;
14623 	mutex_exit(&did_pd->pd_mutex);
14624 }
14625 
14626 
14627 /*
14628  * Check with NS for the presence of this port WWN
14629  */
14630 static int
14631 fp_ns_validate_device(fc_local_port_t *port, fc_remote_port_t *pd,
14632     job_request_t *job, int polled, int sleep)
14633 {
14634 	la_wwn_t	pwwn;
14635 	uint32_t	flags;
14636 	fctl_ns_req_t	*ns_cmd;
14637 
14638 	flags = FCTL_NS_VALIDATE_PD | ((polled) ? 0: FCTL_NS_ASYNC_REQUEST);
14639 	ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t),
14640 	    sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t),
14641 	    flags, sleep);
14642 	if (ns_cmd == NULL) {
14643 		return (FC_NOMEM);
14644 	}
14645 
14646 	mutex_enter(&pd->pd_mutex);
14647 	pwwn = pd->pd_port_name;
14648 	mutex_exit(&pd->pd_mutex);
14649 
14650 	ns_cmd->ns_cmd_code = NS_GID_PN;
14651 	ns_cmd->ns_pd = pd;
14652 	((ns_req_gid_pn_t *)ns_cmd->ns_cmd_buf)->pwwn = pwwn;
14653 	((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->pid.port_id = 0;
14654 	((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->pid.priv_lilp_posit = 0;
14655 
14656 	return (fp_ns_query(port, ns_cmd, job, polled, sleep));
14657 }
14658 
14659 
14660 /*
14661  * Sanity check the LILP map returned by FCA
14662  */
14663 static int
14664 fp_validate_lilp_map(fc_lilpmap_t *lilp_map)
14665 {
14666 	int	count;
14667 
14668 	if (lilp_map->lilp_length == 0) {
14669 		return (FC_FAILURE);
14670 	}
14671 
14672 	for (count = 0; count < lilp_map->lilp_length; count++) {
14673 		if (fp_is_valid_alpa(lilp_map->lilp_alpalist[count]) !=
14674 		    FC_SUCCESS) {
14675 			return (FC_FAILURE);
14676 		}
14677 	}
14678 
14679 	return (FC_SUCCESS);
14680 }
14681 
14682 
14683 /*
14684  * Sanity check if the AL_PA is a valid address
14685  */
14686 static int
14687 fp_is_valid_alpa(uchar_t al_pa)
14688 {
14689 	int 	count;
14690 
14691 	for (count = 0; count < sizeof (fp_valid_alpas); count++) {
14692 		if (al_pa == fp_valid_alpas[count] || al_pa == 0) {
14693 			return (FC_SUCCESS);
14694 		}
14695 	}
14696 
14697 	return (FC_FAILURE);
14698 }
14699 
14700 
14701 /*
14702  * Post unsolicited callbacks to ULPs
14703  */
14704 static void
14705 fp_ulp_unsol_cb(void *arg)
14706 {
14707 	fp_unsol_spec_t	*ub_spec = (fp_unsol_spec_t *)arg;
14708 
14709 	fctl_ulp_unsol_cb(ub_spec->port, ub_spec->buf,
14710 	    ub_spec->buf->ub_frame.type);
14711 	kmem_free(ub_spec, sizeof (*ub_spec));
14712 }
14713 
14714 
14715 /*
14716  * Perform message reporting in a consistent manner. Unless there is
14717  * a strong reason NOT to use this function (which is very very rare)
14718  * all message reporting should go through this.
14719  */
14720 static void
14721 fp_printf(fc_local_port_t *port, int level, fp_mesg_dest_t dest, int fc_errno,
14722     fc_packet_t *pkt, const char *fmt, ...)
14723 {
14724 	caddr_t		buf;
14725 	va_list		ap;
14726 
14727 	switch (level) {
14728 	case CE_NOTE:
14729 		if ((port->fp_verbose & FP_WARNING_MESSAGES) == 0) {
14730 			return;
14731 		}
14732 		break;
14733 
14734 	case CE_WARN:
14735 		if ((port->fp_verbose & FP_FATAL_MESSAGES) == 0) {
14736 			return;
14737 		}
14738 		break;
14739 	}
14740 
14741 	buf = kmem_zalloc(256, KM_NOSLEEP);
14742 	if (buf == NULL) {
14743 		return;
14744 	}
14745 
14746 	(void) sprintf(buf, "fp(%d): ", port->fp_instance);
14747 
14748 	va_start(ap, fmt);
14749 	(void) vsprintf(buf + strlen(buf), fmt, ap);
14750 	va_end(ap);
14751 
14752 	if (fc_errno) {
14753 		char *errmsg;
14754 
14755 		(void) fc_ulp_error(fc_errno, &errmsg);
14756 		(void) sprintf(buf + strlen(buf), " FC Error=%s", errmsg);
14757 	} else {
14758 		if (pkt) {
14759 			caddr_t	state, reason, action, expln;
14760 
14761 			(void) fc_ulp_pkt_error(pkt, &state, &reason,
14762 			    &action, &expln);
14763 
14764 			(void) sprintf(buf + strlen(buf),
14765 			    " state=%s, reason=%s", state, reason);
14766 
14767 			if (pkt->pkt_resp_resid) {
14768 				(void) sprintf(buf + strlen(buf),
14769 				    " resp resid=%x\n", pkt->pkt_resp_resid);
14770 			}
14771 		}
14772 	}
14773 
14774 	switch (dest) {
14775 	case FP_CONSOLE_ONLY:
14776 		cmn_err(level, "^%s", buf);
14777 		break;
14778 
14779 	case FP_LOG_ONLY:
14780 		cmn_err(level, "!%s", buf);
14781 		break;
14782 
14783 	default:
14784 		cmn_err(level, "%s", buf);
14785 		break;
14786 	}
14787 
14788 	kmem_free(buf, 256);
14789 }
14790 
14791 static int
14792 fp_fcio_login(fc_local_port_t *port, fcio_t *fcio, job_request_t *job)
14793 {
14794 	int			ret;
14795 	uint32_t 		d_id;
14796 	la_wwn_t		pwwn;
14797 	fc_remote_port_t 	*pd = NULL;
14798 	fc_remote_port_t 	*held_pd = NULL;
14799 	fctl_ns_req_t		*ns_cmd;
14800 	fc_portmap_t		*changelist;
14801 
14802 	bcopy(fcio->fcio_ibuf, &pwwn, sizeof (pwwn));
14803 
14804 	mutex_enter(&port->fp_mutex);
14805 	if (FC_IS_TOP_SWITCH(port->fp_topology)) {
14806 		mutex_exit(&port->fp_mutex);
14807 		job->job_counter = 1;
14808 
14809 		job->job_result = FC_SUCCESS;
14810 
14811 		ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t),
14812 		    sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t),
14813 		    FCTL_NS_BUF_IS_USERLAND, KM_SLEEP);
14814 
14815 		ASSERT(ns_cmd != NULL);
14816 
14817 		ns_cmd->ns_cmd_code = NS_GID_PN;
14818 		((ns_req_gid_pn_t *)(ns_cmd->ns_cmd_buf))->pwwn = pwwn;
14819 
14820 		ret = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP);
14821 
14822 		if (ret != FC_SUCCESS || job->job_result != FC_SUCCESS) {
14823 			if (ret != FC_SUCCESS) {
14824 				fcio->fcio_errno = ret;
14825 			} else {
14826 				fcio->fcio_errno = job->job_result;
14827 			}
14828 			fctl_free_ns_cmd(ns_cmd);
14829 			return (EIO);
14830 		}
14831 		d_id = BE_32(*((uint32_t *)ns_cmd->ns_data_buf));
14832 		fctl_free_ns_cmd(ns_cmd);
14833 	} else {
14834 		mutex_exit(&port->fp_mutex);
14835 
14836 		held_pd = fctl_hold_remote_port_by_pwwn(port, &pwwn);
14837 		if (held_pd == NULL) {
14838 			fcio->fcio_errno = FC_BADWWN;
14839 			return (EIO);
14840 		}
14841 		pd = held_pd;
14842 
14843 		mutex_enter(&pd->pd_mutex);
14844 		d_id = pd->pd_port_id.port_id;
14845 		mutex_exit(&pd->pd_mutex);
14846 	}
14847 
14848 	job->job_counter = 1;
14849 
14850 	pd = fctl_get_remote_port_by_did(port, d_id);
14851 
14852 	if (pd) {
14853 		mutex_enter(&pd->pd_mutex);
14854 		if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
14855 			pd->pd_login_count++;
14856 			mutex_exit(&pd->pd_mutex);
14857 
14858 			fcio->fcio_errno = FC_SUCCESS;
14859 			if (held_pd) {
14860 				fctl_release_remote_port(held_pd);
14861 			}
14862 
14863 			return (0);
14864 		}
14865 		mutex_exit(&pd->pd_mutex);
14866 	} else {
14867 		mutex_enter(&port->fp_mutex);
14868 		if (FC_IS_TOP_SWITCH(port->fp_topology)) {
14869 			mutex_exit(&port->fp_mutex);
14870 			pd = fp_create_remote_port_by_ns(port, d_id, KM_SLEEP);
14871 			if (pd == NULL) {
14872 				fcio->fcio_errno = FC_FAILURE;
14873 				if (held_pd) {
14874 					fctl_release_remote_port(held_pd);
14875 				}
14876 				return (EIO);
14877 			}
14878 		} else {
14879 			mutex_exit(&port->fp_mutex);
14880 		}
14881 	}
14882 
14883 	job->job_flags &= ~JOB_TYPE_FP_ASYNC;
14884 	job->job_counter = 1;
14885 
14886 	ret = fp_port_login(port, d_id, job, FP_CMD_PLOGI_RETAIN,
14887 	    KM_SLEEP, pd, NULL);
14888 
14889 	if (ret != FC_SUCCESS) {
14890 		fcio->fcio_errno = ret;
14891 		if (held_pd) {
14892 			fctl_release_remote_port(held_pd);
14893 		}
14894 		return (EIO);
14895 	}
14896 	fp_jobwait(job);
14897 
14898 	fcio->fcio_errno = job->job_result;
14899 
14900 	if (held_pd) {
14901 		fctl_release_remote_port(held_pd);
14902 	}
14903 
14904 	if (job->job_result != FC_SUCCESS) {
14905 		return (EIO);
14906 	}
14907 
14908 	pd = fctl_hold_remote_port_by_pwwn(port, &pwwn);
14909 	if (pd == NULL) {
14910 		fcio->fcio_errno = FC_BADDEV;
14911 		return (ENODEV);
14912 	}
14913 
14914 	changelist = kmem_zalloc(sizeof (*changelist), KM_SLEEP);
14915 
14916 	fctl_copy_portmap(changelist, pd);
14917 	changelist->map_type = PORT_DEVICE_USER_LOGIN;
14918 
14919 	(void) fp_ulp_devc_cb(port, changelist, 1, 1, KM_SLEEP, 1);
14920 
14921 	mutex_enter(&pd->pd_mutex);
14922 	pd->pd_type = PORT_DEVICE_NOCHANGE;
14923 	mutex_exit(&pd->pd_mutex);
14924 
14925 	fctl_release_remote_port(pd);
14926 
14927 	return (0);
14928 }
14929 
14930 
14931 static int
14932 fp_fcio_logout(fc_local_port_t *port, fcio_t *fcio, job_request_t *job)
14933 {
14934 	la_wwn_t		pwwn;
14935 	fp_cmd_t		*cmd;
14936 	fc_portmap_t		*changelist;
14937 	fc_remote_port_t 	*pd;
14938 
14939 	bcopy(fcio->fcio_ibuf, &pwwn, sizeof (pwwn));
14940 
14941 	pd = fctl_hold_remote_port_by_pwwn(port, &pwwn);
14942 	if (pd == NULL) {
14943 		fcio->fcio_errno = FC_BADWWN;
14944 		return (ENXIO);
14945 	}
14946 
14947 	mutex_enter(&pd->pd_mutex);
14948 	if (pd->pd_state != PORT_DEVICE_LOGGED_IN) {
14949 		fcio->fcio_errno = FC_LOGINREQ;
14950 		mutex_exit(&pd->pd_mutex);
14951 
14952 		fctl_release_remote_port(pd);
14953 
14954 		return (EINVAL);
14955 	}
14956 
14957 	ASSERT(pd->pd_login_count >= 1);
14958 
14959 	if (pd->pd_flags == PD_ELS_IN_PROGRESS) {
14960 		fcio->fcio_errno = FC_FAILURE;
14961 		mutex_exit(&pd->pd_mutex);
14962 
14963 		fctl_release_remote_port(pd);
14964 
14965 		return (EBUSY);
14966 	}
14967 
14968 	if (pd->pd_login_count > 1) {
14969 		pd->pd_login_count--;
14970 		fcio->fcio_errno = FC_SUCCESS;
14971 		mutex_exit(&pd->pd_mutex);
14972 
14973 		changelist = kmem_zalloc(sizeof (*changelist), KM_SLEEP);
14974 
14975 		fctl_copy_portmap(changelist, pd);
14976 		changelist->map_type = PORT_DEVICE_USER_LOGOUT;
14977 
14978 		fctl_release_remote_port(pd);
14979 
14980 		(void) fp_ulp_devc_cb(port, changelist, 1, 1, KM_SLEEP, 1);
14981 
14982 		return (0);
14983 	}
14984 
14985 	pd->pd_flags = PD_ELS_IN_PROGRESS;
14986 	mutex_exit(&pd->pd_mutex);
14987 
14988 	job->job_counter = 1;
14989 
14990 	cmd = fp_alloc_pkt(port, sizeof (la_els_logo_t),
14991 	    FP_PORT_IDENTIFIER_LEN, KM_SLEEP, pd);
14992 	if (cmd == NULL) {
14993 		fcio->fcio_errno = FC_NOMEM;
14994 		fctl_release_remote_port(pd);
14995 
14996 		mutex_enter(&pd->pd_mutex);
14997 		pd->pd_flags = PD_IDLE;
14998 		mutex_exit(&pd->pd_mutex);
14999 
15000 		return (ENOMEM);
15001 	}
15002 
15003 	mutex_enter(&port->fp_mutex);
15004 	mutex_enter(&pd->pd_mutex);
15005 
15006 	cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
15007 	cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
15008 	cmd->cmd_flags = FP_CMD_PLOGI_DONT_CARE;
15009 	cmd->cmd_retry_count = 1;
15010 	cmd->cmd_ulp_pkt = NULL;
15011 
15012 	fp_logo_init(pd, cmd, job);
15013 
15014 	mutex_exit(&pd->pd_mutex);
15015 	mutex_exit(&port->fp_mutex);
15016 
15017 	if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
15018 		mutex_enter(&pd->pd_mutex);
15019 		pd->pd_flags = PD_IDLE;
15020 		mutex_exit(&pd->pd_mutex);
15021 
15022 		fp_free_pkt(cmd);
15023 		fctl_release_remote_port(pd);
15024 
15025 		return (EIO);
15026 	}
15027 
15028 	fp_jobwait(job);
15029 
15030 	fcio->fcio_errno = job->job_result;
15031 	if (job->job_result != FC_SUCCESS) {
15032 		mutex_enter(&pd->pd_mutex);
15033 		pd->pd_flags = PD_IDLE;
15034 		mutex_exit(&pd->pd_mutex);
15035 
15036 		fctl_release_remote_port(pd);
15037 
15038 		return (EIO);
15039 	}
15040 
15041 	ASSERT(pd != NULL);
15042 
15043 	changelist = kmem_zalloc(sizeof (*changelist), KM_SLEEP);
15044 
15045 	fctl_copy_portmap(changelist, pd);
15046 	changelist->map_type = PORT_DEVICE_USER_LOGOUT;
15047 	changelist->map_state = PORT_DEVICE_INVALID;
15048 
15049 	mutex_enter(&port->fp_mutex);
15050 	mutex_enter(&pd->pd_mutex);
15051 
15052 	fctl_delist_did_table(port, pd);
15053 	fctl_delist_pwwn_table(port, pd);
15054 	pd->pd_flags = PD_IDLE;
15055 
15056 	mutex_exit(&pd->pd_mutex);
15057 	mutex_exit(&port->fp_mutex);
15058 
15059 	(void) fp_ulp_devc_cb(port, changelist, 1, 1, KM_SLEEP, 1);
15060 
15061 	fctl_release_remote_port(pd);
15062 
15063 	return (0);
15064 }
15065 
15066 
15067 
15068 /*
15069  * Send a syslog event for adapter port level events.
15070  */
15071 static void
15072 fp_log_port_event(fc_local_port_t *port, char *subclass)
15073 {
15074 	nvlist_t *attr_list;
15075 
15076 	if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE,
15077 	    KM_SLEEP) != DDI_SUCCESS) {
15078 		goto alloc_failed;
15079 	}
15080 
15081 	if (nvlist_add_uint32(attr_list, "instance",
15082 	    port->fp_instance) != DDI_SUCCESS) {
15083 		goto error;
15084 	}
15085 
15086 	if (nvlist_add_byte_array(attr_list, "port-wwn",
15087 	    port->fp_service_params.nport_ww_name.raw_wwn,
15088 	    sizeof (la_wwn_t)) != DDI_SUCCESS) {
15089 		goto error;
15090 	}
15091 
15092 	(void) ddi_log_sysevent(port->fp_port_dip, DDI_VENDOR_SUNW, EC_SUNFC,
15093 	    subclass, attr_list, NULL, DDI_SLEEP);
15094 
15095 	nvlist_free(attr_list);
15096 	return;
15097 
15098 error:
15099 	nvlist_free(attr_list);
15100 alloc_failed:
15101 	FP_TRACE(FP_NHEAD1(9, 0), "Unable to send %s event", subclass);
15102 }
15103 
15104 
15105 static void
15106 fp_log_target_event(fc_local_port_t *port, char *subclass, la_wwn_t tgt_pwwn,
15107     uint32_t port_id)
15108 {
15109 	nvlist_t *attr_list;
15110 
15111 	if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE,
15112 	    KM_SLEEP) != DDI_SUCCESS) {
15113 		goto alloc_failed;
15114 	}
15115 
15116 	if (nvlist_add_uint32(attr_list, "instance",
15117 	    port->fp_instance) != DDI_SUCCESS) {
15118 		goto error;
15119 	}
15120 
15121 	if (nvlist_add_byte_array(attr_list, "port-wwn",
15122 	    port->fp_service_params.nport_ww_name.raw_wwn,
15123 	    sizeof (la_wwn_t)) != DDI_SUCCESS) {
15124 		goto error;
15125 	}
15126 
15127 	if (nvlist_add_byte_array(attr_list, "target-port-wwn",
15128 	    tgt_pwwn.raw_wwn, sizeof (la_wwn_t)) != DDI_SUCCESS) {
15129 		goto error;
15130 	}
15131 
15132 	if (nvlist_add_uint32(attr_list, "target-port-id",
15133 	    port_id) != DDI_SUCCESS) {
15134 		goto error;
15135 	}
15136 
15137 	(void) ddi_log_sysevent(port->fp_port_dip, DDI_VENDOR_SUNW, EC_SUNFC,
15138 	    subclass, attr_list, NULL, DDI_SLEEP);
15139 
15140 	nvlist_free(attr_list);
15141 	return;
15142 
15143 error:
15144 	nvlist_free(attr_list);
15145 alloc_failed:
15146 	FP_TRACE(FP_NHEAD1(9, 0), "Unable to send %s event", subclass);
15147 }
15148 
15149 static uint32_t
15150 fp_map_remote_port_state(uint32_t rm_state)
15151 {
15152 	switch (rm_state) {
15153 		case PORT_DEVICE_LOGGED_IN:
15154 			return (FC_HBA_PORTSTATE_ONLINE);
15155 		case PORT_DEVICE_VALID:
15156 		case PORT_DEVICE_INVALID:
15157 		default:
15158 			return (FC_HBA_PORTSTATE_UNKNOWN);
15159 	}
15160 }
15161