Home | History | Annotate | Download | only in impl
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  *
     25  * NOT a DDI compliant Sun Fibre Channel port driver(fp)
     26  *
     27  */
     28 
     29 #include <sys/types.h>
     30 #include <sys/varargs.h>
     31 #include <sys/param.h>
     32 #include <sys/errno.h>
     33 #include <sys/uio.h>
     34 #include <sys/buf.h>
     35 #include <sys/modctl.h>
     36 #include <sys/open.h>
     37 #include <sys/file.h>
     38 #include <sys/kmem.h>
     39 #include <sys/poll.h>
     40 #include <sys/conf.h>
     41 #include <sys/thread.h>
     42 #include <sys/var.h>
     43 #include <sys/cmn_err.h>
     44 #include <sys/stat.h>
     45 #include <sys/ddi.h>
     46 #include <sys/sunddi.h>
     47 #include <sys/promif.h>
     48 #include <sys/nvpair.h>
     49 #include <sys/byteorder.h>
     50 #include <sys/scsi/scsi.h>
     51 #include <sys/fibre-channel/fc.h>
     52 #include <sys/fibre-channel/impl/fc_ulpif.h>
     53 #include <sys/fibre-channel/impl/fc_fcaif.h>
     54 #include <sys/fibre-channel/impl/fctl_private.h>
     55 #include <sys/fibre-channel/impl/fc_portif.h>
     56 #include <sys/fibre-channel/impl/fp.h>
     57 
     58 /* These are defined in fctl.c! */
     59 extern int did_table_size;
     60 extern int pwwn_table_size;
     61 
     62 static struct cb_ops fp_cb_ops = {
     63 	fp_open,			/* open */
     64 	fp_close,			/* close */
     65 	nodev,				/* strategy */
     66 	nodev,				/* print */
     67 	nodev,				/* dump */
     68 	nodev,				/* read */
     69 	nodev,				/* write */
     70 	fp_ioctl,			/* ioctl */
     71 	nodev,				/* devmap */
     72 	nodev,				/* mmap */
     73 	nodev,				/* segmap */
     74 	nochpoll,			/* chpoll */
     75 	ddi_prop_op,			/* cb_prop_op */
     76 	0,				/* streamtab */
     77 	D_NEW | D_MP | D_HOTPLUG,	/* cb_flag */
     78 	CB_REV,				/* rev */
     79 	nodev,				/* aread */
     80 	nodev				/* awrite */
     81 };
     82 
     83 static struct dev_ops fp_ops = {
     84 	DEVO_REV,			/* build revision */
     85 	0,				/* reference count */
     86 	fp_getinfo,			/* getinfo */
     87 	nulldev,			/* identify - Obsoleted */
     88 	nulldev,			/* probe */
     89 	fp_attach,			/* attach */
     90 	fp_detach,			/* detach */
     91 	nodev,				/* reset */
     92 	&fp_cb_ops,			/* cb_ops */
     93 	NULL,				/* bus_ops */
     94 	fp_power,			/* power */
     95 	ddi_quiesce_not_needed 		/* quiesce */
     96 };
     97 
     98 #define	FP_VERSION		"20091123-1.101"
     99 #define	FP_NAME_VERSION		"SunFC Port v" FP_VERSION
    100 
    101 char *fp_version = FP_NAME_VERSION;
    102 
    103 static struct modldrv modldrv = {
    104 	&mod_driverops,			/* Type of Module */
    105 	FP_NAME_VERSION,		/* Name/Version of fp */
    106 	&fp_ops				/* driver ops */
    107 };
    108 
    109 static struct modlinkage modlinkage = {
    110 	MODREV_1,	/* Rev of the loadable modules system */
    111 	&modldrv,	/* NULL terminated list of */
    112 	NULL		/* Linkage structures */
    113 };
    114 
    115 
    116 
    117 static uint16_t ns_reg_cmds[] = {
    118 	NS_RPN_ID,
    119 	NS_RNN_ID,
    120 	NS_RCS_ID,
    121 	NS_RFT_ID,
    122 	NS_RPT_ID,
    123 	NS_RSPN_ID,
    124 	NS_RSNN_NN
    125 };
    126 
    127 struct fp_xlat {
    128 	uchar_t	xlat_state;
    129 	int	xlat_rval;
    130 } fp_xlat [] = {
    131 	{ FC_PKT_SUCCESS,	FC_SUCCESS },
    132 	{ FC_PKT_REMOTE_STOP,	FC_FAILURE },
    133 	{ FC_PKT_LOCAL_RJT,	FC_FAILURE },
    134 	{ FC_PKT_NPORT_RJT,	FC_ELS_PREJECT },
    135 	{ FC_PKT_FABRIC_RJT,	FC_ELS_FREJECT },
    136 	{ FC_PKT_LOCAL_BSY,	FC_TRAN_BUSY },
    137 	{ FC_PKT_TRAN_BSY,	FC_TRAN_BUSY },
    138 	{ FC_PKT_NPORT_BSY,	FC_PBUSY },
    139 	{ FC_PKT_FABRIC_BSY,	FC_FBUSY },
    140 	{ FC_PKT_LS_RJT,	FC_FAILURE },
    141 	{ FC_PKT_BA_RJT,	FC_FAILURE },
    142 	{ FC_PKT_TIMEOUT,	FC_FAILURE },
    143 	{ FC_PKT_TRAN_ERROR,	FC_TRANSPORT_ERROR },
    144 	{ FC_PKT_FAILURE,	FC_FAILURE },
    145 	{ FC_PKT_PORT_OFFLINE,	FC_OFFLINE }
    146 };
    147 
    148 static uchar_t fp_valid_alpas[] = {
    149 	0x01, 0x02, 0x04, 0x08, 0x0F, 0x10, 0x17, 0x18, 0x1B,
    150 	0x1D, 0x1E, 0x1F, 0x23, 0x25, 0x26, 0x27, 0x29, 0x2A,
    151 	0x2B, 0x2C, 0x2D, 0x2E, 0x31, 0x32, 0x33, 0x34, 0x35,
    152 	0x36, 0x39, 0x3A, 0x3C, 0x43, 0x45, 0x46, 0x47, 0x49,
    153 	0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x51, 0x52, 0x53, 0x54,
    154 	0x55, 0x56, 0x59, 0x5A, 0x5C, 0x63, 0x65, 0x66, 0x67,
    155 	0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x71, 0x72, 0x73,
    156 	0x74, 0x75, 0x76, 0x79, 0x7A, 0x7C, 0x80, 0x81, 0x82,
    157 	0x84, 0x88, 0x8F, 0x90, 0x97, 0x98, 0x9B, 0x9D, 0x9E,
    158 	0x9F, 0xA3, 0xA5, 0xA6, 0xA7, 0xA9, 0xAA, 0xAB, 0xAC,
    159 	0xAD, 0xAE, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB9,
    160 	0xBA, 0xBC, 0xC3, 0xC5, 0xC6, 0xC7, 0xC9, 0xCA, 0xCB,
    161 	0xCC, 0xCD, 0xCE, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
    162 	0xD9, 0xDA, 0xDC, 0xE0, 0xE1, 0xE2, 0xE4, 0xE8, 0xEF
    163 };
    164 
    165 static struct fp_perms {
    166 	uint16_t	fp_ioctl_cmd;
    167 	uchar_t		fp_open_flag;
    168 } fp_perm_list [] = {
    169 	{ FCIO_GET_NUM_DEVS,		FP_OPEN },
    170 	{ FCIO_GET_DEV_LIST,		FP_OPEN },
    171 	{ FCIO_GET_SYM_PNAME,		FP_OPEN },
    172 	{ FCIO_GET_SYM_NNAME,		FP_OPEN },
    173 	{ FCIO_SET_SYM_PNAME,		FP_EXCL },
    174 	{ FCIO_SET_SYM_NNAME,		FP_EXCL },
    175 	{ FCIO_GET_LOGI_PARAMS,		FP_OPEN },
    176 	{ FCIO_DEV_LOGIN,		FP_EXCL },
    177 	{ FCIO_DEV_LOGOUT,		FP_EXCL },
    178 	{ FCIO_GET_STATE,		FP_OPEN },
    179 	{ FCIO_DEV_REMOVE,		FP_EXCL },
    180 	{ FCIO_GET_FCODE_REV,		FP_OPEN },
    181 	{ FCIO_GET_FW_REV,		FP_OPEN },
    182 	{ FCIO_GET_DUMP_SIZE,		FP_OPEN },
    183 	{ FCIO_FORCE_DUMP,		FP_EXCL },
    184 	{ FCIO_GET_DUMP,		FP_OPEN },
    185 	{ FCIO_GET_TOPOLOGY,		FP_OPEN },
    186 	{ FCIO_RESET_LINK,		FP_EXCL },
    187 	{ FCIO_RESET_HARD,		FP_EXCL },
    188 	{ FCIO_RESET_HARD_CORE,		FP_EXCL },
    189 	{ FCIO_DIAG,			FP_OPEN },
    190 	{ FCIO_NS,			FP_EXCL },
    191 	{ FCIO_DOWNLOAD_FW,		FP_EXCL },
    192 	{ FCIO_DOWNLOAD_FCODE,		FP_EXCL },
    193 	{ FCIO_LINK_STATUS,		FP_OPEN },
    194 	{ FCIO_GET_HOST_PARAMS,		FP_OPEN },
    195 	{ FCIO_GET_NODE_ID,		FP_OPEN },
    196 	{ FCIO_SET_NODE_ID,		FP_EXCL },
    197 	{ FCIO_SEND_NODE_ID,		FP_OPEN },
    198 	{ FCIO_GET_ADAPTER_ATTRIBUTES,	FP_OPEN },
    199 	{ FCIO_GET_OTHER_ADAPTER_PORTS,	FP_OPEN },
    200 	{ FCIO_GET_ADAPTER_PORT_ATTRIBUTES,	FP_OPEN },
    201 	{ FCIO_GET_DISCOVERED_PORT_ATTRIBUTES,	FP_OPEN },
    202 	{ FCIO_GET_PORT_ATTRIBUTES,	FP_OPEN },
    203 	{ FCIO_GET_ADAPTER_PORT_STATS,	FP_OPEN },
    204 	{ FCIO_GET_ADAPTER_PORT_NPIV_ATTRIBUTES, FP_OPEN },
    205 	{ FCIO_GET_NPIV_PORT_LIST, FP_OPEN },
    206 	{ FCIO_DELETE_NPIV_PORT, FP_OPEN },
    207 	{ FCIO_GET_NPIV_ATTRIBUTES, FP_OPEN },
    208 	{ FCIO_CREATE_NPIV_PORT, FP_OPEN },
    209 	{ FCIO_NPIV_GET_ADAPTER_ATTRIBUTES, FP_OPEN }
    210 };
    211 
    212 static char *fp_pm_comps[] = {
    213 	"NAME=FC Port",
    214 	"0=Port Down",
    215 	"1=Port Up"
    216 };
    217 
    218 
    219 #ifdef	_LITTLE_ENDIAN
    220 #define	MAKE_BE_32(x)	{						\
    221 		uint32_t	*ptr1, i;				\
    222 		ptr1 = (uint32_t *)(x);					\
    223 		for (i = 0; i < sizeof (*(x)) / sizeof (uint32_t); i++) { \
    224 			*ptr1 = BE_32(*ptr1);				\
    225 			ptr1++;						\
    226 		}							\
    227 	}
    228 #else
    229 #define	MAKE_BE_32(x)
    230 #endif
    231 
    232 static uchar_t fp_verbosity = (FP_WARNING_MESSAGES | FP_FATAL_MESSAGES);
    233 static uint32_t fp_options = 0;
    234 
    235 static int fp_cmd_wait_cnt = FP_CMDWAIT_DELAY;
    236 static int fp_retry_delay = FP_RETRY_DELAY;	/* retry after this delay */
    237 static int fp_retry_count = FP_RETRY_COUNT;	/* number of retries */
    238 unsigned int fp_offline_ticker;			/* seconds */
    239 
    240 /*
    241  * Driver global variable to anchor the list of soft state structs for
    242  * all fp driver instances.  Used with the Solaris DDI soft state functions.
    243  */
    244 static void *fp_driver_softstate;
    245 
    246 static clock_t	fp_retry_ticks;
    247 static clock_t	fp_offline_ticks;
    248 
    249 static int fp_retry_ticker;
    250 static uint32_t fp_unsol_buf_count = FP_UNSOL_BUF_COUNT;
    251 static uint32_t fp_unsol_buf_size = FP_UNSOL_BUF_SIZE;
    252 
    253 static int		fp_log_size = FP_LOG_SIZE;
    254 static int		fp_trace = FP_TRACE_DEFAULT;
    255 static fc_trace_logq_t	*fp_logq = NULL;
    256 
    257 int fp_get_adapter_paths(char *pathList, int count);
    258 static void fp_log_port_event(fc_local_port_t *port, char *subclass);
    259 static void fp_log_target_event(fc_local_port_t *port, char *subclass,
    260     la_wwn_t tgt_pwwn, uint32_t port_id);
    261 static uint32_t fp_map_remote_port_state(uint32_t rm_state);
    262 static void fp_init_symbolic_names(fc_local_port_t *port);
    263 
    264 
    265 /*
    266  * Perform global initialization
    267  */
    268 int
    269 _init(void)
    270 {
    271 	int ret;
    272 
    273 	if ((ret = ddi_soft_state_init(&fp_driver_softstate,
    274 	    sizeof (struct fc_local_port), 8)) != 0) {
    275 		return (ret);
    276 	}
    277 
    278 	if ((ret = scsi_hba_init(&modlinkage)) != 0) {
    279 		ddi_soft_state_fini(&fp_driver_softstate);
    280 		return (ret);
    281 	}
    282 
    283 	fp_logq = fc_trace_alloc_logq(fp_log_size);
    284 
    285 	if ((ret = mod_install(&modlinkage)) != 0) {
    286 		fc_trace_free_logq(fp_logq);
    287 		ddi_soft_state_fini(&fp_driver_softstate);
    288 		scsi_hba_fini(&modlinkage);
    289 	}
    290 
    291 	return (ret);
    292 }
    293 
    294 
    295 /*
    296  * Prepare for driver unload
    297  */
    298 int
    299 _fini(void)
    300 {
    301 	int ret;
    302 
    303 	if ((ret = mod_remove(&modlinkage)) == 0) {
    304 		fc_trace_free_logq(fp_logq);
    305 		ddi_soft_state_fini(&fp_driver_softstate);
    306 		scsi_hba_fini(&modlinkage);
    307 	}
    308 
    309 	return (ret);
    310 }
    311 
    312 
    313 /*
    314  * Request mod_info() to handle all cases
    315  */
    316 int
    317 _info(struct modinfo *modinfo)
    318 {
    319 	return (mod_info(&modlinkage, modinfo));
    320 }
    321 
    322 
    323 /*
    324  * fp_attach:
    325  *
    326  * The respective cmd handlers take care of performing
    327  * ULP related invocations
    328  */
    329 static int
    330 fp_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
    331 {
    332 	int rval;
    333 
    334 	/*
    335 	 * We check the value of fp_offline_ticker at this
    336 	 * point. The variable is global for the driver and
    337 	 * not specific to an instance.
    338 	 *
    339 	 * If there is no user-defined value found in /etc/system
    340 	 * or fp.conf, then we use 90 seconds (FP_OFFLINE_TICKER).
    341 	 * The minimum setting for this offline timeout according
    342 	 * to the FC-FS2 standard (Fibre Channel Framing and
    343 	 * Signalling-2, see www.t11.org) is R_T_TOV == 100msec.
    344 	 *
    345 	 * We do not recommend setting the value to less than 10
    346 	 * seconds (RA_TOV) or more than 90 seconds. If this
    347 	 * variable is greater than 90 seconds then drivers above
    348 	 * fp (fcp, sd, scsi_vhci, vxdmp et al) might complain.
    349 	 */
    350 
    351 	fp_offline_ticker = ddi_prop_get_int(DDI_DEV_T_ANY,
    352 	    dip, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "fp_offline_ticker",
    353 	    FP_OFFLINE_TICKER);
    354 
    355 	if ((fp_offline_ticker < 10) ||
    356 	    (fp_offline_ticker > 90)) {
    357 		cmn_err(CE_WARN, "Setting fp_offline_ticker to "
    358 		    "%d second(s). This is outside the "
    359 		    "recommended range of 10..90 seconds",
    360 		    fp_offline_ticker);
    361 	}
    362 
    363 	/*
    364 	 * Tick every second when there are commands to retry.
    365 	 * It should tick at the least granular value of pkt_timeout
    366 	 * (which is one second)
    367 	 */
    368 	fp_retry_ticker = 1;
    369 
    370 	fp_retry_ticks = drv_usectohz(fp_retry_ticker * 1000 * 1000);
    371 	fp_offline_ticks = drv_usectohz(fp_offline_ticker * 1000 * 1000);
    372 
    373 	switch (cmd) {
    374 	case DDI_ATTACH:
    375 		rval = fp_attach_handler(dip);
    376 		break;
    377 
    378 	case DDI_RESUME:
    379 		rval = fp_resume_handler(dip);
    380 		break;
    381 
    382 	default:
    383 		rval = DDI_FAILURE;
    384 		break;
    385 	}
    386 	return (rval);
    387 }
    388 
    389 
    390 /*
    391  * fp_detach:
    392  *
    393  * If a ULP fails to handle cmd request converse of
    394  * cmd is invoked for ULPs that previously succeeded
    395  * cmd request.
    396  */
    397 static int
    398 fp_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
    399 {
    400 	int			rval = DDI_FAILURE;
    401 	fc_local_port_t		*port;
    402 	fc_attach_cmd_t		converse;
    403 	uint8_t			cnt;
    404 
    405 	if ((port = ddi_get_soft_state(fp_driver_softstate,
    406 	    ddi_get_instance(dip))) == NULL) {
    407 		return (DDI_FAILURE);
    408 	}
    409 
    410 	mutex_enter(&port->fp_mutex);
    411 
    412 	if (port->fp_ulp_attach) {
    413 		mutex_exit(&port->fp_mutex);
    414 		return (DDI_FAILURE);
    415 	}
    416 
    417 	switch (cmd) {
    418 	case DDI_DETACH:
    419 		if (port->fp_task != FP_TASK_IDLE) {
    420 			mutex_exit(&port->fp_mutex);
    421 			return (DDI_FAILURE);
    422 		}
    423 
    424 		/* Let's attempt to quit the job handler gracefully */
    425 		port->fp_soft_state |= FP_DETACH_INPROGRESS;
    426 
    427 		mutex_exit(&port->fp_mutex);
    428 		converse = FC_CMD_ATTACH;
    429 		if (fctl_detach_ulps(port, FC_CMD_DETACH,
    430 		    &modlinkage) != FC_SUCCESS) {
    431 			mutex_enter(&port->fp_mutex);
    432 			port->fp_soft_state &= ~FP_DETACH_INPROGRESS;
    433 			mutex_exit(&port->fp_mutex);
    434 			rval = DDI_FAILURE;
    435 			break;
    436 		}
    437 
    438 		mutex_enter(&port->fp_mutex);
    439 		for (cnt = 0; (port->fp_job_head) && (cnt < fp_cmd_wait_cnt);
    440 		    cnt++) {
    441 			mutex_exit(&port->fp_mutex);
    442 			delay(drv_usectohz(1000000));
    443 			mutex_enter(&port->fp_mutex);
    444 		}
    445 
    446 		if (port->fp_job_head) {
    447 			mutex_exit(&port->fp_mutex);
    448 			rval = DDI_FAILURE;
    449 			break;
    450 		}
    451 		mutex_exit(&port->fp_mutex);
    452 
    453 		rval = fp_detach_handler(port);
    454 		break;
    455 
    456 	case DDI_SUSPEND:
    457 		mutex_exit(&port->fp_mutex);
    458 		converse = FC_CMD_RESUME;
    459 		if (fctl_detach_ulps(port, FC_CMD_SUSPEND,
    460 		    &modlinkage) != FC_SUCCESS) {
    461 			rval = DDI_FAILURE;
    462 			break;
    463 		}
    464 		if ((rval = fp_suspend_handler(port)) != DDI_SUCCESS) {
    465 			(void) callb_generic_cpr(&port->fp_cpr_info,
    466 			    CB_CODE_CPR_RESUME);
    467 		}
    468 		break;
    469 
    470 	default:
    471 		mutex_exit(&port->fp_mutex);
    472 		break;
    473 	}
    474 
    475 	/*
    476 	 * Use softint to perform reattach.  Mark fp_ulp_attach so we
    477 	 * don't attempt to do this repeatedly on behalf of some persistent
    478 	 * caller.
    479 	 */
    480 	if (rval != DDI_SUCCESS) {
    481 		mutex_enter(&port->fp_mutex);
    482 		port->fp_ulp_attach = 1;
    483 
    484 		/*
    485 		 * If the port is in the low power mode then there is
    486 		 * possibility that fca too could be in low power mode.
    487 		 * Try to raise the power before calling attach ulps.
    488 		 */
    489 
    490 		if ((port->fp_soft_state & FP_SOFT_POWER_DOWN) &&
    491 		    (!(port->fp_soft_state & FP_SOFT_NO_PMCOMP))) {
    492 			mutex_exit(&port->fp_mutex);
    493 			(void) pm_raise_power(port->fp_port_dip,
    494 			    FP_PM_COMPONENT, FP_PM_PORT_UP);
    495 		} else {
    496 			mutex_exit(&port->fp_mutex);
    497 		}
    498 
    499 
    500 		fp_attach_ulps(port, converse);
    501 
    502 		mutex_enter(&port->fp_mutex);
    503 		while (port->fp_ulp_attach) {
    504 			cv_wait(&port->fp_attach_cv, &port->fp_mutex);
    505 		}
    506 
    507 		port->fp_soft_state &= ~FP_DETACH_INPROGRESS;
    508 
    509 		/*
    510 		 * Mark state as detach failed so asynchronous ULP attach
    511 		 * events (downstream, not the ones we're initiating with
    512 		 * the call to fp_attach_ulps) are not honored.	 We're
    513 		 * really still in pending detach.
    514 		 */
    515 		port->fp_soft_state |= FP_DETACH_FAILED;
    516 
    517 		mutex_exit(&port->fp_mutex);
    518 	}
    519 
    520 	return (rval);
    521 }
    522 
    523 
    524 /*
    525  * fp_getinfo:
    526  *   Given the device number, return either the
    527  *   dev_info_t pointer or the instance number.
    528  */
    529 
    530 /* ARGSUSED */
    531 static int
    532 fp_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
    533 {
    534 	int		rval;
    535 	minor_t		instance;
    536 	fc_local_port_t *port;
    537 
    538 	rval = DDI_SUCCESS;
    539 	instance = getminor((dev_t)arg);
    540 
    541 	switch (cmd) {
    542 	case DDI_INFO_DEVT2DEVINFO:
    543 		if ((port = ddi_get_soft_state(fp_driver_softstate,
    544 		    instance)) == NULL) {
    545 			rval = DDI_FAILURE;
    546 			break;
    547 		}
    548 		*result = (void *)port->fp_port_dip;
    549 		break;
    550 
    551 	case DDI_INFO_DEVT2INSTANCE:
    552 		*result = (void *)(uintptr_t)instance;
    553 		break;
    554 
    555 	default:
    556 		rval = DDI_FAILURE;
    557 		break;
    558 	}
    559 
    560 	return (rval);
    561 }
    562 
    563 
    564 /*
    565  * Entry point for power up and power down request from kernel
    566  */
    567 static int
    568 fp_power(dev_info_t *dip, int comp, int level)
    569 {
    570 	int		rval = DDI_FAILURE;
    571 	fc_local_port_t	*port;
    572 
    573 	port = ddi_get_soft_state(fp_driver_softstate, ddi_get_instance(dip));
    574 	if (port == NULL || comp != FP_PM_COMPONENT) {
    575 		return (rval);
    576 	}
    577 
    578 	switch (level) {
    579 	case FP_PM_PORT_UP:
    580 		rval = DDI_SUCCESS;
    581 
    582 		/*
    583 		 * If the port is DDI_SUSPENDed, let the DDI_RESUME
    584 		 * code complete the rediscovery.
    585 		 */
    586 		mutex_enter(&port->fp_mutex);
    587 		if (port->fp_soft_state & FP_SOFT_SUSPEND) {
    588 			port->fp_soft_state &= ~FP_SOFT_POWER_DOWN;
    589 			port->fp_pm_level = FP_PM_PORT_UP;
    590 			mutex_exit(&port->fp_mutex);
    591 			fctl_attach_ulps(port, FC_CMD_POWER_UP, &modlinkage);
    592 			break;
    593 		}
    594 
    595 		if (port->fp_soft_state & FP_SOFT_POWER_DOWN) {
    596 			ASSERT(port->fp_pm_level == FP_PM_PORT_DOWN);
    597 
    598 			port->fp_pm_level = FP_PM_PORT_UP;
    599 			rval = fp_power_up(port);
    600 			if (rval != DDI_SUCCESS) {
    601 				port->fp_pm_level = FP_PM_PORT_DOWN;
    602 			}
    603 		} else {
    604 			port->fp_pm_level = FP_PM_PORT_UP;
    605 		}
    606 		mutex_exit(&port->fp_mutex);
    607 		break;
    608 
    609 	case FP_PM_PORT_DOWN:
    610 		mutex_enter(&port->fp_mutex);
    611 
    612 		ASSERT(!(port->fp_soft_state & FP_SOFT_NO_PMCOMP));
    613 		if (port->fp_soft_state & FP_SOFT_NO_PMCOMP) {
    614 			/*
    615 			 * PM framework goofed up. We have don't
    616 			 * have any PM components. Let's never go down.
    617 			 */
    618 			mutex_exit(&port->fp_mutex);
    619 			break;
    620 
    621 		}
    622 
    623 		if (port->fp_ulp_attach) {
    624 			/* We shouldn't let the power go down */
    625 			mutex_exit(&port->fp_mutex);
    626 			break;
    627 		}
    628 
    629 		/*
    630 		 * Not a whole lot to do if we are detaching
    631 		 */
    632 		if (port->fp_soft_state & FP_SOFT_IN_DETACH) {
    633 			port->fp_pm_level = FP_PM_PORT_DOWN;
    634 			mutex_exit(&port->fp_mutex);
    635 			rval = DDI_SUCCESS;
    636 			break;
    637 		}
    638 
    639 		if (!port->fp_pm_busy && !port->fp_pm_busy_nocomp) {
    640 			port->fp_pm_level = FP_PM_PORT_DOWN;
    641 
    642 			rval = fp_power_down(port);
    643 			if (rval != DDI_SUCCESS) {
    644 				port->fp_pm_level = FP_PM_PORT_UP;
    645 				ASSERT(!(port->fp_soft_state &
    646 				    FP_SOFT_POWER_DOWN));
    647 			} else {
    648 				ASSERT(port->fp_soft_state &
    649 				    FP_SOFT_POWER_DOWN);
    650 			}
    651 		}
    652 		mutex_exit(&port->fp_mutex);
    653 		break;
    654 
    655 	default:
    656 		break;
    657 	}
    658 
    659 	return (rval);
    660 }
    661 
    662 
    663 /*
    664  * Open FC port devctl node
    665  */
    666 static int
    667 fp_open(dev_t *devp, int flag, int otype, cred_t *credp)
    668 {
    669 	int		instance;
    670 	fc_local_port_t *port;
    671 
    672 	if (otype != OTYP_CHR) {
    673 		return (EINVAL);
    674 	}
    675 
    676 	/*
    677 	 * This is not a toy to play with. Allow only powerful
    678 	 * users (hopefully knowledgeable) to access the port
    679 	 * (A hacker potentially could download a sick binary
    680 	 * file into FCA)
    681 	 */
    682 	if (drv_priv(credp)) {
    683 		return (EPERM);
    684 	}
    685 
    686 	instance = (int)getminor(*devp);
    687 
    688 	port = ddi_get_soft_state(fp_driver_softstate, instance);
    689 	if (port == NULL) {
    690 		return (ENXIO);
    691 	}
    692 
    693 	mutex_enter(&port->fp_mutex);
    694 	if (port->fp_flag & FP_EXCL) {
    695 		/*
    696 		 * It is already open for exclusive access.
    697 		 * So shut the door on this caller.
    698 		 */
    699 		mutex_exit(&port->fp_mutex);
    700 		return (EBUSY);
    701 	}
    702 
    703 	if (flag & FEXCL) {
    704 		if (port->fp_flag & FP_OPEN) {
    705 			/*
    706 			 * Exclusive operation not possible
    707 			 * as it is already opened
    708 			 */
    709 			mutex_exit(&port->fp_mutex);
    710 			return (EBUSY);
    711 		}
    712 		port->fp_flag |= FP_EXCL;
    713 	}
    714 	port->fp_flag |= FP_OPEN;
    715 	mutex_exit(&port->fp_mutex);
    716 
    717 	return (0);
    718 }
    719 
    720 
    721 /*
    722  * The driver close entry point is called on the last close()
    723  * of a device. So it is perfectly alright to just clobber the
    724  * open flag and reset it to idle (instead of having to reset
    725  * each flag bits). For any confusion, check out close(9E).
    726  */
    727 
    728 /* ARGSUSED */
    729 static int
    730 fp_close(dev_t dev, int flag, int otype, cred_t *credp)
    731 {
    732 	int		instance;
    733 	fc_local_port_t *port;
    734 
    735 	if (otype != OTYP_CHR) {
    736 		return (EINVAL);
    737 	}
    738 
    739 	instance = (int)getminor(dev);
    740 
    741 	port = ddi_get_soft_state(fp_driver_softstate, instance);
    742 	if (port == NULL) {
    743 		return (ENXIO);
    744 	}
    745 
    746 	mutex_enter(&port->fp_mutex);
    747 	if ((port->fp_flag & FP_OPEN) == 0) {
    748 		mutex_exit(&port->fp_mutex);
    749 		return (ENODEV);
    750 	}
    751 	port->fp_flag = FP_IDLE;
    752 	mutex_exit(&port->fp_mutex);
    753 
    754 	return (0);
    755 }
    756 
    757 /*
    758  * Handle IOCTL requests
    759  */
    760 
    761 /* ARGSUSED */
    762 static int
    763 fp_ioctl(dev_t dev, int cmd, intptr_t data, int mode, cred_t *credp, int *rval)
    764 {
    765 	int		instance;
    766 	int		ret = 0;
    767 	fcio_t		fcio;
    768 	fc_local_port_t *port;
    769 
    770 	instance = (int)getminor(dev);
    771 
    772 	port = ddi_get_soft_state(fp_driver_softstate, instance);
    773 	if (port == NULL) {
    774 		return (ENXIO);
    775 	}
    776 
    777 	mutex_enter(&port->fp_mutex);
    778 	if ((port->fp_flag & FP_OPEN) == 0) {
    779 		mutex_exit(&port->fp_mutex);
    780 		return (ENXIO);
    781 	}
    782 
    783 	if (port->fp_soft_state & FP_SOFT_SUSPEND) {
    784 		mutex_exit(&port->fp_mutex);
    785 		return (ENXIO);
    786 	}
    787 
    788 	mutex_exit(&port->fp_mutex);
    789 
    790 	/* this will raise power if necessary */
    791 	ret = fctl_busy_port(port);
    792 	if (ret != 0) {
    793 		return (ret);
    794 	}
    795 
    796 	ASSERT(port->fp_pm_level == FP_PM_PORT_UP);
    797 
    798 
    799 	switch (cmd) {
    800 	case FCIO_CMD: {
    801 #ifdef	_MULTI_DATAMODEL
    802 		switch (ddi_model_convert_from(mode & FMODELS)) {
    803 		case DDI_MODEL_ILP32: {
    804 			struct fcio32 fcio32;
    805 
    806 			if (ddi_copyin((void *)data, (void *)&fcio32,
    807 			    sizeof (struct fcio32), mode)) {
    808 				ret = EFAULT;
    809 				break;
    810 			}
    811 			fcio.fcio_xfer = fcio32.fcio_xfer;
    812 			fcio.fcio_cmd = fcio32.fcio_cmd;
    813 			fcio.fcio_flags = fcio32.fcio_flags;
    814 			fcio.fcio_cmd_flags = fcio32.fcio_cmd_flags;
    815 			fcio.fcio_ilen = (size_t)fcio32.fcio_ilen;
    816 			fcio.fcio_ibuf =
    817 			    (caddr_t)(uintptr_t)fcio32.fcio_ibuf;
    818 			fcio.fcio_olen = (size_t)fcio32.fcio_olen;
    819 			fcio.fcio_obuf =
    820 			    (caddr_t)(uintptr_t)fcio32.fcio_obuf;
    821 			fcio.fcio_alen = (size_t)fcio32.fcio_alen;
    822 			fcio.fcio_abuf =
    823 			    (caddr_t)(uintptr_t)fcio32.fcio_abuf;
    824 			fcio.fcio_errno = fcio32.fcio_errno;
    825 			break;
    826 		}
    827 
    828 		case DDI_MODEL_NONE:
    829 			if (ddi_copyin((void *)data, (void *)&fcio,
    830 			    sizeof (fcio_t), mode)) {
    831 				ret = EFAULT;
    832 			}
    833 			break;
    834 		}
    835 #else	/* _MULTI_DATAMODEL */
    836 		if (ddi_copyin((void *)data, (void *)&fcio,
    837 		    sizeof (fcio_t), mode)) {
    838 			ret = EFAULT;
    839 			break;
    840 		}
    841 #endif	/* _MULTI_DATAMODEL */
    842 		if (!ret) {
    843 			ret = fp_fciocmd(port, data, mode, &fcio);
    844 		}
    845 		break;
    846 	}
    847 
    848 	default:
    849 		ret = fctl_ulp_port_ioctl(port, dev, cmd, data,
    850 		    mode, credp, rval);
    851 	}
    852 
    853 	fctl_idle_port(port);
    854 
    855 	return (ret);
    856 }
    857 
    858 
    859 /*
    860  * Init Symbolic Port Name and Node Name
    861  * LV will try to get symbolic names from FCA driver
    862  * and register these to name server,
    863  * if LV fails to get these,
    864  * LV will register its default symbolic names to name server.
    865  * The Default symbolic node name format is :
    866  *	<hostname>:<hba driver name>(instance)
    867  * The Default symbolic port name format is :
    868  *	<fp path name>
    869  */
    870 static void
    871 fp_init_symbolic_names(fc_local_port_t *port)
    872 {
    873 	const char *vendorname = ddi_driver_name(port->fp_fca_dip);
    874 	char *sym_name;
    875 	char fcaname[50] = {0};
    876 	int hostnlen, fcanlen;
    877 
    878 	if (port->fp_sym_node_namelen == 0) {
    879 		hostnlen = strlen(utsname.nodename);
    880 		(void) snprintf(fcaname, sizeof (fcaname),
    881 		    "%s%d", vendorname, ddi_get_instance(port->fp_fca_dip));
    882 		fcanlen = strlen(fcaname);
    883 
    884 		sym_name = kmem_zalloc(hostnlen + fcanlen + 2, KM_SLEEP);
    885 		(void) sprintf(sym_name, "%s:%s", utsname.nodename, fcaname);
    886 		port->fp_sym_node_namelen = strlen(sym_name);
    887 		if (port->fp_sym_node_namelen >= FCHBA_SYMB_NAME_LEN) {
    888 			port->fp_sym_node_namelen = FCHBA_SYMB_NAME_LEN;
    889 		}
    890 		(void) strncpy(port->fp_sym_node_name, sym_name,
    891 		    port->fp_sym_node_namelen);
    892 		kmem_free(sym_name, hostnlen + fcanlen + 2);
    893 	}
    894 
    895 	if (port->fp_sym_port_namelen == 0) {
    896 		char *pathname = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
    897 
    898 		(void) ddi_pathname(port->fp_port_dip, pathname);
    899 		port->fp_sym_port_namelen = strlen(pathname);
    900 		if (port->fp_sym_port_namelen >= FCHBA_SYMB_NAME_LEN) {
    901 			port->fp_sym_port_namelen = FCHBA_SYMB_NAME_LEN;
    902 		}
    903 		(void) strncpy(port->fp_sym_port_name, pathname,
    904 		    port->fp_sym_port_namelen);
    905 		kmem_free(pathname, MAXPATHLEN);
    906 	}
    907 }
    908 
    909 
    910 /*
    911  * Perform port attach
    912  */
    913 static int
    914 fp_attach_handler(dev_info_t *dip)
    915 {
    916 	int			rval;
    917 	int			instance;
    918 	int			port_num;
    919 	int			port_len;
    920 	char			name[30];
    921 	char			i_pwwn[17];
    922 	fp_cmd_t		*pkt;
    923 	uint32_t		ub_count;
    924 	fc_local_port_t		*port;
    925 	job_request_t		*job;
    926 	fc_local_port_t *phyport = NULL;
    927 	int portpro1;
    928 	char pwwn[17], nwwn[17];
    929 
    930 	instance = ddi_get_instance(dip);
    931 	port_len = sizeof (port_num);
    932 	rval = ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF,
    933 	    DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "port",
    934 	    (caddr_t)&port_num, &port_len);
    935 	if (rval != DDI_SUCCESS) {
    936 		cmn_err(CE_WARN, "fp(%d): No port property in devinfo",
    937 		    instance);
    938 		return (DDI_FAILURE);
    939 	}
    940 
    941 	if (ddi_create_minor_node(dip, "devctl", S_IFCHR, instance,
    942 	    DDI_NT_NEXUS, 0) != DDI_SUCCESS) {
    943 		cmn_err(CE_WARN, "fp(%d): failed to create devctl minor node",
    944 		    instance);
    945 		return (DDI_FAILURE);
    946 	}
    947 
    948 	if (ddi_create_minor_node(dip, "fc", S_IFCHR, instance,
    949 	    DDI_NT_FC_ATTACHMENT_POINT, 0) != DDI_SUCCESS) {
    950 		cmn_err(CE_WARN, "fp(%d): failed to create fc attachment"
    951 		    " point minor node", instance);
    952 		ddi_remove_minor_node(dip, NULL);
    953 		return (DDI_FAILURE);
    954 	}
    955 
    956 	if (ddi_soft_state_zalloc(fp_driver_softstate, instance)
    957 	    != DDI_SUCCESS) {
    958 		cmn_err(CE_WARN, "fp(%d): failed to alloc soft state",
    959 		    instance);
    960 		ddi_remove_minor_node(dip, NULL);
    961 		return (DDI_FAILURE);
    962 	}
    963 	port = ddi_get_soft_state(fp_driver_softstate, instance);
    964 
    965 	(void) sprintf(port->fp_ibuf, "fp(%d)", instance);
    966 
    967 	port->fp_instance = instance;
    968 	port->fp_ulp_attach = 1;
    969 	port->fp_port_num = port_num;
    970 	port->fp_verbose = fp_verbosity;
    971 	port->fp_options = fp_options;
    972 
    973 	port->fp_fca_dip = ddi_get_parent(dip);
    974 	port->fp_port_dip = dip;
    975 	port->fp_fca_tran = (fc_fca_tran_t *)
    976 	    ddi_get_driver_private(port->fp_fca_dip);
    977 
    978 	port->fp_task = port->fp_last_task = FP_TASK_IDLE;
    979 
    980 	/*
    981 	 * Init the starting value of fp_rscn_count. Note that if
    982 	 * FC_INVALID_RSCN_COUNT is 0 (which is what it currently is), the
    983 	 * actual # of RSCNs will be (fp_rscn_count - 1)
    984 	 */
    985 	port->fp_rscn_count = FC_INVALID_RSCN_COUNT + 1;
    986 
    987 	mutex_init(&port->fp_mutex, NULL, MUTEX_DRIVER, NULL);
    988 	cv_init(&port->fp_cv, NULL, CV_DRIVER, NULL);
    989 	cv_init(&port->fp_attach_cv, NULL, CV_DRIVER, NULL);
    990 
    991 	(void) sprintf(name, "fp%d_cache", instance);
    992 
    993 	if ((portpro1 = ddi_prop_get_int(DDI_DEV_T_ANY,
    994 	    dip, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
    995 	    "phyport-instance", -1)) != -1) {
    996 		phyport = ddi_get_soft_state(fp_driver_softstate, portpro1);
    997 		fc_wwn_to_str(&phyport->fp_service_params.nport_ww_name, pwwn);
    998 		fc_wwn_to_str(&phyport->fp_service_params.node_ww_name, nwwn);
    999 		port->fp_npiv_type = FC_NPIV_PORT;
   1000 	}
   1001 
   1002 	/*
   1003 	 * Allocate the pool of fc_packet_t structs to be used with
   1004 	 * this fp instance.
   1005 	 */
   1006 	port->fp_pkt_cache = kmem_cache_create(name,
   1007 	    (port->fp_fca_tran->fca_pkt_size) + sizeof (fp_cmd_t), 8,
   1008 	    fp_cache_constructor, fp_cache_destructor, NULL, (void *)port,
   1009 	    NULL, 0);
   1010 	port->fp_out_fpcmds = 0;
   1011 	if (port->fp_pkt_cache == NULL) {
   1012 		goto cache_alloc_failed;
   1013 	}
   1014 
   1015 
   1016 	/*
   1017 	 * Allocate the d_id and pwwn hash tables for all remote ports
   1018 	 * connected to this local port.
   1019 	 */
   1020 	port->fp_did_table = kmem_zalloc(did_table_size *
   1021 	    sizeof (struct d_id_hash), KM_SLEEP);
   1022 
   1023 	port->fp_pwwn_table = kmem_zalloc(pwwn_table_size *
   1024 	    sizeof (struct pwwn_hash), KM_SLEEP);
   1025 
   1026 	port->fp_taskq = taskq_create("fp_ulp_callback", 1,
   1027 	    MINCLSYSPRI, 1, 16, 0);
   1028 
   1029 	/* Indicate that don't have the pm components yet */
   1030 	port->fp_soft_state |=	FP_SOFT_NO_PMCOMP;
   1031 
   1032 	/*
   1033 	 * Bind the callbacks with the FCA driver. This will open the gate
   1034 	 * for asynchronous callbacks, so after this call the fp_mutex
   1035 	 * must be held when updating the fc_local_port_t struct.
   1036 	 *
   1037 	 * This is done _before_ setting up the job thread so we can avoid
   1038 	 * cleaning up after the thread_create() in the error path. This
   1039 	 * also means fp will be operating with fp_els_resp_pkt set to NULL.
   1040 	 */
   1041 	if (fp_bind_callbacks(port) != DDI_SUCCESS) {
   1042 		goto bind_callbacks_failed;
   1043 	}
   1044 
   1045 	if (phyport) {
   1046 		mutex_enter(&phyport->fp_mutex);
   1047 		if (phyport->fp_port_next) {
   1048 			phyport->fp_port_next->fp_port_prev = port;
   1049 			port->fp_port_next =  phyport->fp_port_next;
   1050 			phyport->fp_port_next = port;
   1051 			port->fp_port_prev = phyport;
   1052 		} else {
   1053 			phyport->fp_port_next = port;
   1054 			phyport->fp_port_prev = port;
   1055 			port->fp_port_next =  phyport;
   1056 			port->fp_port_prev = phyport;
   1057 		}
   1058 		mutex_exit(&phyport->fp_mutex);
   1059 	}
   1060 
   1061 	/*
   1062 	 * Init Symbolic Names
   1063 	 */
   1064 	fp_init_symbolic_names(port);
   1065 
   1066 	pkt = fp_alloc_pkt(port, sizeof (la_els_logi_t), sizeof (la_els_logi_t),
   1067 	    KM_SLEEP, NULL);
   1068 
   1069 	if (pkt == NULL) {
   1070 		cmn_err(CE_WARN, "fp(%d): failed to allocate ELS packet",
   1071 		    instance);
   1072 		goto alloc_els_packet_failed;
   1073 	}
   1074 
   1075 	(void) thread_create(NULL, 0, fp_job_handler, port, 0, &p0, TS_RUN,
   1076 	    v.v_maxsyspri - 2);
   1077 
   1078 	fc_wwn_to_str(&port->fp_service_params.nport_ww_name, i_pwwn);
   1079 	if (ddi_prop_update_string(DDI_DEV_T_NONE, dip, "initiator-port",
   1080 	    i_pwwn) != DDI_PROP_SUCCESS) {
   1081 		fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
   1082 		    "fp(%d): Updating 'initiator-port' property"
   1083 		    " on fp dev_info node failed", instance);
   1084 	}
   1085 
   1086 	fc_wwn_to_str(&port->fp_service_params.node_ww_name, i_pwwn);
   1087 	if (ddi_prop_update_string(DDI_DEV_T_NONE, dip, "initiator-node",
   1088 	    i_pwwn) != DDI_PROP_SUCCESS) {
   1089 		fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
   1090 		    "fp(%d): Updating 'initiator-node' property"
   1091 		    " on fp dev_info node failed", instance);
   1092 	}
   1093 
   1094 	mutex_enter(&port->fp_mutex);
   1095 	port->fp_els_resp_pkt = pkt;
   1096 	mutex_exit(&port->fp_mutex);
   1097 
   1098 	/*
   1099 	 * Determine the count of unsolicited buffers this FCA can support
   1100 	 */
   1101 	fp_retrieve_caps(port);
   1102 
   1103 	/*
   1104 	 * Allocate unsolicited buffer tokens
   1105 	 */
   1106 	if (port->fp_ub_count) {
   1107 		ub_count = port->fp_ub_count;
   1108 		port->fp_ub_tokens = kmem_zalloc(ub_count *
   1109 		    sizeof (*port->fp_ub_tokens), KM_SLEEP);
   1110 		/*
   1111 		 * Do not fail the attach if unsolicited buffer allocation
   1112 		 * fails; Just try to get along with whatever the FCA can do.
   1113 		 */
   1114 		if (fc_ulp_uballoc(port, &ub_count, fp_unsol_buf_size,
   1115 		    FC_TYPE_EXTENDED_LS, port->fp_ub_tokens) !=
   1116 		    FC_SUCCESS || ub_count != port->fp_ub_count) {
   1117 			cmn_err(CE_WARN, "fp(%d): failed to allocate "
   1118 			    " Unsolicited buffers. proceeding with attach...",
   1119 			    instance);
   1120 			kmem_free(port->fp_ub_tokens,
   1121 			    sizeof (*port->fp_ub_tokens) * port->fp_ub_count);
   1122 			port->fp_ub_tokens = NULL;
   1123 		}
   1124 	}
   1125 
   1126 	fp_load_ulp_modules(dip, port);
   1127 
   1128 	/*
   1129 	 * Enable DDI_SUSPEND and DDI_RESUME for this instance.
   1130 	 */
   1131 	(void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
   1132 	    "pm-hardware-state", "needs-suspend-resume",
   1133 	    strlen("needs-suspend-resume") + 1);
   1134 
   1135 	/*
   1136 	 * fctl maintains a list of all port handles, so
   1137 	 * help fctl add this one to its list now.
   1138 	 */
   1139 	mutex_enter(&port->fp_mutex);
   1140 	fctl_add_port(port);
   1141 
   1142 	/*
   1143 	 * If a state change is already in progress, set the bind state t
   1144 	 * OFFLINE as well, so further state change callbacks into ULPs
   1145 	 * will pass the appropriate states
   1146 	 */
   1147 	if (FC_PORT_STATE_MASK(port->fp_bind_state) == FC_STATE_OFFLINE ||
   1148 	    port->fp_statec_busy) {
   1149 		port->fp_bind_state = FC_STATE_OFFLINE;
   1150 		mutex_exit(&port->fp_mutex);
   1151 
   1152 		fp_startup_done((opaque_t)port, FC_PKT_SUCCESS);
   1153 	} else {
   1154 		/*
   1155 		 * Without dropping the mutex, ensure that the port
   1156 		 * startup happens ahead of state change callback
   1157 		 * processing
   1158 		 */
   1159 		ASSERT(port->fp_job_tail == NULL && port->fp_job_head == NULL);
   1160 
   1161 		port->fp_last_task = port->fp_task;
   1162 		port->fp_task = FP_TASK_PORT_STARTUP;
   1163 
   1164 		job = fctl_alloc_job(JOB_PORT_STARTUP, JOB_TYPE_FCTL_ASYNC,
   1165 		    fp_startup_done, (opaque_t)port, KM_SLEEP);
   1166 
   1167 		port->fp_job_head = port->fp_job_tail = job;
   1168 
   1169 		cv_signal(&port->fp_cv);
   1170 
   1171 		mutex_exit(&port->fp_mutex);
   1172 	}
   1173 
   1174 	mutex_enter(&port->fp_mutex);
   1175 	while (port->fp_ulp_attach) {
   1176 		cv_wait(&port->fp_attach_cv, &port->fp_mutex);
   1177 	}
   1178 	mutex_exit(&port->fp_mutex);
   1179 
   1180 	if (ddi_prop_update_string_array(DDI_DEV_T_NONE, dip,
   1181 	    "pm-components", fp_pm_comps,
   1182 	    sizeof (fp_pm_comps) / sizeof (fp_pm_comps[0])) !=
   1183 	    DDI_PROP_SUCCESS) {
   1184 		FP_TRACE(FP_NHEAD2(9, 0), "Failed to create PM"
   1185 		    " components property, PM disabled on this port.");
   1186 		mutex_enter(&port->fp_mutex);
   1187 		port->fp_pm_level = FP_PM_PORT_UP;
   1188 		mutex_exit(&port->fp_mutex);
   1189 	} else {
   1190 		if (pm_raise_power(dip, FP_PM_COMPONENT,
   1191 		    FP_PM_PORT_UP) != DDI_SUCCESS) {
   1192 			FP_TRACE(FP_NHEAD2(9, 0), "Failed to raise"
   1193 			    " power level");
   1194 			mutex_enter(&port->fp_mutex);
   1195 			port->fp_pm_level = FP_PM_PORT_UP;
   1196 			mutex_exit(&port->fp_mutex);
   1197 		}
   1198 
   1199 		/*
   1200 		 * Don't unset the FP_SOFT_NO_PMCOMP flag until after
   1201 		 * the call to pm_raise_power.	The PM framework can't
   1202 		 * handle multiple threads calling into it during attach.
   1203 		 */
   1204 
   1205 		mutex_enter(&port->fp_mutex);
   1206 		port->fp_soft_state &=	~FP_SOFT_NO_PMCOMP;
   1207 		mutex_exit(&port->fp_mutex);
   1208 	}
   1209 
   1210 	ddi_report_dev(dip);
   1211 
   1212 	fp_log_port_event(port, ESC_SUNFC_PORT_ATTACH);
   1213 
   1214 	return (DDI_SUCCESS);
   1215 
   1216 	/*
   1217 	 * Unwind any/all preceeding allocations in the event of an error.
   1218 	 */
   1219 
   1220 alloc_els_packet_failed:
   1221 
   1222 	if (port->fp_fca_handle != NULL) {
   1223 		port->fp_fca_tran->fca_unbind_port(port->fp_fca_handle);
   1224 		port->fp_fca_handle = NULL;
   1225 	}
   1226 
   1227 	if (port->fp_ub_tokens != NULL) {
   1228 		(void) fc_ulp_ubfree(port, port->fp_ub_count,
   1229 		    port->fp_ub_tokens);
   1230 		kmem_free(port->fp_ub_tokens,
   1231 		    port->fp_ub_count * sizeof (*port->fp_ub_tokens));
   1232 		port->fp_ub_tokens = NULL;
   1233 	}
   1234 
   1235 	if (port->fp_els_resp_pkt != NULL) {
   1236 		fp_free_pkt(port->fp_els_resp_pkt);
   1237 		port->fp_els_resp_pkt = NULL;
   1238 	}
   1239 
   1240 bind_callbacks_failed:
   1241 
   1242 	if (port->fp_taskq != NULL) {
   1243 		taskq_destroy(port->fp_taskq);
   1244 	}
   1245 
   1246 	if (port->fp_pwwn_table != NULL) {
   1247 		kmem_free(port->fp_pwwn_table,
   1248 		    pwwn_table_size * sizeof (struct pwwn_hash));
   1249 		port->fp_pwwn_table = NULL;
   1250 	}
   1251 
   1252 	if (port->fp_did_table != NULL) {
   1253 		kmem_free(port->fp_did_table,
   1254 		    did_table_size * sizeof (struct d_id_hash));
   1255 		port->fp_did_table = NULL;
   1256 	}
   1257 
   1258 	if (port->fp_pkt_cache != NULL) {
   1259 		kmem_cache_destroy(port->fp_pkt_cache);
   1260 		port->fp_pkt_cache = NULL;
   1261 	}
   1262 
   1263 cache_alloc_failed:
   1264 
   1265 	cv_destroy(&port->fp_attach_cv);
   1266 	cv_destroy(&port->fp_cv);
   1267 	mutex_destroy(&port->fp_mutex);
   1268 	ddi_remove_minor_node(port->fp_port_dip, NULL);
   1269 	ddi_soft_state_free(fp_driver_softstate, instance);
   1270 	ddi_prop_remove_all(dip);
   1271 
   1272 	return (DDI_FAILURE);
   1273 }
   1274 
   1275 
   1276 /*
   1277  * Handle DDI_RESUME request
   1278  */
   1279 static int
   1280 fp_resume_handler(dev_info_t *dip)
   1281 {
   1282 	int		rval;
   1283 	fc_local_port_t *port;
   1284 
   1285 	port = ddi_get_soft_state(fp_driver_softstate, ddi_get_instance(dip));
   1286 
   1287 	ASSERT(port != NULL);
   1288 
   1289 #ifdef	DEBUG
   1290 	mutex_enter(&port->fp_mutex);
   1291 	ASSERT(port->fp_soft_state & FP_SOFT_SUSPEND);
   1292 	mutex_exit(&port->fp_mutex);
   1293 #endif
   1294 
   1295 	/*
   1296 	 * If the port was power suspended, raise the power level
   1297 	 */
   1298 	mutex_enter(&port->fp_mutex);
   1299 	if ((port->fp_soft_state & FP_SOFT_POWER_DOWN) &&
   1300 	    (!(port->fp_soft_state & FP_SOFT_NO_PMCOMP))) {
   1301 		ASSERT(port->fp_pm_level == FP_PM_PORT_DOWN);
   1302 
   1303 		mutex_exit(&port->fp_mutex);
   1304 		if (pm_raise_power(dip, FP_PM_COMPONENT,
   1305 		    FP_PM_PORT_UP) != DDI_SUCCESS) {
   1306 			FP_TRACE(FP_NHEAD2(9, 0),
   1307 			    "Failed to raise the power level");
   1308 			return (DDI_FAILURE);
   1309 		}
   1310 		mutex_enter(&port->fp_mutex);
   1311 	}
   1312 	port->fp_soft_state &= ~FP_SOFT_SUSPEND;
   1313 	mutex_exit(&port->fp_mutex);
   1314 
   1315 	/*
   1316 	 * All the discovery is initiated and handled by per-port thread.
   1317 	 * Further all the discovery is done in handled in callback mode
   1318 	 * (not polled mode); In a specific case such as this, the discovery
   1319 	 * is required to happen in polled mode. The easiest way out is
   1320 	 * to bail out port thread and get started. Come back and fix this
   1321 	 * to do on demand discovery initiated by ULPs. ULPs such as FCP
   1322 	 * will do on-demand discovery during pre-power-up busctl handling
   1323 	 * which will only be possible when SCSA provides a new HBA vector
   1324 	 * for sending down the PM busctl requests.
   1325 	 */
   1326 	(void) callb_generic_cpr(&port->fp_cpr_info, CB_CODE_CPR_RESUME);
   1327 
   1328 	rval = fp_resume_all(port, FC_CMD_RESUME);
   1329 	if (rval != DDI_SUCCESS) {
   1330 		mutex_enter(&port->fp_mutex);
   1331 		port->fp_soft_state |= FP_SOFT_SUSPEND;
   1332 		mutex_exit(&port->fp_mutex);
   1333 		(void) callb_generic_cpr(&port->fp_cpr_info,
   1334 		    CB_CODE_CPR_CHKPT);
   1335 	}
   1336 
   1337 	return (rval);
   1338 }
   1339 
   1340 /*
   1341  * Perform FC Port power on initialization
   1342  */
   1343 static int
   1344 fp_power_up(fc_local_port_t *port)
   1345 {
   1346 	int	rval;
   1347 
   1348 	ASSERT(MUTEX_HELD(&port->fp_mutex));
   1349 
   1350 	ASSERT((port->fp_soft_state & FP_SOFT_SUSPEND) == 0);
   1351 	ASSERT(port->fp_soft_state & FP_SOFT_POWER_DOWN);
   1352 
   1353 	port->fp_soft_state &= ~FP_SOFT_POWER_DOWN;
   1354 
   1355 	mutex_exit(&port->fp_mutex);
   1356 
   1357 	rval = fp_resume_all(port, FC_CMD_POWER_UP);
   1358 	if (rval != DDI_SUCCESS) {
   1359 		mutex_enter(&port->fp_mutex);
   1360 		port->fp_soft_state |= FP_SOFT_POWER_DOWN;
   1361 	} else {
   1362 		mutex_enter(&port->fp_mutex);
   1363 	}
   1364 
   1365 	return (rval);
   1366 }
   1367 
   1368 
   1369 /*
   1370  * It is important to note that the power may possibly be removed between
   1371  * SUSPEND and the ensuing RESUME operation. In such a context the underlying
   1372  * FC port hardware would have gone through an OFFLINE to ONLINE transition
   1373  * (hardware state). In this case, the port driver may need to rediscover the
   1374  * topology, perform LOGINs, register with the name server again and perform
   1375  * any such port initialization procedures. To perform LOGINs, the driver could
   1376  * use the port device handle to see if a LOGIN needs to be performed and use
   1377  * the D_ID and WWN in it. The LOGINs may fail (if the hardware is reconfigured
   1378  * or removed) which will be reflected in the map the ULPs will see.
   1379  */
   1380 static int
   1381 fp_resume_all(fc_local_port_t *port, fc_attach_cmd_t cmd)
   1382 {
   1383 
   1384 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
   1385 
   1386 	if (fp_bind_callbacks(port) != DDI_SUCCESS) {
   1387 		return (DDI_FAILURE);
   1388 	}
   1389 
   1390 	mutex_enter(&port->fp_mutex);
   1391 
   1392 	/*
   1393 	 * If there are commands queued for delayed retry, instead of
   1394 	 * working the hard way to figure out which ones are good for
   1395 	 * restart and which ones not (ELSs are definitely not good
   1396 	 * as the port will have to go through a new spin of rediscovery
   1397 	 * now), so just flush them out.
   1398 	 */
   1399 	if (port->fp_restore & FP_RESTORE_WAIT_TIMEOUT) {
   1400 		fp_cmd_t	*cmd;
   1401 
   1402 		port->fp_restore &= ~FP_RESTORE_WAIT_TIMEOUT;
   1403 
   1404 		mutex_exit(&port->fp_mutex);
   1405 		while ((cmd = fp_deque_cmd(port)) != NULL) {
   1406 			cmd->cmd_pkt.pkt_state = FC_PKT_TRAN_ERROR;
   1407 			fp_iodone(cmd);
   1408 		}
   1409 		mutex_enter(&port->fp_mutex);
   1410 	}
   1411 
   1412 	if (FC_PORT_STATE_MASK(port->fp_bind_state) == FC_STATE_OFFLINE) {
   1413 		if ((port->fp_restore & FP_RESTORE_OFFLINE_TIMEOUT) ||
   1414 		    port->fp_dev_count) {
   1415 			port->fp_restore &= ~FP_RESTORE_OFFLINE_TIMEOUT;
   1416 			port->fp_offline_tid = timeout(fp_offline_timeout,
   1417 			    (caddr_t)port, fp_offline_ticks);
   1418 		}
   1419 		if (port->fp_job_head) {
   1420 			cv_signal(&port->fp_cv);
   1421 		}
   1422 		mutex_exit(&port->fp_mutex);
   1423 		fctl_attach_ulps(port, cmd, &modlinkage);
   1424 	} else {
   1425 		struct job_request *job;
   1426 
   1427 		/*
   1428 		 * If an OFFLINE timer was running at the time of
   1429 		 * suspending, there is no need to restart it as
   1430 		 * the port is ONLINE now.
   1431 		 */
   1432 		port->fp_restore &= ~FP_RESTORE_OFFLINE_TIMEOUT;
   1433 		if (port->fp_statec_busy == 0) {
   1434 			port->fp_soft_state |= FP_SOFT_IN_STATEC_CB;
   1435 		}
   1436 		port->fp_statec_busy++;
   1437 		mutex_exit(&port->fp_mutex);
   1438 
   1439 		job = fctl_alloc_job(JOB_PORT_ONLINE,
   1440 		    JOB_CANCEL_ULP_NOTIFICATION, NULL, NULL, KM_SLEEP);
   1441 		fctl_enque_job(port, job);
   1442 
   1443 		fctl_jobwait(job);
   1444 		fctl_remove_oldies(port);
   1445 
   1446 		fctl_attach_ulps(port, cmd, &modlinkage);
   1447 		fctl_dealloc_job(job);
   1448 	}
   1449 
   1450 	return (DDI_SUCCESS);
   1451 }
   1452 
   1453 
   1454 /*
   1455  * At this time, there shouldn't be any I/O requests on this port.
   1456  * But the unsolicited callbacks from the underlying FCA port need
   1457  * to be handled very carefully. The steps followed to handle the
   1458  * DDI_DETACH are:
   1459  *	+	Grab the port driver mutex, check if the unsolicited
   1460  *		callback is currently under processing. If true, fail
   1461  *		the DDI_DETACH request by printing a message; If false
   1462  *		mark the DDI_DETACH as under progress, so that any
   1463  *		further unsolicited callbacks get bounced.
   1464  *	+	Perform PRLO/LOGO if necessary, cleanup all the data
   1465  *		structures.
   1466  *	+	Get the job_handler thread to gracefully exit.
   1467  *	+	Unregister callbacks with the FCA port.
   1468  *	+	Now that some peace is found, notify all the ULPs of
   1469  *		DDI_DETACH request (using ulp_port_detach entry point)
   1470  *	+	Free all mutexes, semaphores, conditional variables.
   1471  *	+	Free the soft state, return success.
   1472  *
   1473  * Important considerations:
   1474  *		Port driver de-registers state change and unsolicited
   1475  *		callbacks before taking up the task of notifying ULPs
   1476  *		and performing PRLO and LOGOs.
   1477  *
   1478  *		A port may go offline at the time PRLO/LOGO is being
   1479  *		requested. It is expected of all FCA drivers to fail
   1480  *		such requests either immediately with a FC_OFFLINE
   1481  *		return code to fc_fca_transport() or return the packet
   1482  *		asynchronously with pkt state set to FC_PKT_PORT_OFFLINE
   1483  */
   1484 static int
   1485 fp_detach_handler(fc_local_port_t *port)
   1486 {
   1487 	job_request_t	*job;
   1488 	uint32_t	delay_count;
   1489 	fc_orphan_t	*orp, *tmporp;
   1490 
   1491 	/*
   1492 	 * In a Fabric topology with many host ports connected to
   1493 	 * a switch, another detaching instance of fp might have
   1494 	 * triggered a LOGO (which is an unsolicited request to
   1495 	 * this instance). So in order to be able to successfully
   1496 	 * detach by taking care of such cases a delay of about
   1497 	 * 30 seconds is introduced.
   1498 	 */
   1499 	delay_count = 0;
   1500 	mutex_enter(&port->fp_mutex);
   1501 	if (port->fp_out_fpcmds != 0) {
   1502 		/*
   1503 		 * At this time we can only check fp internal commands, because
   1504 		 * sd/ssd/scsi_vhci should have finsihed all their commands,
   1505 		 * fcp/fcip/fcsm should have finished all their commands.
   1506 		 *
   1507 		 * It seems that all fp internal commands are asynchronous now.
   1508 		 */
   1509 		port->fp_soft_state &= ~FP_DETACH_INPROGRESS;
   1510 		mutex_exit(&port->fp_mutex);
   1511 
   1512 		cmn_err(CE_WARN, "fp(%d): %d fp_cmd(s) is/are in progress"
   1513 		    " Failing detach", port->fp_instance, port->fp_out_fpcmds);
   1514 		return (DDI_FAILURE);
   1515 	}
   1516 
   1517 	while ((port->fp_soft_state &
   1518 	    (FP_SOFT_IN_STATEC_CB | FP_SOFT_IN_UNSOL_CB)) &&
   1519 	    (delay_count < 30)) {
   1520 		mutex_exit(&port->fp_mutex);
   1521 		delay_count++;
   1522 		delay(drv_usectohz(1000000));
   1523 		mutex_enter(&port->fp_mutex);
   1524 	}
   1525 
   1526 	if (port->fp_soft_state &
   1527 	    (FP_SOFT_IN_STATEC_CB | FP_SOFT_IN_UNSOL_CB)) {
   1528 		port->fp_soft_state &= ~FP_DETACH_INPROGRESS;
   1529 		mutex_exit(&port->fp_mutex);
   1530 
   1531 		cmn_err(CE_WARN, "fp(%d): FCA callback in progress: "
   1532 		    " Failing detach", port->fp_instance);
   1533 		return (DDI_FAILURE);
   1534 	}
   1535 
   1536 	port->fp_soft_state |= FP_SOFT_IN_DETACH;
   1537 	port->fp_soft_state &= ~FP_DETACH_INPROGRESS;
   1538 	mutex_exit(&port->fp_mutex);
   1539 
   1540 	/*
   1541 	 * If we're powered down, we need to raise power prior to submitting
   1542 	 * the JOB_PORT_SHUTDOWN job.  Otherwise, the job handler will never
   1543 	 * process the shutdown job.
   1544 	 */
   1545 	if (fctl_busy_port(port) != 0) {
   1546 		cmn_err(CE_WARN, "fp(%d): fctl_busy_port failed",
   1547 		    port->fp_instance);
   1548 		mutex_enter(&port->fp_mutex);
   1549 		port->fp_soft_state &= ~FP_SOFT_IN_DETACH;
   1550 		mutex_exit(&port->fp_mutex);
   1551 		return (DDI_FAILURE);
   1552 	}
   1553 
   1554 	/*
   1555 	 * This will deallocate data structs and cause the "job" thread
   1556 	 * to exit, in preparation for DDI_DETACH on the instance.
   1557 	 * This can sleep for an arbitrary duration, since it waits for
   1558 	 * commands over the wire, timeout(9F) callbacks, etc.
   1559 	 *
   1560 	 * CAUTION: There is still a race here, where the "job" thread
   1561 	 * can still be executing code even tho the fctl_jobwait() call
   1562 	 * below has returned to us.  In theory the fp driver could even be
   1563 	 * modunloaded even tho the job thread isn't done executing.
   1564 	 * without creating the race condition.
   1565 	 */
   1566 	job = fctl_alloc_job(JOB_PORT_SHUTDOWN, 0, NULL,
   1567 	    (opaque_t)port, KM_SLEEP);
   1568 	fctl_enque_job(port, job);
   1569 	fctl_jobwait(job);
   1570 	fctl_dealloc_job(job);
   1571 
   1572 
   1573 	(void) pm_lower_power(port->fp_port_dip, FP_PM_COMPONENT,
   1574 	    FP_PM_PORT_DOWN);
   1575 
   1576 	if (port->fp_taskq) {
   1577 		taskq_destroy(port->fp_taskq);
   1578 	}
   1579 
   1580 	ddi_prop_remove_all(port->fp_port_dip);
   1581 
   1582 	ddi_remove_minor_node(port->fp_port_dip, NULL);
   1583 
   1584 	fctl_remove_port(port);
   1585 
   1586 	fp_free_pkt(port->fp_els_resp_pkt);
   1587 
   1588 	if (port->fp_ub_tokens) {
   1589 		if (fc_ulp_ubfree(port, port->fp_ub_count,
   1590 		    port->fp_ub_tokens) != FC_SUCCESS) {
   1591 			cmn_err(CE_WARN, "fp(%d): couldn't free "
   1592 			    " unsolicited buffers", port->fp_instance);
   1593 		}
   1594 		kmem_free(port->fp_ub_tokens,
   1595 		    sizeof (*port->fp_ub_tokens) * port->fp_ub_count);
   1596 		port->fp_ub_tokens = NULL;
   1597 	}
   1598 
   1599 	if (port->fp_pkt_cache != NULL) {
   1600 		kmem_cache_destroy(port->fp_pkt_cache);
   1601 	}
   1602 
   1603 	port->fp_fca_tran->fca_unbind_port(port->fp_fca_handle);
   1604 
   1605 	mutex_enter(&port->fp_mutex);
   1606 	if (port->fp_did_table) {
   1607 		kmem_free(port->fp_did_table, did_table_size *
   1608 		    sizeof (struct d_id_hash));
   1609 	}
   1610 
   1611 	if (port->fp_pwwn_table) {
   1612 		kmem_free(port->fp_pwwn_table, pwwn_table_size *
   1613 		    sizeof (struct pwwn_hash));
   1614 	}
   1615 	orp = port->fp_orphan_list;
   1616 	while (orp) {
   1617 		tmporp = orp;
   1618 		orp = orp->orp_next;
   1619 		kmem_free(tmporp, sizeof (*orp));
   1620 	}
   1621 
   1622 	mutex_exit(&port->fp_mutex);
   1623 
   1624 	fp_log_port_event(port, ESC_SUNFC_PORT_DETACH);
   1625 
   1626 	mutex_destroy(&port->fp_mutex);
   1627 	cv_destroy(&port->fp_attach_cv);
   1628 	cv_destroy(&port->fp_cv);
   1629 	ddi_soft_state_free(fp_driver_softstate, port->fp_instance);
   1630 
   1631 	return (DDI_SUCCESS);
   1632 }
   1633 
   1634 
   1635 /*
   1636  * Steps to perform DDI_SUSPEND operation on a FC port
   1637  *
   1638  *	- If already suspended return DDI_FAILURE
   1639  *	- If already power-suspended return DDI_SUCCESS
   1640  *	- If an unsolicited callback or state change handling is in
   1641  *	    in progress, throw a warning message, return DDI_FAILURE
   1642  *	- Cancel timeouts
   1643  *	- SUSPEND the job_handler thread (means do nothing as it is
   1644  *	    taken care of by the CPR frame work)
   1645  */
   1646 static int
   1647 fp_suspend_handler(fc_local_port_t *port)
   1648 {
   1649 	uint32_t	delay_count;
   1650 
   1651 	mutex_enter(&port->fp_mutex);
   1652 
   1653 	/*
   1654 	 * The following should never happen, but
   1655 	 * let the driver be more defensive here
   1656 	 */
   1657 	if (port->fp_soft_state & FP_SOFT_SUSPEND) {
   1658 		mutex_exit(&port->fp_mutex);
   1659 		return (DDI_FAILURE);
   1660 	}
   1661 
   1662 	/*
   1663 	 * If the port is already power suspended, there
   1664 	 * is nothing else to do, So return DDI_SUCCESS,
   1665 	 * but mark the SUSPEND bit in the soft state
   1666 	 * before leaving.
   1667 	 */
   1668 	if (port->fp_soft_state & FP_SOFT_POWER_DOWN) {
   1669 		port->fp_soft_state |= FP_SOFT_SUSPEND;
   1670 		mutex_exit(&port->fp_mutex);
   1671 		return (DDI_SUCCESS);
   1672 	}
   1673 
   1674 	/*
   1675 	 * Check if an unsolicited callback or state change handling is
   1676 	 * in progress. If true, fail the suspend operation; also throw
   1677 	 * a warning message notifying the failure. Note that Sun PCI
   1678 	 * hotplug spec recommends messages in cases of failure (but
   1679 	 * not flooding the console)
   1680 	 *
   1681 	 * Busy waiting for a short interval (500 millisecond ?) to see
   1682 	 * if the callback processing completes may be another idea. Since
   1683 	 * most of the callback processing involves a lot of work, it
   1684 	 * is safe to just fail the SUSPEND operation. It is definitely
   1685 	 * not bad to fail the SUSPEND operation if the driver is busy.
   1686 	 */
   1687 	delay_count = 0;
   1688 	while ((port->fp_soft_state & (FP_SOFT_IN_STATEC_CB |
   1689 	    FP_SOFT_IN_UNSOL_CB)) && (delay_count < 30)) {
   1690 		mutex_exit(&port->fp_mutex);
   1691 		delay_count++;
   1692 		delay(drv_usectohz(1000000));
   1693 		mutex_enter(&port->fp_mutex);
   1694 	}
   1695 
   1696 	if (port->fp_soft_state & (FP_SOFT_IN_STATEC_CB |
   1697 	    FP_SOFT_IN_UNSOL_CB)) {
   1698 		mutex_exit(&port->fp_mutex);
   1699 		cmn_err(CE_WARN, "fp(%d): FCA callback in progress: "
   1700 		    " Failing suspend", port->fp_instance);
   1701 		return (DDI_FAILURE);
   1702 	}
   1703 
   1704 	/*
   1705 	 * Check of FC port thread is busy
   1706 	 */
   1707 	if (port->fp_job_head) {
   1708 		mutex_exit(&port->fp_mutex);
   1709 		FP_TRACE(FP_NHEAD2(9, 0),
   1710 		    "FC port thread is busy: Failing suspend");
   1711 		return (DDI_FAILURE);
   1712 	}
   1713 	port->fp_soft_state |= FP_SOFT_SUSPEND;
   1714 
   1715 	fp_suspend_all(port);
   1716 	mutex_exit(&port->fp_mutex);
   1717 
   1718 	return (DDI_SUCCESS);
   1719 }
   1720 
   1721 
   1722 /*
   1723  * Prepare for graceful power down of a FC port
   1724  */
   1725 static int
   1726 fp_power_down(fc_local_port_t *port)
   1727 {
   1728 	ASSERT(MUTEX_HELD(&port->fp_mutex));
   1729 
   1730 	/*
   1731 	 * Power down request followed by a DDI_SUSPEND should
   1732 	 * never happen; If it does return DDI_SUCCESS
   1733 	 */
   1734 	if (port->fp_soft_state & FP_SOFT_SUSPEND) {
   1735 		port->fp_soft_state |= FP_SOFT_POWER_DOWN;
   1736 		return (DDI_SUCCESS);
   1737 	}
   1738 
   1739 	/*
   1740 	 * If the port is already power suspended, there
   1741 	 * is nothing else to do, So return DDI_SUCCESS,
   1742 	 */
   1743 	if (port->fp_soft_state & FP_SOFT_POWER_DOWN) {
   1744 		return (DDI_SUCCESS);
   1745 	}
   1746 
   1747 	/*
   1748 	 * Check if an unsolicited callback or state change handling
   1749 	 * is in progress. If true, fail the PM suspend operation.
   1750 	 * But don't print a message unless the verbosity of the
   1751 	 * driver desires otherwise.
   1752 	 */
   1753 	if ((port->fp_soft_state & FP_SOFT_IN_STATEC_CB) ||
   1754 	    (port->fp_soft_state & FP_SOFT_IN_UNSOL_CB)) {
   1755 		FP_TRACE(FP_NHEAD2(9, 0),
   1756 		    "Unsolicited callback in progress: Failing power down");
   1757 		return (DDI_FAILURE);
   1758 	}
   1759 
   1760 	/*
   1761 	 * Check of FC port thread is busy
   1762 	 */
   1763 	if (port->fp_job_head) {
   1764 		FP_TRACE(FP_NHEAD2(9, 0),
   1765 		    "FC port thread is busy: Failing power down");
   1766 		return (DDI_FAILURE);
   1767 	}
   1768 	port->fp_soft_state |= FP_SOFT_POWER_DOWN;
   1769 
   1770 	/*
   1771 	 * check if the ULPs are ready for power down
   1772 	 */
   1773 	mutex_exit(&port->fp_mutex);
   1774 	if (fctl_detach_ulps(port, FC_CMD_POWER_DOWN,
   1775 	    &modlinkage) != FC_SUCCESS) {
   1776 		mutex_enter(&port->fp_mutex);
   1777 		port->fp_soft_state &= ~FP_SOFT_POWER_DOWN;
   1778 		mutex_exit(&port->fp_mutex);
   1779 
   1780 		/*
   1781 		 * Power back up the obedient ULPs that went down
   1782 		 */
   1783 		fp_attach_ulps(port, FC_CMD_POWER_UP);
   1784 
   1785 		FP_TRACE(FP_NHEAD2(9, 0),
   1786 		    "ULP(s) busy, detach_ulps failed. Failing power down");
   1787 		mutex_enter(&port->fp_mutex);
   1788 		return (DDI_FAILURE);
   1789 	}
   1790 	mutex_enter(&port->fp_mutex);
   1791 
   1792 	fp_suspend_all(port);
   1793 
   1794 	return (DDI_SUCCESS);
   1795 }
   1796 
   1797 
   1798 /*
   1799  * Suspend the entire FC port
   1800  */
   1801 static void
   1802 fp_suspend_all(fc_local_port_t *port)
   1803 {
   1804 	int			index;
   1805 	struct pwwn_hash	*head;
   1806 	fc_remote_port_t	*pd;
   1807 
   1808 	ASSERT(MUTEX_HELD(&port->fp_mutex));
   1809 
   1810 	if (port->fp_wait_tid != 0) {
   1811 		timeout_id_t	tid;
   1812 
   1813 		tid = port->fp_wait_tid;
   1814 		port->fp_wait_tid = (timeout_id_t)NULL;
   1815 		mutex_exit(&port->fp_mutex);
   1816 		(void) untimeout(tid);
   1817 		mutex_enter(&port->fp_mutex);
   1818 		port->fp_restore |= FP_RESTORE_WAIT_TIMEOUT;
   1819 	}
   1820 
   1821 	if (port->fp_offline_tid) {
   1822 		timeout_id_t	tid;
   1823 
   1824 		tid = port->fp_offline_tid;
   1825 		port->fp_offline_tid = (timeout_id_t)NULL;
   1826 		mutex_exit(&port->fp_mutex);
   1827 		(void) untimeout(tid);
   1828 		mutex_enter(&port->fp_mutex);
   1829 		port->fp_restore |= FP_RESTORE_OFFLINE_TIMEOUT;
   1830 	}
   1831 	mutex_exit(&port->fp_mutex);
   1832 	port->fp_fca_tran->fca_unbind_port(port->fp_fca_handle);
   1833 	mutex_enter(&port->fp_mutex);
   1834 
   1835 	/*
   1836 	 * Mark all devices as OLD, and reset the LOGIN state as well
   1837 	 * (this will force the ULPs to perform a LOGIN after calling
   1838 	 * fc_portgetmap() during RESUME/PM_RESUME)
   1839 	 */
   1840 	for (index = 0; index < pwwn_table_size; index++) {
   1841 		head = &port->fp_pwwn_table[index];
   1842 		pd = head->pwwn_head;
   1843 		while (pd != NULL) {
   1844 			mutex_enter(&pd->pd_mutex);
   1845 			fp_remote_port_offline(pd);
   1846 			fctl_delist_did_table(port, pd);
   1847 			pd->pd_state = PORT_DEVICE_VALID;
   1848 			pd->pd_login_count = 0;
   1849 			mutex_exit(&pd->pd_mutex);
   1850 			pd = pd->pd_wwn_hnext;
   1851 		}
   1852 	}
   1853 }
   1854 
   1855 
   1856 /*
   1857  * fp_cache_constructor: Constructor function for kmem_cache_create(9F).
   1858  * Performs intializations for fc_packet_t structs.
   1859  * Returns 0 for success or -1 for failure.
   1860  *
   1861  * This function allocates DMA handles for both command and responses.
   1862  * Most of the ELSs used have both command and responses so it is strongly
   1863  * desired to move them to cache constructor routine.
   1864  *
   1865  * Context: Can sleep iff called with KM_SLEEP flag.
   1866  */
   1867 static int
   1868 fp_cache_constructor(void *buf, void *cdarg, int kmflags)
   1869 {
   1870 	int		(*cb) (caddr_t);
   1871 	fc_packet_t	*pkt;
   1872 	fp_cmd_t	*cmd = (fp_cmd_t *)buf;
   1873 	fc_local_port_t *port = (fc_local_port_t *)cdarg;
   1874 
   1875 	cb = (kmflags == KM_SLEEP) ? DDI_DMA_SLEEP : DDI_DMA_DONTWAIT;
   1876 
   1877 	cmd->cmd_next = NULL;
   1878 	cmd->cmd_flags = 0;
   1879 	cmd->cmd_dflags = 0;
   1880 	cmd->cmd_job = NULL;
   1881 	cmd->cmd_port = port;
   1882 	pkt = &cmd->cmd_pkt;
   1883 
   1884 	if (!(port->fp_soft_state & FP_SOFT_FCA_IS_NODMA)) {
   1885 		if (ddi_dma_alloc_handle(port->fp_fca_dip,
   1886 		    port->fp_fca_tran->fca_dma_attr, cb, NULL,
   1887 		    &pkt->pkt_cmd_dma) != DDI_SUCCESS) {
   1888 			return (-1);
   1889 		}
   1890 
   1891 		if (ddi_dma_alloc_handle(port->fp_fca_dip,
   1892 		    port->fp_fca_tran->fca_dma_attr, cb, NULL,
   1893 		    &pkt->pkt_resp_dma) != DDI_SUCCESS) {
   1894 			ddi_dma_free_handle(&pkt->pkt_cmd_dma);
   1895 			return (-1);
   1896 		}
   1897 	} else {
   1898 		pkt->pkt_cmd_dma = 0;
   1899 		pkt->pkt_resp_dma = 0;
   1900 	}
   1901 
   1902 	pkt->pkt_cmd_acc = pkt->pkt_resp_acc = NULL;
   1903 	pkt->pkt_cmd_cookie_cnt = pkt->pkt_resp_cookie_cnt =
   1904 	    pkt->pkt_data_cookie_cnt = 0;
   1905 	pkt->pkt_cmd_cookie = pkt->pkt_resp_cookie =
   1906 	    pkt->pkt_data_cookie = NULL;
   1907 	pkt->pkt_fca_private = (caddr_t)buf + sizeof (fp_cmd_t);
   1908 
   1909 	return (0);
   1910 }
   1911 
   1912 
   1913 /*
   1914  * fp_cache_destructor: Destructor function for kmem_cache_create().
   1915  * Performs un-intializations for fc_packet_t structs.
   1916  */
   1917 /* ARGSUSED */
   1918 static void
   1919 fp_cache_destructor(void *buf, void *cdarg)
   1920 {
   1921 	fp_cmd_t	*cmd = (fp_cmd_t *)buf;
   1922 	fc_packet_t	*pkt;
   1923 
   1924 	pkt = &cmd->cmd_pkt;
   1925 	if (pkt->pkt_cmd_dma) {
   1926 		ddi_dma_free_handle(&pkt->pkt_cmd_dma);
   1927 	}
   1928 
   1929 	if (pkt->pkt_resp_dma) {
   1930 		ddi_dma_free_handle(&pkt->pkt_resp_dma);
   1931 	}
   1932 }
   1933 
   1934 
   1935 /*
   1936  * Packet allocation for ELS and any other port driver commands
   1937  *
   1938  * Some ELSs like FLOGI and PLOGI are critical for topology and
   1939  * device discovery and a system's inability to allocate memory
   1940  * or DVMA resources while performing some of these critical ELSs
   1941  * cause a lot of problem. While memory allocation failures are
   1942  * rare, DVMA resource failures are common as the applications
   1943  * are becoming more and more powerful on huge servers.	 So it
   1944  * is desirable to have a framework support to reserve a fragment
   1945  * of DVMA. So until this is fixed the correct way, the suffering
   1946  * is huge whenever a LIP happens at a time DVMA resources are
   1947  * drained out completely - So an attempt needs to be made to
   1948  * KM_SLEEP while requesting for these resources, hoping that
   1949  * the requests won't hang forever.
   1950  *
   1951  * The fc_remote_port_t argument is stored into the pkt_pd field in the
   1952  * fc_packet_t struct prior to the fc_ulp_init_packet() call.  This
   1953  * ensures that the pd_ref_count for the fc_remote_port_t is valid.
   1954  * If there is no fc_remote_port_t associated with the fc_packet_t, then
   1955  * fp_alloc_pkt() must be called with pd set to NULL.
   1956  *
   1957  * fp/fctl will resue fp_cmd_t somewhere, and change pkt_cmdlen/rsplen,
   1958  * actually, it's a design fault. But there's no problem for physical
   1959  * FCAs. But it will cause memory leak or panic for virtual FCAs like fcoei.
   1960  *
   1961  * For FCAs that don't support DMA, such as fcoei, we will use
   1962  * pkt_fctl_rsvd1/rsvd2 to keep the real cmd_len/resp_len.
   1963  */
   1964 
   1965 static fp_cmd_t *
   1966 fp_alloc_pkt(fc_local_port_t *port, int cmd_len, int resp_len, int kmflags,
   1967     fc_remote_port_t *pd)
   1968 {
   1969 	int		rval;
   1970 	ulong_t		real_len;
   1971 	fp_cmd_t	*cmd;
   1972 	fc_packet_t	*pkt;
   1973 	int		(*cb) (caddr_t);
   1974 	ddi_dma_cookie_t	pkt_cookie;
   1975 	ddi_dma_cookie_t	*cp;
   1976 	uint32_t		cnt;
   1977 
   1978 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
   1979 
   1980 	cb = (kmflags == KM_SLEEP) ? DDI_DMA_SLEEP : DDI_DMA_DONTWAIT;
   1981 
   1982 	cmd = (fp_cmd_t *)kmem_cache_alloc(port->fp_pkt_cache, kmflags);
   1983 	if (cmd == NULL) {
   1984 		return (cmd);
   1985 	}
   1986 
   1987 	cmd->cmd_ulp_pkt = NULL;
   1988 	cmd->cmd_flags = 0;
   1989 	pkt = &cmd->cmd_pkt;
   1990 	ASSERT(cmd->cmd_dflags == 0);
   1991 
   1992 	pkt->pkt_datalen = 0;
   1993 	pkt->pkt_data = NULL;
   1994 	pkt->pkt_state = 0;
   1995 	pkt->pkt_action = 0;
   1996 	pkt->pkt_reason = 0;
   1997 	pkt->pkt_expln = 0;
   1998 	pkt->pkt_cmd = NULL;
   1999 	pkt->pkt_resp = NULL;
   2000 	pkt->pkt_fctl_rsvd1 = NULL;
   2001 	pkt->pkt_fctl_rsvd2 = NULL;
   2002 
   2003 	/*
   2004 	 * Init pkt_pd with the given pointer; this must be done _before_
   2005 	 * the call to fc_ulp_init_packet().
   2006 	 */
   2007 	pkt->pkt_pd = pd;
   2008 
   2009 	/* Now call the FCA driver to init its private, per-packet fields */
   2010 	if (fc_ulp_init_packet((opaque_t)port, pkt, kmflags) != FC_SUCCESS) {
   2011 		goto alloc_pkt_failed;
   2012 	}
   2013 
   2014 	if (cmd_len && !(port->fp_soft_state & FP_SOFT_FCA_IS_NODMA)) {
   2015 		ASSERT(pkt->pkt_cmd_dma != NULL);
   2016 
   2017 		rval = ddi_dma_mem_alloc(pkt->pkt_cmd_dma, cmd_len,
   2018 		    port->fp_fca_tran->fca_acc_attr, DDI_DMA_CONSISTENT,
   2019 		    cb, NULL, (caddr_t *)&pkt->pkt_cmd, &real_len,
   2020 		    &pkt->pkt_cmd_acc);
   2021 
   2022 		if (rval != DDI_SUCCESS) {
   2023 			goto alloc_pkt_failed;
   2024 		}
   2025 		cmd->cmd_dflags |= FP_CMD_VALID_DMA_MEM;
   2026 
   2027 		if (real_len < cmd_len) {
   2028 			goto alloc_pkt_failed;
   2029 		}
   2030 
   2031 		rval = ddi_dma_addr_bind_handle(pkt->pkt_cmd_dma, NULL,
   2032 		    pkt->pkt_cmd, real_len, DDI_DMA_WRITE |
   2033 		    DDI_DMA_CONSISTENT, cb, NULL,
   2034 		    &pkt_cookie, &pkt->pkt_cmd_cookie_cnt);
   2035 
   2036 		if (rval != DDI_DMA_MAPPED) {
   2037 			goto alloc_pkt_failed;
   2038 		}
   2039 
   2040 		cmd->cmd_dflags |= FP_CMD_VALID_DMA_BIND;
   2041 
   2042 		if (pkt->pkt_cmd_cookie_cnt >
   2043 		    port->fp_fca_tran->fca_dma_attr->dma_attr_sgllen) {
   2044 			goto alloc_pkt_failed;
   2045 		}
   2046 
   2047 		ASSERT(pkt->pkt_cmd_cookie_cnt != 0);
   2048 
   2049 		cp = pkt->pkt_cmd_cookie = (ddi_dma_cookie_t *)kmem_alloc(
   2050 		    pkt->pkt_cmd_cookie_cnt * sizeof (pkt_cookie),
   2051 		    KM_NOSLEEP);
   2052 
   2053 		if (cp == NULL) {
   2054 			goto alloc_pkt_failed;
   2055 		}
   2056 
   2057 		*cp = pkt_cookie;
   2058 		cp++;
   2059 		for (cnt = 1; cnt < pkt->pkt_cmd_cookie_cnt; cnt++, cp++) {
   2060 			ddi_dma_nextcookie(pkt->pkt_cmd_dma, &pkt_cookie);
   2061 			*cp = pkt_cookie;
   2062 		}
   2063 	} else if (cmd_len != 0) {
   2064 		pkt->pkt_cmd = kmem_alloc(cmd_len, KM_SLEEP);
   2065 		pkt->pkt_fctl_rsvd1 = (opaque_t)(uintptr_t)cmd_len;
   2066 	}
   2067 
   2068 	if (resp_len && !(port->fp_soft_state & FP_SOFT_FCA_IS_NODMA)) {
   2069 		ASSERT(pkt->pkt_resp_dma != NULL);
   2070 
   2071 		rval = ddi_dma_mem_alloc(pkt->pkt_resp_dma, resp_len,
   2072 		    port->fp_fca_tran->fca_acc_attr,
   2073 		    DDI_DMA_CONSISTENT, cb, NULL,
   2074 		    (caddr_t *)&pkt->pkt_resp, &real_len,
   2075 		    &pkt->pkt_resp_acc);
   2076 
   2077 		if (rval != DDI_SUCCESS) {
   2078 			goto alloc_pkt_failed;
   2079 		}
   2080 		cmd->cmd_dflags |= FP_RESP_VALID_DMA_MEM;
   2081 
   2082 		if (real_len < resp_len) {
   2083 			goto alloc_pkt_failed;
   2084 		}
   2085 
   2086 		rval = ddi_dma_addr_bind_handle(pkt->pkt_resp_dma, NULL,
   2087 		    pkt->pkt_resp, real_len, DDI_DMA_READ |
   2088 		    DDI_DMA_CONSISTENT, cb, NULL,
   2089 		    &pkt_cookie, &pkt->pkt_resp_cookie_cnt);
   2090 
   2091 		if (rval != DDI_DMA_MAPPED) {
   2092 			goto alloc_pkt_failed;
   2093 		}
   2094 
   2095 		cmd->cmd_dflags |= FP_RESP_VALID_DMA_BIND;
   2096 
   2097 		if (pkt->pkt_resp_cookie_cnt >
   2098 		    port->fp_fca_tran->fca_dma_attr->dma_attr_sgllen) {
   2099 			goto alloc_pkt_failed;
   2100 		}
   2101 
   2102 		ASSERT(pkt->pkt_cmd_cookie_cnt != 0);
   2103 
   2104 		cp = pkt->pkt_resp_cookie = (ddi_dma_cookie_t *)kmem_alloc(
   2105 		    pkt->pkt_resp_cookie_cnt * sizeof (pkt_cookie),
   2106 		    KM_NOSLEEP);
   2107 
   2108 		if (cp == NULL) {
   2109 			goto alloc_pkt_failed;
   2110 		}
   2111 
   2112 		*cp = pkt_cookie;
   2113 		cp++;
   2114 		for (cnt = 1; cnt < pkt->pkt_resp_cookie_cnt; cnt++, cp++) {
   2115 			ddi_dma_nextcookie(pkt->pkt_resp_dma, &pkt_cookie);
   2116 			*cp = pkt_cookie;
   2117 		}
   2118 	} else if (resp_len != 0) {
   2119 		pkt->pkt_resp = kmem_alloc(resp_len, KM_SLEEP);
   2120 		pkt->pkt_fctl_rsvd2 = (opaque_t)(uintptr_t)resp_len;
   2121 	}
   2122 
   2123 	pkt->pkt_cmdlen = cmd_len;
   2124 	pkt->pkt_rsplen = resp_len;
   2125 	pkt->pkt_ulp_private = cmd;
   2126 
   2127 	return (cmd);
   2128 
   2129 alloc_pkt_failed:
   2130 
   2131 	fp_free_dma(cmd);
   2132 
   2133 	if (pkt->pkt_cmd_cookie != NULL) {
   2134 		kmem_free(pkt->pkt_cmd_cookie,
   2135 		    pkt->pkt_cmd_cookie_cnt * sizeof (ddi_dma_cookie_t));
   2136 		pkt->pkt_cmd_cookie = NULL;
   2137 	}
   2138 
   2139 	if (pkt->pkt_resp_cookie != NULL) {
   2140 		kmem_free(pkt->pkt_resp_cookie,
   2141 		    pkt->pkt_resp_cookie_cnt * sizeof (ddi_dma_cookie_t));
   2142 		pkt->pkt_resp_cookie = NULL;
   2143 	}
   2144 
   2145 	if (port->fp_soft_state & FP_SOFT_FCA_IS_NODMA) {
   2146 		if (pkt->pkt_cmd) {
   2147 			kmem_free(pkt->pkt_cmd, cmd_len);
   2148 		}
   2149 
   2150 		if (pkt->pkt_resp) {
   2151 			kmem_free(pkt->pkt_resp, resp_len);
   2152 		}
   2153 	}
   2154 
   2155 	kmem_cache_free(port->fp_pkt_cache, cmd);
   2156 
   2157 	return (NULL);
   2158 }
   2159 
   2160 
   2161 /*
   2162  * Free FC packet
   2163  */
   2164 static void
   2165 fp_free_pkt(fp_cmd_t *cmd)
   2166 {
   2167 	fc_local_port_t *port;
   2168 	fc_packet_t	*pkt;
   2169 
   2170 	ASSERT(!MUTEX_HELD(&cmd->cmd_port->fp_mutex));
   2171 
   2172 	cmd->cmd_next = NULL;
   2173 	cmd->cmd_job = NULL;
   2174 	pkt = &cmd->cmd_pkt;
   2175 	pkt->pkt_ulp_private = 0;
   2176 	pkt->pkt_tran_flags = 0;
   2177 	pkt->pkt_tran_type = 0;
   2178 	port = cmd->cmd_port;
   2179 
   2180 	if (pkt->pkt_cmd_cookie != NULL) {
   2181 		kmem_free(pkt->pkt_cmd_cookie, pkt->pkt_cmd_cookie_cnt *
   2182 		    sizeof (ddi_dma_cookie_t));
   2183 		pkt->pkt_cmd_cookie = NULL;
   2184 	}
   2185 
   2186 	if (pkt->pkt_resp_cookie != NULL) {
   2187 		kmem_free(pkt->pkt_resp_cookie, pkt->pkt_resp_cookie_cnt *
   2188 		    sizeof (ddi_dma_cookie_t));
   2189 		pkt->pkt_resp_cookie = NULL;
   2190 	}
   2191 
   2192 	if (port->fp_soft_state & FP_SOFT_FCA_IS_NODMA) {
   2193 		if (pkt->pkt_cmd) {
   2194 			kmem_free(pkt->pkt_cmd,
   2195 			    (uint32_t)(uintptr_t)pkt->pkt_fctl_rsvd1);
   2196 		}
   2197 
   2198 		if (pkt->pkt_resp) {
   2199 			kmem_free(pkt->pkt_resp,
   2200 			    (uint32_t)(uintptr_t)pkt->pkt_fctl_rsvd2);
   2201 		}
   2202 	}
   2203 
   2204 	fp_free_dma(cmd);
   2205 	(void) fc_ulp_uninit_packet((opaque_t)port, pkt);
   2206 	kmem_cache_free(port->fp_pkt_cache, (void *)cmd);
   2207 }
   2208 
   2209 
   2210 /*
   2211  * Release DVMA resources
   2212  */
   2213 static void
   2214 fp_free_dma(fp_cmd_t *cmd)
   2215 {
   2216 	fc_packet_t *pkt = &cmd->cmd_pkt;
   2217 
   2218 	pkt->pkt_cmdlen = 0;
   2219 	pkt->pkt_rsplen = 0;
   2220 	pkt->pkt_tran_type = 0;
   2221 	pkt->pkt_tran_flags = 0;
   2222 
   2223 	if (cmd->cmd_dflags & FP_CMD_VALID_DMA_BIND) {
   2224 		(void) ddi_dma_unbind_handle(pkt->pkt_cmd_dma);
   2225 	}
   2226 
   2227 	if (cmd->cmd_dflags & FP_CMD_VALID_DMA_MEM) {
   2228 		if (pkt->pkt_cmd_acc) {
   2229 			ddi_dma_mem_free(&pkt->pkt_cmd_acc);
   2230 		}
   2231 	}
   2232 
   2233 	if (cmd->cmd_dflags & FP_RESP_VALID_DMA_BIND) {
   2234 		(void) ddi_dma_unbind_handle(pkt->pkt_resp_dma);
   2235 	}
   2236 
   2237 	if (cmd->cmd_dflags & FP_RESP_VALID_DMA_MEM) {
   2238 		if (pkt->pkt_resp_acc) {
   2239 			ddi_dma_mem_free(&pkt->pkt_resp_acc);
   2240 		}
   2241 	}
   2242 	cmd->cmd_dflags = 0;
   2243 }
   2244 
   2245 
   2246 /*
   2247  * Dedicated thread to perform various activities.  One thread for
   2248  * each fc_local_port_t (driver soft state) instance.
   2249  * Note, this effectively works out to one thread for each local
   2250  * port, but there are also some Solaris taskq threads in use on a per-local
   2251  * port basis; these also need to be taken into consideration.
   2252  */
   2253 static void
   2254 fp_job_handler(fc_local_port_t *port)
   2255 {
   2256 	int			rval;
   2257 	uint32_t		*d_id;
   2258 	fc_remote_port_t	*pd;
   2259 	job_request_t		*job;
   2260 
   2261 #ifndef	__lock_lint
   2262 	/*
   2263 	 * Solaris-internal stuff for proper operation of kernel threads
   2264 	 * with Solaris CPR.
   2265 	 */
   2266 	CALLB_CPR_INIT(&port->fp_cpr_info, &port->fp_mutex,
   2267 	    callb_generic_cpr, "fp_job_handler");
   2268 #endif
   2269 
   2270 
   2271 	/* Loop forever waiting for work to do */
   2272 	for (;;) {
   2273 
   2274 		mutex_enter(&port->fp_mutex);
   2275 
   2276 		/*
   2277 		 * Sleep if no work to do right now, or if we want
   2278 		 * to suspend or power-down.
   2279 		 */
   2280 		while (port->fp_job_head == NULL ||
   2281 		    (port->fp_soft_state & (FP_SOFT_POWER_DOWN |
   2282 		    FP_SOFT_SUSPEND))) {
   2283 			CALLB_CPR_SAFE_BEGIN(&port->fp_cpr_info);
   2284 			cv_wait(&port->fp_cv, &port->fp_mutex);
   2285 			CALLB_CPR_SAFE_END(&port->fp_cpr_info, &port->fp_mutex);
   2286 		}
   2287 
   2288 		/*
   2289 		 * OK, we've just been woken up, so retrieve the next entry
   2290 		 * from the head of the job queue for this local port.
   2291 		 */
   2292 		job = fctl_deque_job(port);
   2293 
   2294 		/*
   2295 		 * Handle all the fp driver's supported job codes here
   2296 		 * in this big honkin' switch.
   2297 		 */
   2298 		switch (job->job_code) {
   2299 		case JOB_PORT_SHUTDOWN:
   2300 			/*
   2301 			 * fp_port_shutdown() is only called from here. This
   2302 			 * will prepare the local port instance (softstate)
   2303 			 * for detaching.  This cancels timeout callbacks,
   2304 			 * executes LOGOs with remote ports, cleans up tables,
   2305 			 * and deallocates data structs.
   2306 			 */
   2307 			fp_port_shutdown(port, job);
   2308 
   2309 			/*
   2310 			 * This will exit the job thread.
   2311 			 */
   2312 #ifndef __lock_lint
   2313 			CALLB_CPR_EXIT(&(port->fp_cpr_info));
   2314 #else
   2315 			mutex_exit(&port->fp_mutex);
   2316 #endif
   2317 			fctl_jobdone(job);
   2318 			thread_exit();
   2319 
   2320 			/* NOTREACHED */
   2321 
   2322 		case JOB_ATTACH_ULP: {
   2323 			/*
   2324 			 * This job is spawned in response to a ULP calling
   2325 			 * fc_ulp_add().
   2326 			 */
   2327 
   2328 			boolean_t do_attach_ulps = B_TRUE;
   2329 
   2330 			/*
   2331 			 * If fp is detaching, we don't want to call
   2332 			 * fp_startup_done as this asynchronous
   2333 			 * notification may interfere with the re-attach.
   2334 			 */
   2335 
   2336 			if (port->fp_soft_state & (FP_DETACH_INPROGRESS |
   2337 			    FP_SOFT_IN_DETACH | FP_DETACH_FAILED)) {
   2338 				do_attach_ulps = B_FALSE;
   2339 			} else {
   2340 				/*
   2341 				 * We are going to force the transport
   2342 				 * to attach to the ULPs, so set
   2343 				 * fp_ulp_attach.  This will keep any
   2344 				 * potential detach from occurring until
   2345 				 * we are done.
   2346 				 */
   2347 				port->fp_ulp_attach = 1;
   2348 			}
   2349 
   2350 			mutex_exit(&port->fp_mutex);
   2351 
   2352 			/*
   2353 			 * NOTE: Since we just dropped the mutex, there is now
   2354 			 * a race window where the fp_soft_state check above
   2355 			 * could change here.  This race is covered because an
   2356 			 * additional check was added in the functions hidden
   2357 			 * under fp_startup_done().
   2358 			 */
   2359 			if (do_attach_ulps == B_TRUE) {
   2360 				/*
   2361 				 * This goes thru a bit of a convoluted call
   2362 				 * chain before spawning off a DDI taskq
   2363 				 * request to perform the actual attach
   2364 				 * operations. Blocking can occur at a number
   2365 				 * of points.
   2366 				 */
   2367 				fp_startup_done((opaque_t)port, FC_PKT_SUCCESS);
   2368 			}
   2369 			job->job_result = FC_SUCCESS;
   2370 			fctl_jobdone(job);
   2371 			break;
   2372 		}
   2373 
   2374 		case JOB_ULP_NOTIFY: {
   2375 			/*
   2376 			 * Pass state change notifications up to any/all
   2377 			 * registered ULPs.
   2378 			 */
   2379 			uint32_t statec;
   2380 
   2381 			statec = job->job_ulp_listlen;
   2382 			if (statec == FC_STATE_RESET_REQUESTED) {
   2383 				port->fp_last_task = port->fp_task;
   2384 				port->fp_task = FP_TASK_OFFLINE;
   2385 				fp_port_offline(port, 0);
   2386 				port->fp_task = port->fp_last_task;
   2387 				port->fp_last_task = FP_TASK_IDLE;
   2388 			}
   2389 
   2390 			if (--port->fp_statec_busy == 0) {
   2391 				port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
   2392 			}
   2393 
   2394 			mutex_exit(&port->fp_mutex);
   2395 
   2396 			job->job_result = fp_ulp_notify(port, statec, KM_SLEEP);
   2397 			fctl_jobdone(job);
   2398 			break;
   2399 		}
   2400 
   2401 		case JOB_PLOGI_ONE:
   2402 			/*
   2403 			 * Issue a PLOGI to a single remote port. Multiple
   2404 			 * PLOGIs to different remote ports may occur in
   2405 			 * parallel.
   2406 			 * This can create the fc_remote_port_t if it does not
   2407 			 * already exist.
   2408 			 */
   2409 
   2410 			mutex_exit(&port->fp_mutex);
   2411 			d_id = (uint32_t *)job->job_private;
   2412 			pd = fctl_get_remote_port_by_did(port, *d_id);
   2413 
   2414 			if (pd) {
   2415 				mutex_enter(&pd->pd_mutex);
   2416 				if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
   2417 					pd->pd_login_count++;
   2418 					mutex_exit(&pd->pd_mutex);
   2419 					job->job_result = FC_SUCCESS;
   2420 					fctl_jobdone(job);
   2421 					break;
   2422 				}
   2423 				mutex_exit(&pd->pd_mutex);
   2424 			} else {
   2425 				mutex_enter(&port->fp_mutex);
   2426 				if (FC_IS_TOP_SWITCH(port->fp_topology)) {
   2427 					mutex_exit(&port->fp_mutex);
   2428 					pd = fp_create_remote_port_by_ns(port,
   2429 					    *d_id, KM_SLEEP);
   2430 					if (pd == NULL) {
   2431 						job->job_result = FC_FAILURE;
   2432 						fctl_jobdone(job);
   2433 						break;
   2434 					}
   2435 				} else {
   2436 					mutex_exit(&port->fp_mutex);
   2437 				}
   2438 			}
   2439 
   2440 			job->job_flags |= JOB_TYPE_FP_ASYNC;
   2441 			job->job_counter = 1;
   2442 
   2443 			rval = fp_port_login(port, *d_id, job,
   2444 			    FP_CMD_PLOGI_RETAIN, KM_SLEEP, pd, NULL);
   2445 
   2446 			if (rval != FC_SUCCESS) {
   2447 				job->job_result = rval;
   2448 				fctl_jobdone(job);
   2449 			}
   2450 			break;
   2451 
   2452 		case JOB_LOGO_ONE: {
   2453 			/*
   2454 			 * Issue a PLOGO to a single remote port. Multiple
   2455 			 * PLOGOs to different remote ports may occur in
   2456 			 * parallel.
   2457 			 */
   2458 			fc_remote_port_t *pd;
   2459 
   2460 #ifndef	__lock_lint
   2461 			ASSERT(job->job_counter > 0);
   2462 #endif
   2463 
   2464 			pd = (fc_remote_port_t *)job->job_ulp_pkts;
   2465 
   2466 			mutex_enter(&pd->pd_mutex);
   2467 			if (pd->pd_state != PORT_DEVICE_LOGGED_IN) {
   2468 				mutex_exit(&pd->pd_mutex);
   2469 				job->job_result = FC_LOGINREQ;
   2470 				mutex_exit(&port->fp_mutex);
   2471 				fctl_jobdone(job);
   2472 				break;
   2473 			}
   2474 			if (pd->pd_login_count > 1) {
   2475 				pd->pd_login_count--;
   2476 				mutex_exit(&pd->pd_mutex);
   2477 				job->job_result = FC_SUCCESS;
   2478 				mutex_exit(&port->fp_mutex);
   2479 				fctl_jobdone(job);
   2480 				break;
   2481 			}
   2482 			mutex_exit(&pd->pd_mutex);
   2483 			mutex_exit(&port->fp_mutex);
   2484 			job->job_flags |= JOB_TYPE_FP_ASYNC;
   2485 			(void) fp_logout(port, pd, job);
   2486 			break;
   2487 		}
   2488 
   2489 		case JOB_FCIO_LOGIN:
   2490 			/*
   2491 			 * PLOGI initiated at ioctl request.
   2492 			 */
   2493 			mutex_exit(&port->fp_mutex);
   2494 			job->job_result =
   2495 			    fp_fcio_login(port, job->job_private, job);
   2496 			fctl_jobdone(job);
   2497 			break;
   2498 
   2499 		case JOB_FCIO_LOGOUT:
   2500 			/*
   2501 			 * PLOGO initiated at ioctl request.
   2502 			 */
   2503 			mutex_exit(&port->fp_mutex);
   2504 			job->job_result =
   2505 			    fp_fcio_logout(port, job->job_private, job);
   2506 			fctl_jobdone(job);
   2507 			break;
   2508 
   2509 		case JOB_PORT_GETMAP:
   2510 		case JOB_PORT_GETMAP_PLOGI_ALL: {
   2511 			port->fp_last_task = port->fp_task;
   2512 			port->fp_task = FP_TASK_GETMAP;
   2513 
   2514 			switch (port->fp_topology) {
   2515 			case FC_TOP_PRIVATE_LOOP:
   2516 				job->job_counter = 1;
   2517 
   2518 				fp_get_loopmap(port, job);
   2519 				mutex_exit(&port->fp_mutex);
   2520 				fp_jobwait(job);
   2521 				fctl_fillout_map(port,
   2522 				    (fc_portmap_t **)job->job_private,
   2523 				    (uint32_t *)job->job_arg, 1, 0, 0);
   2524 				fctl_jobdone(job);
   2525 				mutex_enter(&port->fp_mutex);
   2526 				break;
   2527 
   2528 			case FC_TOP_PUBLIC_LOOP:
   2529 			case FC_TOP_FABRIC:
   2530 				mutex_exit(&port->fp_mutex);
   2531 				job->job_counter = 1;
   2532 
   2533 				job->job_result = fp_ns_getmap(port,
   2534 				    job, (fc_portmap_t **)job->job_private,
   2535 				    (uint32_t *)job->job_arg,
   2536 				    FCTL_GAN_START_ID);
   2537 				fctl_jobdone(job);
   2538 				mutex_enter(&port->fp_mutex);
   2539 				break;
   2540 
   2541 			case FC_TOP_PT_PT:
   2542 				mutex_exit(&port->fp_mutex);
   2543 				fctl_fillout_map(port,
   2544 				    (fc_portmap_t **)job->job_private,
   2545 				    (uint32_t *)job->job_arg, 1, 0, 0);
   2546 				fctl_jobdone(job);
   2547 				mutex_enter(&port->fp_mutex);
   2548 				break;
   2549 
   2550 			default:
   2551 				mutex_exit(&port->fp_mutex);
   2552 				fctl_jobdone(job);
   2553 				mutex_enter(&port->fp_mutex);
   2554 				break;
   2555 			}
   2556 			port->fp_task = port->fp_last_task;
   2557 			port->fp_last_task = FP_TASK_IDLE;
   2558 			mutex_exit(&port->fp_mutex);
   2559 			break;
   2560 		}
   2561 
   2562 		case JOB_PORT_OFFLINE: {
   2563 			fp_log_port_event(port, ESC_SUNFC_PORT_OFFLINE);
   2564 
   2565 			port->fp_last_task = port->fp_task;
   2566 			port->fp_task = FP_TASK_OFFLINE;
   2567 
   2568 			if (port->fp_statec_busy > 2) {
   2569 				job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION;
   2570 				fp_port_offline(port, 0);
   2571 				if (--port->fp_statec_busy == 0) {
   2572 					port->fp_soft_state &=
   2573 					    ~FP_SOFT_IN_STATEC_CB;
   2574 				}
   2575 			} else {
   2576 				fp_port_offline(port, 1);
   2577 			}
   2578 
   2579 			port->fp_task = port->fp_last_task;
   2580 			port->fp_last_task = FP_TASK_IDLE;
   2581 
   2582 			mutex_exit(&port->fp_mutex);
   2583 
   2584 			fctl_jobdone(job);
   2585 			break;
   2586 		}
   2587 
   2588 		case JOB_PORT_STARTUP: {
   2589 			if ((rval = fp_port_startup(port, job)) != FC_SUCCESS) {
   2590 				if (port->fp_statec_busy > 1) {
   2591 					mutex_exit(&port->fp_mutex);
   2592 					break;
   2593 				}
   2594 				mutex_exit(&port->fp_mutex);
   2595 
   2596 				FP_TRACE(FP_NHEAD2(9, rval),
   2597 				    "Topology discovery failed");
   2598 				break;
   2599 			}
   2600 
   2601 			/*
   2602 			 * Attempt building device handles in case
   2603 			 * of private Loop.
   2604 			 */
   2605 			if (port->fp_topology == FC_TOP_PRIVATE_LOOP) {
   2606 				job->job_counter = 1;
   2607 
   2608 				fp_get_loopmap(port, job);
   2609 				mutex_exit(&port->fp_mutex);
   2610 				fp_jobwait(job);
   2611 				mutex_enter(&port->fp_mutex);
   2612 				if (port->fp_lilp_map.lilp_magic < MAGIC_LIRP) {
   2613 					ASSERT(port->fp_total_devices == 0);
   2614 					port->fp_total_devices =
   2615 					    port->fp_dev_count;
   2616 				}
   2617 			} else if (FC_IS_TOP_SWITCH(port->fp_topology)) {
   2618 				/*
   2619 				 * Hack to avoid state changes going up early
   2620 				 */
   2621 				port->fp_statec_busy++;
   2622 				port->fp_soft_state |= FP_SOFT_IN_STATEC_CB;
   2623 
   2624 				job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION;
   2625 				fp_fabric_online(port, job);
   2626 				job->job_flags &= ~JOB_CANCEL_ULP_NOTIFICATION;
   2627 			}
   2628 			mutex_exit(&port->fp_mutex);
   2629 			fctl_jobdone(job);
   2630 			break;
   2631 		}
   2632 
   2633 		case JOB_PORT_ONLINE: {
   2634 			char		*newtop;
   2635 			char		*oldtop;
   2636 			uint32_t	old_top;
   2637 
   2638 			fp_log_port_event(port, ESC_SUNFC_PORT_ONLINE);
   2639 
   2640 			/*
   2641 			 * Bail out early if there are a lot of
   2642 			 * state changes in the pipeline
   2643 			 */
   2644 			if (port->fp_statec_busy > 1) {
   2645 				--port->fp_statec_busy;
   2646 				mutex_exit(&port->fp_mutex);
   2647 				fctl_jobdone(job);
   2648 				break;
   2649 			}
   2650 
   2651 			switch (old_top = port->fp_topology) {
   2652 			case FC_TOP_PRIVATE_LOOP:
   2653 				oldtop = "Private Loop";
   2654 				break;
   2655 
   2656 			case FC_TOP_PUBLIC_LOOP:
   2657 				oldtop = "Public Loop";
   2658 				break;
   2659 
   2660 			case FC_TOP_PT_PT:
   2661 				oldtop = "Point to Point";
   2662 				break;
   2663 
   2664 			case FC_TOP_FABRIC:
   2665 				oldtop = "Fabric";
   2666 				break;
   2667 
   2668 			default:
   2669 				oldtop = NULL;
   2670 				break;
   2671 			}
   2672 
   2673 			port->fp_last_task = port->fp_task;
   2674 			port->fp_task = FP_TASK_ONLINE;
   2675 
   2676 			if ((rval = fp_port_startup(port, job)) != FC_SUCCESS) {
   2677 
   2678 				port->fp_task = port->fp_last_task;
   2679 				port->fp_last_task = FP_TASK_IDLE;
   2680 
   2681 				if (port->fp_statec_busy > 1) {
   2682 					--port->fp_statec_busy;
   2683 					mutex_exit(&port->fp_mutex);
   2684 					break;
   2685 				}
   2686 
   2687 				port->fp_state = FC_STATE_OFFLINE;
   2688 
   2689 				FP_TRACE(FP_NHEAD2(9, rval),
   2690 				    "Topology discovery failed");
   2691 
   2692 				if (--port->fp_statec_busy == 0) {
   2693 					port->fp_soft_state &=
   2694 					    ~FP_SOFT_IN_STATEC_CB;
   2695 				}
   2696 
   2697 				if (port->fp_offline_tid == NULL) {
   2698 					port->fp_offline_tid =
   2699 					    timeout(fp_offline_timeout,
   2700 					    (caddr_t)port, fp_offline_ticks);
   2701 				}
   2702 
   2703 				mutex_exit(&port->fp_mutex);
   2704 				break;
   2705 			}
   2706 
   2707 			switch (port->fp_topology) {
   2708 			case FC_TOP_PRIVATE_LOOP:
   2709 				newtop = "Private Loop";
   2710 				break;
   2711 
   2712 			case FC_TOP_PUBLIC_LOOP:
   2713 				newtop = "Public Loop";
   2714 				break;
   2715 
   2716 			case FC_TOP_PT_PT:
   2717 				newtop = "Point to Point";
   2718 				break;
   2719 
   2720 			case FC_TOP_FABRIC:
   2721 				newtop = "Fabric";
   2722 				break;
   2723 
   2724 			default:
   2725 				newtop = NULL;
   2726 				break;
   2727 			}
   2728 
   2729 			if (oldtop && newtop && strcmp(oldtop, newtop)) {
   2730 				fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
   2731 				    "Change in FC Topology old = %s new = %s",
   2732 				    oldtop, newtop);
   2733 			}
   2734 
   2735 			switch (port->fp_topology) {
   2736 			case FC_TOP_PRIVATE_LOOP: {
   2737 				int orphan = (old_top == FC_TOP_FABRIC ||
   2738 				    old_top == FC_TOP_PUBLIC_LOOP) ? 1 : 0;
   2739 
   2740 				mutex_exit(&port->fp_mutex);
   2741 				fp_loop_online(port, job, orphan);
   2742 				break;
   2743 			}
   2744 
   2745 			case FC_TOP_PUBLIC_LOOP:
   2746 				/* FALLTHROUGH */
   2747 			case FC_TOP_FABRIC:
   2748 				fp_fabric_online(port, job);
   2749 				mutex_exit(&port->fp_mutex);
   2750 				break;
   2751 
   2752 			case FC_TOP_PT_PT:
   2753 				fp_p2p_online(port, job);
   2754 				mutex_exit(&port->fp_mutex);
   2755 				break;
   2756 
   2757 			default:
   2758 				if (--port->fp_statec_busy != 0) {
   2759 					/*
   2760 					 * Watch curiously at what the next
   2761 					 * state transition can do.
   2762 					 */
   2763 					mutex_exit(&port->fp_mutex);
   2764 					break;
   2765 				}
   2766 
   2767 				FP_TRACE(FP_NHEAD2(9, 0),
   2768 				    "Topology Unknown, Offlining the port..");
   2769 
   2770 				port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
   2771 				port->fp_state = FC_STATE_OFFLINE;
   2772 
   2773 				if (port->fp_offline_tid == NULL) {
   2774 					port->fp_offline_tid =
   2775 					    timeout(fp_offline_timeout,
   2776 					    (caddr_t)port, fp_offline_ticks);
   2777 				}
   2778 				mutex_exit(&port->fp_mutex);
   2779 				break;
   2780 			}
   2781 
   2782 			mutex_enter(&port->fp_mutex);
   2783 
   2784 			port->fp_task = port->fp_last_task;
   2785 			port->fp_last_task = FP_TASK_IDLE;
   2786 
   2787 			mutex_exit(&port->fp_mutex);
   2788 
   2789 			fctl_jobdone(job);
   2790 			break;
   2791 		}
   2792 
   2793 		case JOB_PLOGI_GROUP: {
   2794 			mutex_exit(&port->fp_mutex);
   2795 			fp_plogi_group(port, job);
   2796 			break;
   2797 		}
   2798 
   2799 		case JOB_UNSOL_REQUEST: {
   2800 			mutex_exit(&port->fp_mutex);
   2801 			fp_handle_unsol_buf(port,
   2802 			    (fc_unsol_buf_t *)job->job_private, job);
   2803 			fctl_dealloc_job(job);
   2804 			break;
   2805 		}
   2806 
   2807 		case JOB_NS_CMD: {
   2808 			fctl_ns_req_t *ns_cmd;
   2809 
   2810 			mutex_exit(&port->fp_mutex);
   2811 
   2812 			job->job_flags |= JOB_TYPE_FP_ASYNC;
   2813 			ns_cmd = (fctl_ns_req_t *)job->job_private;
   2814 			if (ns_cmd->ns_cmd_code < NS_GA_NXT ||
   2815 			    ns_cmd->ns_cmd_code > NS_DA_ID) {
   2816 				job->job_result = FC_BADCMD;
   2817 				fctl_jobdone(job);
   2818 				break;
   2819 			}
   2820 
   2821 			if (FC_IS_CMD_A_REG(ns_cmd->ns_cmd_code)) {
   2822 				if (ns_cmd->ns_pd != NULL) {
   2823 					job->job_result = FC_BADOBJECT;
   2824 					fctl_jobdone(job);
   2825 					break;
   2826 				}
   2827 
   2828 				job->job_counter = 1;
   2829 
   2830 				rval = fp_ns_reg(port, ns_cmd->ns_pd,
   2831 				    ns_cmd->ns_cmd_code, job, 0, KM_SLEEP);
   2832 
   2833 				if (rval != FC_SUCCESS) {
   2834 					job->job_result = rval;
   2835 					fctl_jobdone(job);
   2836 				}
   2837 				break;
   2838 			}
   2839 			job->job_result = FC_SUCCESS;
   2840 			job->job_counter = 1;
   2841 
   2842 			rval = fp_ns_query(port, ns_cmd, job, 0, KM_SLEEP);
   2843 			if (rval != FC_SUCCESS) {
   2844 				fctl_jobdone(job);
   2845 			}
   2846 			break;
   2847 		}
   2848 
   2849 		case JOB_LINK_RESET: {
   2850 			la_wwn_t *pwwn;
   2851 			uint32_t topology;
   2852 
   2853 			pwwn = (la_wwn_t *)job->job_private;
   2854 			ASSERT(pwwn != NULL);
   2855 
   2856 			topology = port->fp_topology;
   2857 			mutex_exit(&port->fp_mutex);
   2858 
   2859 			if (fctl_is_wwn_zero(pwwn) == FC_SUCCESS ||
   2860 			    topology == FC_TOP_PRIVATE_LOOP) {
   2861 				job->job_flags |= JOB_TYPE_FP_ASYNC;
   2862 				rval = port->fp_fca_tran->fca_reset(
   2863 				    port->fp_fca_handle, FC_FCA_LINK_RESET);
   2864 				job->job_result = rval;
   2865 				fp_jobdone(job);
   2866 			} else {
   2867 				ASSERT((job->job_flags &
   2868 				    JOB_TYPE_FP_ASYNC) == 0);
   2869 
   2870 				if (FC_IS_TOP_SWITCH(topology)) {
   2871 					rval = fp_remote_lip(port, pwwn,
   2872 					    KM_SLEEP, job);
   2873 				} else {
   2874 					rval = FC_FAILURE;
   2875 				}
   2876 				if (rval != FC_SUCCESS) {
   2877 					job->job_result = rval;
   2878 				}
   2879 				fctl_jobdone(job);
   2880 			}
   2881 			break;
   2882 		}
   2883 
   2884 		default:
   2885 			mutex_exit(&port->fp_mutex);
   2886 			job->job_result = FC_BADCMD;
   2887 			fctl_jobdone(job);
   2888 			break;
   2889 		}
   2890 	}
   2891 	/* NOTREACHED */
   2892 }
   2893 
   2894 
   2895 /*
   2896  * Perform FC port bring up initialization
   2897  */
   2898 static int
   2899 fp_port_startup(fc_local_port_t *port, job_request_t *job)
   2900 {
   2901 	int		rval;
   2902 	uint32_t	state;
   2903 	uint32_t	src_id;
   2904 	fc_lilpmap_t	*lilp_map;
   2905 
   2906 	ASSERT(MUTEX_HELD(&port->fp_mutex));
   2907 	ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
   2908 
   2909 	FP_DTRACE(FP_NHEAD1(2, 0), "Entering fp_port_startup;"
   2910 	    " port=%p, job=%p", port, job);
   2911 
   2912 	port->fp_topology = FC_TOP_UNKNOWN;
   2913 	port->fp_port_id.port_id = 0;
   2914 	state = FC_PORT_STATE_MASK(port->fp_state);
   2915 
   2916 	if (state == FC_STATE_OFFLINE) {
   2917 		port->fp_port_type.port_type = FC_NS_PORT_UNKNOWN;
   2918 		job->job_result = FC_OFFLINE;
   2919 		mutex_exit(&port->fp_mutex);
   2920 		fctl_jobdone(job);
   2921 		mutex_enter(&port->fp_mutex);
   2922 		return (FC_OFFLINE);
   2923 	}
   2924 
   2925 	if (state == FC_STATE_LOOP) {
   2926 		port->fp_port_type.port_type = FC_NS_PORT_NL;
   2927 		mutex_exit(&port->fp_mutex);
   2928 
   2929 		lilp_map = &port->fp_lilp_map;
   2930 		if ((rval = fp_get_lilpmap(port, lilp_map)) != FC_SUCCESS) {
   2931 			job->job_result = FC_FAILURE;
   2932 			fctl_jobdone(job);
   2933 
   2934 			FP_TRACE(FP_NHEAD1(9, rval),
   2935 			    "LILP map Invalid or not present");
   2936 			mutex_enter(&port->fp_mutex);
   2937 			return (FC_FAILURE);
   2938 		}
   2939 
   2940 		if (lilp_map->lilp_length == 0) {
   2941 			job->job_result = FC_NO_MAP;
   2942 			fctl_jobdone(job);
   2943 			fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
   2944 			    "LILP map length zero");
   2945 			mutex_enter(&port->fp_mutex);
   2946 			return (FC_NO_MAP);
   2947 		}
   2948 		src_id = lilp_map->lilp_myalpa & 0xFF;
   2949 	} else {
   2950 		fc_remote_port_t	*pd;
   2951 		fc_fca_pm_t		pm;
   2952 		fc_fca_p2p_info_t	p2p_info;
   2953 		int			pd_recepient;
   2954 
   2955 		/*
   2956 		 * Get P2P remote port info if possible
   2957 		 */
   2958 		bzero((caddr_t)&pm, sizeof (pm));
   2959 
   2960 		pm.pm_cmd_flags = FC_FCA_PM_READ;
   2961 		pm.pm_cmd_code = FC_PORT_GET_P2P_INFO;
   2962 		pm.pm_data_len = sizeof (fc_fca_p2p_info_t);
   2963 		pm.pm_data_buf = (caddr_t)&p2p_info;
   2964 
   2965 		rval = port->fp_fca_tran->fca_port_manage(
   2966 		    port->fp_fca_handle, &pm);
   2967 
   2968 		if (rval == FC_SUCCESS) {
   2969 			port->fp_port_id.port_id = p2p_info.fca_d_id;
   2970 			port->fp_port_type.port_type = FC_NS_PORT_N;
   2971 			port->fp_topology = FC_TOP_PT_PT;
   2972 			port->fp_total_devices = 1;
   2973 			pd_recepient = fctl_wwn_cmp(
   2974 			    &port->fp_service_params.nport_ww_name,
   2975 			    &p2p_info.pwwn) < 0 ?
   2976 			    PD_PLOGI_RECEPIENT : PD_PLOGI_INITIATOR;
   2977 			mutex_exit(&port->fp_mutex);
   2978 			pd = fctl_create_remote_port(port,
   2979 			    &p2p_info.nwwn,
   2980 			    &p2p_info.pwwn,
   2981 			    p2p_info.d_id,
   2982 			    pd_recepient, KM_NOSLEEP);
   2983 			FP_DTRACE(FP_NHEAD1(2, 0), "Exiting fp_port_startup;"
   2984 			    " P2P port=%p pd=%p fp %x pd %x", port, pd,
   2985 			    port->fp_port_id.port_id, p2p_info.d_id);
   2986 			mutex_enter(&port->fp_mutex);
   2987 			return (FC_SUCCESS);
   2988 		}
   2989 		port->fp_port_type.port_type = FC_NS_PORT_N;
   2990 		mutex_exit(&port->fp_mutex);
   2991 		src_id = 0;
   2992 	}
   2993 
   2994 	job->job_counter = 1;
   2995 	job->job_result = FC_SUCCESS;
   2996 
   2997 	if ((rval = fp_fabric_login(port, src_id, job, FP_CMD_PLOGI_DONT_CARE,
   2998 	    KM_SLEEP)) != FC_SUCCESS) {
   2999 		port->fp_port_type.port_type = FC_NS_PORT_UNKNOWN;
   3000 		job->job_result = FC_FAILURE;
   3001 		fctl_jobdone(job);
   3002 
   3003 		mutex_enter(&port->fp_mutex);
   3004 		if (port->fp_statec_busy <= 1) {
   3005 			mutex_exit(&port->fp_mutex);
   3006 			fp_printf(port, CE_NOTE, FP_LOG_ONLY, rval, NULL,
   3007 			    "Couldn't transport FLOGI");
   3008 			mutex_enter(&port->fp_mutex);
   3009 		}
   3010 		return (FC_FAILURE);
   3011 	}
   3012 
   3013 	fp_jobwait(job);
   3014 
   3015 	mutex_enter(&port->fp_mutex);
   3016 	if (job->job_result == FC_SUCCESS) {
   3017 		if (FC_IS_TOP_SWITCH(port->fp_topology)) {
   3018 			mutex_exit(&port->fp_mutex);
   3019 			fp_ns_init(port, job, KM_SLEEP);
   3020 			mutex_enter(&port->fp_mutex);
   3021 		}
   3022 	} else {
   3023 		if (state == FC_STATE_LOOP) {
   3024 			port->fp_topology = FC_TOP_PRIVATE_LOOP;
   3025 			port->fp_port_id.port_id =
   3026 			    port->fp_lilp_map.lilp_myalpa & 0xFF;
   3027 		}
   3028 	}
   3029 
   3030 	FP_DTRACE(FP_NHEAD1(2, 0), "Exiting fp_port_startup; port=%p, job=%p",
   3031 	    port, job);
   3032 
   3033 	return (FC_SUCCESS);
   3034 }
   3035 
   3036 
   3037 /*
   3038  * Perform ULP invocations following FC port startup
   3039  */
   3040 /* ARGSUSED */
   3041 static void
   3042 fp_startup_done(opaque_t arg, uchar_t result)
   3043 {
   3044 	fc_local_port_t *port = arg;
   3045 
   3046 	fp_attach_ulps(port, FC_CMD_ATTACH);
   3047 
   3048 	FP_DTRACE(FP_NHEAD1(2, 0), "fp_startup almost complete; port=%p", port);
   3049 }
   3050 
   3051 
   3052 /*
   3053  * Perform ULP port attach
   3054  */
   3055 static void
   3056 fp_ulp_port_attach(void *arg)
   3057 {
   3058 	fp_soft_attach_t *att = (fp_soft_attach_t *)arg;
   3059 	fc_local_port_t	 *port = att->att_port;
   3060 
   3061 	FP_DTRACE(FP_NHEAD1(1, 0), "port attach of"
   3062 	    " ULPs begin; port=%p, cmd=%x", port, att->att_cmd);
   3063 
   3064 	fctl_attach_ulps(att->att_port, att->att_cmd, &modlinkage);
   3065 
   3066 	if (att->att_need_pm_idle == B_TRUE) {
   3067 		fctl_idle_port(port);
   3068 	}
   3069 
   3070 	FP_DTRACE(FP_NHEAD1(1, 0), "port attach of"
   3071 	    " ULPs end; port=%p, cmd=%x", port, att->att_cmd);
   3072 
   3073 	mutex_enter(&att->att_port->fp_mutex);
   3074 	att->att_port->fp_ulp_attach = 0;
   3075 
   3076 	port->fp_task = port->fp_last_task;
   3077 	port->fp_last_task = FP_TASK_IDLE;
   3078 
   3079 	cv_signal(&att->att_port->fp_attach_cv);
   3080 
   3081 	mutex_exit(&att->att_port->fp_mutex);
   3082 
   3083 	kmem_free(att, sizeof (fp_soft_attach_t));
   3084 }
   3085 
   3086 /*
   3087  * Entry point to funnel all requests down to FCAs
   3088  */
   3089 static int
   3090 fp_sendcmd(fc_local_port_t *port, fp_cmd_t *cmd, opaque_t fca_handle)
   3091 {
   3092 	int rval;
   3093 
   3094 	mutex_enter(&port->fp_mutex);
   3095 	if (port->fp_statec_busy > 1 || (cmd->cmd_ulp_pkt != NULL &&
   3096 	    (port->fp_statec_busy || FC_PORT_STATE_MASK(port->fp_state) ==
   3097 	    FC_STATE_OFFLINE))) {
   3098 		/*
   3099 		 * This means there is more than one state change
   3100 		 * at this point of time - Since they are processed
   3101 		 * serially, any processing of the current one should
   3102 		 * be failed, failed and move up in processing the next
   3103 		 */
   3104 		cmd->cmd_pkt.pkt_state = FC_PKT_ELS_IN_PROGRESS;
   3105 		cmd->cmd_pkt.pkt_reason = FC_REASON_OFFLINE;
   3106 		if (cmd->cmd_job) {
   3107 			/*
   3108 			 * A state change that is going to be invalidated
   3109 			 * by another one already in the port driver's queue
   3110 			 * need not go up to all ULPs. This will minimize
   3111 			 * needless processing and ripples in ULP modules
   3112 			 */
   3113 			cmd->cmd_job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION;
   3114 		}
   3115 		mutex_exit(&port->fp_mutex);
   3116 		return (FC_STATEC_BUSY);
   3117 	}
   3118 
   3119 	if (FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) {
   3120 		cmd->cmd_pkt.pkt_state = FC_PKT_PORT_OFFLINE;
   3121 		cmd->cmd_pkt.pkt_reason = FC_REASON_OFFLINE;
   3122 		mutex_exit(&port->fp_mutex);
   3123 
   3124 		return (FC_OFFLINE);
   3125 	}
   3126 	mutex_exit(&port->fp_mutex);
   3127 
   3128 	rval = cmd->cmd_transport(fca_handle, &cmd->cmd_pkt);
   3129 	if (rval != FC_SUCCESS) {
   3130 		if (rval == FC_TRAN_BUSY) {
   3131 			cmd->cmd_retry_interval = fp_retry_delay;
   3132 			rval = fp_retry_cmd(&cmd->cmd_pkt);
   3133 			if (rval == FC_FAILURE) {
   3134 				cmd->cmd_pkt.pkt_state = FC_PKT_TRAN_BSY;
   3135 			}
   3136 		}
   3137 	} else {
   3138 		mutex_enter(&port->fp_mutex);
   3139 		port->fp_out_fpcmds++;
   3140 		mutex_exit(&port->fp_mutex);
   3141 	}
   3142 
   3143 	return (rval);
   3144 }
   3145 
   3146 
   3147 /*
   3148  * Each time a timeout kicks in, walk the wait queue, decrement the
   3149  * the retry_interval, when the retry_interval becomes less than
   3150  * or equal to zero, re-transport the command: If the re-transport
   3151  * fails with BUSY, enqueue the command in the wait queue.
   3152  *
   3153  * In order to prevent looping forever because of commands enqueued
   3154  * from within this function itself, save the current tail pointer
   3155  * (in cur_tail) and exit the loop after serving this command.
   3156  */
   3157 static void
   3158 fp_resendcmd(void *port_handle)
   3159 {
   3160 	int		rval;
   3161 	fc_local_port_t	*port;
   3162 	fp_cmd_t	*cmd;
   3163 	fp_cmd_t	*cur_tail;
   3164 
   3165 	port = port_handle;
   3166 	mutex_enter(&port->fp_mutex);
   3167 	cur_tail = port->fp_wait_tail;
   3168 	mutex_exit(&port->fp_mutex);
   3169 
   3170 	while ((cmd = fp_deque_cmd(port)) != NULL) {
   3171 		cmd->cmd_retry_interval -= fp_retry_ticker;
   3172 		/* Check if we are detaching */
   3173 		if (port->fp_soft_state &
   3174 		    (FP_SOFT_IN_DETACH | FP_DETACH_INPROGRESS)) {
   3175 			cmd->cmd_pkt.pkt_state = FC_PKT_TRAN_ERROR;
   3176 			cmd->cmd_pkt.pkt_reason = 0;
   3177 			fp_iodone(cmd);
   3178 		} else if (cmd->cmd_retry_interval <= 0) {
   3179 			rval = cmd->cmd_transport(port->fp_fca_handle,
   3180 			    &cmd->cmd_pkt);
   3181 
   3182 			if (rval != FC_SUCCESS) {
   3183 				if (cmd->cmd_pkt.pkt_state == FC_PKT_TRAN_BSY) {
   3184 					if (--cmd->cmd_retry_count) {
   3185 						fp_enque_cmd(port, cmd);
   3186 						if (cmd == cur_tail) {
   3187 							break;
   3188 						}
   3189 						continue;
   3190 					}
   3191 					cmd->cmd_pkt.pkt_state =
   3192 					    FC_PKT_TRAN_BSY;
   3193 				} else {
   3194 					cmd->cmd_pkt.pkt_state =
   3195 					    FC_PKT_TRAN_ERROR;
   3196 				}
   3197 				cmd->cmd_pkt.pkt_reason = 0;
   3198 				fp_iodone(cmd);
   3199 			} else {
   3200 				mutex_enter(&port->fp_mutex);
   3201 				port->fp_out_fpcmds++;
   3202 				mutex_exit(&port->fp_mutex);
   3203 			}
   3204 		} else {
   3205 			fp_enque_cmd(port, cmd);
   3206 		}
   3207 
   3208 		if (cmd == cur_tail) {
   3209 			break;
   3210 		}
   3211 	}
   3212 
   3213 	mutex_enter(&port->fp_mutex);
   3214 	if (port->fp_wait_head) {
   3215 		timeout_id_t tid;
   3216 
   3217 		mutex_exit(&port->fp_mutex);
   3218 		tid = timeout(fp_resendcmd, (caddr_t)port,
   3219 		    fp_retry_ticks);
   3220 		mutex_enter(&port->fp_mutex);
   3221 		port->fp_wait_tid = tid;
   3222 	} else {
   3223 		port->fp_wait_tid = NULL;
   3224 	}
   3225 	mutex_exit(&port->fp_mutex);
   3226 }
   3227 
   3228 
   3229 /*
   3230  * Handle Local, Fabric, N_Port, Transport (whatever that means) BUSY here.
   3231  *
   3232  * Yes, as you can see below, cmd_retry_count is used here too.	 That means
   3233  * the retries for BUSY are less if there were transport failures (transport
   3234  * failure means fca_transport failure). The goal is not to exceed overall
   3235  * retries set in the cmd_retry_count (whatever may be the reason for retry)
   3236  *
   3237  * Return Values:
   3238  *	FC_SUCCESS
   3239  *	FC_FAILURE
   3240  */
   3241 static int
   3242 fp_retry_cmd(fc_packet_t *pkt)
   3243 {
   3244 	fp_cmd_t *cmd;
   3245 
   3246 	cmd = pkt->pkt_ulp_private;
   3247 
   3248 	if (--cmd->cmd_retry_count) {
   3249 		fp_enque_cmd(cmd->cmd_port, cmd);
   3250 		return (FC_SUCCESS);
   3251 	} else {
   3252 		return (FC_FAILURE);
   3253 	}
   3254 }
   3255 
   3256 
   3257 /*
   3258  * Queue up FC packet for deferred retry
   3259  */
   3260 static void
   3261 fp_enque_cmd(fc_local_port_t *port, fp_cmd_t *cmd)
   3262 {
   3263 	timeout_id_t tid;
   3264 
   3265 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
   3266 
   3267 #ifdef	DEBUG
   3268 	fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, &cmd->cmd_pkt,
   3269 	    "Retrying ELS for %x", cmd->cmd_pkt.pkt_cmd_fhdr.d_id);
   3270 #endif
   3271 
   3272 	mutex_enter(&port->fp_mutex);
   3273 	if (port->fp_wait_tail) {
   3274 		port->fp_wait_tail->cmd_next = cmd;
   3275 		port->fp_wait_tail = cmd;
   3276 	} else {
   3277 		ASSERT(port->fp_wait_head == NULL);
   3278 		port->fp_wait_head = port->fp_wait_tail = cmd;
   3279 		if (port->fp_wait_tid == NULL) {
   3280 			mutex_exit(&port->fp_mutex);
   3281 			tid = timeout(fp_resendcmd, (caddr_t)port,
   3282 			    fp_retry_ticks);
   3283 			mutex_enter(&port->fp_mutex);
   3284 			port->fp_wait_tid = tid;
   3285 		}
   3286 	}
   3287 	mutex_exit(&port->fp_mutex);
   3288 }
   3289 
   3290 
   3291 /*
   3292  * Handle all RJT codes
   3293  */
   3294 static int
   3295 fp_handle_reject(fc_packet_t *pkt)
   3296 {
   3297 	int		rval = FC_FAILURE;
   3298 	uchar_t		next_class;
   3299 	fp_cmd_t	*cmd;
   3300 	fc_local_port_t *port;
   3301 
   3302 	cmd = pkt->pkt_ulp_private;
   3303 	port = cmd->cmd_port;
   3304 
   3305 	switch (pkt->pkt_state) {
   3306 	case FC_PKT_FABRIC_RJT:
   3307 	case FC_PKT_NPORT_RJT:
   3308 		if (pkt->pkt_reason == FC_REASON_CLASS_NOT_SUPP) {
   3309 			next_class = fp_get_nextclass(cmd->cmd_port,
   3310 			    FC_TRAN_CLASS(pkt->pkt_tran_flags));
   3311 
   3312 			if (next_class == FC_TRAN_CLASS_INVALID) {
   3313 				return (rval);
   3314 			}
   3315 			pkt->pkt_tran_flags = FC_TRAN_INTR | next_class;
   3316 			pkt->pkt_tran_type = FC_PKT_EXCHANGE;
   3317 
   3318 			rval = fp_sendcmd(cmd->cmd_port, cmd,
   3319 			    cmd->cmd_port->fp_fca_handle);
   3320 
   3321 			if (rval != FC_SUCCESS) {
   3322 				pkt->pkt_state = FC_PKT_TRAN_ERROR;
   3323 			}
   3324 		}
   3325 		break;
   3326 
   3327 	case FC_PKT_LS_RJT:
   3328 	case FC_PKT_BA_RJT:
   3329 		if ((pkt->pkt_reason == FC_REASON_LOGICAL_ERROR) ||
   3330 		    (pkt->pkt_reason == FC_REASON_LOGICAL_BSY)) {
   3331 			cmd->cmd_retry_interval = fp_retry_delay;
   3332 			rval = fp_retry_cmd(pkt);
   3333 		}
   3334 		break;
   3335 
   3336 	case FC_PKT_FS_RJT:
   3337 		if ((pkt->pkt_reason == FC_REASON_FS_LOGICAL_BUSY) ||
   3338 		    ((pkt->pkt_reason == FC_REASON_FS_CMD_UNABLE) &&
   3339 		    (pkt->pkt_expln == 0x00))) {
   3340 			cmd->cmd_retry_interval = fp_retry_delay;
   3341 			rval = fp_retry_cmd(pkt);
   3342 		}
   3343 		break;
   3344 
   3345 	case FC_PKT_LOCAL_RJT:
   3346 		if (pkt->pkt_reason == FC_REASON_QFULL) {
   3347 			cmd->cmd_retry_interval = fp_retry_delay;
   3348 			rval = fp_retry_cmd(pkt);
   3349 		}
   3350 		break;
   3351 
   3352 	default:
   3353 		FP_TRACE(FP_NHEAD1(1, 0),
   3354 		    "fp_handle_reject(): Invalid pkt_state");
   3355 		break;
   3356 	}
   3357 
   3358 	return (rval);
   3359 }
   3360 
   3361 
   3362 /*
   3363  * Return the next class of service supported by the FCA
   3364  */
   3365 static uchar_t
   3366 fp_get_nextclass(fc_local_port_t *port, uchar_t cur_class)
   3367 {
   3368 	uchar_t next_class;
   3369 
   3370 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
   3371 
   3372 	switch (cur_class) {
   3373 	case FC_TRAN_CLASS_INVALID:
   3374 		if (port->fp_cos & FC_NS_CLASS1) {
   3375 			next_class = FC_TRAN_CLASS1;
   3376 			break;
   3377 		}
   3378 		/* FALLTHROUGH */
   3379 
   3380 	case FC_TRAN_CLASS1:
   3381 		if (port->fp_cos & FC_NS_CLASS2) {
   3382 			next_class = FC_TRAN_CLASS2;
   3383 			break;
   3384 		}
   3385 		/* FALLTHROUGH */
   3386 
   3387 	case FC_TRAN_CLASS2:
   3388 		if (port->fp_cos & FC_NS_CLASS3) {
   3389 			next_class = FC_TRAN_CLASS3;
   3390 			break;
   3391 		}
   3392 		/* FALLTHROUGH */
   3393 
   3394 	case FC_TRAN_CLASS3:
   3395 	default:
   3396 		next_class = FC_TRAN_CLASS_INVALID;
   3397 		break;
   3398 	}
   3399 
   3400 	return (next_class);
   3401 }
   3402 
   3403 
   3404 /*
   3405  * Determine if a class of service is supported by the FCA
   3406  */
   3407 static int
   3408 fp_is_class_supported(uint32_t cos, uchar_t tran_class)
   3409 {
   3410 	int rval;
   3411 
   3412 	switch (tran_class) {
   3413 	case FC_TRAN_CLASS1:
   3414 		if (cos & FC_NS_CLASS1) {
   3415 			rval = FC_SUCCESS;
   3416 		} else {
   3417 			rval = FC_FAILURE;
   3418 		}
   3419 		break;
   3420 
   3421 	case FC_TRAN_CLASS2:
   3422 		if (cos & FC_NS_CLASS2) {
   3423 			rval = FC_SUCCESS;
   3424 		} else {
   3425 			rval = FC_FAILURE;
   3426 		}
   3427 		break;
   3428 
   3429 	case FC_TRAN_CLASS3:
   3430 		if (cos & FC_NS_CLASS3) {
   3431 			rval = FC_SUCCESS;
   3432 		} else {
   3433 			rval = FC_FAILURE;
   3434 		}
   3435 		break;
   3436 
   3437 	default:
   3438 		rval = FC_FAILURE;
   3439 		break;
   3440 	}
   3441 
   3442 	return (rval);
   3443 }
   3444 
   3445 
   3446 /*
   3447  * Dequeue FC packet for retry
   3448  */
   3449 static fp_cmd_t *
   3450 fp_deque_cmd(fc_local_port_t *port)
   3451 {
   3452 	fp_cmd_t *cmd;
   3453 
   3454 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
   3455 
   3456 	mutex_enter(&port->fp_mutex);
   3457 
   3458 	if (port->fp_wait_head == NULL) {
   3459 		/*
   3460 		 * To avoid races, NULL the fp_wait_tid as
   3461 		 * we are about to exit the timeout thread.
   3462 		 */
   3463 		port->fp_wait_tid = NULL;
   3464 		mutex_exit(&port->fp_mutex);
   3465 		return (NULL);
   3466 	}
   3467 
   3468 	cmd = port->fp_wait_head;
   3469 	port->fp_wait_head = cmd->cmd_next;
   3470 	cmd->cmd_next = NULL;
   3471 
   3472 	if (port->fp_wait_head == NULL) {
   3473 		port->fp_wait_tail = NULL;
   3474 	}
   3475 	mutex_exit(&port->fp_mutex);
   3476 
   3477 	return (cmd);
   3478 }
   3479 
   3480 
   3481 /*
   3482  * Wait for job completion
   3483  */
   3484 static void
   3485 fp_jobwait(job_request_t *job)
   3486 {
   3487 	sema_p(&job->job_port_sema);
   3488 }
   3489 
   3490 
   3491 /*
   3492  * Convert FC packet state to FC errno
   3493  */
   3494 int
   3495 fp_state_to_rval(uchar_t state)
   3496 {
   3497 	int count;
   3498 
   3499 	for (count = 0; count < sizeof (fp_xlat) /
   3500 	    sizeof (fp_xlat[0]); count++) {
   3501 		if (fp_xlat[count].xlat_state == state) {
   3502 			return (fp_xlat[count].xlat_rval);
   3503 		}
   3504 	}
   3505 
   3506 	return (FC_FAILURE);
   3507 }
   3508 
   3509 
   3510 /*
   3511  * For Synchronous I/O requests, the caller is
   3512  * expected to do fctl_jobdone(if necessary)
   3513  *
   3514  * We want to preserve at least one failure in the
   3515  * job_result if it happens.
   3516  *
   3517  */
   3518 static void
   3519 fp_iodone(fp_cmd_t *cmd)
   3520 {
   3521 	fc_packet_t		*ulp_pkt = cmd->cmd_ulp_pkt;
   3522 	job_request_t		*job = cmd->cmd_job;
   3523 	fc_remote_port_t	*pd = cmd->cmd_pkt.pkt_pd;
   3524 
   3525 	ASSERT(job != NULL);
   3526 	ASSERT(cmd->cmd_port != NULL);
   3527 	ASSERT(&cmd->cmd_pkt != NULL);
   3528 
   3529 	mutex_enter(&job->job_mutex);
   3530 	if (job->job_result == FC_SUCCESS) {
   3531 		job->job_result = fp_state_to_rval(cmd->cmd_pkt.pkt_state);
   3532 	}
   3533 	mutex_exit(&job->job_mutex);
   3534 
   3535 	if (pd) {
   3536 		mutex_enter(&pd->pd_mutex);
   3537 		pd->pd_flags = PD_IDLE;
   3538 		mutex_exit(&pd->pd_mutex);
   3539 	}
   3540 
   3541 	if (ulp_pkt) {
   3542 		if (pd && cmd->cmd_flags & FP_CMD_DELDEV_ON_ERROR &&
   3543 		    FP_IS_PKT_ERROR(ulp_pkt)) {
   3544 			fc_local_port_t		*port;
   3545 			fc_remote_node_t	*node;
   3546 
   3547 			port = cmd->cmd_port;
   3548 
   3549 			mutex_enter(&pd->pd_mutex);
   3550 			pd->pd_state = PORT_DEVICE_INVALID;
   3551 			pd->pd_ref_count--;
   3552 			node = pd->pd_remote_nodep;
   3553 			mutex_exit(&pd->pd_mutex);
   3554 
   3555 			ASSERT(node != NULL);
   3556 			ASSERT(port != NULL);
   3557 
   3558 			if (fctl_destroy_remote_port(port, pd) == 0) {
   3559 				fctl_destroy_remote_node(node);
   3560 			}
   3561 
   3562 			ulp_pkt->pkt_pd = NULL;
   3563 		}
   3564 
   3565 		ulp_pkt->pkt_comp(ulp_pkt);
   3566 	}
   3567 
   3568 	fp_free_pkt(cmd);
   3569 	fp_jobdone(job);
   3570 }
   3571 
   3572 
   3573 /*
   3574  * Job completion handler
   3575  */
   3576 static void
   3577 fp_jobdone(job_request_t *job)
   3578 {
   3579 	mutex_enter(&job->job_mutex);
   3580 	ASSERT(job->job_counter > 0);
   3581 
   3582 	if (--job->job_counter != 0) {
   3583 		mutex_exit(&job->job_mutex);
   3584 		return;
   3585 	}
   3586 
   3587 	if (job->job_ulp_pkts) {
   3588 		ASSERT(job->job_ulp_listlen > 0);
   3589 		kmem_free(job->job_ulp_pkts,
   3590 		    sizeof (fc_packet_t *) * job->job_ulp_listlen);
   3591 	}
   3592 
   3593 	if (job->job_flags & JOB_TYPE_FP_ASYNC) {
   3594 		mutex_exit(&job->job_mutex);
   3595 		fctl_jobdone(job);
   3596 	} else {
   3597 		mutex_exit(&job->job_mutex);
   3598 		sema_v(&job->job_port_sema);
   3599 	}
   3600 }
   3601 
   3602 
   3603 /*
   3604  * Try to perform shutdown of a port during a detach. No return
   3605  * value since the detach should not fail because the port shutdown
   3606  * failed.
   3607  */
   3608 static void
   3609 fp_port_shutdown(fc_local_port_t *port, job_request_t *job)
   3610 {
   3611 	int			index;
   3612 	int			count;
   3613 	int			flags;
   3614 	fp_cmd_t		*cmd;
   3615 	struct pwwn_hash	*head;
   3616 	fc_remote_port_t	*pd;
   3617 
   3618 	ASSERT(MUTEX_HELD(&port->fp_mutex));
   3619 
   3620 	job->job_result = FC_SUCCESS;
   3621 
   3622 	if (port->fp_taskq) {
   3623 		/*
   3624 		 * We must release the mutex here to ensure that other
   3625 		 * potential jobs can complete their processing.  Many
   3626 		 * also need this mutex.
   3627 		 */
   3628 		mutex_exit(&port->fp_mutex);
   3629 		taskq_wait(port->fp_taskq);
   3630 		mutex_enter(&port->fp_mutex);
   3631 	}
   3632 
   3633 	if (port->fp_offline_tid) {
   3634 		timeout_id_t tid;
   3635 
   3636 		tid = port->fp_offline_tid;
   3637 		port->fp_offline_tid = NULL;
   3638 		mutex_exit(&port->fp_mutex);
   3639 		(void) untimeout(tid);
   3640 		mutex_enter(&port->fp_mutex);
   3641 	}
   3642 
   3643 	if (port->fp_wait_tid) {
   3644 		timeout_id_t tid;
   3645 
   3646 		tid = port->fp_wait_tid;
   3647 		port->fp_wait_tid = NULL;
   3648 		mutex_exit(&port->fp_mutex);
   3649 		(void) untimeout(tid);
   3650 	} else {
   3651 		mutex_exit(&port->fp_mutex);
   3652 	}
   3653 
   3654 	/*
   3655 	 * While we cancel the timeout, let's also return the
   3656 	 * the outstanding requests back to the callers.
   3657 	 */
   3658 	while ((cmd = fp_deque_cmd(port)) != NULL) {
   3659 		ASSERT(cmd->cmd_job != NULL);
   3660 		cmd->cmd_job->job_result = FC_OFFLINE;
   3661 		fp_iodone(cmd);
   3662 	}
   3663 
   3664 	/*
   3665 	 * Gracefully LOGO with all the devices logged in.
   3666 	 */
   3667 	mutex_enter(&port->fp_mutex);
   3668 
   3669 	for (count = index = 0; index < pwwn_table_size; index++) {
   3670 		head = &port->fp_pwwn_table[index];
   3671 		pd = head->pwwn_head;
   3672 		while (pd != NULL) {
   3673 			mutex_enter(&pd->pd_mutex);
   3674 			if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
   3675 				count++;
   3676 			}
   3677 			mutex_exit(&pd->pd_mutex);
   3678 			pd = pd->pd_wwn_hnext;
   3679 		}
   3680 	}
   3681 
   3682 	if (job->job_flags & JOB_TYPE_FP_ASYNC) {
   3683 		flags = job->job_flags;
   3684 		job->job_flags &= ~JOB_TYPE_FP_ASYNC;
   3685 	} else {
   3686 		flags = 0;
   3687 	}
   3688 	if (count) {
   3689 		job->job_counter = count;
   3690 
   3691 		for (index = 0; index < pwwn_table_size; index++) {
   3692 			head = &port->fp_pwwn_table[index];
   3693 			pd = head->pwwn_head;
   3694 			while (pd != NULL) {
   3695 				mutex_enter(&pd->pd_mutex);
   3696 				if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
   3697 					ASSERT(pd->pd_login_count > 0);
   3698 					/*
   3699 					 * Force the counter to ONE in order
   3700 					 * for us to really send LOGO els.
   3701 					 */
   3702 					pd->pd_login_count = 1;
   3703 					mutex_exit(&pd->pd_mutex);
   3704 					mutex_exit(&port->fp_mutex);
   3705 					(void) fp_logout(port, pd, job);
   3706 					mutex_enter(&port->fp_mutex);
   3707 				} else {
   3708 					mutex_exit(&pd->pd_mutex);
   3709 				}
   3710 				pd = pd->pd_wwn_hnext;
   3711 			}
   3712 		}
   3713 		mutex_exit(&port->fp_mutex);
   3714 		fp_jobwait(job);
   3715 	} else {
   3716 		mutex_exit(&port->fp_mutex);
   3717 	}
   3718 
   3719 	if (job->job_result != FC_SUCCESS) {
   3720 		FP_TRACE(FP_NHEAD1(9, 0),
   3721 		    "Can't logout all devices. Proceeding with"
   3722 		    " port shutdown");
   3723 		job->job_result = FC_SUCCESS;
   3724 	}
   3725 
   3726 	fctl_destroy_all_remote_ports(port);
   3727 
   3728 	mutex_enter(&port->fp_mutex);
   3729 	if (FC_IS_TOP_SWITCH(port->fp_topology)) {
   3730 		mutex_exit(&port->fp_mutex);
   3731 		fp_ns_fini(port, job);
   3732 	} else {
   3733 		mutex_exit(&port->fp_mutex);
   3734 	}
   3735 
   3736 	if (flags) {
   3737 		job->job_flags = flags;
   3738 	}
   3739 
   3740 	mutex_enter(&port->fp_mutex);
   3741 
   3742 }
   3743 
   3744 
   3745 /*
   3746  * Build the port driver's data structures based on the AL_PA list
   3747  */
   3748 static void
   3749 fp_get_loopmap(fc_local_port_t *port, job_request_t *job)
   3750 {
   3751 	int			rval;
   3752 	int			flag;
   3753 	int			count;
   3754 	uint32_t		d_id;
   3755 	fc_remote_port_t	*pd;
   3756 	fc_lilpmap_t		*lilp_map;
   3757 
   3758 	ASSERT(MUTEX_HELD(&port->fp_mutex));
   3759 
   3760 	if (FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) {
   3761 		job->job_result = FC_OFFLINE;
   3762 		mutex_exit(&port->fp_mutex);
   3763 		fp_jobdone(job);
   3764 		mutex_enter(&port->fp_mutex);
   3765 		return;
   3766 	}
   3767 
   3768 	if (port->fp_lilp_map.lilp_length == 0) {
   3769 		mutex_exit(&port->fp_mutex);
   3770 		job->job_result = FC_NO_MAP;
   3771 		fp_jobdone(job);
   3772 		mutex_enter(&port->fp_mutex);
   3773 		return;
   3774 	}
   3775 	mutex_exit(&port->fp_mutex);
   3776 
   3777 	lilp_map = &port->fp_lilp_map;
   3778 	job->job_counter = lilp_map->lilp_length;
   3779 
   3780 	if (job->job_code == JOB_PORT_GETMAP_PLOGI_ALL) {
   3781 		flag = FP_CMD_PLOGI_RETAIN;
   3782 	} else {
   3783 		flag = FP_CMD_PLOGI_DONT_CARE;
   3784 	}
   3785 
   3786 	for (count = 0; count < lilp_map->lilp_length; count++) {
   3787 		d_id = lilp_map->lilp_alpalist[count];
   3788 
   3789 		if (d_id == (lilp_map->lilp_myalpa & 0xFF)) {
   3790 			fp_jobdone(job);
   3791 			continue;
   3792 		}
   3793 
   3794 		pd = fctl_get_remote_port_by_did(port, d_id);
   3795 		if (pd) {
   3796 			mutex_enter(&pd->pd_mutex);
   3797 			if (flag == FP_CMD_PLOGI_DONT_CARE ||
   3798 			    pd->pd_state == PORT_DEVICE_LOGGED_IN) {
   3799 				mutex_exit(&pd->pd_mutex);
   3800 				fp_jobdone(job);
   3801 				continue;
   3802 			}
   3803 			mutex_exit(&pd->pd_mutex);
   3804 		}
   3805 
   3806 		rval = fp_port_login(port, d_id, job, flag,
   3807 		    KM_SLEEP, pd, NULL);
   3808 		if (rval != FC_SUCCESS) {
   3809 			fp_jobdone(job);
   3810 		}
   3811 	}
   3812 
   3813 	mutex_enter(&port->fp_mutex);
   3814 }
   3815 
   3816 
   3817 /*
   3818  * Perform loop ONLINE processing
   3819  */
   3820 static void
   3821 fp_loop_online(fc_local_port_t *port, job_request_t *job, int orphan)
   3822 {
   3823 	int			count;
   3824 	int			rval;
   3825 	uint32_t		d_id;
   3826 	uint32_t		listlen;
   3827 	fc_lilpmap_t		*lilp_map;
   3828 	fc_remote_port_t	*pd;
   3829 	fc_portmap_t		*changelist;
   3830 
   3831 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
   3832 
   3833 	FP_TRACE(FP_NHEAD1(1, 0), "fp_loop_online begin; port=%p, job=%p",
   3834 	    port, job);
   3835 
   3836 	lilp_map = &port->fp_lilp_map;
   3837 
   3838 	if (lilp_map->lilp_length) {
   3839 		mutex_enter(&port->fp_mutex);
   3840 		if (port->fp_soft_state & FP_SOFT_IN_FCA_RESET) {
   3841 			port->fp_soft_state &= ~FP_SOFT_IN_FCA_RESET;
   3842 			mutex_exit(&port->fp_mutex);
   3843 			delay(drv_usectohz(PLDA_RR_TOV * 1000 * 1000));
   3844 		} else {
   3845 			mutex_exit(&port->fp_mutex);
   3846 		}
   3847 
   3848 		job->job_counter = lilp_map->lilp_length;
   3849 
   3850 		for (count = 0; count < lilp_map->lilp_length; count++) {
   3851 			d_id = lilp_map->lilp_alpalist[count];
   3852 
   3853 			if (d_id == (lilp_map->lilp_myalpa & 0xFF)) {
   3854 				fp_jobdone(job);
   3855 				continue;
   3856 			}
   3857 
   3858 			pd = fctl_get_remote_port_by_did(port, d_id);
   3859 			if (pd != NULL) {
   3860 #ifdef	DEBUG
   3861 				mutex_enter(&pd->pd_mutex);
   3862 				if (pd->pd_recepient == PD_PLOGI_INITIATOR) {
   3863 					ASSERT(pd->pd_type != PORT_DEVICE_OLD);
   3864 				}
   3865 				mutex_exit(&pd->pd_mutex);
   3866 #endif
   3867 				fp_jobdone(job);
   3868 				continue;
   3869 			}
   3870 
   3871 			rval = fp_port_login(port, d_id, job,
   3872 			    FP_CMD_PLOGI_DONT_CARE, KM_SLEEP, pd, NULL);
   3873 
   3874 			if (rval != FC_SUCCESS) {
   3875 				fp_jobdone(job);
   3876 			}
   3877 		}
   3878 		fp_jobwait(job);
   3879 	}
   3880 	listlen = 0;
   3881 	changelist = NULL;
   3882 
   3883 	if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) {
   3884 		mutex_enter(&port->fp_mutex);
   3885 		ASSERT(port->fp_statec_busy > 0);
   3886 		if (port->fp_statec_busy == 1) {
   3887 			mutex_exit(&port->fp_mutex);
   3888 			fctl_fillout_map(port, &changelist, &listlen,
   3889 			    1, 0, orphan);
   3890 
   3891 			mutex_enter(&port->fp_mutex);
   3892 			if (port->fp_lilp_map.lilp_magic < MAGIC_LIRP) {
   3893 				ASSERT(port->fp_total_devices == 0);
   3894 				port->fp_total_devices = port->fp_dev_count;
   3895 			}
   3896 		} else {
   3897 			job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION;
   3898 		}
   3899 		mutex_exit(&port->fp_mutex);
   3900 	}
   3901 
   3902 	if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) {
   3903 		(void) fp_ulp_statec_cb(port, FC_STATE_ONLINE, changelist,
   3904 		    listlen, listlen, KM_SLEEP);
   3905 	} else {
   3906 		mutex_enter(&port->fp_mutex);
   3907 		if (--port->fp_statec_busy == 0) {
   3908 			port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
   3909 		}
   3910 		ASSERT(changelist == NULL && listlen == 0);
   3911 		mutex_exit(&port->fp_mutex);
   3912 	}
   3913 
   3914 	FP_TRACE(FP_NHEAD1(1, 0), "fp_loop_online end; port=%p, job=%p",
   3915 	    port, job);
   3916 }
   3917 
   3918 
   3919 /*
   3920  * Get an Arbitrated Loop map from the underlying FCA
   3921  */
   3922 static int
   3923 fp_get_lilpmap(fc_local_port_t *port, fc_lilpmap_t *lilp_map)
   3924 {
   3925 	int rval;
   3926 
   3927 	FP_TRACE(FP_NHEAD1(1, 0), "fp_get_lilpmap Begin; port=%p, map=%p",
   3928 	    port, lilp_map);
   3929 
   3930 	bzero((caddr_t)lilp_map, sizeof (fc_lilpmap_t));
   3931 	rval = port->fp_fca_tran->fca_getmap(port->fp_fca_handle, lilp_map);
   3932 	lilp_map->lilp_magic &= 0xFF;	/* Ignore upper byte */
   3933 
   3934 	if (rval != FC_SUCCESS) {
   3935 		rval = FC_NO_MAP;
   3936 	} else if (lilp_map->lilp_length == 0 &&
   3937 	    (lilp_map->lilp_magic >= MAGIC_LISM &&
   3938 	    lilp_map->lilp_magic < MAGIC_LIRP)) {
   3939 		uchar_t lilp_length;
   3940 
   3941 		/*
   3942 		 * Since the map length is zero, provide all
   3943 		 * the valid AL_PAs for NL_ports discovery.
   3944 		 */
   3945 		lilp_length = sizeof (fp_valid_alpas) /
   3946 		    sizeof (fp_valid_alpas[0]);
   3947 		lilp_map->lilp_length = lilp_length;
   3948 		bcopy(fp_valid_alpas, lilp_map->lilp_alpalist,
   3949 		    lilp_length);
   3950 	} else {
   3951 		rval = fp_validate_lilp_map(lilp_map);
   3952 
   3953 		if (rval == FC_SUCCESS) {
   3954 			mutex_enter(&port->fp_mutex);
   3955 			port->fp_total_devices = lilp_map->lilp_length - 1;
   3956 			mutex_exit(&port->fp_mutex);
   3957 		}
   3958 	}
   3959 
   3960 	mutex_enter(&port->fp_mutex);
   3961 	if (rval != FC_SUCCESS && !(port->fp_soft_state & FP_SOFT_BAD_LINK)) {
   3962 		port->fp_soft_state |= FP_SOFT_BAD_LINK;
   3963 		mutex_exit(&port->fp_mutex);
   3964 
   3965 		if (port->fp_fca_tran->fca_reset(port->fp_fca_handle,
   3966 		    FC_FCA_RESET_CORE) != FC_SUCCESS) {
   3967 			FP_TRACE(FP_NHEAD1(9, 0),
   3968 			    "FCA reset failed after LILP map was found"
   3969 			    " to be invalid");
   3970 		}
   3971 	} else if (rval == FC_SUCCESS) {
   3972 		port->fp_soft_state &= ~FP_SOFT_BAD_LINK;
   3973 		mutex_exit(&port->fp_mutex);
   3974 	} else {
   3975 		mutex_exit(&port->fp_mutex);
   3976 	}
   3977 
   3978 	FP_TRACE(FP_NHEAD1(1, 0), "fp_get_lilpmap End; port=%p, map=%p", port,
   3979 	    lilp_map);
   3980 
   3981 	return (rval);
   3982 }
   3983 
   3984 
   3985 /*
   3986  * Perform Fabric Login:
   3987  *
   3988  * Return Values:
   3989  *		FC_SUCCESS
   3990  *		FC_FAILURE
   3991  *		FC_NOMEM
   3992  *		FC_TRANSPORT_ERROR
   3993  *		and a lot others defined in fc_error.h
   3994  */
   3995 static int
   3996 fp_fabric_login(fc_local_port_t *port, uint32_t s_id, job_request_t *job,
   3997     int flag, int sleep)
   3998 {
   3999 	int		rval;
   4000 	fp_cmd_t	*cmd;
   4001 	uchar_t		class;
   4002 
   4003 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
   4004 
   4005 	FP_TRACE(FP_NHEAD1(1, 0), "fp_fabric_login Begin; port=%p, job=%p",
   4006 	    port, job);
   4007 
   4008 	class = fp_get_nextclass(port, FC_TRAN_CLASS_INVALID);
   4009 	if (class == FC_TRAN_CLASS_INVALID) {
   4010 		return (FC_ELS_BAD);
   4011 	}
   4012 
   4013 	cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t),
   4014 	    sizeof (la_els_logi_t), sleep, NULL);
   4015 	if (cmd == NULL) {
   4016 		return (FC_NOMEM);
   4017 	}
   4018 
   4019 	cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class;
   4020 	cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
   4021 	cmd->cmd_flags = flag;
   4022 	cmd->cmd_retry_count = fp_retry_count;
   4023 	cmd->cmd_ulp_pkt = NULL;
   4024 
   4025 	fp_xlogi_init(port, cmd, s_id, 0xFFFFFE, fp_flogi_intr,
   4026 	    job, LA_ELS_FLOGI);
   4027 
   4028 	rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
   4029 	if (rval != FC_SUCCESS) {
   4030 		fp_free_pkt(cmd);
   4031 	}
   4032 
   4033 	FP_TRACE(FP_NHEAD1(1, 0), "fp_fabric_login End; port=%p, job=%p",
   4034 	    port, job);
   4035 
   4036 	return (rval);
   4037 }
   4038 
   4039 
   4040 /*
   4041  * In some scenarios such as private loop device discovery period
   4042  * the fc_remote_port_t data structure isn't allocated. The allocation
   4043  * is done when the PLOGI is successful. In some other scenarios
   4044  * such as Fabric topology, the fc_remote_port_t is already created
   4045  * and initialized with appropriate values (as the NS provides
   4046  * them)
   4047  */
   4048 static int
   4049 fp_port_login(fc_local_port_t *port, uint32_t d_id, job_request_t *job,
   4050     int cmd_flag, int sleep, fc_remote_port_t *pd, fc_packet_t *ulp_pkt)
   4051 {
   4052 	uchar_t class;
   4053 	fp_cmd_t *cmd;
   4054 	uint32_t src_id;
   4055 	fc_remote_port_t *tmp_pd;
   4056 	int relogin;
   4057 	int found = 0;
   4058 
   4059 #ifdef	DEBUG
   4060 	if (pd == NULL) {
   4061 		ASSERT(fctl_get_remote_port_by_did(port, d_id) == NULL);
   4062 	}
   4063 #endif
   4064 	ASSERT(job->job_counter > 0);
   4065 
   4066 	class = fp_get_nextclass(port, FC_TRAN_CLASS_INVALID);
   4067 	if (class == FC_TRAN_CLASS_INVALID) {
   4068 		return (FC_ELS_BAD);
   4069 	}
   4070 
   4071 	mutex_enter(&port->fp_mutex);
   4072 	tmp_pd = fctl_lookup_pd_by_did(port, d_id);
   4073 	mutex_exit(&port->fp_mutex);
   4074 
   4075 	relogin = 1;
   4076 	if (tmp_pd) {
   4077 		mutex_enter(&tmp_pd->pd_mutex);
   4078 		if ((tmp_pd->pd_aux_flags & PD_DISABLE_RELOGIN) &&
   4079 		    !(tmp_pd->pd_aux_flags & PD_LOGGED_OUT)) {
   4080 			tmp_pd->pd_state = PORT_DEVICE_LOGGED_IN;
   4081 			relogin = 0;
   4082 		}
   4083 		mutex_exit(&tmp_pd->pd_mutex);
   4084 	}
   4085 
   4086 	if (!relogin) {
   4087 		mutex_enter(&tmp_pd->pd_mutex);
   4088 		if (tmp_pd->pd_state == PORT_DEVICE_LOGGED_IN) {
   4089 			cmd_flag |= FP_CMD_PLOGI_RETAIN;
   4090 		}
   4091 		mutex_exit(&tmp_pd->pd_mutex);
   4092 
   4093 		cmd = fp_alloc_pkt(port, sizeof (la_els_adisc_t),
   4094 		    sizeof (la_els_adisc_t), sleep, tmp_pd);
   4095 		if (cmd == NULL) {
   4096 			return (FC_NOMEM);
   4097 		}
   4098 
   4099 		cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class;
   4100 		cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
   4101 		cmd->cmd_flags = cmd_flag;
   4102 		cmd->cmd_retry_count = fp_retry_count;
   4103 		cmd->cmd_ulp_pkt = ulp_pkt;
   4104 
   4105 		mutex_enter(&port->fp_mutex);
   4106 		mutex_enter(&tmp_pd->pd_mutex);
   4107 		fp_adisc_init(cmd, job);
   4108 		mutex_exit(&tmp_pd->pd_mutex);
   4109 		mutex_exit(&port->fp_mutex);
   4110 
   4111 		cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_adisc_t);
   4112 		cmd->cmd_pkt.pkt_rsplen = sizeof (la_els_adisc_t);
   4113 
   4114 	} else {
   4115 		cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t),
   4116 		    sizeof (la_els_logi_t), sleep, pd);
   4117 		if (cmd == NULL) {
   4118 			return (FC_NOMEM);
   4119 		}
   4120 
   4121 		cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class;
   4122 		cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
   4123 		cmd->cmd_flags = cmd_flag;
   4124 		cmd->cmd_retry_count = fp_retry_count;
   4125 		cmd->cmd_ulp_pkt = ulp_pkt;
   4126 
   4127 		mutex_enter(&port->fp_mutex);
   4128 		src_id = port->fp_port_id.port_id;
   4129 		mutex_exit(&port->fp_mutex);
   4130 
   4131 		fp_xlogi_init(port, cmd, src_id, d_id, fp_plogi_intr,
   4132 		    job, LA_ELS_PLOGI);
   4133 	}
   4134 
   4135 	if (pd) {
   4136 		mutex_enter(&pd->pd_mutex);
   4137 		pd->pd_flags = PD_ELS_IN_PROGRESS;
   4138 		mutex_exit(&pd->pd_mutex);
   4139 	}
   4140 
   4141 	/* npiv check to make sure we don't log into ourself */
   4142 	if (relogin &&
   4143 	    ((port->fp_npiv_type == FC_NPIV_PORT) ||
   4144 	    (port->fp_npiv_flag == FC_NPIV_ENABLE))) {
   4145 		if ((d_id & 0xffff00) ==
   4146 		    (port->fp_port_id.port_id & 0xffff00)) {
   4147 			found = 1;
   4148 		}
   4149 	}
   4150 
   4151 	if (found ||
   4152 	    (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS)) {
   4153 		if (found) {
   4154 			fc_packet_t *pkt = &cmd->cmd_pkt;
   4155 			pkt->pkt_state = FC_PKT_NPORT_RJT;
   4156 		}
   4157 		if (pd) {
   4158 			mutex_enter(&pd->pd_mutex);
   4159 			pd->pd_flags = PD_IDLE;
   4160 			mutex_exit(&pd->pd_mutex);
   4161 		}
   4162 
   4163 		if (ulp_pkt) {
   4164 			fc_packet_t *pkt = &cmd->cmd_pkt;
   4165 
   4166 			ulp_pkt->pkt_state = pkt->pkt_state;
   4167 			ulp_pkt->pkt_reason = pkt->pkt_reason;
   4168 			ulp_pkt->pkt_action = pkt->pkt_action;
   4169 			ulp_pkt->pkt_expln = pkt->pkt_expln;
   4170 		}
   4171 
   4172 		fp_iodone(cmd);
   4173 	}
   4174 
   4175 	return (FC_SUCCESS);
   4176 }
   4177 
   4178 
   4179 /*
   4180  * Register the LOGIN parameters with a port device
   4181  */
   4182 static void
   4183 fp_register_login(ddi_acc_handle_t *handle, fc_remote_port_t *pd,
   4184     la_els_logi_t *acc, uchar_t class)
   4185 {
   4186 	fc_remote_node_t	*node;
   4187 
   4188 	ASSERT(pd != NULL);
   4189 
   4190 	mutex_enter(&pd->pd_mutex);
   4191 	node = pd->pd_remote_nodep;
   4192 	if (pd->pd_login_count == 0) {
   4193 		pd->pd_login_count++;
   4194 	}
   4195 
   4196 	if (handle) {
   4197 		FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)&pd->pd_csp,
   4198 		    (uint8_t *)&acc->common_service,
   4199 		    sizeof (acc->common_service), DDI_DEV_AUTOINCR);
   4200 		FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)&pd->pd_clsp1,
   4201 		    (uint8_t *)&acc->class_1, sizeof (acc->class_1),
   4202 		    DDI_DEV_AUTOINCR);
   4203 		FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)&pd->pd_clsp2,
   4204 		    (uint8_t *)&acc->class_2, sizeof (acc->class_2),
   4205 		    DDI_DEV_AUTOINCR);
   4206 		FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)&pd->pd_clsp3,
   4207 		    (uint8_t *)&acc->class_3, sizeof (acc->class_3),
   4208 		    DDI_DEV_AUTOINCR);
   4209 	} else {
   4210 		pd->pd_csp = acc->common_service;
   4211 		pd->pd_clsp1 = acc->class_1;
   4212 		pd->pd_clsp2 = acc->class_2;
   4213 		pd->pd_clsp3 = acc->class_3;
   4214 	}
   4215 
   4216 	pd->pd_state = PORT_DEVICE_LOGGED_IN;
   4217 	pd->pd_login_class = class;
   4218 	mutex_exit(&pd->pd_mutex);
   4219 
   4220 #ifndef	__lock_lint
   4221 	ASSERT(fctl_get_remote_port_by_did(pd->pd_port,
   4222 	    pd->pd_port_id.port_id) == pd);
   4223 #endif
   4224 
   4225 	mutex_enter(&node->fd_mutex);
   4226 	if (handle) {
   4227 		FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)node->fd_vv,
   4228 		    (uint8_t *)acc->vendor_version, sizeof (node->fd_vv),
   4229 		    DDI_DEV_AUTOINCR);
   4230 	} else {
   4231 		bcopy(acc->vendor_version, node->fd_vv, sizeof (node->fd_vv));
   4232 	}
   4233 	mutex_exit(&node->fd_mutex);
   4234 }
   4235 
   4236 
   4237 /*
   4238  * Mark the remote port as OFFLINE
   4239  */
   4240 static void
   4241 fp_remote_port_offline(fc_remote_port_t *pd)
   4242 {
   4243 	ASSERT(MUTEX_HELD(&pd->pd_mutex));
   4244 	if (pd->pd_login_count &&
   4245 	    ((pd->pd_aux_flags & PD_DISABLE_RELOGIN) == 0)) {
   4246 		bzero((caddr_t)&pd->pd_csp, sizeof (struct common_service));
   4247 		bzero((caddr_t)&pd->pd_clsp1, sizeof (struct service_param));
   4248 		bzero((caddr_t)&pd->pd_clsp2, sizeof (struct service_param));
   4249 		bzero((caddr_t)&pd->pd_clsp3, sizeof (struct service_param));
   4250 		pd->pd_login_class = 0;
   4251 	}
   4252 	pd->pd_type = PORT_DEVICE_OLD;
   4253 	pd->pd_flags = PD_IDLE;
   4254 	fctl_tc_reset(&pd->pd_logo_tc);
   4255 }
   4256 
   4257 
   4258 /*
   4259  * Deregistration of a port device
   4260  */
   4261 static void
   4262 fp_unregister_login(fc_remote_port_t *pd)
   4263 {
   4264 	fc_remote_node_t *node;
   4265 
   4266 	ASSERT(pd != NULL);
   4267 
   4268 	mutex_enter(&pd->pd_mutex);
   4269 	pd->pd_login_count = 0;
   4270 	bzero((caddr_t)&pd->pd_csp, sizeof (struct common_service));
   4271 	bzero((caddr_t)&pd->pd_clsp1, sizeof (struct service_param));
   4272 	bzero((caddr_t)&pd->pd_clsp2, sizeof (struct service_param));
   4273 	bzero((caddr_t)&pd->pd_clsp3, sizeof (struct service_param));
   4274 
   4275 	pd->pd_state = PORT_DEVICE_VALID;
   4276 	pd->pd_login_class = 0;
   4277 	node = pd->pd_remote_nodep;
   4278 	mutex_exit(&pd->pd_mutex);
   4279 
   4280 	mutex_enter(&node->fd_mutex);
   4281 	bzero(node->fd_vv, sizeof (node->fd_vv));
   4282 	mutex_exit(&node->fd_mutex);
   4283 }
   4284 
   4285 
   4286 /*
   4287  * Handle OFFLINE state of an FCA port
   4288  */
   4289 static void
   4290 fp_port_offline(fc_local_port_t *port, int notify)
   4291 {
   4292 	int			index;
   4293 	int			statec;
   4294 	timeout_id_t		tid;
   4295 	struct pwwn_hash	*head;
   4296 	fc_remote_port_t	*pd;
   4297 
   4298 	ASSERT(MUTEX_HELD(&port->fp_mutex));
   4299 
   4300 	for (index = 0; index < pwwn_table_size; index++) {
   4301 		head = &port->fp_pwwn_table[index];
   4302 		pd = head->pwwn_head;
   4303 		while (pd != NULL) {
   4304 			mutex_enter(&pd->pd_mutex);
   4305 			fp_remote_port_offline(pd);
   4306 			fctl_delist_did_table(port, pd);
   4307 			mutex_exit(&pd->pd_mutex);
   4308 			pd = pd->pd_wwn_hnext;
   4309 		}
   4310 	}
   4311 	port->fp_total_devices = 0;
   4312 
   4313 	statec = 0;
   4314 	if (notify) {
   4315 		/*
   4316 		 * Decrement the statec busy counter as we
   4317 		 * are almost done with handling the state
   4318 		 * change
   4319 		 */
   4320 		ASSERT(port->fp_statec_busy > 0);
   4321 		if (--port->fp_statec_busy == 0) {
   4322 			port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
   4323 		}
   4324 		mutex_exit(&port->fp_mutex);
   4325 		(void) fp_ulp_statec_cb(port, FC_STATE_OFFLINE, NULL,
   4326 		    0, 0, KM_SLEEP);
   4327 		mutex_enter(&port->fp_mutex);
   4328 
   4329 		if (port->fp_statec_busy) {
   4330 			statec++;
   4331 		}
   4332 	} else if (port->fp_statec_busy > 1) {
   4333 		statec++;
   4334 	}
   4335 
   4336 	if ((tid = port->fp_offline_tid) != NULL) {
   4337 		mutex_exit(&port->fp_mutex);
   4338 		(void) untimeout(tid);
   4339 		mutex_enter(&port->fp_mutex);
   4340 	}
   4341 
   4342 	if (!statec) {
   4343 		port->fp_offline_tid = timeout(fp_offline_timeout,
   4344 		    (caddr_t)port, fp_offline_ticks);
   4345 	}
   4346 }
   4347 
   4348 
   4349 /*
   4350  * Offline devices and send up a state change notification to ULPs
   4351  */
   4352 static void
   4353 fp_offline_timeout(void *port_handle)
   4354 {
   4355 	int		ret;
   4356 	fc_local_port_t *port = port_handle;
   4357 	uint32_t	listlen = 0;
   4358 	fc_portmap_t	*changelist = NULL;
   4359 
   4360 	mutex_enter(&port->fp_mutex);
   4361 
   4362 	if ((FC_PORT_STATE_MASK(port->fp_state) != FC_STATE_OFFLINE) ||
   4363 	    (port->fp_soft_state &
   4364 	    (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN)) ||
   4365 	    port->fp_dev_count == 0 || port->fp_statec_busy) {
   4366 		port->fp_offline_tid = NULL;
   4367 		mutex_exit(&port->fp_mutex);
   4368 		return;
   4369 	}
   4370 
   4371 	mutex_exit(&port->fp_mutex);
   4372 
   4373 	FP_TRACE(FP_NHEAD2(9, 0), "OFFLINE timeout");
   4374 
   4375 	if (port->fp_options & FP_CORE_ON_OFFLINE_TIMEOUT) {
   4376 		if ((ret = port->fp_fca_tran->fca_reset(port->fp_fca_handle,
   4377 		    FC_FCA_CORE)) != FC_SUCCESS) {
   4378 			FP_TRACE(FP_NHEAD1(9, ret),
   4379 			    "Failed to force adapter dump");
   4380 		} else {
   4381 			FP_TRACE(FP_NHEAD1(9, 0),
   4382 			    "Forced adapter dump successfully");
   4383 		}
   4384 	} else if (port->fp_options & FP_RESET_CORE_ON_OFFLINE_TIMEOUT) {
   4385 		if ((ret = port->fp_fca_tran->fca_reset(port->fp_fca_handle,
   4386 		    FC_FCA_RESET_CORE)) != FC_SUCCESS) {
   4387 			FP_TRACE(FP_NHEAD1(9, ret),
   4388 			    "Failed to force adapter dump and reset");
   4389 		} else {
   4390 			FP_TRACE(FP_NHEAD1(9, 0),
   4391 			    "Forced adapter dump and reset successfully");
   4392 		}
   4393 	}
   4394 
   4395 	fctl_fillout_map(port, &changelist, &listlen, 1, 0, 0);
   4396 	(void) fp_ulp_statec_cb(port, FC_STATE_OFFLINE, changelist,
   4397 	    listlen, listlen, KM_SLEEP);
   4398 
   4399 	mutex_enter(&port->fp_mutex);
   4400 	port->fp_offline_tid = NULL;
   4401 	mutex_exit(&port->fp_mutex);
   4402 }
   4403 
   4404 
   4405 /*
   4406  * Perform general purpose ELS request initialization
   4407  */
   4408 static void
   4409 fp_els_init(fp_cmd_t *cmd, uint32_t s_id, uint32_t d_id,
   4410     void (*comp) (), job_request_t *job)
   4411 {
   4412 	fc_packet_t *pkt;
   4413 
   4414 	pkt = &cmd->cmd_pkt;
   4415 	cmd->cmd_job = job;
   4416 
   4417 	pkt->pkt_cmd_fhdr.r_ctl = R_CTL_ELS_REQ;
   4418 	pkt->pkt_cmd_fhdr.d_id = d_id;
   4419 	pkt->pkt_cmd_fhdr.s_id = s_id;
   4420 	pkt->pkt_cmd_fhdr.type = FC_TYPE_EXTENDED_LS;
   4421 	pkt->pkt_cmd_fhdr.f_ctl = F_CTL_SEQ_INITIATIVE | F_CTL_FIRST_SEQ;
   4422 	pkt->pkt_cmd_fhdr.seq_id = 0;
   4423 	pkt->pkt_cmd_fhdr.df_ctl  = 0;
   4424 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
   4425 	pkt->pkt_cmd_fhdr.ox_id = 0xffff;
   4426 	pkt->pkt_cmd_fhdr.rx_id = 0xffff;
   4427 	pkt->pkt_cmd_fhdr.ro = 0;
   4428 	pkt->pkt_cmd_fhdr.rsvd = 0;
   4429 	pkt->pkt_comp = comp;
   4430 	pkt->pkt_timeout = FP_ELS_TIMEOUT;
   4431 }
   4432 
   4433 
   4434 /*
   4435  * Initialize PLOGI/FLOGI ELS request
   4436  */
   4437 static void
   4438 fp_xlogi_init(fc_local_port_t *port, fp_cmd_t *cmd, uint32_t s_id,
   4439     uint32_t d_id, void (*intr) (), job_request_t *job, uchar_t ls_code)
   4440 {
   4441 	ls_code_t	payload;
   4442 
   4443 	fp_els_init(cmd, s_id, d_id, intr, job);
   4444 	cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
   4445 
   4446 	payload.ls_code = ls_code;
   4447 	payload.mbz = 0;
   4448 
   4449 	FC_SET_CMD(port, cmd->cmd_pkt.pkt_cmd_acc,
   4450 	    (uint8_t *)&port->fp_service_params,
   4451 	    (uint8_t *)cmd->cmd_pkt.pkt_cmd, sizeof (port->fp_service_params),
   4452 	    DDI_DEV_AUTOINCR);
   4453 
   4454 	FC_SET_CMD(port, cmd->cmd_pkt.pkt_cmd_acc, (uint8_t *)&payload,
   4455 	    (uint8_t *)cmd->cmd_pkt.pkt_cmd, sizeof (payload),
   4456 	    DDI_DEV_AUTOINCR);
   4457 }
   4458 
   4459 
   4460 /*
   4461  * Initialize LOGO ELS request
   4462  */
   4463 static void
   4464 fp_logo_init(fc_remote_port_t *pd, fp_cmd_t *cmd, job_request_t *job)
   4465 {
   4466 	fc_local_port_t	*port;
   4467 	fc_packet_t	*pkt;
   4468 	la_els_logo_t	payload;
   4469 
   4470 	port = pd->pd_port;
   4471 	pkt = &cmd->cmd_pkt;
   4472 	ASSERT(MUTEX_HELD(&port->fp_mutex));
   4473 	ASSERT(MUTEX_HELD(&pd->pd_mutex));
   4474 
   4475 	fp_els_init(cmd, port->fp_port_id.port_id, pd->pd_port_id.port_id,
   4476 	    fp_logo_intr, job);
   4477 
   4478 	cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
   4479 
   4480 	pkt->pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
   4481 	pkt->pkt_tran_type = FC_PKT_EXCHANGE;
   4482 
   4483 	payload.ls_code.ls_code = LA_ELS_LOGO;
   4484 	payload.ls_code.mbz = 0;
   4485 	payload.nport_ww_name = port->fp_service_params.nport_ww_name;
   4486 	payload.nport_id = port->fp_port_id;
   4487 
   4488 	FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
   4489 	    (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
   4490 }
   4491 
   4492 /*
   4493  * Initialize RNID ELS request
   4494  */
   4495 static void
   4496 fp_rnid_init(fp_cmd_t *cmd, uint16_t flag, job_request_t *job)
   4497 {
   4498 	fc_local_port_t	*port;
   4499 	fc_packet_t	*pkt;
   4500 	la_els_rnid_t	payload;
   4501 	fc_remote_port_t	*pd;
   4502 
   4503 	pkt = &cmd->cmd_pkt;
   4504 	pd = pkt->pkt_pd;
   4505 	port = pd->pd_port;
   4506 
   4507 	ASSERT(MUTEX_HELD(&port->fp_mutex));
   4508 	ASSERT(MUTEX_HELD(&pd->pd_mutex));
   4509 
   4510 	fp_els_init(cmd, port->fp_port_id.port_id, pd->pd_port_id.port_id,
   4511 	    fp_rnid_intr, job);
   4512 
   4513 	cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
   4514 	pkt->pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
   4515 	pkt->pkt_tran_type = FC_PKT_EXCHANGE;
   4516 
   4517 	payload.ls_code.ls_code = LA_ELS_RNID;
   4518 	payload.ls_code.mbz = 0;
   4519 	payload.data_format = flag;
   4520 
   4521 	FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
   4522 	    (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
   4523 }
   4524 
   4525 /*
   4526  * Initialize RLS ELS request
   4527  */
   4528 static void
   4529 fp_rls_init(fp_cmd_t *cmd, job_request_t *job)
   4530 {
   4531 	fc_local_port_t	*port;
   4532 	fc_packet_t	*pkt;
   4533 	la_els_rls_t	payload;
   4534 	fc_remote_port_t	*pd;
   4535 
   4536 	pkt = &cmd->cmd_pkt;
   4537 	pd = pkt->pkt_pd;
   4538 	port = pd->pd_port;
   4539 
   4540 	ASSERT(MUTEX_HELD(&port->fp_mutex));
   4541 	ASSERT(MUTEX_HELD(&pd->pd_mutex));
   4542 
   4543 	fp_els_init(cmd, port->fp_port_id.port_id, pd->pd_port_id.port_id,
   4544 	    fp_rls_intr, job);
   4545 
   4546 	cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
   4547 	pkt->pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
   4548 	pkt->pkt_tran_type = FC_PKT_EXCHANGE;
   4549 
   4550 	payload.ls_code.ls_code = LA_ELS_RLS;
   4551 	payload.ls_code.mbz = 0;
   4552 	payload.rls_portid = port->fp_port_id;
   4553 
   4554 	FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
   4555 	    (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
   4556 }
   4557 
   4558 
   4559 /*
   4560  * Initialize an ADISC ELS request
   4561  */
   4562 static void
   4563 fp_adisc_init(fp_cmd_t *cmd, job_request_t *job)
   4564 {
   4565 	fc_local_port_t *port;
   4566 	fc_packet_t	*pkt;
   4567 	la_els_adisc_t	payload;
   4568 	fc_remote_port_t	*pd;
   4569 
   4570 	pkt = &cmd->cmd_pkt;
   4571 	pd = pkt->pkt_pd;
   4572 	port = pd->pd_port;
   4573 
   4574 	ASSERT(MUTEX_HELD(&pd->pd_mutex));
   4575 	ASSERT(MUTEX_HELD(&pd->pd_port->fp_mutex));
   4576 
   4577 	fp_els_init(cmd, port->fp_port_id.port_id, pd->pd_port_id.port_id,
   4578 	    fp_adisc_intr, job);
   4579 
   4580 	cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
   4581 	pkt->pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
   4582 	pkt->pkt_tran_type = FC_PKT_EXCHANGE;
   4583 
   4584 	payload.ls_code.ls_code = LA_ELS_ADISC;
   4585 	payload.ls_code.mbz = 0;
   4586 	payload.nport_id = port->fp_port_id;
   4587 	payload.port_wwn = port->fp_service_params.nport_ww_name;
   4588 	payload.node_wwn = port->fp_service_params.node_ww_name;
   4589 	payload.hard_addr = port->fp_hard_addr;
   4590 
   4591 	FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
   4592 	    (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
   4593 }
   4594 
   4595 
   4596 /*
   4597  * Send up a state change notification to ULPs.
   4598  * Spawns a call to fctl_ulp_statec_cb in a taskq thread.
   4599  */
   4600 static int
   4601 fp_ulp_statec_cb(fc_local_port_t *port, uint32_t state,
   4602     fc_portmap_t *changelist, uint32_t listlen, uint32_t alloc_len, int sleep)
   4603 {
   4604 	fc_port_clist_t		*clist;
   4605 	fc_remote_port_t	*pd;
   4606 	int			count;
   4607 
   4608 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
   4609 
   4610 	clist = kmem_zalloc(sizeof (*clist), sleep);
   4611 	if (clist == NULL) {
   4612 		kmem_free(changelist, alloc_len * sizeof (*changelist));
   4613 		return (FC_NOMEM);
   4614 	}
   4615 
   4616 	clist->clist_state = state;
   4617 
   4618 	mutex_enter(&port->fp_mutex);
   4619 	clist->clist_flags = port->fp_topology;
   4620 	mutex_exit(&port->fp_mutex);
   4621 
   4622 	clist->clist_port = (opaque_t)port;
   4623 	clist->clist_len = listlen;
   4624 	clist->clist_size = alloc_len;
   4625 	clist->clist_map = changelist;
   4626 
   4627 	/*
   4628 	 * Bump the reference count of each fc_remote_port_t in this changelist.
   4629 	 * This is necessary since these devices will be sitting in a taskq
   4630 	 * and referenced later.  When the state change notification is
   4631 	 * complete, the reference counts will be decremented.
   4632 	 */
   4633 	for (count = 0; count < clist->clist_len; count++) {
   4634 		pd = clist->clist_map[count].map_pd;
   4635 
   4636 		if (pd != NULL) {
   4637 			mutex_enter(&pd->pd_mutex);
   4638 			ASSERT((pd->pd_ref_count >= 0) ||
   4639 			    (pd->pd_aux_flags & PD_GIVEN_TO_ULPS));
   4640 			pd->pd_ref_count++;
   4641 
   4642 			if (clist->clist_map[count].map_state !=
   4643 			    PORT_DEVICE_INVALID) {
   4644 				pd->pd_aux_flags |= PD_GIVEN_TO_ULPS;
   4645 			}
   4646 
   4647 			mutex_exit(&pd->pd_mutex);
   4648 		}
   4649 	}
   4650 
   4651 #ifdef	DEBUG
   4652 	/*
   4653 	 * Sanity check for presence of OLD devices in the hash lists
   4654 	 */
   4655 	if (clist->clist_size) {
   4656 		ASSERT(clist->clist_map != NULL);
   4657 		for (count = 0; count < clist->clist_len; count++) {
   4658 			if (clist->clist_map[count].map_state ==
   4659 			    PORT_DEVICE_INVALID) {
   4660 				la_wwn_t	pwwn;
   4661 				fc_portid_t	d_id;
   4662 
   4663 				pd = clist->clist_map[count].map_pd;
   4664 				ASSERT(pd != NULL);
   4665 
   4666 				mutex_enter(&pd->pd_mutex);
   4667 				pwwn = pd->pd_port_name;
   4668 				d_id = pd->pd_port_id;
   4669 				mutex_exit(&pd->pd_mutex);
   4670 
   4671 				pd = fctl_get_remote_port_by_pwwn(port, &pwwn);
   4672 				ASSERT(pd != clist->clist_map[count].map_pd);
   4673 
   4674 				pd = fctl_get_remote_port_by_did(port,
   4675 				    d_id.port_id);
   4676 				ASSERT(pd != clist->clist_map[count].map_pd);
   4677 			}
   4678 		}
   4679 	}
   4680 #endif
   4681 
   4682 	mutex_enter(&port->fp_mutex);
   4683 
   4684 	if (state == FC_STATE_ONLINE) {
   4685 		if (--port->fp_statec_busy == 0) {
   4686 			port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
   4687 		}
   4688 	}
   4689 	mutex_exit(&port->fp_mutex);
   4690 
   4691 	(void) taskq_dispatch(port->fp_taskq, fctl_ulp_statec_cb,
   4692 	    clist, KM_SLEEP);
   4693 
   4694 	FP_TRACE(FP_NHEAD1(4, 0), "fp_ulp_statec fired; Port=%p,"
   4695 	    "state=%x, len=%d", port, state, listlen);
   4696 
   4697 	return (FC_SUCCESS);
   4698 }
   4699 
   4700 
   4701 /*
   4702  * Send up a FC_STATE_DEVICE_CHANGE state notification to ULPs
   4703  */
   4704 static int
   4705 fp_ulp_devc_cb(fc_local_port_t *port, fc_portmap_t *changelist,
   4706     uint32_t listlen, uint32_t alloc_len, int sleep, int sync)
   4707 {
   4708 	int		ret;
   4709 	fc_port_clist_t *clist;
   4710 
   4711 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
   4712 
   4713 	clist = kmem_zalloc(sizeof (*clist), sleep);
   4714 	if (clist == NULL) {
   4715 		kmem_free(changelist, alloc_len * sizeof (*changelist));
   4716 		return (FC_NOMEM);
   4717 	}
   4718 
   4719 	clist->clist_state = FC_STATE_DEVICE_CHANGE;
   4720 
   4721 	mutex_enter(&port->fp_mutex);
   4722 	clist->clist_flags = port->fp_topology;
   4723 	mutex_exit(&port->fp_mutex);
   4724 
   4725 	clist->clist_port = (opaque_t)port;
   4726 	clist->clist_len = listlen;
   4727 	clist->clist_size = alloc_len;
   4728 	clist->clist_map = changelist;
   4729 
   4730 	/* Send sysevents for target state changes */
   4731 
   4732 	if (clist->clist_size) {
   4733 		int			count;
   4734 		fc_remote_port_t	*pd;
   4735 
   4736 		ASSERT(clist->clist_map != NULL);
   4737 		for (count = 0; count < clist->clist_len; count++) {
   4738 			pd = clist->clist_map[count].map_pd;
   4739 
   4740 			/*
   4741 			 * Bump reference counts on all fc_remote_port_t
   4742 			 * structs in this list.  We don't know when the task
   4743 			 * will fire, and we don't need these fc_remote_port_t
   4744 			 * structs going away behind our back.
   4745 			 */
   4746 			if (pd) {
   4747 				mutex_enter(&pd->pd_mutex);
   4748 				ASSERT((pd->pd_ref_count >= 0) ||
   4749 				    (pd->pd_aux_flags & PD_GIVEN_TO_ULPS));
   4750 				pd->pd_ref_count++;
   4751 				mutex_exit(&pd->pd_mutex);
   4752 			}
   4753 
   4754 			if (clist->clist_map[count].map_state ==
   4755 			    PORT_DEVICE_VALID) {
   4756 				if (clist->clist_map[count].map_type ==
   4757 				    PORT_DEVICE_NEW) {
   4758 					/* Update our state change counter */
   4759 					mutex_enter(&port->fp_mutex);
   4760 					port->fp_last_change++;
   4761 					mutex_exit(&port->fp_mutex);
   4762 
   4763 					/* Additions */
   4764 					fp_log_target_event(port,
   4765 					    ESC_SUNFC_TARGET_ADD,
   4766 					    clist->clist_map[count].map_pwwn,
   4767 					    clist->clist_map[count].map_did.
   4768 					    port_id);
   4769 				}
   4770 
   4771 			} else if ((clist->clist_map[count].map_type ==
   4772 			    PORT_DEVICE_OLD) &&
   4773 			    (clist->clist_map[count].map_state ==
   4774 			    PORT_DEVICE_INVALID)) {
   4775 				/* Update our state change counter */
   4776 				mutex_enter(&port->fp_mutex);
   4777 				port->fp_last_change++;
   4778 				mutex_exit(&port->fp_mutex);
   4779 
   4780 				/*
   4781 				 * For removals, we don't decrement
   4782 				 * pd_ref_count until after the ULP's
   4783 				 * state change callback function has
   4784 				 * completed.
   4785 				 */
   4786 
   4787 				/* Removals */
   4788 				fp_log_target_event(port,
   4789 				    ESC_SUNFC_TARGET_REMOVE,
   4790 				    clist->clist_map[count].map_pwwn,
   4791 				    clist->clist_map[count].map_did.port_id);
   4792 			}
   4793 
   4794 			if (clist->clist_map[count].map_state !=
   4795 			    PORT_DEVICE_INVALID) {
   4796 				/*
   4797 				 * Indicate that the ULPs are now aware of
   4798 				 * this device.
   4799 				 */
   4800 
   4801 				mutex_enter(&pd->pd_mutex);
   4802 				pd->pd_aux_flags |= PD_GIVEN_TO_ULPS;
   4803 				mutex_exit(&pd->pd_mutex);
   4804 			}
   4805 
   4806 #ifdef	DEBUG
   4807 			/*
   4808 			 * Sanity check for OLD devices in the hash lists
   4809 			 */
   4810 			if (pd && clist->clist_map[count].map_state ==
   4811 			    PORT_DEVICE_INVALID) {
   4812 				la_wwn_t	pwwn;
   4813 				fc_portid_t	d_id;
   4814 
   4815 				mutex_enter(&pd->pd_mutex);
   4816 				pwwn = pd->pd_port_name;
   4817 				d_id = pd->pd_port_id;
   4818 				mutex_exit(&pd->pd_mutex);
   4819 
   4820 				/*
   4821 				 * This overwrites the 'pd' local variable.
   4822 				 * Beware of this if 'pd' ever gets
   4823 				 * referenced below this block.
   4824 				 */
   4825 				pd = fctl_get_remote_port_by_pwwn(port, &pwwn);
   4826 				ASSERT(pd != clist->clist_map[count].map_pd);
   4827 
   4828 				pd = fctl_get_remote_port_by_did(port,
   4829 				    d_id.port_id);
   4830 				ASSERT(pd != clist->clist_map[count].map_pd);
   4831 			}
   4832 #endif
   4833 		}
   4834 	}
   4835 
   4836 	if (sync) {
   4837 		clist->clist_wait = 1;
   4838 		mutex_init(&clist->clist_mutex, NULL, MUTEX_DRIVER, NULL);
   4839 		cv_init(&clist->clist_cv, NULL, CV_DRIVER, NULL);
   4840 	}
   4841 
   4842 	ret = taskq_dispatch(port->fp_taskq, fctl_ulp_statec_cb, clist, sleep);
   4843 	if (sync && ret) {
   4844 		mutex_enter(&clist->clist_mutex);
   4845 		while (clist->clist_wait) {
   4846 			cv_wait(&clist->clist_cv, &clist->clist_mutex);
   4847 		}
   4848 		mutex_exit(&clist->clist_mutex);
   4849 
   4850 		mutex_destroy(&clist->clist_mutex);
   4851 		cv_destroy(&clist->clist_cv);
   4852 		kmem_free(clist, sizeof (*clist));
   4853 	}
   4854 
   4855 	if (!ret) {
   4856 		FP_TRACE(FP_NHEAD1(4, 0), "fp_ulp_devc dispatch failed; "
   4857 		    "port=%p", port);
   4858 		kmem_free(clist->clist_map,
   4859 		    sizeof (*(clist->clist_map)) * clist->clist_size);
   4860 		kmem_free(clist, sizeof (*clist));
   4861 	} else {
   4862 		FP_TRACE(FP_NHEAD1(4, 0), "fp_ulp_devc fired; port=%p, len=%d",
   4863 		    port, listlen);
   4864 	}
   4865 
   4866 	return (FC_SUCCESS);
   4867 }
   4868 
   4869 
   4870 /*
   4871  * Perform PLOGI to the group of devices for ULPs
   4872  */
   4873 static void
   4874 fp_plogi_group(fc_local_port_t *port, job_request_t *job)
   4875 {
   4876 	int			offline;
   4877 	int			count;
   4878 	int			rval;
   4879 	uint32_t		listlen;
   4880 	uint32_t		done;
   4881 	uint32_t		d_id;
   4882 	fc_remote_node_t	*node;
   4883 	fc_remote_port_t	*pd;
   4884 	fc_remote_port_t	*tmp_pd;
   4885 	fc_packet_t		*ulp_pkt;
   4886 	la_els_logi_t		*els_data;
   4887 	ls_code_t		ls_code;
   4888 
   4889 	FP_TRACE(FP_NHEAD1(1, 0), "fp_plogi_group begin; port=%p, job=%p",
   4890 	    port, job);
   4891 
   4892 	done = 0;
   4893 	listlen = job->job_ulp_listlen;
   4894 	job->job_counter = job->job_ulp_listlen;
   4895 
   4896 	mutex_enter(&port->fp_mutex);
   4897 	offline = (port->fp_statec_busy ||
   4898 	    FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) ? 1 : 0;
   4899 	mutex_exit(&port->fp_mutex);
   4900 
   4901 	for (count = 0; count < listlen; count++) {
   4902 		ASSERT(job->job_ulp_pkts[count]->pkt_rsplen >=
   4903 		    sizeof (la_els_logi_t));
   4904 
   4905 		ulp_pkt = job->job_ulp_pkts[count];
   4906 		pd = ulp_pkt->pkt_pd;
   4907 		d_id = ulp_pkt->pkt_cmd_fhdr.d_id;
   4908 
   4909 		if (offline) {
   4910 			done++;
   4911 
   4912 			ulp_pkt->pkt_state = FC_PKT_PORT_OFFLINE;
   4913 			ulp_pkt->pkt_reason = FC_REASON_OFFLINE;
   4914 			ulp_pkt->pkt_pd = NULL;
   4915 			ulp_pkt->pkt_comp(ulp_pkt);
   4916 
   4917 			job->job_ulp_pkts[count] = NULL;
   4918 
   4919 			fp_jobdone(job);
   4920 			continue;
   4921 		}
   4922 
   4923 		if (pd == NULL) {
   4924 			pd = fctl_get_remote_port_by_did(port, d_id);
   4925 			if (pd == NULL) {
   4926 				/* reset later */
   4927 				ulp_pkt->pkt_state = FC_PKT_FAILURE;
   4928 				continue;
   4929 			}
   4930 			mutex_enter(&pd->pd_mutex);
   4931 			if (pd->pd_flags == PD_ELS_IN_PROGRESS) {
   4932 				mutex_exit(&pd->pd_mutex);
   4933 				ulp_pkt->pkt_state = FC_PKT_ELS_IN_PROGRESS;
   4934 				done++;
   4935 				ulp_pkt->pkt_comp(ulp_pkt);
   4936 				job->job_ulp_pkts[count] = NULL;
   4937 				fp_jobdone(job);
   4938 			} else {
   4939 				ulp_pkt->pkt_state = FC_PKT_FAILURE;
   4940 				mutex_exit(&pd->pd_mutex);
   4941 			}
   4942 			continue;
   4943 		}
   4944 
   4945 		switch (ulp_pkt->pkt_state) {
   4946 		case FC_PKT_ELS_IN_PROGRESS:
   4947 			ulp_pkt->pkt_reason = FC_REASON_OFFLINE;
   4948 			/* FALLTHRU */
   4949 		case FC_PKT_LOCAL_RJT:
   4950 			done++;
   4951 			ulp_pkt->pkt_comp(ulp_pkt);
   4952 			job->job_ulp_pkts[count] = NULL;
   4953 			fp_jobdone(job);
   4954 			continue;
   4955 		default:
   4956 			break;
   4957 		}
   4958 
   4959 		/*
   4960 		 * Validate the pd corresponding to the d_id passed
   4961 		 * by the ULPs
   4962 		 */
   4963 		tmp_pd = fctl_get_remote_port_by_did(port, d_id);
   4964 		if ((tmp_pd == NULL) || (pd != tmp_pd)) {
   4965 			done++;
   4966 			ulp_pkt->pkt_state = FC_PKT_FAILURE;
   4967 			ulp_pkt->pkt_reason = FC_REASON_NO_CONNECTION;
   4968 			ulp_pkt->pkt_pd = NULL;
   4969 			ulp_pkt->pkt_comp(ulp_pkt);
   4970 			job->job_ulp_pkts[count] = NULL;
   4971 			fp_jobdone(job);
   4972 			continue;
   4973 		}
   4974 
   4975 		FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_group contd; "
   4976 		    "port=%p, pd=%p", port, pd);
   4977 
   4978 		mutex_enter(&pd->pd_mutex);
   4979 
   4980 		if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
   4981 			done++;
   4982 			els_data = (la_els_logi_t *)ulp_pkt->pkt_resp;
   4983 
   4984 			ls_code.ls_code = LA_ELS_ACC;
   4985 			ls_code.mbz = 0;
   4986 
   4987 			FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
   4988 			    (uint8_t *)&ls_code, (uint8_t *)&els_data->ls_code,
   4989 			    sizeof (ls_code_t), DDI_DEV_AUTOINCR);
   4990 
   4991 			FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
   4992 			    (uint8_t *)&pd->pd_csp,
   4993 			    (uint8_t *)&els_data->common_service,
   4994 			    sizeof (pd->pd_csp), DDI_DEV_AUTOINCR);
   4995 
   4996 			FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
   4997 			    (uint8_t *)&pd->pd_port_name,
   4998 			    (uint8_t *)&els_data->nport_ww_name,
   4999 			    sizeof (pd->pd_port_name), DDI_DEV_AUTOINCR);
   5000 
   5001 			FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
   5002 			    (uint8_t *)&pd->pd_clsp1,
   5003 			    (uint8_t *)&els_data->class_1,
   5004 			    sizeof (pd->pd_clsp1), DDI_DEV_AUTOINCR);
   5005 
   5006 			FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
   5007 			    (uint8_t *)&pd->pd_clsp2,
   5008 			    (uint8_t *)&els_data->class_2,
   5009 			    sizeof (pd->pd_clsp2), DDI_DEV_AUTOINCR);
   5010 
   5011 			FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
   5012 			    (uint8_t *)&pd->pd_clsp3,
   5013 			    (uint8_t *)&els_data->class_3,
   5014 			    sizeof (pd->pd_clsp3), DDI_DEV_AUTOINCR);
   5015 
   5016 			node = pd->pd_remote_nodep;
   5017 			pd->pd_login_count++;
   5018 			pd->pd_flags = PD_IDLE;
   5019 			ulp_pkt->pkt_pd = pd;
   5020 			mutex_exit(&pd->pd_mutex);
   5021 
   5022 			mutex_enter(&node->fd_mutex);
   5023 			FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
   5024 			    (uint8_t *)&node->fd_node_name,
   5025 			    (uint8_t *)(&els_data->node_ww_name),
   5026 			    sizeof (node->fd_node_name), DDI_DEV_AUTOINCR);
   5027 
   5028 			FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
   5029 			    (uint8_t *)&node->fd_vv,
   5030 			    (uint8_t *)(&els_data->vendor_version),
   5031 			    sizeof (node->fd_vv), DDI_DEV_AUTOINCR);
   5032 
   5033 			mutex_exit(&node->fd_mutex);
   5034 			ulp_pkt->pkt_state = FC_PKT_SUCCESS;
   5035 		} else {
   5036 
   5037 			ulp_pkt->pkt_state = FC_PKT_FAILURE; /* reset later */
   5038 			mutex_exit(&pd->pd_mutex);
   5039 		}
   5040 
   5041 		if (ulp_pkt->pkt_state != FC_PKT_FAILURE) {
   5042 			ulp_pkt->pkt_comp(ulp_pkt);
   5043 			job->job_ulp_pkts[count] = NULL;
   5044 			fp_jobdone(job);
   5045 		}
   5046 	}
   5047 
   5048 	if (done == listlen) {
   5049 		fp_jobwait(job);
   5050 		fctl_jobdone(job);
   5051 		return;
   5052 	}
   5053 
   5054 	job->job_counter = listlen - done;
   5055 
   5056 	for (count = 0; count < listlen; count++) {
   5057 		int cmd_flags;
   5058 
   5059 		if ((ulp_pkt = job->job_ulp_pkts[count]) == NULL) {
   5060 			continue;
   5061 		}
   5062 
   5063 		ASSERT(ulp_pkt->pkt_state == FC_PKT_FAILURE);
   5064 
   5065 		cmd_flags = FP_CMD_PLOGI_RETAIN;
   5066 
   5067 		d_id = ulp_pkt->pkt_cmd_fhdr.d_id;
   5068 		ASSERT(d_id != 0);
   5069 
   5070 		pd = fctl_get_remote_port_by_did(port, d_id);
   5071 
   5072 		/*
   5073 		 * We need to properly adjust the port device
   5074 		 * reference counter before we assign the pd
   5075 		 * to the ULP packets port device pointer.
   5076 		 */
   5077 		if (pd != NULL && ulp_pkt->pkt_pd == NULL) {
   5078 			mutex_enter(&pd->pd_mutex);
   5079 			pd->pd_ref_count++;
   5080 			mutex_exit(&pd->pd_mutex);
   5081 			FP_TRACE(FP_NHEAD1(3, 0),
   5082 			    "fp_plogi_group: DID = 0x%x using new pd %p \
   5083 			    old pd NULL\n", d_id, pd);
   5084 		} else if (pd != NULL && ulp_pkt->pkt_pd != NULL &&
   5085 		    ulp_pkt->pkt_pd != pd) {
   5086 			mutex_enter(&pd->pd_mutex);
   5087 			pd->pd_ref_count++;
   5088 			mutex_exit(&pd->pd_mutex);
   5089 			mutex_enter(&ulp_pkt->pkt_pd->pd_mutex);
   5090 			ulp_pkt->pkt_pd->pd_ref_count--;
   5091 			mutex_exit(&ulp_pkt->pkt_pd->pd_mutex);
   5092 			FP_TRACE(FP_NHEAD1(3, 0),
   5093 			    "fp_plogi_group: DID = 0x%x pkt_pd %p != pd %p\n",
   5094 			    d_id, ulp_pkt->pkt_pd, pd);
   5095 		} else if (pd == NULL && ulp_pkt->pkt_pd != NULL) {
   5096 			mutex_enter(&ulp_pkt->pkt_pd->pd_mutex);
   5097 			ulp_pkt->pkt_pd->pd_ref_count--;
   5098 			mutex_exit(&ulp_pkt->pkt_pd->pd_mutex);
   5099 			FP_TRACE(FP_NHEAD1(3, 0),
   5100 			    "fp_plogi_group: DID = 0x%x pd is NULL and \
   5101 			    pkt_pd = %p\n", d_id, ulp_pkt->pkt_pd);
   5102 		}
   5103 
   5104 		ulp_pkt->pkt_pd = pd;
   5105 
   5106 		if (pd != NULL) {
   5107 			mutex_enter(&pd->pd_mutex);
   5108 			d_id = pd->pd_port_id.port_id;
   5109 			pd->pd_flags = PD_ELS_IN_PROGRESS;
   5110 			mutex_exit(&pd->pd_mutex);
   5111 		} else {
   5112 			d_id = ulp_pkt->pkt_cmd_fhdr.d_id;
   5113 #ifdef	DEBUG
   5114 			pd = fctl_get_remote_port_by_did(port, d_id);
   5115 			ASSERT(pd == NULL);
   5116 #endif
   5117 			/*
   5118 			 * In the Fabric topology, use NS to create
   5119 			 * port device, and if that fails still try
   5120 			 * with PLOGI - which will make yet another
   5121 			 * attempt to create after successful PLOGI
   5122 			 */
   5123 			mutex_enter(&port->fp_mutex);
   5124 			if (FC_IS_TOP_SWITCH(port->fp_topology)) {
   5125 				mutex_exit(&port->fp_mutex);
   5126 				pd = fp_create_remote_port_by_ns(port,
   5127 				    d_id, KM_SLEEP);
   5128 				if (pd) {
   5129 					cmd_flags |= FP_CMD_DELDEV_ON_ERROR;
   5130 
   5131 					mutex_enter(&pd->pd_mutex);
   5132 					pd->pd_flags = PD_ELS_IN_PROGRESS;
   5133 					mutex_exit(&pd->pd_mutex);
   5134 
   5135 					FP_TRACE(FP_NHEAD1(3, 0),
   5136 					    "fp_plogi_group;"
   5137 					    " NS created PD port=%p, job=%p,"
   5138 					    " pd=%p", port, job, pd);
   5139 				}
   5140 			} else {
   5141 				mutex_exit(&port->fp_mutex);
   5142 			}
   5143 			if ((ulp_pkt->pkt_pd == NULL) && (pd != NULL)) {
   5144 				FP_TRACE(FP_NHEAD1(3, 0),
   5145 				    "fp_plogi_group;"
   5146 				    "ulp_pkt's pd is NULL, get a pd %p",
   5147 				    pd);
   5148 				mutex_enter(&pd->pd_mutex);
   5149 				pd->pd_ref_count++;
   5150 				mutex_exit(&pd->pd_mutex);
   5151 			}
   5152 			ulp_pkt->pkt_pd = pd;
   5153 		}
   5154 
   5155 		rval = fp_port_login(port, d_id, job, cmd_flags,
   5156 		    KM_SLEEP, pd, ulp_pkt);
   5157 
   5158 		if (rval == FC_SUCCESS) {
   5159 			continue;
   5160 		}
   5161 
   5162 		if (rval == FC_STATEC_BUSY) {
   5163 			ulp_pkt->pkt_state = FC_PKT_PORT_OFFLINE;
   5164 			ulp_pkt->pkt_reason = FC_REASON_OFFLINE;
   5165 		} else {
   5166 			ulp_pkt->pkt_state = FC_PKT_FAILURE;
   5167 		}
   5168 
   5169 		if (pd) {
   5170 			mutex_enter(&pd->pd_mutex);
   5171 			pd->pd_flags = PD_IDLE;
   5172 			mutex_exit(&pd->pd_mutex);
   5173 		}
   5174 
   5175 		if (cmd_flags & FP_CMD_DELDEV_ON_ERROR) {
   5176 			ASSERT(pd != NULL);
   5177 
   5178 			FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_group: NS created,"
   5179 			    " PD removed; port=%p, job=%p", port, job);
   5180 
   5181 			mutex_enter(&pd->pd_mutex);
   5182 			pd->pd_ref_count--;
   5183 			node = pd->pd_remote_nodep;
   5184 			mutex_exit(&pd->pd_mutex);
   5185 
   5186 			ASSERT(node != NULL);
   5187 
   5188 			if (fctl_destroy_remote_port(port, pd) == 0) {
   5189 				fctl_destroy_remote_node(node);
   5190 			}
   5191 			ulp_pkt->pkt_pd = NULL;
   5192 		}
   5193 		ulp_pkt->pkt_comp(ulp_pkt);
   5194 		fp_jobdone(job);
   5195 	}
   5196 
   5197 	fp_jobwait(job);
   5198 	fctl_jobdone(job);
   5199 
   5200 	FP_TRACE(FP_NHEAD1(1, 0), "fp_plogi_group end: port=%p, job=%p",
   5201 	    port, job);
   5202 }
   5203 
   5204 
   5205 /*
   5206  * Name server request initialization
   5207  */
   5208 static void
   5209 fp_ns_init(fc_local_port_t *port, job_request_t *job, int sleep)
   5210 {
   5211 	int rval;
   5212 	int count;
   5213 	int size;
   5214 
   5215 	ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
   5216 
   5217 	job->job_counter = 1;
   5218 	job->job_result = FC_SUCCESS;
   5219 
   5220 	rval = fp_port_login(port, 0xFFFFFC, job, FP_CMD_PLOGI_RETAIN,
   5221 	    KM_SLEEP, NULL, NULL);
   5222 
   5223 	if (rval != FC_SUCCESS) {
   5224 		mutex_enter(&port->fp_mutex);
   5225 		port->fp_topology = FC_TOP_NO_NS;
   5226 		mutex_exit(&port->fp_mutex);
   5227 		return;
   5228 	}
   5229 
   5230 	fp_jobwait(job);
   5231 
   5232 	if (job->job_result != FC_SUCCESS) {
   5233 		mutex_enter(&port->fp_mutex);
   5234 		port->fp_topology = FC_TOP_NO_NS;
   5235 		mutex_exit(&port->fp_mutex);
   5236 		return;
   5237 	}
   5238 
   5239 	/*
   5240 	 * At this time, we'll do NS registration for objects in the
   5241 	 * ns_reg_cmds (see top of this file) array.
   5242 	 *
   5243 	 * Each time a ULP module registers with the transport, the
   5244 	 * appropriate fc4 bit is set fc4 types and registered with
   5245 	 * the NS for this support. Also, ULPs and FC admin utilities
   5246 	 * may do registration for objects like IP address, symbolic
   5247 	 * port/node name, Initial process associator at run time.
   5248 	 */
   5249 	size = sizeof (ns_reg_cmds) / sizeof (ns_reg_cmds[0]);
   5250 	job->job_counter = size;
   5251 	job->job_result = FC_SUCCESS;
   5252 
   5253 	for (count = 0; count < size; count++) {
   5254 		if (fp_ns_reg(port, NULL, ns_reg_cmds[count],
   5255 		    job, 0, sleep) != FC_SUCCESS) {
   5256 			fp_jobdone(job);
   5257 		}
   5258 	}
   5259 	if (size) {
   5260 		fp_jobwait(job);
   5261 	}
   5262 
   5263 	job->job_result = FC_SUCCESS;
   5264 
   5265 	(void) fp_ns_get_devcount(port, job, 0, KM_SLEEP);
   5266 
   5267 	if (port->fp_dev_count < FP_MAX_DEVICES) {
   5268 		(void) fp_ns_get_devcount(port, job, 1, KM_SLEEP);
   5269 	}
   5270 
   5271 	job->job_counter = 1;
   5272 
   5273 	if (fp_ns_scr(port, job, FC_SCR_FULL_REGISTRATION,
   5274 	    sleep) == FC_SUCCESS) {
   5275 		fp_jobwait(job);
   5276 	}
   5277 }
   5278 
   5279 
   5280 /*
   5281  * Name server finish:
   5282  *	Unregister for RSCNs
   5283  *	Unregister all the host port objects in the Name Server
   5284  *	Perform LOGO with the NS;
   5285  */
   5286 static void
   5287 fp_ns_fini(fc_local_port_t *port, job_request_t *job)
   5288 {
   5289 	fp_cmd_t	*cmd;
   5290 	uchar_t		class;
   5291 	uint32_t	s_id;
   5292 	fc_packet_t	*pkt;
   5293 	la_els_logo_t	payload;
   5294 
   5295 	ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
   5296 
   5297 	job->job_counter = 1;
   5298 
   5299 	if (fp_ns_scr(port, job, FC_SCR_CLEAR_REGISTRATION, KM_SLEEP) !=
   5300 	    FC_SUCCESS) {
   5301 		fp_jobdone(job);
   5302 	}
   5303 	fp_jobwait(job);
   5304 
   5305 	job->job_counter = 1;
   5306 
   5307 	if (fp_ns_reg(port, NULL, NS_DA_ID, job, 0, KM_SLEEP) != FC_SUCCESS) {
   5308 		fp_jobdone(job);
   5309 	}
   5310 	fp_jobwait(job);
   5311 
   5312 	job->job_counter = 1;
   5313 
   5314 	cmd = fp_alloc_pkt(port, sizeof (la_els_logo_t),
   5315 	    FP_PORT_IDENTIFIER_LEN, KM_SLEEP, NULL);
   5316 	pkt = &cmd->cmd_pkt;
   5317 
   5318 	mutex_enter(&port->fp_mutex);
   5319 	class = port->fp_ns_login_class;
   5320 	s_id = port->fp_port_id.port_id;
   5321 	payload.nport_id = port->fp_port_id;
   5322 	mutex_exit(&port->fp_mutex);
   5323 
   5324 	cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class;
   5325 	cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
   5326 	cmd->cmd_flags = FP_CMD_PLOGI_DONT_CARE;
   5327 	cmd->cmd_retry_count = 1;
   5328 	cmd->cmd_ulp_pkt = NULL;
   5329 
   5330 	if (port->fp_npiv_type == FC_NPIV_PORT) {
   5331 		fp_els_init(cmd, s_id, 0xFFFFFE, fp_logo_intr, job);
   5332 	} else {
   5333 		fp_els_init(cmd, s_id, 0xFFFFFC, fp_logo_intr, job);
   5334 	}
   5335 
   5336 	cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
   5337 
   5338 	payload.ls_code.ls_code = LA_ELS_LOGO;
   5339 	payload.ls_code.mbz = 0;
   5340 	payload.nport_ww_name = port->fp_service_params.nport_ww_name;
   5341 
   5342 	FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
   5343 	    (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
   5344 
   5345 	if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
   5346 		fp_iodone(cmd);
   5347 	}
   5348 	fp_jobwait(job);
   5349 }
   5350 
   5351 
   5352 /*
   5353  * NS Registration function.
   5354  *
   5355  *	It should be seriously noted that FC-GS-2 currently doesn't support
   5356  *	an Object Registration by a D_ID other than the owner of the object.
   5357  *	What we are aiming at currently is to at least allow Symbolic Node/Port
   5358  *	Name registration for any N_Port Identifier by the host software.
   5359  *
   5360  *	Anyway, if the second argument (fc_remote_port_t *) is NULL, this
   5361  *	function treats the request as Host NS Object.
   5362  */
   5363 static int
   5364 fp_ns_reg(fc_local_port_t *port, fc_remote_port_t *pd, uint16_t cmd_code,
   5365     job_request_t *job, int polled, int sleep)
   5366 {
   5367 	int		rval;
   5368 	fc_portid_t	s_id;
   5369 	fc_packet_t	*pkt;
   5370 	fp_cmd_t	*cmd;
   5371 
   5372 	if (pd == NULL) {
   5373 		mutex_enter(&port->fp_mutex);
   5374 		s_id = port->fp_port_id;
   5375 		mutex_exit(&port->fp_mutex);
   5376 	} else {
   5377 		mutex_enter(&pd->pd_mutex);
   5378 		s_id = pd->pd_port_id;
   5379 		mutex_exit(&pd->pd_mutex);
   5380 	}
   5381 
   5382 	if (polled) {
   5383 		job->job_counter = 1;
   5384 	}
   5385 
   5386 	switch (cmd_code) {
   5387 	case NS_RPN_ID:
   5388 	case NS_RNN_ID: {
   5389 		ns_rxn_req_t rxn;
   5390 
   5391 		cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
   5392 		    sizeof (ns_rxn_req_t), sizeof (fc_reg_resp_t), sleep, NULL);
   5393 		if (cmd == NULL) {
   5394 			return (FC_NOMEM);
   5395 		}
   5396 		fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
   5397 		pkt = &cmd->cmd_pkt;
   5398 
   5399 		if (pd == NULL) {
   5400 			rxn.rxn_xname = ((cmd_code == NS_RPN_ID) ?
   5401 			    (port->fp_service_params.nport_ww_name) :
   5402 			    (port->fp_service_params.node_ww_name));
   5403 		} else {
   5404 			if (cmd_code == NS_RPN_ID) {
   5405 				mutex_enter(&pd->pd_mutex);
   5406 				rxn.rxn_xname = pd->pd_port_name;
   5407 				mutex_exit(&pd->pd_mutex);
   5408 			} else {
   5409 				fc_remote_node_t *node;
   5410 
   5411 				mutex_enter(&pd->pd_mutex);
   5412 				node = pd->pd_remote_nodep;
   5413 				mutex_exit(&pd->pd_mutex);
   5414 
   5415 				mutex_enter(&node->fd_mutex);
   5416 				rxn.rxn_xname = node->fd_node_name;
   5417 				mutex_exit(&node->fd_mutex);
   5418 			}
   5419 		}
   5420 		rxn.rxn_port_id = s_id;
   5421 
   5422 		FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rxn,
   5423 		    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
   5424 		    sizeof (rxn), DDI_DEV_AUTOINCR);
   5425 
   5426 		break;
   5427 	}
   5428 
   5429 	case NS_RCS_ID: {
   5430 		ns_rcos_t rcos;
   5431 
   5432 		cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
   5433 		    sizeof (ns_rcos_t), sizeof (fc_reg_resp_t), sleep, NULL);
   5434 		if (cmd == NULL) {
   5435 			return (FC_NOMEM);
   5436 		}
   5437 		fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
   5438 		pkt = &cmd->cmd_pkt;
   5439 
   5440 		if (pd == NULL) {
   5441 			rcos.rcos_cos = port->fp_cos;
   5442 		} else {
   5443 			mutex_enter(&pd->pd_mutex);
   5444 			rcos.rcos_cos = pd->pd_cos;
   5445 			mutex_exit(&pd->pd_mutex);
   5446 		}
   5447 		rcos.rcos_port_id = s_id;
   5448 
   5449 		FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rcos,
   5450 		    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
   5451 		    sizeof (rcos), DDI_DEV_AUTOINCR);
   5452 
   5453 		break;
   5454 	}
   5455 
   5456 	case NS_RFT_ID: {
   5457 		ns_rfc_type_t rfc;
   5458 
   5459 		cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
   5460 		    sizeof (ns_rfc_type_t), sizeof (fc_reg_resp_t), sleep,
   5461 		    NULL);
   5462 		if (cmd == NULL) {
   5463 			return (FC_NOMEM);
   5464 		}
   5465 		fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
   5466 		pkt = &cmd->cmd_pkt;
   5467 
   5468 		if (pd == NULL) {
   5469 			mutex_enter(&port->fp_mutex);
   5470 			bcopy(port->fp_fc4_types, rfc.rfc_types,
   5471 			    sizeof (port->fp_fc4_types));
   5472 			mutex_exit(&port->fp_mutex);
   5473 		} else {
   5474 			mutex_enter(&pd->pd_mutex);
   5475 			bcopy(pd->pd_fc4types, rfc.rfc_types,
   5476 			    sizeof (pd->pd_fc4types));
   5477 			mutex_exit(&pd->pd_mutex);
   5478 		}
   5479 		rfc.rfc_port_id = s_id;
   5480 
   5481 		FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rfc,
   5482 		    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
   5483 		    sizeof (rfc), DDI_DEV_AUTOINCR);
   5484 
   5485 		break;
   5486 	}
   5487 
   5488 	case NS_RSPN_ID: {
   5489 		uchar_t		name_len;
   5490 		int		pl_size;
   5491 		fc_portid_t	spn;
   5492 
   5493 		if (pd == NULL) {
   5494 			mutex_enter(&port->fp_mutex);
   5495 			name_len = port->fp_sym_port_namelen;
   5496 			mutex_exit(&port->fp_mutex);
   5497 		} else {
   5498 			mutex_enter(&pd->pd_mutex);
   5499 			name_len = pd->pd_spn_len;
   5500 			mutex_exit(&pd->pd_mutex);
   5501 		}
   5502 
   5503 		pl_size = sizeof (fc_portid_t) + name_len + 1;
   5504 
   5505 		cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) + pl_size,
   5506 		    sizeof (fc_reg_resp_t), sleep, NULL);
   5507 		if (cmd == NULL) {
   5508 			return (FC_NOMEM);
   5509 		}
   5510 
   5511 		fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
   5512 
   5513 		pkt = &cmd->cmd_pkt;
   5514 
   5515 		spn = s_id;
   5516 
   5517 		FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&spn, (uint8_t *)
   5518 		    (pkt->pkt_cmd + sizeof (fc_ct_header_t)), sizeof (spn),
   5519 		    DDI_DEV_AUTOINCR);
   5520 		FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&name_len,
   5521 		    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)
   5522 		    + sizeof (fc_portid_t)), 1, DDI_DEV_AUTOINCR);
   5523 
   5524 		if (pd == NULL) {
   5525 			mutex_enter(&port->fp_mutex);
   5526 			FC_SET_CMD(port, pkt->pkt_cmd_acc,
   5527 			    (uint8_t *)port->fp_sym_port_name, (uint8_t *)
   5528 			    (pkt->pkt_cmd + sizeof (fc_ct_header_t) +
   5529 			    sizeof (spn) + 1), name_len, DDI_DEV_AUTOINCR);
   5530 			mutex_exit(&port->fp_mutex);
   5531 		} else {
   5532 			mutex_enter(&pd->pd_mutex);
   5533 			FC_SET_CMD(port, pkt->pkt_cmd_acc,
   5534 			    (uint8_t *)pd->pd_spn,
   5535 			    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t) +
   5536 			    sizeof (spn) + 1), name_len, DDI_DEV_AUTOINCR);
   5537 			mutex_exit(&pd->pd_mutex);
   5538 		}
   5539 		break;
   5540 	}
   5541 
   5542 	case NS_RPT_ID: {
   5543 		ns_rpt_t rpt;
   5544 
   5545 		cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
   5546 		    sizeof (ns_rpt_t), sizeof (fc_reg_resp_t), sleep, NULL);
   5547 		if (cmd == NULL) {
   5548 			return (FC_NOMEM);
   5549 		}
   5550 		fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
   5551 		pkt = &cmd->cmd_pkt;
   5552 
   5553 		if (pd == NULL) {
   5554 			rpt.rpt_type = port->fp_port_type;
   5555 		} else {
   5556 			mutex_enter(&pd->pd_mutex);
   5557 			rpt.rpt_type = pd->pd_porttype;
   5558 			mutex_exit(&pd->pd_mutex);
   5559 		}
   5560 		rpt.rpt_port_id = s_id;
   5561 
   5562 		FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rpt,
   5563 		    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
   5564 		    sizeof (rpt), DDI_DEV_AUTOINCR);
   5565 
   5566 		break;
   5567 	}
   5568 
   5569 	case NS_RIP_NN: {
   5570 		ns_rip_t rip;
   5571 
   5572 		cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
   5573 		    sizeof (ns_rip_t), sizeof (fc_reg_resp_t), sleep, NULL);
   5574 		if (cmd == NULL) {
   5575 			return (FC_NOMEM);
   5576 		}
   5577 		fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
   5578 		pkt = &cmd->cmd_pkt;
   5579 
   5580 		if (pd == NULL) {
   5581 			rip.rip_node_name =
   5582 			    port->fp_service_params.node_ww_name;
   5583 			bcopy(port->fp_ip_addr, rip.rip_ip_addr,
   5584 			    sizeof (port->fp_ip_addr));
   5585 		} else {
   5586 			fc_remote_node_t *node;
   5587 
   5588 			/*
   5589 			 * The most correct implementation should have the IP
   5590 			 * address in the fc_remote_node_t structure; I believe
   5591 			 * Node WWN and IP address should have one to one
   5592 			 * correlation (but guess what this is changing in
   5593 			 * FC-GS-2 latest draft)
   5594 			 */
   5595 			mutex_enter(&pd->pd_mutex);
   5596 			node = pd->pd_remote_nodep;
   5597 			bcopy(pd->pd_ip_addr, rip.rip_ip_addr,
   5598 			    sizeof (pd->pd_ip_addr));
   5599 			mutex_exit(&pd->pd_mutex);
   5600 
   5601 			mutex_enter(&node->fd_mutex);
   5602 			rip.rip_node_name = node->fd_node_name;
   5603 			mutex_exit(&node->fd_mutex);
   5604 		}
   5605 
   5606 		FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rip,
   5607 		    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
   5608 		    sizeof (rip), DDI_DEV_AUTOINCR);
   5609 
   5610 		break;
   5611 	}
   5612 
   5613 	case NS_RIPA_NN: {
   5614 		ns_ipa_t ipa;
   5615 
   5616 		cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
   5617 		    sizeof (ns_ipa_t), sizeof (fc_reg_resp_t), sleep, NULL);
   5618 		if (cmd == NULL) {
   5619 			return (FC_NOMEM);
   5620 		}
   5621 		fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
   5622 		pkt = &cmd->cmd_pkt;
   5623 
   5624 		if (pd == NULL) {
   5625 			ipa.ipa_node_name =
   5626 			    port->fp_service_params.node_ww_name;
   5627 			bcopy(port->fp_ipa, ipa.ipa_value,
   5628 			    sizeof (port->fp_ipa));
   5629 		} else {
   5630 			fc_remote_node_t *node;
   5631 
   5632 			mutex_enter(&pd->pd_mutex);
   5633 			node = pd->pd_remote_nodep;
   5634 			mutex_exit(&pd->pd_mutex);
   5635 
   5636 			mutex_enter(&node->fd_mutex);
   5637 			ipa.ipa_node_name = node->fd_node_name;
   5638 			bcopy(node->fd_ipa, ipa.ipa_value,
   5639 			    sizeof (node->fd_ipa));
   5640 			mutex_exit(&node->fd_mutex);
   5641 		}
   5642 
   5643 		FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&ipa,
   5644 		    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
   5645 		    sizeof (ipa), DDI_DEV_AUTOINCR);
   5646 
   5647 		break;
   5648 	}
   5649 
   5650 	case NS_RSNN_NN: {
   5651 		uchar_t			name_len;
   5652 		int			pl_size;
   5653 		la_wwn_t		snn;
   5654 		fc_remote_node_t	*node = NULL;
   5655 
   5656 		if (pd == NULL) {
   5657 			mutex_enter(&port->fp_mutex);
   5658 			name_len = port->fp_sym_node_namelen;
   5659 			mutex_exit(&port->fp_mutex);
   5660 		} else {
   5661 			mutex_enter(&pd->pd_mutex);
   5662 			node = pd->pd_remote_nodep;
   5663 			mutex_exit(&pd->pd_mutex);
   5664 
   5665 			mutex_enter(&node->fd_mutex);
   5666 			name_len = node->fd_snn_len;
   5667 			mutex_exit(&node->fd_mutex);
   5668 		}
   5669 
   5670 		pl_size = sizeof (la_wwn_t) + name_len + 1;
   5671 
   5672 		cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
   5673 		    pl_size, sizeof (fc_reg_resp_t), sleep, NULL);
   5674 		if (cmd == NULL) {
   5675 			return (FC_NOMEM);
   5676 		}
   5677 		fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
   5678 
   5679 		pkt = &cmd->cmd_pkt;
   5680 
   5681 		bcopy(&port->fp_service_params.node_ww_name,
   5682 		    &snn, sizeof (la_wwn_t));
   5683 
   5684 		if (pd == NULL) {
   5685 			mutex_enter(&port->fp_mutex);
   5686 			FC_SET_CMD(port, pkt->pkt_cmd_acc,
   5687 			    (uint8_t *)port->fp_sym_node_name, (uint8_t *)
   5688 			    (pkt->pkt_cmd + sizeof (fc_ct_header_t) +
   5689 			    sizeof (snn) + 1), name_len, DDI_DEV_AUTOINCR);
   5690 			mutex_exit(&port->fp_mutex);
   5691 		} else {
   5692 			ASSERT(node != NULL);
   5693 			mutex_enter(&node->fd_mutex);
   5694 			FC_SET_CMD(port, pkt->pkt_cmd_acc,
   5695 			    (uint8_t *)node->fd_snn,
   5696 			    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t) +
   5697 			    sizeof (snn) + 1), name_len, DDI_DEV_AUTOINCR);
   5698 			mutex_exit(&node->fd_mutex);
   5699 		}
   5700 
   5701 		FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&snn,
   5702 		    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
   5703 		    sizeof (snn), DDI_DEV_AUTOINCR);
   5704 		FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&name_len,
   5705 		    (uint8_t *)(pkt->pkt_cmd
   5706 		    + sizeof (fc_ct_header_t) + sizeof (snn)),
   5707 		    1, DDI_DEV_AUTOINCR);
   5708 
   5709 		break;
   5710 	}
   5711 
   5712 	case NS_DA_ID: {
   5713 		ns_remall_t rall;
   5714 		char tmp[4] = {0};
   5715 		char *ptr;
   5716 
   5717 		cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
   5718 		    sizeof (ns_remall_t), sizeof (fc_reg_resp_t), sleep, NULL);
   5719 
   5720 		if (cmd == NULL) {
   5721 			return (FC_NOMEM);
   5722 		}
   5723 
   5724 		fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
   5725 		pkt = &cmd->cmd_pkt;
   5726 
   5727 		ptr = (char *)(&s_id);
   5728 		tmp[3] = *ptr++;
   5729 		tmp[2] = *ptr++;
   5730 		tmp[1] = *ptr++;
   5731 		tmp[0] = *ptr;
   5732 #if defined(_BIT_FIELDS_LTOH)
   5733 		bcopy((caddr_t)tmp, (caddr_t)(&rall.rem_port_id), 4);
   5734 #else
   5735 		rall.rem_port_id = s_id;
   5736 #endif
   5737 		FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rall,
   5738 		    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
   5739 		    sizeof (rall), DDI_DEV_AUTOINCR);
   5740 
   5741 		break;
   5742 	}
   5743 
   5744 	default:
   5745 		return (FC_FAILURE);
   5746 	}
   5747 
   5748 	rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
   5749 
   5750 	if (rval != FC_SUCCESS) {
   5751 		job->job_result = rval;
   5752 		fp_iodone(cmd);
   5753 	}
   5754 
   5755 	if (polled) {
   5756 		ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
   5757 		fp_jobwait(job);
   5758 	} else {
   5759 		rval = FC_SUCCESS;
   5760 	}
   5761 
   5762 	return (rval);
   5763 }
   5764 
   5765 
   5766 /*
   5767  * Common interrupt handler
   5768  */
   5769 static int
   5770 fp_common_intr(fc_packet_t *pkt, int iodone)
   5771 {
   5772 	int		rval = FC_FAILURE;
   5773 	fp_cmd_t	*cmd;
   5774 	fc_local_port_t	*port;
   5775 
   5776 	cmd = pkt->pkt_ulp_private;
   5777 	port = cmd->cmd_port;
   5778 
   5779 	/*
   5780 	 * Fail fast the upper layer requests if
   5781 	 * a state change has occurred amidst.
   5782 	 */
   5783 	mutex_enter(&port->fp_mutex);
   5784 	if (cmd->cmd_ulp_pkt != NULL && port->fp_statec_busy) {
   5785 		mutex_exit(&port->fp_mutex);
   5786 		cmd->cmd_ulp_pkt->pkt_state = FC_PKT_PORT_OFFLINE;
   5787 		cmd->cmd_ulp_pkt->pkt_reason = FC_REASON_OFFLINE;
   5788 	} else if (!(port->fp_soft_state &
   5789 	    (FP_SOFT_IN_DETACH | FP_DETACH_INPROGRESS))) {
   5790 		mutex_exit(&port->fp_mutex);
   5791 
   5792 		switch (pkt->pkt_state) {
   5793 		case FC_PKT_LOCAL_BSY:
   5794 		case FC_PKT_FABRIC_BSY:
   5795 		case FC_PKT_NPORT_BSY:
   5796 		case FC_PKT_TIMEOUT:
   5797 			cmd->cmd_retry_interval = (pkt->pkt_state ==
   5798 			    FC_PKT_TIMEOUT) ? 0 : fp_retry_delay;
   5799 			rval = fp_retry_cmd(pkt);
   5800 			break;
   5801 
   5802 		case FC_PKT_FABRIC_RJT:
   5803 		case FC_PKT_NPORT_RJT:
   5804 		case FC_PKT_LOCAL_RJT:
   5805 		case FC_PKT_LS_RJT:
   5806 		case FC_PKT_FS_RJT:
   5807 		case FC_PKT_BA_RJT:
   5808 			rval = fp_handle_reject(pkt);
   5809 			break;
   5810 
   5811 		default:
   5812 			if (pkt->pkt_resp_resid) {
   5813 				cmd->cmd_retry_interval = 0;
   5814 				rval = fp_retry_cmd(pkt);
   5815 			}
   5816 			break;
   5817 		}
   5818 	} else {
   5819 		mutex_exit(&port->fp_mutex);
   5820 	}
   5821 
   5822 	if (rval != FC_SUCCESS && iodone) {
   5823 		fp_iodone(cmd);
   5824 		rval = FC_SUCCESS;
   5825 	}
   5826 
   5827 	return (rval);
   5828 }
   5829 
   5830 
   5831 /*
   5832  * Some not so long winding theory on point to point topology:
   5833  *
   5834  *	In the ACC payload, if the D_ID is ZERO and the common service
   5835  *	parameters indicate N_Port, then the topology is POINT TO POINT.
   5836  *
   5837  *	In a point to point topology with an N_Port, during Fabric Login,
   5838  *	the destination N_Port will check with our WWN and decide if it
   5839  *	needs to issue PLOGI or not. That means, FLOGI could potentially
   5840  *	trigger an unsolicited PLOGI from an N_Port. The Unsolicited
   5841  *	PLOGI creates the device handles.
   5842  *
   5843  *	Assuming that the host port WWN is greater than the other N_Port
   5844  *	WWN, then we become the master (be aware that this isn't the word
   5845  *	used in the FC standards) and initiate the PLOGI.
   5846  *
   5847  */
   5848 static void
   5849 fp_flogi_intr(fc_packet_t *pkt)
   5850 {
   5851 	int			state;
   5852 	int			f_port;
   5853 	uint32_t		s_id;
   5854 	uint32_t		d_id;
   5855 	fp_cmd_t		*cmd;
   5856 	fc_local_port_t		*port;
   5857 	la_wwn_t		*swwn;
   5858 	la_wwn_t		dwwn;
   5859 	la_wwn_t		nwwn;
   5860 	fc_remote_port_t	*pd;
   5861 	la_els_logi_t		*acc;
   5862 	com_svc_t		csp;
   5863 	ls_code_t		resp;
   5864 
   5865 	cmd = pkt->pkt_ulp_private;
   5866 	port = cmd->cmd_port;
   5867 
   5868 	mutex_enter(&port->fp_mutex);
   5869 	port->fp_out_fpcmds--;
   5870 	mutex_exit(&port->fp_mutex);
   5871 
   5872 	FP_TRACE(FP_NHEAD1(1, 0), "fp_flogi_intr; port=%p, pkt=%p, state=%x",
   5873 	    port, pkt, pkt->pkt_state);
   5874 
   5875 	if (FP_IS_PKT_ERROR(pkt)) {
   5876 		(void) fp_common_intr(pkt, 1);
   5877 		return;
   5878 	}
   5879 
   5880 	/*
   5881 	 * Currently, we don't need to swap bytes here because qlc is faking the
   5882 	 * response for us and so endianness is getting taken care of. But we
   5883 	 * have to fix this and generalize this at some point
   5884 	 */
   5885 	acc = (la_els_logi_t *)pkt->pkt_resp;
   5886 
   5887 	FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp, (uint8_t *)acc,
   5888 	    sizeof (resp), DDI_DEV_AUTOINCR);
   5889 
   5890 	ASSERT(resp.ls_code == LA_ELS_ACC);
   5891 	if (resp.ls_code != LA_ELS_ACC) {
   5892 		(void) fp_common_intr(pkt, 1);
   5893 		return;
   5894 	}
   5895 
   5896 	FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&csp,
   5897 	    (uint8_t *)&acc->common_service, sizeof (csp), DDI_DEV_AUTOINCR);
   5898 
   5899 	f_port = FP_IS_F_PORT(csp.cmn_features) ? 1 : 0;
   5900 
   5901 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
   5902 
   5903 	mutex_enter(&port->fp_mutex);
   5904 	state = FC_PORT_STATE_MASK(port->fp_state);
   5905 	mutex_exit(&port->fp_mutex);
   5906 
   5907 	if (f_port == 0) {
   5908 		if (state != FC_STATE_LOOP) {
   5909 			swwn = &port->fp_service_params.nport_ww_name;
   5910 
   5911 			FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&dwwn,
   5912 			    (uint8_t *)&acc->nport_ww_name, sizeof (la_wwn_t),
   5913 			    DDI_DEV_AUTOINCR);
   5914 
   5915 			FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&nwwn,
   5916 			    (uint8_t *)&acc->node_ww_name, sizeof (la_wwn_t),
   5917 			    DDI_DEV_AUTOINCR);
   5918 
   5919 			mutex_enter(&port->fp_mutex);
   5920 
   5921 			port->fp_topology = FC_TOP_PT_PT;
   5922 			port->fp_total_devices = 1;
   5923 			if (fctl_wwn_cmp(swwn, &dwwn) >= 0) {
   5924 				port->fp_ptpt_master = 1;
   5925 				/*
   5926 				 * Let us choose 'X' as S_ID and 'Y'
   5927 				 * as D_ID and that'll work; hopefully
   5928 				 * If not, it will get changed.
   5929 				 */
   5930 				s_id = port->fp_instance + FP_DEFAULT_SID;
   5931 				d_id = port->fp_instance + FP_DEFAULT_DID;
   5932 				port->fp_port_id.port_id = s_id;
   5933 				mutex_exit(&port->fp_mutex);
   5934 
   5935 				FP_TRACE(FP_NHEAD1(1, 0), "fp_flogi_intr: fp %x"
   5936 				    "pd %x", port->fp_port_id.port_id, d_id);
   5937 				pd = fctl_create_remote_port(port,
   5938 				    &nwwn, &dwwn, d_id, PD_PLOGI_INITIATOR,
   5939 				    KM_NOSLEEP);
   5940 				if (pd == NULL) {
   5941 					fp_printf(port, CE_NOTE, FP_LOG_ONLY,
   5942 					    0, NULL, "couldn't create device"
   5943 					    " d_id=%X", d_id);
   5944 					fp_iodone(cmd);
   5945 					return;
   5946 				}
   5947 
   5948 				cmd->cmd_pkt.pkt_tran_flags =
   5949 				    pkt->pkt_tran_flags;
   5950 				cmd->cmd_pkt.pkt_tran_type = pkt->pkt_tran_type;
   5951 				cmd->cmd_flags = FP_CMD_PLOGI_RETAIN;
   5952 				cmd->cmd_retry_count = fp_retry_count;
   5953 
   5954 				fp_xlogi_init(port, cmd, s_id, d_id,
   5955 				    fp_plogi_intr, cmd->cmd_job, LA_ELS_PLOGI);
   5956 
   5957 				(&cmd->cmd_pkt)->pkt_pd = pd;
   5958 
   5959 				/*
   5960 				 * We've just created this fc_remote_port_t, and
   5961 				 * we're about to use it to send a PLOGI, so
   5962 				 * bump the reference count right now.	When
   5963 				 * the packet is freed, the reference count will
   5964 				 * be decremented.  The ULP may also start using
   5965 				 * it, so mark it as given away as well.
   5966 				 */
   5967 				pd->pd_ref_count++;
   5968 				pd->pd_aux_flags |= PD_GIVEN_TO_ULPS;
   5969 
   5970 				if (fp_sendcmd(port, cmd,
   5971 				    port->fp_fca_handle) == FC_SUCCESS) {
   5972 					return;
   5973 				}
   5974 			} else {
   5975 				/*
   5976 				 * The device handles will be created when the
   5977 				 * unsolicited PLOGI is completed successfully
   5978 				 */
   5979 				port->fp_ptpt_master = 0;
   5980 				mutex_exit(&port->fp_mutex);
   5981 			}
   5982 		}
   5983 		pkt->pkt_state = FC_PKT_FAILURE;
   5984 	} else {
   5985 		if (f_port) {
   5986 			mutex_enter(&port->fp_mutex);
   5987 			if (state == FC_STATE_LOOP) {
   5988 				port->fp_topology = FC_TOP_PUBLIC_LOOP;
   5989 			} else {
   5990 				port->fp_topology = FC_TOP_FABRIC;
   5991 
   5992 				FC_GET_RSP(port, pkt->pkt_resp_acc,
   5993 				    (uint8_t *)&port->fp_fabric_name,
   5994 				    (uint8_t *)&acc->node_ww_name,
   5995 				    sizeof (la_wwn_t),
   5996 				    DDI_DEV_AUTOINCR);
   5997 			}
   5998 			port->fp_port_id.port_id = pkt->pkt_resp_fhdr.d_id;
   5999 			mutex_exit(&port->fp_mutex);
   6000 		} else {
   6001 			pkt->pkt_state = FC_PKT_FAILURE;
   6002 		}
   6003 	}
   6004 	fp_iodone(cmd);
   6005 }
   6006 
   6007 
   6008 /*
   6009  * Handle solicited PLOGI response
   6010  */
   6011 static void
   6012 fp_plogi_intr(fc_packet_t *pkt)
   6013 {
   6014 	int			nl_port;
   6015 	int			bailout;
   6016 	uint32_t		d_id;
   6017 	fp_cmd_t		*cmd;
   6018 	la_els_logi_t		*acc;
   6019 	fc_local_port_t		*port;
   6020 	fc_remote_port_t	*pd;
   6021 	la_wwn_t		nwwn;
   6022 	la_wwn_t		pwwn;
   6023 	ls_code_t		resp;
   6024 
   6025 	nl_port = 0;
   6026 	cmd = pkt->pkt_ulp_private;
   6027 	port = cmd->cmd_port;
   6028 	d_id = pkt->pkt_cmd_fhdr.d_id;
   6029 
   6030 #ifndef	__lock_lint
   6031 	ASSERT(cmd->cmd_job && cmd->cmd_job->job_counter);
   6032 #endif
   6033 
   6034 	FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_intr: port=%p, job=%p, d_id=%x,"
   6035 	    " jcount=%d pkt=%p, state=%x", port, cmd->cmd_job, d_id,
   6036 	    cmd->cmd_job->job_counter, pkt, pkt->pkt_state);
   6037 
   6038 	/*
   6039 	 * Bail out early on ULP initiated requests if the
   6040 	 * state change has occurred
   6041 	 */
   6042 	mutex_enter(&port->fp_mutex);
   6043 	port->fp_out_fpcmds--;
   6044 	bailout = ((port->fp_statec_busy ||
   6045 	    FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) &&
   6046 	    cmd->cmd_ulp_pkt) ? 1 : 0;
   6047 	mutex_exit(&port->fp_mutex);
   6048 
   6049 	if (FP_IS_PKT_ERROR(pkt) || bailout) {
   6050 		int skip_msg = 0;
   6051 		int giveup = 0;
   6052 
   6053 		if (cmd->cmd_ulp_pkt) {
   6054 			cmd->cmd_ulp_pkt->pkt_state = pkt->pkt_state;
   6055 			cmd->cmd_ulp_pkt->pkt_reason = pkt->pkt_reason;
   6056 			cmd->cmd_ulp_pkt->pkt_action = pkt->pkt_action;
   6057 			cmd->cmd_ulp_pkt->pkt_expln = pkt->pkt_expln;
   6058 		}
   6059 
   6060 		/*
   6061 		 * If an unsolicited cross login already created
   6062 		 * a device speed up the discovery by not retrying
   6063 		 * the command mindlessly.
   6064 		 */
   6065 		if (pkt->pkt_pd == NULL &&
   6066 		    fctl_get_remote_port_by_did(port, d_id) != NULL) {
   6067 			fp_iodone(cmd);
   6068 			return;
   6069 		}
   6070 
   6071 		if (pkt->pkt_pd != NULL) {
   6072 			giveup = (pkt->pkt_pd->pd_recepient ==
   6073 			    PD_PLOGI_RECEPIENT) ? 1 : 0;
   6074 			if (giveup) {
   6075 				/*
   6076 				 * This pd is marked as plogi
   6077 				 * recipient, stop retrying
   6078 				 */
   6079 				FP_TRACE(FP_NHEAD1(3, 0),
   6080 				    "fp_plogi_intr: stop retry as"
   6081 				    " a cross login was accepted"
   6082 				    " from d_id=%x, port=%p.",
   6083 				    d_id, port);
   6084 				fp_iodone(cmd);
   6085 				return;
   6086 			}
   6087 		}
   6088 
   6089 		if (fp_common_intr(pkt, 0) == FC_SUCCESS) {
   6090 			return;
   6091 		}
   6092 
   6093 		if ((pd = fctl_get_remote_port_by_did(port, d_id)) != NULL) {
   6094 			mutex_enter(&pd->pd_mutex);
   6095 			if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
   6096 				skip_msg++;
   6097 			}
   6098 			mutex_exit(&pd->pd_mutex);
   6099 		}
   6100 
   6101 		mutex_enter(&port->fp_mutex);
   6102 		if (!bailout && !(skip_msg && port->fp_statec_busy) &&
   6103 		    port->fp_statec_busy <= 1 &&
   6104 		    pkt->pkt_reason != FC_REASON_FCAL_OPN_FAIL) {
   6105 			mutex_exit(&port->fp_mutex);
   6106 			/*
   6107 			 * In case of Login Collisions, JNI HBAs returns the
   6108 			 * FC pkt back to the Initiator with the state set to
   6109 			 * FC_PKT_LS_RJT and reason to FC_REASON_LOGICAL_ERROR.
   6110 			 * QLC HBAs handles such cases in the FW and doesnot
   6111 			 * return the LS_RJT with Logical error when
   6112 			 * login collision happens.
   6113 			 */
   6114 			if ((pkt->pkt_state != FC_PKT_LS_RJT) ||
   6115 			    (pkt->pkt_reason != FC_REASON_LOGICAL_ERROR)) {
   6116 				fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, pkt,
   6117 				    "PLOGI to %x failed", d_id);
   6118 			}
   6119 			FP_TRACE(FP_NHEAD2(9, 0),
   6120 			    "PLOGI to %x failed. state=%x reason=%x.",
   6121 			    d_id, pkt->pkt_state, pkt->pkt_reason);
   6122 		} else {
   6123 			mutex_exit(&port->fp_mutex);
   6124 		}
   6125 
   6126 		fp_iodone(cmd);
   6127 		return;
   6128 	}
   6129 
   6130 	acc = (la_els_logi_t *)pkt->pkt_resp;
   6131 
   6132 	FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp, (uint8_t *)acc,
   6133 	    sizeof (resp), DDI_DEV_AUTOINCR);
   6134 
   6135 	ASSERT(resp.ls_code == LA_ELS_ACC);
   6136 	if (resp.ls_code != LA_ELS_ACC) {
   6137 		(void) fp_common_intr(pkt, 1);
   6138 		return;
   6139 	}
   6140 
   6141 	if (d_id == FS_NAME_SERVER || d_id == FS_FABRIC_CONTROLLER) {
   6142 		mutex_enter(&port->fp_mutex);
   6143 		port->fp_ns_login_class = FC_TRAN_CLASS(pkt->pkt_tran_flags);
   6144 		mutex_exit(&port->fp_mutex);
   6145 		fp_iodone(cmd);
   6146 		return;
   6147 	}
   6148 
   6149 	ASSERT(acc == (la_els_logi_t *)pkt->pkt_resp);
   6150 
   6151 	FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&pwwn,
   6152 	    (uint8_t *)&acc->nport_ww_name, sizeof (la_wwn_t),
   6153 	    DDI_DEV_AUTOINCR);
   6154 
   6155 	FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&nwwn,
   6156 	    (uint8_t *)&acc->node_ww_name, sizeof (la_wwn_t),
   6157 	    DDI_DEV_AUTOINCR);
   6158 
   6159 	ASSERT(fctl_is_wwn_zero(&pwwn) == FC_FAILURE);
   6160 	ASSERT(fctl_is_wwn_zero(&nwwn) == FC_FAILURE);
   6161 
   6162 	if ((pd = pkt->pkt_pd) == NULL) {
   6163 		pd = fctl_get_remote_port_by_pwwn(port, &pwwn);
   6164 		if (pd == NULL) {
   6165 			FP_TRACE(FP_NHEAD2(9, 0), "fp_plogi_intr: fp %x pd %x",
   6166 			    port->fp_port_id.port_id, d_id);
   6167 			pd = fctl_create_remote_port(port, &nwwn, &pwwn, d_id,
   6168 			    PD_PLOGI_INITIATOR, KM_NOSLEEP);
   6169 			if (pd == NULL) {
   6170 				fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
   6171 				    "couldn't create port device handles"
   6172 				    " d_id=%x", d_id);
   6173 				fp_iodone(cmd);
   6174 				return;
   6175 			}
   6176 		} else {
   6177 			fc_remote_port_t *tmp_pd;
   6178 
   6179 			tmp_pd = fctl_get_remote_port_by_did(port, d_id);
   6180 			if (tmp_pd != NULL) {
   6181 				fp_iodone(cmd);
   6182 				return;
   6183 			}
   6184 
   6185 			mutex_enter(&port->fp_mutex);
   6186 			mutex_enter(&pd->pd_mutex);
   6187 			if ((pd->pd_state == PORT_DEVICE_LOGGED_IN) ||
   6188 			    (pd->pd_aux_flags & PD_LOGGED_OUT)) {
   6189 				cmd->cmd_flags |= FP_CMD_PLOGI_RETAIN;
   6190 			}
   6191 
   6192 			if (pd->pd_type == PORT_DEVICE_OLD) {
   6193 				if (pd->pd_port_id.port_id != d_id) {
   6194 					fctl_delist_did_table(port, pd);
   6195 					pd->pd_type = PORT_DEVICE_CHANGED;
   6196 					pd->pd_port_id.port_id = d_id;
   6197 				} else {
   6198 					pd->pd_type = PORT_DEVICE_NOCHANGE;
   6199 				}
   6200 			}
   6201 
   6202 			if (pd->pd_aux_flags & PD_IN_DID_QUEUE) {
   6203 				char ww_name[17];
   6204 
   6205 				fc_wwn_to_str(&pd->pd_port_name, ww_name);
   6206 
   6207 				mutex_exit(&pd->pd_mutex);
   6208 				mutex_exit(&port->fp_mutex);
   6209 				FP_TRACE(FP_NHEAD2(9, 0),
   6210 				    "Possible Duplicate name or address"
   6211 				    " identifiers in the PLOGI response"
   6212 				    " D_ID=%x, PWWN=%s: Please check the"
   6213 				    " configuration", d_id, ww_name);
   6214 				fp_iodone(cmd);
   6215 				return;
   6216 			}
   6217 			fctl_enlist_did_table(port, pd);
   6218 			pd->pd_aux_flags &= ~PD_LOGGED_OUT;
   6219 			mutex_exit(&pd->pd_mutex);
   6220 			mutex_exit(&port->fp_mutex);
   6221 		}
   6222 	} else {
   6223 		fc_remote_port_t *tmp_pd, *new_wwn_pd;
   6224 
   6225 		tmp_pd = fctl_get_remote_port_by_did(port, d_id);
   6226 		new_wwn_pd = fctl_get_remote_port_by_pwwn(port, &pwwn);
   6227 
   6228 		mutex_enter(&port->fp_mutex);
   6229 		mutex_enter(&pd->pd_mutex);
   6230 		if (fctl_wwn_cmp(&pd->pd_port_name, &pwwn) == 0) {
   6231 			FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_intr: d_id=%x,"
   6232 			    " pd_state=%x pd_type=%x", d_id, pd->pd_state,
   6233 			    pd->pd_type);
   6234 			if ((pd->pd_state == PORT_DEVICE_LOGGED_IN &&
   6235 			    pd->pd_type == PORT_DEVICE_OLD) ||
   6236 			    (pd->pd_aux_flags & PD_LOGGED_OUT)) {
   6237 				pd->pd_type = PORT_DEVICE_NOCHANGE;
   6238 			} else if (pd->pd_state != PORT_DEVICE_LOGGED_IN) {
   6239 				pd->pd_type = PORT_DEVICE_NEW;
   6240 			}
   6241 		} else {
   6242 			char	old_name[17];
   6243 			char	new_name[17];
   6244 
   6245 			fc_wwn_to_str(&pd->pd_port_name, old_name);
   6246 			fc_wwn_to_str(&pwwn, new_name);
   6247 
   6248 			FP_TRACE(FP_NHEAD1(9, 0),
   6249 			    "fp_plogi_intr: PWWN of a device with D_ID=%x "
   6250 			    "changed. New PWWN = %s, OLD PWWN = %s ; tmp_pd:%p "
   6251 			    "pd:%p new_wwn_pd:%p, cmd_ulp_pkt:%p, bailout:0x%x",
   6252 			    d_id, new_name, old_name, tmp_pd, pd, new_wwn_pd,
   6253 			    cmd->cmd_ulp_pkt, bailout);
   6254 
   6255 			FP_TRACE(FP_NHEAD2(9, 0),
   6256 			    "PWWN of a device with D_ID=%x changed."
   6257 			    " New PWWN = %s, OLD PWWN = %s", d_id,
   6258 			    new_name, old_name);
   6259 
   6260 			if (cmd->cmd_ulp_pkt && !bailout) {
   6261 				fc_remote_node_t	*rnodep;
   6262 				fc_portmap_t	*changelist;
   6263 				fc_portmap_t	*listptr;
   6264 				int		len = 1;
   6265 				/* # entries in changelist */
   6266 
   6267 				fctl_delist_pwwn_table(port, pd);
   6268 
   6269 				/*
   6270 				 * Lets now check if there already is a pd with
   6271 				 * this new WWN in the table. If so, we'll mark
   6272 				 * it as invalid
   6273 				 */
   6274 
   6275 				if (new_wwn_pd) {
   6276 					/*
   6277 					 * There is another pd with in the pwwn
   6278 					 * table with the same WWN that we got
   6279 					 * in the PLOGI payload. We have to get
   6280 					 * it out of the pwwn table, update the
   6281 					 * pd's state (fp_fillout_old_map does
   6282 					 * this for us) and add it to the
   6283 					 * changelist that goes up to ULPs.
   6284 					 *
   6285 					 * len is length of changelist and so
   6286 					 * increment it.
   6287 					 */
   6288 					len++;
   6289 
   6290 					if (tmp_pd != pd) {
   6291 						/*
   6292 						 * Odd case where pwwn and did
   6293 						 * tables are out of sync but
   6294 						 * we will handle that too. See
   6295 						 * more comments below.
   6296 						 *
   6297 						 * One more device that ULPs
   6298 						 * should know about and so len
   6299 						 * gets incremented again.
   6300 						 */
   6301 						len++;
   6302 					}
   6303 
   6304 					listptr = changelist = kmem_zalloc(len *
   6305 					    sizeof (*changelist), KM_SLEEP);
   6306 
   6307 					mutex_enter(&new_wwn_pd->pd_mutex);
   6308 					rnodep = new_wwn_pd->pd_remote_nodep;
   6309 					mutex_exit(&new_wwn_pd->pd_mutex);
   6310 
   6311 					/*
   6312 					 * Hold the fd_mutex since
   6313 					 * fctl_copy_portmap_held expects it.
   6314 					 * Preserve lock hierarchy by grabbing
   6315 					 * fd_mutex before pd_mutex
   6316 					 */
   6317 					if (rnodep) {
   6318 						mutex_enter(&rnodep->fd_mutex);
   6319 					}
   6320 					mutex_enter(&new_wwn_pd->pd_mutex);
   6321 					fp_fillout_old_map_held(listptr++,
   6322 					    new_wwn_pd, 0);
   6323 					mutex_exit(&new_wwn_pd->pd_mutex);
   6324 					if (rnodep) {
   6325 						mutex_exit(&rnodep->fd_mutex);
   6326 					}
   6327 
   6328 					/*
   6329 					 * Safety check :
   6330 					 * Lets ensure that the pwwn and did
   6331 					 * tables are in sync. Ideally, we
   6332 					 * should not find that these two pd's
   6333 					 * are different.
   6334 					 */
   6335 					if (tmp_pd != pd) {
   6336 						mutex_enter(&tmp_pd->pd_mutex);
   6337 						rnodep =
   6338 						    tmp_pd->pd_remote_nodep;
   6339 						mutex_exit(&tmp_pd->pd_mutex);
   6340 
   6341 						/* As above grab fd_mutex */
   6342 						if (rnodep) {
   6343 							mutex_enter(&rnodep->
   6344 							    fd_mutex);
   6345 						}
   6346 						mutex_enter(&tmp_pd->pd_mutex);
   6347 
   6348 						fp_fillout_old_map_held(
   6349 						    listptr++, tmp_pd, 0);
   6350 
   6351 						mutex_exit(&tmp_pd->pd_mutex);
   6352 						if (rnodep) {
   6353 							mutex_exit(&rnodep->
   6354 							    fd_mutex);
   6355 						}
   6356 
   6357 						/*
   6358 						 * Now add "pd" (not tmp_pd)
   6359 						 * to fp_did_table to sync it up
   6360 						 * with fp_pwwn_table
   6361 						 *
   6362 						 * pd->pd_mutex is already held
   6363 						 * at this point
   6364 						 */
   6365 						fctl_enlist_did_table(port, pd);
   6366 					}
   6367 				} else {
   6368 					listptr = changelist = kmem_zalloc(
   6369 					    sizeof (*changelist), KM_SLEEP);
   6370 				}
   6371 
   6372 				ASSERT(changelist != NULL);
   6373 
   6374 				fp_fillout_changed_map(listptr, pd, &d_id,
   6375 				    &pwwn);
   6376 				fctl_enlist_pwwn_table(port, pd);
   6377 
   6378 				mutex_exit(&pd->pd_mutex);
   6379 				mutex_exit(&port->fp_mutex);
   6380 
   6381 				fp_iodone(cmd);
   6382 
   6383 				(void) fp_ulp_devc_cb(port, changelist, len,
   6384 				    len, KM_NOSLEEP, 0);
   6385 
   6386 				return;
   6387 			}
   6388 		}
   6389 
   6390 		if (pd->pd_porttype.port_type == FC_NS_PORT_NL) {
   6391 			nl_port = 1;
   6392 		}
   6393 		if (pd->pd_aux_flags & PD_DISABLE_RELOGIN) {
   6394 			pd->pd_aux_flags &= ~PD_LOGGED_OUT;
   6395 		}
   6396 
   6397 		mutex_exit(&pd->pd_mutex);
   6398 		mutex_exit(&port->fp_mutex);
   6399 
   6400 		if (tmp_pd == NULL) {
   6401 			mutex_enter(&port->fp_mutex);
   6402 			mutex_enter(&pd->pd_mutex);
   6403 			if (pd->pd_aux_flags & PD_IN_DID_QUEUE) {
   6404 				char ww_name[17];
   6405 
   6406 				fc_wwn_to_str(&pd->pd_port_name, ww_name);
   6407 				mutex_exit(&pd->pd_mutex);
   6408 				mutex_exit(&port->fp_mutex);
   6409 				FP_TRACE(FP_NHEAD2(9, 0),
   6410 				    "Possible Duplicate name or address"
   6411 				    " identifiers in the PLOGI response"
   6412 				    " D_ID=%x, PWWN=%s: Please check the"
   6413 				    " configuration", d_id, ww_name);
   6414 				fp_iodone(cmd);
   6415 				return;
   6416 			}
   6417 			fctl_enlist_did_table(port, pd);
   6418 			pd->pd_aux_flags &= ~PD_LOGGED_OUT;
   6419 			mutex_exit(&pd->pd_mutex);
   6420 			mutex_exit(&port->fp_mutex);
   6421 		}
   6422 	}
   6423 	fp_register_login(&pkt->pkt_resp_acc, pd, acc,
   6424 	    FC_TRAN_CLASS(pkt->pkt_tran_flags));
   6425 
   6426 	if (cmd->cmd_ulp_pkt) {
   6427 		cmd->cmd_ulp_pkt->pkt_state = pkt->pkt_state;
   6428 		cmd->cmd_ulp_pkt->pkt_action = pkt->pkt_action;
   6429 		cmd->cmd_ulp_pkt->pkt_expln = pkt->pkt_expln;
   6430 		if (cmd->cmd_ulp_pkt->pkt_pd == NULL) {
   6431 			if (pd != NULL) {
   6432 				FP_TRACE(FP_NHEAD1(9, 0),
   6433 				    "fp_plogi_intr;"
   6434 				    "ulp_pkt's pd is NULL, get a pd %p",
   6435 				    pd);
   6436 				mutex_enter(&pd->pd_mutex);
   6437 				pd->pd_ref_count++;
   6438 				mutex_exit(&pd->pd_mutex);
   6439 			}
   6440 			cmd->cmd_ulp_pkt->pkt_pd = pd;
   6441 		}
   6442 		bcopy((caddr_t)&pkt->pkt_resp_fhdr,
   6443 		    (caddr_t)&cmd->cmd_ulp_pkt->pkt_resp_fhdr,
   6444 		    sizeof (fc_frame_hdr_t));
   6445 		bcopy((caddr_t)pkt->pkt_resp,
   6446 		    (caddr_t)cmd->cmd_ulp_pkt->pkt_resp,
   6447 		    sizeof (la_els_logi_t));
   6448 	}
   6449 
   6450 	mutex_enter(&port->fp_mutex);
   6451 	if (port->fp_topology == FC_TOP_PRIVATE_LOOP || nl_port) {
   6452 		mutex_enter(&pd->pd_mutex);
   6453 
   6454 		cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
   6455 		cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
   6456 		cmd->cmd_retry_count = fp_retry_count;
   6457 
   6458 		/*
   6459 		 * If the fc_remote_port_t pointer is not set in the given
   6460 		 * fc_packet_t, then this fc_remote_port_t must have just
   6461 		 * been created.  Save the pointer and also increment the
   6462 		 * fc_remote_port_t reference count.
   6463 		 */
   6464 		if (pkt->pkt_pd == NULL) {
   6465 			pkt->pkt_pd = pd;
   6466 			pd->pd_ref_count++;	/* It's in use! */
   6467 		}
   6468 
   6469 		fp_adisc_init(cmd, cmd->cmd_job);
   6470 
   6471 		pkt->pkt_cmdlen = sizeof (la_els_adisc_t);
   6472 		pkt->pkt_rsplen = sizeof (la_els_adisc_t);
   6473 
   6474 		mutex_exit(&pd->pd_mutex);
   6475 		mutex_exit(&port->fp_mutex);
   6476 
   6477 		if (fp_sendcmd(port, cmd, port->fp_fca_handle) == FC_SUCCESS) {
   6478 			return;
   6479 		}
   6480 	} else {
   6481 		mutex_exit(&port->fp_mutex);
   6482 	}
   6483 
   6484 	if ((cmd->cmd_flags & FP_CMD_PLOGI_RETAIN) == 0) {
   6485 		mutex_enter(&port->fp_mutex);
   6486 		mutex_enter(&pd->pd_mutex);
   6487 
   6488 		cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
   6489 		cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
   6490 		cmd->cmd_retry_count = fp_retry_count;
   6491 
   6492 		fp_logo_init(pd, cmd, cmd->cmd_job);
   6493 
   6494 		pkt->pkt_cmdlen = sizeof (la_els_logo_t);
   6495 		pkt->pkt_rsplen = FP_PORT_IDENTIFIER_LEN;
   6496 
   6497 		mutex_exit(&pd->pd_mutex);
   6498 		mutex_exit(&port->fp_mutex);
   6499 
   6500 		if (fp_sendcmd(port, cmd, port->fp_fca_handle) == FC_SUCCESS) {
   6501 			return;
   6502 		}
   6503 
   6504 	}
   6505 	fp_iodone(cmd);
   6506 }
   6507 
   6508 
   6509 /*
   6510  * Handle solicited ADISC response
   6511  */
   6512 static void
   6513 fp_adisc_intr(fc_packet_t *pkt)
   6514 {
   6515 	int			rval;
   6516 	int			bailout;
   6517 	fp_cmd_t		*cmd;
   6518 	fc_local_port_t		*port;
   6519 	fc_remote_port_t	*pd;
   6520 	la_els_adisc_t		*acc;
   6521 	ls_code_t		resp;
   6522 	fc_hardaddr_t		ha;
   6523 	fc_portmap_t		*changelist;
   6524 	int			initiator, adiscfail = 0;
   6525 
   6526 	pd = pkt->pkt_pd;
   6527 	cmd = pkt->pkt_ulp_private;
   6528 	port = cmd->cmd_port;
   6529 
   6530 #ifndef	__lock_lint
   6531 	ASSERT(cmd->cmd_job && cmd->cmd_job->job_counter);
   6532 #endif
   6533 
   6534 	ASSERT(pd != NULL && port != NULL && cmd != NULL);
   6535 
   6536 	mutex_enter(&port->fp_mutex);
   6537 	port->fp_out_fpcmds--;
   6538 	bailout = ((port->fp_statec_busy ||
   6539 	    FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) &&
   6540 	    cmd->cmd_ulp_pkt) ? 1 : 0;
   6541 	mutex_exit(&port->fp_mutex);
   6542 
   6543 	if (bailout) {
   6544 		fp_iodone(cmd);
   6545 		return;
   6546 	}
   6547 
   6548 	if (pkt->pkt_state == FC_PKT_SUCCESS && pkt->pkt_resp_resid == 0) {
   6549 		acc = (la_els_adisc_t *)pkt->pkt_resp;
   6550 
   6551 		FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp,
   6552 		    (uint8_t *)acc, sizeof (resp), DDI_DEV_AUTOINCR);
   6553 
   6554 		if (resp.ls_code == LA_ELS_ACC) {
   6555 			int	is_private;
   6556 
   6557 			FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&ha,
   6558 			    (uint8_t *)&acc->hard_addr, sizeof (ha),
   6559 			    DDI_DEV_AUTOINCR);
   6560 
   6561 			mutex_enter(&port->fp_mutex);
   6562 
   6563 			is_private =
   6564 			    (port->fp_topology == FC_TOP_PRIVATE_LOOP) ? 1 : 0;
   6565 
   6566 			mutex_enter(&pd->pd_mutex);
   6567 			if ((pd->pd_aux_flags & PD_IN_DID_QUEUE) == 0) {
   6568 				fctl_enlist_did_table(port, pd);
   6569 			}
   6570 			mutex_exit(&pd->pd_mutex);
   6571 
   6572 			mutex_exit(&port->fp_mutex);
   6573 
   6574 			mutex_enter(&pd->pd_mutex);
   6575 			if (pd->pd_type != PORT_DEVICE_NEW) {
   6576 				if (is_private && (pd->pd_hard_addr.hard_addr !=
   6577 				    ha.hard_addr)) {
   6578 					pd->pd_type = PORT_DEVICE_CHANGED;
   6579 				} else {
   6580 					pd->pd_type = PORT_DEVICE_NOCHANGE;
   6581 				}
   6582 			}
   6583 
   6584 			if (is_private && (ha.hard_addr &&
   6585 			    pd->pd_port_id.port_id != ha.hard_addr)) {
   6586 				char ww_name[17];
   6587 
   6588 				fc_wwn_to_str(&pd->pd_port_name, ww_name);
   6589 
   6590 				fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
   6591 				    "NL_Port Identifier %x doesn't match"
   6592 				    " with Hard Address %x, Will use Port"
   6593 				    " WWN %s", pd->pd_port_id.port_id,
   6594 				    ha.hard_addr, ww_name);
   6595 
   6596 				pd->pd_hard_addr.hard_addr = 0;
   6597 			} else {
   6598 				pd->pd_hard_addr.hard_addr = ha.hard_addr;
   6599 			}
   6600 			mutex_exit(&pd->pd_mutex);
   6601 		} else {
   6602 			if (fp_common_intr(pkt, 0) == FC_SUCCESS) {
   6603 				return;
   6604 			}
   6605 		}
   6606 	} else {
   6607 		if (fp_common_intr(pkt, 0) == FC_SUCCESS) {
   6608 			return;
   6609 		}
   6610 
   6611 		mutex_enter(&port->fp_mutex);
   6612 		if (port->fp_statec_busy <= 1) {
   6613 			mutex_exit(&port->fp_mutex);
   6614 			fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, pkt,
   6615 			    "ADISC to %x failed, cmd_flags=%x",
   6616 			    pkt->pkt_cmd_fhdr.d_id, cmd->cmd_flags);
   6617 			cmd->cmd_flags &= ~FP_CMD_PLOGI_RETAIN;
   6618 			adiscfail = 1;
   6619 		} else {
   6620 			mutex_exit(&port->fp_mutex);
   6621 		}
   6622 	}
   6623 
   6624 	if (cmd->cmd_ulp_pkt) {
   6625 		cmd->cmd_ulp_pkt->pkt_state = pkt->pkt_state;
   6626 		cmd->cmd_ulp_pkt->pkt_action = pkt->pkt_action;
   6627 		cmd->cmd_ulp_pkt->pkt_expln = pkt->pkt_expln;
   6628 		if (cmd->cmd_ulp_pkt->pkt_pd == NULL) {
   6629 			cmd->cmd_ulp_pkt->pkt_pd = pd;
   6630 			FP_TRACE(FP_NHEAD1(9, 0),
   6631 			    "fp_adisc__intr;"
   6632 			    "ulp_pkt's pd is NULL, get a pd %p",
   6633 			    pd);
   6634 
   6635 		}
   6636 		bcopy((caddr_t)&pkt->pkt_resp_fhdr,
   6637 		    (caddr_t)&cmd->cmd_ulp_pkt->pkt_resp_fhdr,
   6638 		    sizeof (fc_frame_hdr_t));
   6639 		bcopy((caddr_t)pkt->pkt_resp,
   6640 		    (caddr_t)cmd->cmd_ulp_pkt->pkt_resp,
   6641 		    sizeof (la_els_adisc_t));
   6642 	}
   6643 
   6644 	if ((cmd->cmd_flags & FP_CMD_PLOGI_RETAIN) == 0) {
   6645 		FP_TRACE(FP_NHEAD1(9, 0),
   6646 		    "fp_adisc_intr: Perform LOGO.cmd_flags=%x, "
   6647 		    "fp_retry_count=%x, ulp_pkt=%p",
   6648 		    cmd->cmd_flags, fp_retry_count, cmd->cmd_ulp_pkt);
   6649 
   6650 		mutex_enter(&port->fp_mutex);
   6651 		mutex_enter(&pd->pd_mutex);
   6652 
   6653 		cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
   6654 		cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
   6655 		cmd->cmd_retry_count = fp_retry_count;
   6656 
   6657 		fp_logo_init(pd, cmd, cmd->cmd_job);
   6658 
   6659 		pkt->pkt_cmdlen = sizeof (la_els_logo_t);
   6660 		pkt->pkt_rsplen = FP_PORT_IDENTIFIER_LEN;
   6661 
   6662 		mutex_exit(&pd->pd_mutex);
   6663 		mutex_exit(&port->fp_mutex);
   6664 
   6665 		rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
   6666 		if (adiscfail) {
   6667 			mutex_enter(&pd->pd_mutex);
   6668 			initiator =
   6669 			    ((pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0);
   6670 			pd->pd_state = PORT_DEVICE_VALID;
   6671 			pd->pd_aux_flags |= PD_LOGGED_OUT;
   6672 			if (pd->pd_aux_flags & PD_DISABLE_RELOGIN) {
   6673 				pd->pd_type = PORT_DEVICE_NEW;
   6674 			} else {
   6675 				pd->pd_type = PORT_DEVICE_NOCHANGE;
   6676 			}
   6677 			mutex_exit(&pd->pd_mutex);
   6678 
   6679 			changelist =
   6680 			    kmem_zalloc(sizeof (*changelist), KM_SLEEP);
   6681 
   6682 			if (initiator) {
   6683 				fp_unregister_login(pd);
   6684 				fctl_copy_portmap(changelist, pd);
   6685 			} else {
   6686 				fp_fillout_old_map(changelist, pd, 0);
   6687 			}
   6688 
   6689 			FP_TRACE(FP_NHEAD1(9, 0),
   6690 			    "fp_adisc_intr: Dev change notification "
   6691 			    "to ULP port=%p, pd=%p, map_type=%x map_state=%x "
   6692 			    "map_flags=%x initiator=%d", port, pd,
   6693 			    changelist->map_type, changelist->map_state,
   6694 			    changelist->map_flags, initiator);
   6695 
   6696 			(void) fp_ulp_devc_cb(port, changelist,
   6697 			    1, 1, KM_SLEEP, 0);
   6698 		}
   6699 		if (rval == FC_SUCCESS) {
   6700 			return;
   6701 		}
   6702 	}
   6703 	fp_iodone(cmd);
   6704 }
   6705 
   6706 
   6707 /*
   6708  * Handle solicited LOGO response
   6709  */
   6710 static void
   6711 fp_logo_intr(fc_packet_t *pkt)
   6712 {
   6713 	ls_code_t	resp;
   6714 	fc_local_port_t *port = ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port;
   6715 
   6716 	mutex_enter(&((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_mutex);
   6717 	((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_out_fpcmds--;
   6718 	mutex_exit(&((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_mutex);
   6719 
   6720 	FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp,
   6721 	    (uint8_t *)pkt->pkt_resp, sizeof (resp), DDI_DEV_AUTOINCR);
   6722 
   6723 	if (FP_IS_PKT_ERROR(pkt)) {
   6724 		(void) fp_common_intr(pkt, 1);
   6725 		return;
   6726 	}
   6727 
   6728 	ASSERT(resp.ls_code == LA_ELS_ACC);
   6729 	if (resp.ls_code != LA_ELS_ACC) {
   6730 		(void) fp_common_intr(pkt, 1);
   6731 		return;
   6732 	}
   6733 
   6734 	if (pkt->pkt_pd != NULL) {
   6735 		fp_unregister_login(pkt->pkt_pd);
   6736 	}
   6737 
   6738 	fp_iodone(pkt->pkt_ulp_private);
   6739 }
   6740 
   6741 
   6742 /*
   6743  * Handle solicited RNID response
   6744  */
   6745 static void
   6746 fp_rnid_intr(fc_packet_t *pkt)
   6747 {
   6748 	ls_code_t		resp;
   6749 	job_request_t		*job;
   6750 	fp_cmd_t		*cmd;
   6751 	la_els_rnid_acc_t	*acc;
   6752 	fc_local_port_t *port = ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port;
   6753 
   6754 	FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp,
   6755 	    (uint8_t *)pkt->pkt_resp, sizeof (resp), DDI_DEV_AUTOINCR);
   6756 	cmd = pkt->pkt_ulp_private;
   6757 
   6758 	mutex_enter(&cmd->cmd_port->fp_mutex);
   6759 	cmd->cmd_port->fp_out_fpcmds--;
   6760 	mutex_exit(&cmd->cmd_port->fp_mutex);
   6761 
   6762 	job = cmd->cmd_job;
   6763 	ASSERT(job->job_private != NULL);
   6764 
   6765 	/* If failure or LS_RJT then retry the packet, if needed */
   6766 	if (pkt->pkt_state != FC_PKT_SUCCESS || resp.ls_code != LA_ELS_ACC) {
   6767 		(void) fp_common_intr(pkt, 1);
   6768 		return;
   6769 	}
   6770 
   6771 	/* Save node_id memory allocated in ioctl code */
   6772 	acc = (la_els_rnid_acc_t *)pkt->pkt_resp;
   6773 
   6774 	FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)job->job_private,
   6775 	    (uint8_t *)acc, sizeof (la_els_rnid_acc_t), DDI_DEV_AUTOINCR);
   6776 
   6777 	/* wakeup the ioctl thread and free the pkt */
   6778 	fp_iodone(cmd);
   6779 }
   6780 
   6781 
   6782 /*
   6783  * Handle solicited RLS response
   6784  */
   6785 static void
   6786 fp_rls_intr(fc_packet_t *pkt)
   6787 {
   6788 	ls_code_t		resp;
   6789 	job_request_t		*job;
   6790 	fp_cmd_t		*cmd;
   6791 	la_els_rls_acc_t	*acc;
   6792 	fc_local_port_t *port = ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port;
   6793 
   6794 	FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp,
   6795 	    (uint8_t *)pkt->pkt_resp, sizeof (resp), DDI_DEV_AUTOINCR);
   6796 	cmd = pkt->pkt_ulp_private;
   6797 
   6798 	mutex_enter(&cmd->cmd_port->fp_mutex);
   6799 	cmd->cmd_port->fp_out_fpcmds--;
   6800 	mutex_exit(&cmd->cmd_port->fp_mutex);
   6801 
   6802 	job = cmd->cmd_job;
   6803 	ASSERT(job->job_private != NULL);
   6804 
   6805 	/* If failure or LS_RJT then retry the packet, if needed */
   6806 	if (FP_IS_PKT_ERROR(pkt) || resp.ls_code != LA_ELS_ACC) {
   6807 		(void) fp_common_intr(pkt, 1);
   6808 		return;
   6809 	}
   6810 
   6811 	/* Save link error status block in memory allocated in ioctl code */
   6812 	acc = (la_els_rls_acc_t *)pkt->pkt_resp;
   6813 
   6814 	FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)job->job_private,
   6815 	    (uint8_t *)&acc->rls_link_params, sizeof (fc_rls_acc_t),
   6816 	    DDI_DEV_AUTOINCR);
   6817 
   6818 	/* wakeup the ioctl thread and free the pkt */
   6819 	fp_iodone(cmd);
   6820 }
   6821 
   6822 
   6823 /*
   6824  * A solicited command completion interrupt (mostly for commands
   6825  * that require almost no post processing such as SCR ELS)
   6826  */
   6827 static void
   6828 fp_intr(fc_packet_t *pkt)
   6829 {
   6830 	mutex_enter(&((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_mutex);
   6831 	((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_out_fpcmds--;
   6832 	mutex_exit(&((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_mutex);
   6833 
   6834 	if (FP_IS_PKT_ERROR(pkt)) {
   6835 		(void) fp_common_intr(pkt, 1);
   6836 		return;
   6837 	}
   6838 	fp_iodone(pkt->pkt_ulp_private);
   6839 }
   6840 
   6841 
   6842 /*
   6843  * Handle the underlying port's state change
   6844  */
   6845 static void
   6846 fp_statec_cb(opaque_t port_handle, uint32_t state)
   6847 {
   6848 	fc_local_port_t *port = port_handle;
   6849 	job_request_t	*job;
   6850 
   6851 	/*
   6852 	 * If it is not possible to process the callbacks
   6853 	 * just drop the callback on the floor; Don't bother
   6854 	 * to do something that isn't safe at this time
   6855 	 */
   6856 	mutex_enter(&port->fp_mutex);
   6857 	if ((port->fp_soft_state &
   6858 	    (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN)) ||
   6859 	    (FC_PORT_STATE_MASK(port->fp_state) == FC_PORT_STATE_MASK(state))) {
   6860 		mutex_exit(&port->fp_mutex);
   6861 		return;
   6862 	}
   6863 
   6864 	if (port->fp_statec_busy == 0) {
   6865 		port->fp_soft_state |= FP_SOFT_IN_STATEC_CB;
   6866 #ifdef	DEBUG
   6867 	} else {
   6868 		ASSERT(port->fp_soft_state & FP_SOFT_IN_STATEC_CB);
   6869 #endif
   6870 	}
   6871 
   6872 	port->fp_statec_busy++;
   6873 
   6874 	/*
   6875 	 * For now, force the trusted method of device authentication (by
   6876 	 * PLOGI) when LIPs do not involve OFFLINE to ONLINE transition.
   6877 	 */
   6878 	if (FC_PORT_STATE_MASK(state) == FC_STATE_LIP ||
   6879 	    FC_PORT_STATE_MASK(state) == FC_STATE_LIP_LBIT_SET) {
   6880 		state = FC_PORT_SPEED_MASK(port->fp_state) | FC_STATE_LOOP;
   6881 		fp_port_offline(port, 0);
   6882 	}
   6883 	mutex_exit(&port->fp_mutex);
   6884 
   6885 	switch (FC_PORT_STATE_MASK(state)) {
   6886 	case FC_STATE_OFFLINE:
   6887 		job = fctl_alloc_job(JOB_PORT_OFFLINE,
   6888 		    JOB_TYPE_FCTL_ASYNC, NULL, NULL, KM_NOSLEEP);
   6889 		if (job == NULL) {
   6890 			fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
   6891 			    " fp_statec_cb() couldn't submit a job "
   6892 			    " to the thread: failing..");
   6893 			mutex_enter(&port->fp_mutex);
   6894 			if (--port->fp_statec_busy == 0) {
   6895 				port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
   6896 			}
   6897 			mutex_exit(&port->fp_mutex);
   6898 			return;
   6899 		}
   6900 		mutex_enter(&port->fp_mutex);
   6901 		/*
   6902 		 * Zero out this field so that we do not retain
   6903 		 * the fabric name as its no longer valid
   6904 		 */
   6905 		bzero(&port->fp_fabric_name, sizeof (la_wwn_t));
   6906 		port->fp_state = state;
   6907 		mutex_exit(&port->fp_mutex);
   6908 
   6909 		fctl_enque_job(port, job);
   6910 		break;
   6911 
   6912 	case FC_STATE_ONLINE:
   6913 	case FC_STATE_LOOP:
   6914 		mutex_enter(&port->fp_mutex);
   6915 		port->fp_state = state;
   6916 
   6917 		if (port->fp_offline_tid) {
   6918 			timeout_id_t tid;
   6919 
   6920 			tid = port->fp_offline_tid;
   6921 			port->fp_offline_tid = NULL;
   6922 			mutex_exit(&port->fp_mutex);
   6923 			(void) untimeout(tid);
   6924 		} else {
   6925 			mutex_exit(&port->fp_mutex);
   6926 		}
   6927 
   6928 		job = fctl_alloc_job(JOB_PORT_ONLINE,
   6929 		    JOB_TYPE_FCTL_ASYNC, NULL, NULL, KM_NOSLEEP);
   6930 		if (job == NULL) {
   6931 			fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
   6932 			    "fp_statec_cb() couldn't submit a job "
   6933 			    "to the thread: failing..");
   6934 
   6935 			mutex_enter(&port->fp_mutex);
   6936 			if (--port->fp_statec_busy == 0) {
   6937 				port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
   6938 			}
   6939 			mutex_exit(&port->fp_mutex);
   6940 			return;
   6941 		}
   6942 		fctl_enque_job(port, job);
   6943 		break;
   6944 
   6945 	case FC_STATE_RESET_REQUESTED:
   6946 		mutex_enter(&port->fp_mutex);
   6947 		port->fp_state = FC_STATE_OFFLINE;
   6948 		port->fp_soft_state |= FP_SOFT_IN_FCA_RESET;
   6949 		mutex_exit(&port->fp_mutex);
   6950 		/* FALLTHROUGH */
   6951 
   6952 	case FC_STATE_RESET:
   6953 		job = fctl_alloc_job(JOB_ULP_NOTIFY,
   6954 		    JOB_TYPE_FCTL_ASYNC, NULL, NULL, KM_NOSLEEP);
   6955 		if (job == NULL) {
   6956 			fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
   6957 			    "fp_statec_cb() couldn't submit a job"
   6958 			    " to the thread: failing..");
   6959 
   6960 			mutex_enter(&port->fp_mutex);
   6961 			if (--port->fp_statec_busy == 0) {
   6962 				port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
   6963 			}
   6964 			mutex_exit(&port->fp_mutex);
   6965 			return;
   6966 		}
   6967 
   6968 		/* squeeze into some field in the job structure */
   6969 		job->job_ulp_listlen = FC_PORT_STATE_MASK(state);
   6970 		fctl_enque_job(port, job);
   6971 		break;
   6972 
   6973 	case FC_STATE_TARGET_PORT_RESET:
   6974 		(void) fp_ulp_notify(port, state, KM_NOSLEEP);
   6975 		/* FALLTHROUGH */
   6976 
   6977 	case FC_STATE_NAMESERVICE:
   6978 		/* FALLTHROUGH */
   6979 
   6980 	default:
   6981 		mutex_enter(&port->fp_mutex);
   6982 		if (--port->fp_statec_busy == 0) {
   6983 			port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
   6984 		}
   6985 		mutex_exit(&port->fp_mutex);
   6986 		break;
   6987 	}
   6988 }
   6989 
   6990 
   6991 /*
   6992  * Register with the Name Server for RSCNs
   6993  */
   6994 static int
   6995 fp_ns_scr(fc_local_port_t *port, job_request_t *job, uchar_t scr_func,
   6996     int sleep)
   6997 {
   6998 	uint32_t	s_id;
   6999 	uchar_t		class;
   7000 	fc_scr_req_t	payload;
   7001 	fp_cmd_t	*cmd;
   7002 	fc_packet_t	*pkt;
   7003 
   7004 	mutex_enter(&port->fp_mutex);
   7005 	s_id = port->fp_port_id.port_id;
   7006 	class = port->fp_ns_login_class;
   7007 	mutex_exit(&port->fp_mutex);
   7008 
   7009 	cmd = fp_alloc_pkt(port, sizeof (fc_scr_req_t),
   7010 	    sizeof (fc_scr_resp_t), sleep, NULL);
   7011 	if (cmd == NULL) {
   7012 		return (FC_NOMEM);
   7013 	}
   7014 
   7015 	cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class;
   7016 	cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
   7017 	cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
   7018 	cmd->cmd_retry_count = fp_retry_count;
   7019 	cmd->cmd_ulp_pkt = NULL;
   7020 
   7021 	pkt = &cmd->cmd_pkt;
   7022 	cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
   7023 
   7024 	fp_els_init(cmd, s_id, 0xFFFFFD, fp_intr, job);
   7025 
   7026 	payload.ls_code.ls_code = LA_ELS_SCR;
   7027 	payload.ls_code.mbz = 0;
   7028 	payload.scr_rsvd = 0;
   7029 	payload.scr_func = scr_func;
   7030 
   7031 	FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
   7032 	    (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
   7033 
   7034 	job->job_counter = 1;
   7035 
   7036 	if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
   7037 		fp_iodone(cmd);
   7038 	}
   7039 
   7040 	return (FC_SUCCESS);
   7041 }
   7042 
   7043 
   7044 /*
   7045  * There are basically two methods to determine the total number of
   7046  * devices out in the NS database; Reading the details of the two
   7047  * methods described below, it shouldn't be hard to identify which
   7048  * of the two methods is better.
   7049  *
   7050  *	Method 1.
   7051  *		Iteratively issue GANs until all ports identifiers are walked
   7052  *
   7053  *	Method 2.
   7054  *		Issue GID_PT (get port Identifiers) with Maximum residual
   7055  *		field in the request CT HEADER set to accommodate only the
   7056  *		CT HEADER in the response frame. And if FC-GS2 has been
   7057  *		carefully read, the NS here has a chance to FS_ACC the
   7058  *		request and indicate the residual size in the FS_ACC.
   7059  *
   7060  *	Method 2 is wonderful, although it's not mandatory for the NS
   7061  *	to update the Maximum/Residual Field as can be seen in 4.3.1.6
   7062  *	(note with particular care the use of the auxiliary verb 'may')
   7063  *
   7064  */
   7065 static int
   7066 fp_ns_get_devcount(fc_local_port_t *port, job_request_t *job, int create,
   7067     int sleep)
   7068 {
   7069 	int		flags;
   7070 	int		rval;
   7071 	uint32_t	src_id;
   7072 	fctl_ns_req_t	*ns_cmd;
   7073 
   7074 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
   7075 
   7076 	mutex_enter(&port->fp_mutex);
   7077 	src_id = port->fp_port_id.port_id;
   7078 	mutex_exit(&port->fp_mutex);
   7079 
   7080 	if (!create && (port->fp_options & FP_NS_SMART_COUNT)) {
   7081 		ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pt_t),
   7082 		    sizeof (ns_resp_gid_pt_t), 0,
   7083 		    (FCTL_NS_GET_DEV_COUNT | FCTL_NS_NO_DATA_BUF), sleep);
   7084 
   7085 		if (ns_cmd == NULL) {
   7086 			return (FC_NOMEM);
   7087 		}
   7088 
   7089 		ns_cmd->ns_cmd_code = NS_GID_PT;
   7090 		((ns_req_gid_pt_t *)(ns_cmd->ns_cmd_buf))->port_type.port_type
   7091 		    = FC_NS_PORT_NX;	/* All port types */
   7092 		((ns_req_gid_pt_t *)(ns_cmd->ns_cmd_buf))->port_type.rsvd = 0;
   7093 
   7094 	} else {
   7095 		uint32_t ns_flags;
   7096 
   7097 		ns_flags = FCTL_NS_GET_DEV_COUNT | FCTL_NS_NO_DATA_BUF;
   7098 		if (create) {
   7099 			ns_flags |= FCTL_NS_CREATE_DEVICE;
   7100 		}
   7101 		ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t),
   7102 		    sizeof (ns_resp_gan_t), sizeof (int), ns_flags, sleep);
   7103 
   7104 		if (ns_cmd == NULL) {
   7105 			return (FC_NOMEM);
   7106 		}
   7107 		ns_cmd->ns_gan_index = 0;
   7108 		ns_cmd->ns_gan_sid = FCTL_GAN_START_ID;
   7109 		ns_cmd->ns_cmd_code = NS_GA_NXT;
   7110 		ns_cmd->ns_gan_max = 0xFFFF;
   7111 
   7112 		((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.port_id = src_id;
   7113 		((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.priv_lilp_posit = 0;
   7114 	}
   7115 
   7116 	flags = job->job_flags;
   7117 	job->job_flags &= ~JOB_TYPE_FP_ASYNC;
   7118 	job->job_counter = 1;
   7119 
   7120 	rval = fp_ns_query(port, ns_cmd, job, 1, sleep);
   7121 	job->job_flags = flags;
   7122 
   7123 	if (!create && (port->fp_options & FP_NS_SMART_COUNT)) {
   7124 		uint16_t max_resid;
   7125 
   7126 		/*
   7127 		 * Revert to scanning the NS if NS_GID_PT isn't
   7128 		 * helping us figure out total number of devices.
   7129 		 */
   7130 		if (job->job_result != FC_SUCCESS ||
   7131 		    ns_cmd->ns_resp_hdr.ct_cmdrsp != FS_ACC_IU) {
   7132 			mutex_enter(&port->fp_mutex);
   7133 			port->fp_options &= ~FP_NS_SMART_COUNT;
   7134 			mutex_exit(&port->fp_mutex);
   7135 
   7136 			fctl_free_ns_cmd(ns_cmd);
   7137 			return (fp_ns_get_devcount(port, job, create, sleep));
   7138 		}
   7139 
   7140 		mutex_enter(&port->fp_mutex);
   7141 		port->fp_total_devices = 1;
   7142 		max_resid = ns_cmd->ns_resp_hdr.ct_aiusize;
   7143 		if (max_resid) {
   7144 			/*
   7145 			 * Since port identifier is 4 bytes and max_resid
   7146 			 * is also in WORDS, max_resid simply indicates
   7147 			 * the total number of port identifiers	not
   7148 			 * transferred
   7149 			 */
   7150 			port->fp_total_devices += max_resid;
   7151 		}
   7152 		mutex_exit(&port->fp_mutex);
   7153 	}
   7154 	mutex_enter(&port->fp_mutex);
   7155 	port->fp_total_devices = *((int *)ns_cmd->ns_data_buf);
   7156 	mutex_exit(&port->fp_mutex);
   7157 	fctl_free_ns_cmd(ns_cmd);
   7158 
   7159 	return (rval);
   7160 }
   7161 
   7162 /*
   7163  * One heck of a function to serve userland.
   7164  */
   7165 static int
   7166 fp_fciocmd(fc_local_port_t *port, intptr_t data, int mode, fcio_t *fcio)
   7167 {
   7168 	int		rval = 0;
   7169 	int		jcode;
   7170 	uint32_t	ret;
   7171 	uchar_t		open_flag;
   7172 	fcio_t		*kfcio;
   7173 	job_request_t	*job;
   7174 	boolean_t	use32 = B_FALSE;
   7175 
   7176 #ifdef _MULTI_DATAMODEL
   7177 	switch (ddi_model_convert_from(mode & FMODELS)) {
   7178 	case DDI_MODEL_ILP32:
   7179 		use32 = B_TRUE;
   7180 		break;
   7181 
   7182 	case DDI_MODEL_NONE:
   7183 	default:
   7184 		break;
   7185 	}
   7186 #endif
   7187 
   7188 	mutex_enter(&port->fp_mutex);
   7189 	if (port->fp_soft_state & (FP_SOFT_IN_STATEC_CB |
   7190 	    FP_SOFT_IN_UNSOL_CB)) {
   7191 		fcio->fcio_errno = FC_STATEC_BUSY;
   7192 		mutex_exit(&port->fp_mutex);
   7193 		rval = EAGAIN;
   7194 		if (fp_fcio_copyout(fcio, data, mode)) {
   7195 			rval = EFAULT;
   7196 		}
   7197 		return (rval);
   7198 	}
   7199 	open_flag = port->fp_flag;
   7200 	mutex_exit(&port->fp_mutex);
   7201 
   7202 	if (fp_check_perms(open_flag, fcio->fcio_cmd) != FC_SUCCESS) {
   7203 		fcio->fcio_errno = FC_FAILURE;
   7204 		rval = EACCES;
   7205 		if (fp_fcio_copyout(fcio, data, mode)) {
   7206 			rval = EFAULT;
   7207 		}
   7208 		return (rval);
   7209 	}
   7210 
   7211 	/*
   7212 	 * If an exclusive open was demanded during open, don't let
   7213 	 * either innocuous or devil threads to share the file
   7214 	 * descriptor and fire down exclusive access commands
   7215 	 */
   7216 	mutex_enter(&port->fp_mutex);
   7217 	if (port->fp_flag & FP_EXCL) {
   7218 		if (port->fp_flag & FP_EXCL_BUSY) {
   7219 			mutex_exit(&port->fp_mutex);
   7220 			fcio->fcio_errno = FC_FAILURE;
   7221 			return (EBUSY);
   7222 		}
   7223 		port->fp_flag |= FP_EXCL_BUSY;
   7224 	}
   7225 	mutex_exit(&port->fp_mutex);
   7226 
   7227 	fcio->fcio_errno = FC_SUCCESS;
   7228 
   7229 	switch (fcio->fcio_cmd) {
   7230 	case FCIO_GET_HOST_PARAMS: {
   7231 		fc_port_dev_t	*val;
   7232 		fc_port_dev32_t	*val32;
   7233 		int		index;
   7234 		int		lilp_device_count;
   7235 		fc_lilpmap_t	*lilp_map;
   7236 		uchar_t		*alpa_list;
   7237 
   7238 		if (use32 == B_TRUE) {
   7239 			if (fcio->fcio_olen != sizeof (*val32) ||
   7240 			    fcio->fcio_xfer != FCIO_XFER_READ) {
   7241 				rval = EINVAL;
   7242 				break;
   7243 			}
   7244 		} else {
   7245 			if (fcio->fcio_olen != sizeof (*val) ||
   7246 			    fcio->fcio_xfer != FCIO_XFER_READ) {
   7247 				rval = EINVAL;
   7248 				break;
   7249 			}
   7250 		}
   7251 
   7252 		val = kmem_zalloc(sizeof (*val), KM_SLEEP);
   7253 
   7254 		mutex_enter(&port->fp_mutex);
   7255 		val->dev_did = port->fp_port_id;
   7256 		val->dev_hard_addr = port->fp_hard_addr;
   7257 		val->dev_pwwn = port->fp_service_params.nport_ww_name;
   7258 		val->dev_nwwn = port->fp_service_params.node_ww_name;
   7259 		val->dev_state = port->fp_state;
   7260 
   7261 		lilp_map = &port->fp_lilp_map;
   7262 		alpa_list = &lilp_map->lilp_alpalist[0];
   7263 		lilp_device_count = lilp_map->lilp_length;
   7264 		for (index = 0; index < lilp_device_count; index++) {
   7265 			uint32_t d_id;
   7266 
   7267 			d_id = alpa_list[index];
   7268 			if (d_id == port->fp_port_id.port_id) {
   7269 				break;
   7270 			}
   7271 		}
   7272 		val->dev_did.priv_lilp_posit = (uint8_t)(index & 0xff);
   7273 
   7274 		bcopy(port->fp_fc4_types, val->dev_type,
   7275 		    sizeof (port->fp_fc4_types));
   7276 		mutex_exit(&port->fp_mutex);
   7277 
   7278 		if (use32 == B_TRUE) {
   7279 			val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP);
   7280 
   7281 			val32->dev_did = val->dev_did;
   7282 			val32->dev_hard_addr = val->dev_hard_addr;
   7283 			val32->dev_pwwn = val->dev_pwwn;
   7284 			val32->dev_nwwn = val->dev_nwwn;
   7285 			val32->dev_state = val->dev_state;
   7286 			val32->dev_did.priv_lilp_posit =
   7287 			    val->dev_did.priv_lilp_posit;
   7288 
   7289 			bcopy(val->dev_type, val32->dev_type,
   7290 			    sizeof (port->fp_fc4_types));
   7291 
   7292 			if (fp_copyout((void *)val32, (void *)fcio->fcio_obuf,
   7293 			    fcio->fcio_olen, mode) == 0) {
   7294 				if (fp_fcio_copyout(fcio, data, mode)) {
   7295 					rval = EFAULT;
   7296 				}
   7297 			} else {
   7298 				rval = EFAULT;
   7299 			}
   7300 
   7301 			kmem_free(val32, sizeof (*val32));
   7302 		} else {
   7303 			if (fp_copyout((void *)val, (void *)fcio->fcio_obuf,
   7304 			    fcio->fcio_olen, mode) == 0) {
   7305 				if (fp_fcio_copyout(fcio, data, mode)) {
   7306 					rval = EFAULT;
   7307 				}
   7308 			} else {
   7309 				rval = EFAULT;
   7310 			}
   7311 		}
   7312 
   7313 		/* need to free "val" here */
   7314 		kmem_free(val, sizeof (*val));
   7315 		break;
   7316 	}
   7317 
   7318 	case FCIO_GET_OTHER_ADAPTER_PORTS: {
   7319 		uint32_t    index;
   7320 		char	    *tmpPath;
   7321 		fc_local_port_t	  *tmpPort;
   7322 
   7323 		if (fcio->fcio_olen < MAXPATHLEN ||
   7324 		    fcio->fcio_ilen != sizeof (uint32_t)) {
   7325 			rval = EINVAL;
   7326 			break;
   7327 		}
   7328 		if (ddi_copyin(fcio->fcio_ibuf, &index, sizeof (index), mode)) {
   7329 			rval = EFAULT;
   7330 			break;
   7331 		}
   7332 
   7333 		tmpPort = fctl_get_adapter_port_by_index(port, index);
   7334 		if (tmpPort == NULL) {
   7335 			FP_TRACE(FP_NHEAD1(9, 0),
   7336 			    "User supplied index out of range");
   7337 			fcio->fcio_errno = FC_BADPORT;
   7338 			rval = EFAULT;
   7339 			if (fp_fcio_copyout(fcio, data, mode)) {
   7340 				rval = EFAULT;
   7341 			}
   7342 			break;
   7343 		}
   7344 
   7345 		tmpPath = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
   7346 		(void) ddi_pathname(tmpPort->fp_port_dip, tmpPath);
   7347 		if (fp_copyout((void *)tmpPath, (void *)fcio->fcio_obuf,
   7348 		    MAXPATHLEN, mode) == 0) {
   7349 			if (fp_fcio_copyout(fcio, data, mode)) {
   7350 				rval = EFAULT;
   7351 			}
   7352 		} else {
   7353 			rval = EFAULT;
   7354 		}
   7355 		kmem_free(tmpPath, MAXPATHLEN);
   7356 		break;
   7357 	}
   7358 
   7359 	case FCIO_NPIV_GET_ADAPTER_ATTRIBUTES:
   7360 	case FCIO_GET_ADAPTER_ATTRIBUTES: {
   7361 		fc_hba_adapter_attributes_t	*val;
   7362 		fc_hba_adapter_attributes32_t	*val32;
   7363 
   7364 		if (use32 == B_TRUE) {
   7365 			if (fcio->fcio_olen < sizeof (*val32) ||
   7366 			    fcio->fcio_xfer != FCIO_XFER_READ) {
   7367 				rval = EINVAL;
   7368 				break;
   7369 			}
   7370 		} else {
   7371 			if (fcio->fcio_olen < sizeof (*val) ||
   7372 			    fcio->fcio_xfer != FCIO_XFER_READ) {
   7373 				rval = EINVAL;
   7374 				break;
   7375 			}
   7376 		}
   7377 
   7378 		val = kmem_zalloc(sizeof (*val), KM_SLEEP);
   7379 		val->version = FC_HBA_ADAPTER_ATTRIBUTES_VERSION;
   7380 		mutex_enter(&port->fp_mutex);
   7381 		bcopy(port->fp_hba_port_attrs.manufacturer,
   7382 		    val->Manufacturer,
   7383 		    sizeof (val->Manufacturer));
   7384 		bcopy(port->fp_hba_port_attrs.serial_number,
   7385 		    val->SerialNumber,
   7386 		    sizeof (val->SerialNumber));
   7387 		bcopy(port->fp_hba_port_attrs.model,
   7388 		    val->Model,
   7389 		    sizeof (val->Model));
   7390 		bcopy(port->fp_hba_port_attrs.model_description,
   7391 		    val->ModelDescription,
   7392 		    sizeof (val->ModelDescription));
   7393 		bcopy(port->fp_sym_node_name, val->NodeSymbolicName,
   7394 		    port->fp_sym_node_namelen);
   7395 		bcopy(port->fp_hba_port_attrs.hardware_version,
   7396 		    val->HardwareVersion,
   7397 		    sizeof (val->HardwareVersion));
   7398 		bcopy(port->fp_hba_port_attrs.option_rom_version,
   7399 		    val->OptionROMVersion,
   7400 		    sizeof (val->OptionROMVersion));
   7401 		bcopy(port->fp_hba_port_attrs.firmware_version,
   7402 		    val->FirmwareVersion,
   7403 		    sizeof (val->FirmwareVersion));
   7404 		val->VendorSpecificID =
   7405 		    port->fp_hba_port_attrs.vendor_specific_id;
   7406 		bcopy(&port->fp_service_params.node_ww_name.raw_wwn,
   7407 		    &val->NodeWWN.raw_wwn,
   7408 		    sizeof (val->NodeWWN.raw_wwn));
   7409 
   7410 
   7411 		bcopy(port->fp_hba_port_attrs.driver_name,
   7412 		    val->DriverName,
   7413 		    sizeof (val->DriverName));
   7414 		bcopy(port->fp_hba_port_attrs.driver_version,
   7415 		    val->DriverVersion,
   7416 		    sizeof (val->DriverVersion));
   7417 		mutex_exit(&port->fp_mutex);
   7418 
   7419 		if (fcio->fcio_cmd == FCIO_GET_ADAPTER_ATTRIBUTES) {
   7420 			val->NumberOfPorts = fctl_count_fru_ports(port, 0);
   7421 		} else {
   7422 			val->NumberOfPorts = fctl_count_fru_ports(port, 1);
   7423 		}
   7424 
   7425 		if (use32 == B_TRUE) {
   7426 			val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP);
   7427 			val32->version = val->version;
   7428 			bcopy(val->Manufacturer, val32->Manufacturer,
   7429 			    sizeof (val->Manufacturer));
   7430 			bcopy(val->SerialNumber, val32->SerialNumber,
   7431 			    sizeof (val->SerialNumber));
   7432 			bcopy(val->Model, val32->Model,
   7433 			    sizeof (val->Model));
   7434 			bcopy(val->ModelDescription, val32->ModelDescription,
   7435 			    sizeof (val->ModelDescription));
   7436 			bcopy(val->NodeSymbolicName, val32->NodeSymbolicName,
   7437 			    sizeof (val->NodeSymbolicName));
   7438 			bcopy(val->HardwareVersion, val32->HardwareVersion,
   7439 			    sizeof (val->HardwareVersion));
   7440 			bcopy(val->OptionROMVersion, val32->OptionROMVersion,
   7441 			    sizeof (val->OptionROMVersion));
   7442 			bcopy(val->FirmwareVersion, val32->FirmwareVersion,
   7443 			    sizeof (val->FirmwareVersion));
   7444 			val32->VendorSpecificID = val->VendorSpecificID;
   7445 			bcopy(&val->NodeWWN.raw_wwn, &val32->NodeWWN.raw_wwn,
   7446 			    sizeof (val->NodeWWN.raw_wwn));
   7447 			bcopy(val->DriverName, val32->DriverName,
   7448 			    sizeof (val->DriverName));
   7449 			bcopy(val->DriverVersion, val32->DriverVersion,
   7450 			    sizeof (val->DriverVersion));
   7451 
   7452 			val32->NumberOfPorts = val->NumberOfPorts;
   7453 
   7454 			if (fp_copyout((void *)val32, (void *)fcio->fcio_obuf,
   7455 			    fcio->fcio_olen, mode) == 0) {
   7456 				if (fp_fcio_copyout(fcio, data, mode)) {
   7457 					rval = EFAULT;
   7458 				}
   7459 			} else {
   7460 				rval = EFAULT;
   7461 			}
   7462 
   7463 			kmem_free(val32, sizeof (*val32));
   7464 		} else {
   7465 			if (fp_copyout((void *)val, (void *)fcio->fcio_obuf,
   7466 			    fcio->fcio_olen, mode) == 0) {
   7467 				if (fp_fcio_copyout(fcio, data, mode)) {
   7468 					rval = EFAULT;
   7469 				}
   7470 			} else {
   7471 				rval = EFAULT;
   7472 			}
   7473 		}
   7474 
   7475 		kmem_free(val, sizeof (*val));
   7476 		break;
   7477 	}
   7478 
   7479 	case FCIO_GET_NPIV_ATTRIBUTES: {
   7480 		fc_hba_npiv_attributes_t *attrs;
   7481 
   7482 		attrs = kmem_zalloc(sizeof (*attrs), KM_SLEEP);
   7483 		mutex_enter(&port->fp_mutex);
   7484 		bcopy(&port->fp_service_params.node_ww_name.raw_wwn,
   7485 		    &attrs->NodeWWN.raw_wwn,
   7486 		    sizeof (attrs->NodeWWN.raw_wwn));
   7487 		bcopy(&port->fp_service_params.nport_ww_name.raw_wwn,
   7488 		    &attrs->PortWWN.raw_wwn,
   7489 		    sizeof (attrs->PortWWN.raw_wwn));
   7490 		mutex_exit(&port->fp_mutex);
   7491 		if (fp_copyout((void *)attrs, (void *)fcio->fcio_obuf,
   7492 		    fcio->fcio_olen, mode) == 0) {
   7493 			if (fp_fcio_copyout(fcio, data, mode)) {
   7494 				rval = EFAULT;
   7495 			}
   7496 		} else {
   7497 			rval = EFAULT;
   7498 		}
   7499 		kmem_free(attrs, sizeof (*attrs));
   7500 		break;
   7501 	}
   7502 
   7503 	case FCIO_DELETE_NPIV_PORT: {
   7504 		fc_local_port_t *tmpport;
   7505 		char	ww_pname[17];
   7506 		la_wwn_t	vwwn[1];
   7507 
   7508 		FP_TRACE(FP_NHEAD1(1, 0), "Delete NPIV Port");
   7509 		if (ddi_copyin(fcio->fcio_ibuf,
   7510 		    &vwwn, sizeof (la_wwn_t), mode)) {
   7511 			rval = EFAULT;
   7512 			break;
   7513 		}
   7514 
   7515 		fc_wwn_to_str(&vwwn[0], ww_pname);
   7516 		FP_TRACE(FP_NHEAD1(3, 0),
   7517 		    "Delete NPIV Port %s", ww_pname);
   7518 		tmpport = fc_delete_npiv_port(port, &vwwn[0]);
   7519 		if (tmpport == NULL) {
   7520 			FP_TRACE(FP_NHEAD1(3, 0),
   7521 			    "Delete NPIV Port : no found");
   7522 			rval = EFAULT;
   7523 		} else {
   7524 			fc_local_port_t *nextport = tmpport->fp_port_next;
   7525 			fc_local_port_t *prevport = tmpport->fp_port_prev;
   7526 			int portlen, portindex, ret;
   7527 
   7528 			portlen = sizeof (portindex);
   7529 			ret = ddi_prop_op(DDI_DEV_T_ANY,
   7530 			    tmpport->fp_port_dip, PROP_LEN_AND_VAL_BUF,
   7531 			    DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "port",
   7532 			    (caddr_t)&portindex, &portlen);
   7533 			if (ret != DDI_SUCCESS) {
   7534 				rval = EFAULT;
   7535 				break;
   7536 			}
   7537 			if (ndi_devi_offline(tmpport->fp_port_dip,
   7538 			    NDI_DEVI_REMOVE) != DDI_SUCCESS) {
   7539 				FP_TRACE(FP_NHEAD1(1, 0),
   7540 				    "Delete NPIV Port failed");
   7541 				mutex_enter(&port->fp_mutex);
   7542 				tmpport->fp_npiv_state = 0;
   7543 				mutex_exit(&port->fp_mutex);
   7544 				rval = EFAULT;
   7545 			} else {
   7546 				mutex_enter(&port->fp_mutex);
   7547 				nextport->fp_port_prev = prevport;
   7548 				prevport->fp_port_next = nextport;
   7549 				if (port == port->fp_port_next) {
   7550 					port->fp_port_next =
   7551 					    port->fp_port_prev = NULL;
   7552 				}
   7553 				port->fp_npiv_portnum--;
   7554 				FP_TRACE(FP_NHEAD1(3, 0),
   7555 				    "Delete NPIV Port %d", portindex);
   7556 				port->fp_npiv_portindex[portindex-1] = 0;
   7557 				mutex_exit(&port->fp_mutex);
   7558 			}
   7559 		}
   7560 		break;
   7561 	}
   7562 
   7563 	case FCIO_CREATE_NPIV_PORT: {
   7564 		char ww_nname[17], ww_pname[17];
   7565 		la_npiv_create_entry_t entrybuf;
   7566 		uint32_t vportindex = 0;
   7567 		int npiv_ret = 0;
   7568 		char *portname, *fcaname;
   7569 
   7570 		portname = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
   7571 		(void) ddi_pathname(port->fp_port_dip, portname);
   7572 		fcaname = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
   7573 		(void) ddi_pathname(port->fp_fca_dip, fcaname);
   7574 		FP_TRACE(FP_NHEAD1(1, 0),
   7575 		    "Create NPIV port %s %s %s", portname, fcaname,
   7576 		    ddi_driver_name(port->fp_fca_dip));
   7577 		kmem_free(portname, MAXPATHLEN);
   7578 		kmem_free(fcaname, MAXPATHLEN);
   7579 		if (ddi_copyin(fcio->fcio_ibuf,
   7580 		    &entrybuf, sizeof (la_npiv_create_entry_t), mode)) {
   7581 			rval = EFAULT;
   7582 			break;
   7583 		}
   7584 
   7585 		fc_wwn_to_str(&entrybuf.VNodeWWN, ww_nname);
   7586 		fc_wwn_to_str(&entrybuf.VPortWWN, ww_pname);
   7587 		vportindex = entrybuf.vindex;
   7588 		FP_TRACE(FP_NHEAD1(3, 0),
   7589 		    "Create NPIV Port %s %s %d",
   7590 		    ww_nname, ww_pname, vportindex);
   7591 
   7592 		if (fc_get_npiv_port(port, &entrybuf.VPortWWN)) {
   7593 			rval = EFAULT;
   7594 			break;
   7595 		}
   7596 		npiv_ret = fctl_fca_create_npivport(port->fp_fca_dip,
   7597 		    port->fp_port_dip, ww_nname, ww_pname, &vportindex);
   7598 		if (npiv_ret == NDI_SUCCESS) {
   7599 			mutex_enter(&port->fp_mutex);
   7600 			port->fp_npiv_portnum++;
   7601 			mutex_exit(&port->fp_mutex);
   7602 			if (fp_copyout((void *)&vportindex,
   7603 			    (void *)fcio->fcio_obuf,
   7604 			    fcio->fcio_olen, mode) == 0) {
   7605 				if (fp_fcio_copyout(fcio, data, mode)) {
   7606 					rval = EFAULT;
   7607 				}
   7608 			} else {
   7609 				rval = EFAULT;
   7610 			}
   7611 		} else {
   7612 			rval = EFAULT;
   7613 		}
   7614 		FP_TRACE(FP_NHEAD1(3, 0),
   7615 		    "Create NPIV Port %d %d", npiv_ret, vportindex);
   7616 		break;
   7617 	}
   7618 
   7619 	case FCIO_GET_NPIV_PORT_LIST: {
   7620 		fc_hba_npiv_port_list_t *list;
   7621 		int count;
   7622 
   7623 		if ((fcio->fcio_xfer != FCIO_XFER_READ) ||
   7624 		    (fcio->fcio_olen == 0) || (fcio->fcio_obuf == 0)) {
   7625 			rval = EINVAL;
   7626 			break;
   7627 		}
   7628 
   7629 		list = kmem_zalloc(fcio->fcio_olen, KM_SLEEP);
   7630 		list->version = FC_HBA_LIST_VERSION;
   7631 		/* build npiv port list */
   7632 		count = fc_ulp_get_npiv_port_list(port, (char *)list->hbaPaths);
   7633 		if (count < 0) {
   7634 			rval = ENXIO;
   7635 			FP_TRACE(FP_NHEAD1(1, 0), "Build NPIV Port List error");
   7636 			kmem_free(list, fcio->fcio_olen);
   7637 			break;
   7638 		}
   7639 		list->numAdapters = count;
   7640 
   7641 		if (fp_copyout((void *)list, (void *)fcio->fcio_obuf,
   7642 		    fcio->fcio_olen, mode) == 0) {
   7643 			if (fp_fcio_copyout(fcio, data, mode)) {
   7644 				FP_TRACE(FP_NHEAD1(1, 0),
   7645 				    "Copy NPIV Port data error");
   7646 				rval = EFAULT;
   7647 			}
   7648 		} else {
   7649 			FP_TRACE(FP_NHEAD1(1, 0), "Copy NPIV Port List error");
   7650 			rval = EFAULT;
   7651 		}
   7652 		kmem_free(list, fcio->fcio_olen);
   7653 		break;
   7654 	}
   7655 
   7656 	case FCIO_GET_ADAPTER_PORT_NPIV_ATTRIBUTES: {
   7657 		fc_hba_port_npiv_attributes_t	*val;
   7658 
   7659 		val<