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 (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  23  *
  24  * NOT a DDI compliant Sun Fibre Channel port driver(fp)
  25  *
  26  */
  27 
  28 #include <sys/types.h>
  29 #include <sys/varargs.h>
  30 #include <sys/param.h>
  31 #include <sys/errno.h>
  32 #include <sys/uio.h>
  33 #include <sys/buf.h>
  34 #include <sys/modctl.h>
  35 #include <sys/open.h>
  36 #include <sys/file.h>
  37 #include <sys/kmem.h>
  38 #include <sys/poll.h>
  39 #include <sys/conf.h>
  40 #include <sys/thread.h>
  41 #include <sys/var.h>
  42 #include <sys/cmn_err.h>
  43 #include <sys/stat.h>
  44 #include <sys/ddi.h>
  45 #include <sys/sunddi.h>
  46 #include <sys/promif.h>
  47 #include <sys/nvpair.h>
  48 #include <sys/byteorder.h>
  49 #include <sys/scsi/scsi.h>
  50 #include <sys/fibre-channel/fc.h>
  51 #include <sys/fibre-channel/impl/fc_ulpif.h>
  52 #include <sys/fibre-channel/impl/fc_fcaif.h>
  53 #include <sys/fibre-channel/impl/fctl_private.h>
  54 #include <sys/fibre-channel/impl/fc_portif.h>
  55 #include <sys/fibre-channel/impl/fp.h>
  56 
  57 /* These are defined in fctl.c! */
  58 extern int did_table_size;
  59 extern int pwwn_table_size;
  60 
  61 static struct cb_ops fp_cb_ops = {
  62         fp_open,                        /* open */
  63         fp_close,                       /* close */
  64         nodev,                          /* strategy */
  65         nodev,                          /* print */
  66         nodev,                          /* dump */
  67         nodev,                          /* read */
  68         nodev,                          /* write */
  69         fp_ioctl,                       /* ioctl */
  70         nodev,                          /* devmap */
  71         nodev,                          /* mmap */
  72         nodev,                          /* segmap */
  73         nochpoll,                       /* chpoll */
  74         ddi_prop_op,                    /* cb_prop_op */
  75         0,                              /* streamtab */
  76         D_NEW | D_MP | D_HOTPLUG,       /* cb_flag */
  77         CB_REV,                         /* rev */
  78         nodev,                          /* aread */
  79         nodev                           /* awrite */
  80 };
  81 
  82 static struct dev_ops fp_ops = {
  83         DEVO_REV,                       /* build revision */
  84         0,                              /* reference count */
  85         fp_getinfo,                     /* getinfo */
  86         nulldev,                        /* identify - Obsoleted */
  87         nulldev,                        /* probe */
  88         fp_attach,                      /* attach */
  89         fp_detach,                      /* detach */
  90         nodev,                          /* reset */
  91         &fp_cb_ops,                 /* cb_ops */
  92         NULL,                           /* bus_ops */
  93         fp_power,                       /* power */
  94         ddi_quiesce_not_needed          /* quiesce */
  95 };
  96 
  97 #define FP_VERSION              "20091123-1.101"
  98 #define FP_NAME_VERSION         "SunFC Port v" FP_VERSION
  99 
 100 char *fp_version = FP_NAME_VERSION;
 101 
 102 static struct modldrv modldrv = {
 103         &mod_driverops,                     /* Type of Module */
 104         FP_NAME_VERSION,                /* Name/Version of fp */
 105         &fp_ops                             /* driver ops */
 106 };
 107 
 108 static struct modlinkage modlinkage = {
 109         MODREV_1,       /* Rev of the loadable modules system */
 110         &modldrv,   /* NULL terminated list of */
 111         NULL            /* Linkage structures */
 112 };
 113 
 114 
 115 
 116 static uint16_t ns_reg_cmds[] = {
 117         NS_RPN_ID,
 118         NS_RNN_ID,
 119         NS_RCS_ID,
 120         NS_RFT_ID,
 121         NS_RPT_ID,
 122         NS_RSPN_ID,
 123         NS_RSNN_NN
 124 };
 125 
 126 struct fp_xlat {
 127         uchar_t xlat_state;
 128         int     xlat_rval;
 129 } fp_xlat [] = {
 130         { FC_PKT_SUCCESS,       FC_SUCCESS },
 131         { FC_PKT_REMOTE_STOP,   FC_FAILURE },
 132         { FC_PKT_LOCAL_RJT,     FC_FAILURE },
 133         { FC_PKT_NPORT_RJT,     FC_ELS_PREJECT },
 134         { FC_PKT_FABRIC_RJT,    FC_ELS_FREJECT },
 135         { FC_PKT_LOCAL_BSY,     FC_TRAN_BUSY },
 136         { FC_PKT_TRAN_BSY,      FC_TRAN_BUSY },
 137         { FC_PKT_NPORT_BSY,     FC_PBUSY },
 138         { FC_PKT_FABRIC_BSY,    FC_FBUSY },
 139         { FC_PKT_LS_RJT,        FC_FAILURE },
 140         { FC_PKT_BA_RJT,        FC_FAILURE },
 141         { FC_PKT_TIMEOUT,       FC_FAILURE },
 142         { FC_PKT_TRAN_ERROR,    FC_TRANSPORT_ERROR },
 143         { FC_PKT_FAILURE,       FC_FAILURE },
 144         { FC_PKT_PORT_OFFLINE,  FC_OFFLINE }
 145 };
 146 
 147 static uchar_t fp_valid_alpas[] = {
 148         0x01, 0x02, 0x04, 0x08, 0x0F, 0x10, 0x17, 0x18, 0x1B,
 149         0x1D, 0x1E, 0x1F, 0x23, 0x25, 0x26, 0x27, 0x29, 0x2A,
 150         0x2B, 0x2C, 0x2D, 0x2E, 0x31, 0x32, 0x33, 0x34, 0x35,
 151         0x36, 0x39, 0x3A, 0x3C, 0x43, 0x45, 0x46, 0x47, 0x49,
 152         0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x51, 0x52, 0x53, 0x54,
 153         0x55, 0x56, 0x59, 0x5A, 0x5C, 0x63, 0x65, 0x66, 0x67,
 154         0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x71, 0x72, 0x73,
 155         0x74, 0x75, 0x76, 0x79, 0x7A, 0x7C, 0x80, 0x81, 0x82,
 156         0x84, 0x88, 0x8F, 0x90, 0x97, 0x98, 0x9B, 0x9D, 0x9E,
 157         0x9F, 0xA3, 0xA5, 0xA6, 0xA7, 0xA9, 0xAA, 0xAB, 0xAC,
 158         0xAD, 0xAE, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB9,
 159         0xBA, 0xBC, 0xC3, 0xC5, 0xC6, 0xC7, 0xC9, 0xCA, 0xCB,
 160         0xCC, 0xCD, 0xCE, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
 161         0xD9, 0xDA, 0xDC, 0xE0, 0xE1, 0xE2, 0xE4, 0xE8, 0xEF
 162 };
 163 
 164 static struct fp_perms {
 165         uint16_t        fp_ioctl_cmd;
 166         uchar_t         fp_open_flag;
 167 } fp_perm_list [] = {
 168         { FCIO_GET_NUM_DEVS,            FP_OPEN },
 169         { FCIO_GET_DEV_LIST,            FP_OPEN },
 170         { FCIO_GET_SYM_PNAME,           FP_OPEN },
 171         { FCIO_GET_SYM_NNAME,           FP_OPEN },
 172         { FCIO_SET_SYM_PNAME,           FP_EXCL },
 173         { FCIO_SET_SYM_NNAME,           FP_EXCL },
 174         { FCIO_GET_LOGI_PARAMS,         FP_OPEN },
 175         { FCIO_DEV_LOGIN,               FP_EXCL },
 176         { FCIO_DEV_LOGOUT,              FP_EXCL },
 177         { FCIO_GET_STATE,               FP_OPEN },
 178         { FCIO_DEV_REMOVE,              FP_EXCL },
 179         { FCIO_GET_FCODE_REV,           FP_OPEN },
 180         { FCIO_GET_FW_REV,              FP_OPEN },
 181         { FCIO_GET_DUMP_SIZE,           FP_OPEN },
 182         { FCIO_FORCE_DUMP,              FP_EXCL },
 183         { FCIO_GET_DUMP,                FP_OPEN },
 184         { FCIO_GET_TOPOLOGY,            FP_OPEN },
 185         { FCIO_RESET_LINK,              FP_EXCL },
 186         { FCIO_RESET_HARD,              FP_EXCL },
 187         { FCIO_RESET_HARD_CORE,         FP_EXCL },
 188         { FCIO_DIAG,                    FP_OPEN },
 189         { FCIO_NS,                      FP_EXCL },
 190         { FCIO_DOWNLOAD_FW,             FP_EXCL },
 191         { FCIO_DOWNLOAD_FCODE,          FP_EXCL },
 192         { FCIO_LINK_STATUS,             FP_OPEN },
 193         { FCIO_GET_HOST_PARAMS,         FP_OPEN },
 194         { FCIO_GET_NODE_ID,             FP_OPEN },
 195         { FCIO_SET_NODE_ID,             FP_EXCL },
 196         { FCIO_SEND_NODE_ID,            FP_OPEN },
 197         { FCIO_GET_ADAPTER_ATTRIBUTES,  FP_OPEN },
 198         { FCIO_GET_OTHER_ADAPTER_PORTS, FP_OPEN },
 199         { FCIO_GET_ADAPTER_PORT_ATTRIBUTES,     FP_OPEN },
 200         { FCIO_GET_DISCOVERED_PORT_ATTRIBUTES,  FP_OPEN },
 201         { FCIO_GET_PORT_ATTRIBUTES,     FP_OPEN },
 202         { FCIO_GET_ADAPTER_PORT_STATS,  FP_OPEN },
 203         { FCIO_GET_ADAPTER_PORT_NPIV_ATTRIBUTES, FP_OPEN },
 204         { FCIO_GET_NPIV_PORT_LIST, FP_OPEN },
 205         { FCIO_DELETE_NPIV_PORT, FP_OPEN },
 206         { FCIO_GET_NPIV_ATTRIBUTES, FP_OPEN },
 207         { FCIO_CREATE_NPIV_PORT, FP_OPEN },
 208         { FCIO_NPIV_GET_ADAPTER_ATTRIBUTES, FP_OPEN }
 209 };
 210 
 211 static char *fp_pm_comps[] = {
 212         "NAME=FC Port",
 213         "0=Port Down",
 214         "1=Port Up"
 215 };
 216 
 217 
 218 #ifdef  _LITTLE_ENDIAN
 219 #define MAKE_BE_32(x)   {                                               \
 220                 uint32_t        *ptr1, i;                               \
 221                 ptr1 = (uint32_t *)(x);                                 \
 222                 for (i = 0; i < sizeof (*(x)) / sizeof (uint32_t); i++) { \
 223                         *ptr1 = BE_32(*ptr1);                           \
 224                         ptr1++;                                         \
 225                 }                                                       \
 226         }
 227 #else
 228 #define MAKE_BE_32(x)
 229 #endif
 230 
 231 static uchar_t fp_verbosity = (FP_WARNING_MESSAGES | FP_FATAL_MESSAGES);
 232 static uint32_t fp_options = 0;
 233 
 234 static int fp_cmd_wait_cnt = FP_CMDWAIT_DELAY;
 235 static int fp_retry_delay = FP_RETRY_DELAY;     /* retry after this delay */
 236 static int fp_retry_count = FP_RETRY_COUNT;     /* number of retries */
 237 unsigned int fp_offline_ticker;                 /* seconds */
 238 
 239 /*
 240  * Driver global variable to anchor the list of soft state structs for
 241  * all fp driver instances.  Used with the Solaris DDI soft state functions.
 242  */
 243 static void *fp_driver_softstate;
 244 
 245 static clock_t  fp_retry_ticks;
 246 static clock_t  fp_offline_ticks;
 247 
 248 static int fp_retry_ticker;
 249 static uint32_t fp_unsol_buf_count = FP_UNSOL_BUF_COUNT;
 250 static uint32_t fp_unsol_buf_size = FP_UNSOL_BUF_SIZE;
 251 
 252 static int              fp_log_size = FP_LOG_SIZE;
 253 static int              fp_trace = FP_TRACE_DEFAULT;
 254 static fc_trace_logq_t  *fp_logq = NULL;
 255 
 256 int fp_get_adapter_paths(char *pathList, int count);
 257 static void fp_log_port_event(fc_local_port_t *port, char *subclass);
 258 static void fp_log_target_event(fc_local_port_t *port, char *subclass,
 259     la_wwn_t tgt_pwwn, uint32_t port_id);
 260 static uint32_t fp_map_remote_port_state(uint32_t rm_state);
 261 static void fp_init_symbolic_names(fc_local_port_t *port);
 262 
 263 
 264 /*
 265  * Perform global initialization
 266  */
 267 int
 268 _init(void)
 269 {
 270         int ret;
 271 
 272         if ((ret = ddi_soft_state_init(&fp_driver_softstate,
 273             sizeof (struct fc_local_port), 8)) != 0) {
 274                 return (ret);
 275         }
 276 
 277         if ((ret = scsi_hba_init(&modlinkage)) != 0) {
 278                 ddi_soft_state_fini(&fp_driver_softstate);
 279                 return (ret);
 280         }
 281 
 282         fp_logq = fc_trace_alloc_logq(fp_log_size);
 283 
 284         if ((ret = mod_install(&modlinkage)) != 0) {
 285                 fc_trace_free_logq(fp_logq);
 286                 ddi_soft_state_fini(&fp_driver_softstate);
 287                 scsi_hba_fini(&modlinkage);
 288         }
 289 
 290         return (ret);
 291 }
 292 
 293 
 294 /*
 295  * Prepare for driver unload
 296  */
 297 int
 298 _fini(void)
 299 {
 300         int ret;
 301 
 302         if ((ret = mod_remove(&modlinkage)) == 0) {
 303                 fc_trace_free_logq(fp_logq);
 304                 ddi_soft_state_fini(&fp_driver_softstate);
 305                 scsi_hba_fini(&modlinkage);
 306         }
 307 
 308         return (ret);
 309 }
 310 
 311 
 312 /*
 313  * Request mod_info() to handle all cases
 314  */
 315 int
 316 _info(struct modinfo *modinfo)
 317 {
 318         return (mod_info(&modlinkage, modinfo));
 319 }
 320 
 321 
 322 /*
 323  * fp_attach:
 324  *
 325  * The respective cmd handlers take care of performing
 326  * ULP related invocations
 327  */
 328 static int
 329 fp_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 330 {
 331         int rval;
 332 
 333         /*
 334          * We check the value of fp_offline_ticker at this
 335          * point. The variable is global for the driver and
 336          * not specific to an instance.
 337          *
 338          * If there is no user-defined value found in /etc/system
 339          * or fp.conf, then we use 90 seconds (FP_OFFLINE_TICKER).
 340          * The minimum setting for this offline timeout according
 341          * to the FC-FS2 standard (Fibre Channel Framing and
 342          * Signalling-2, see www.t11.org) is R_T_TOV == 100msec.
 343          *
 344          * We do not recommend setting the value to less than 10
 345          * seconds (RA_TOV) or more than 90 seconds. If this
 346          * variable is greater than 90 seconds then drivers above
 347          * fp (fcp, sd, scsi_vhci, vxdmp et al) might complain.
 348          */
 349 
 350         fp_offline_ticker = ddi_prop_get_int(DDI_DEV_T_ANY,
 351             dip, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "fp_offline_ticker",
 352             FP_OFFLINE_TICKER);
 353 
 354         if ((fp_offline_ticker < 10) ||
 355             (fp_offline_ticker > 90)) {
 356                 cmn_err(CE_WARN, "Setting fp_offline_ticker to "
 357                     "%d second(s). This is outside the "
 358                     "recommended range of 10..90 seconds",
 359                     fp_offline_ticker);
 360         }
 361 
 362         /*
 363          * Tick every second when there are commands to retry.
 364          * It should tick at the least granular value of pkt_timeout
 365          * (which is one second)
 366          */
 367         fp_retry_ticker = 1;
 368 
 369         fp_retry_ticks = drv_usectohz(fp_retry_ticker * 1000 * 1000);
 370         fp_offline_ticks = drv_usectohz(fp_offline_ticker * 1000 * 1000);
 371 
 372         switch (cmd) {
 373         case DDI_ATTACH:
 374                 rval = fp_attach_handler(dip);
 375                 break;
 376 
 377         case DDI_RESUME:
 378                 rval = fp_resume_handler(dip);
 379                 break;
 380 
 381         default:
 382                 rval = DDI_FAILURE;
 383                 break;
 384         }
 385         return (rval);
 386 }
 387 
 388 
 389 /*
 390  * fp_detach:
 391  *
 392  * If a ULP fails to handle cmd request converse of
 393  * cmd is invoked for ULPs that previously succeeded
 394  * cmd request.
 395  */
 396 static int
 397 fp_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
 398 {
 399         int                     rval = DDI_FAILURE;
 400         fc_local_port_t         *port;
 401         fc_attach_cmd_t         converse;
 402         uint8_t                 cnt;
 403 
 404         if ((port = ddi_get_soft_state(fp_driver_softstate,
 405             ddi_get_instance(dip))) == NULL) {
 406                 return (DDI_FAILURE);
 407         }
 408 
 409         mutex_enter(&port->fp_mutex);
 410 
 411         if (port->fp_ulp_attach) {
 412                 mutex_exit(&port->fp_mutex);
 413                 return (DDI_FAILURE);
 414         }
 415 
 416         switch (cmd) {
 417         case DDI_DETACH:
 418                 if (port->fp_task != FP_TASK_IDLE) {
 419                         mutex_exit(&port->fp_mutex);
 420                         return (DDI_FAILURE);
 421                 }
 422 
 423                 /* Let's attempt to quit the job handler gracefully */
 424                 port->fp_soft_state |= FP_DETACH_INPROGRESS;
 425 
 426                 mutex_exit(&port->fp_mutex);
 427                 converse = FC_CMD_ATTACH;
 428                 if (fctl_detach_ulps(port, FC_CMD_DETACH,
 429                     &modlinkage) != FC_SUCCESS) {
 430                         mutex_enter(&port->fp_mutex);
 431                         port->fp_soft_state &= ~FP_DETACH_INPROGRESS;
 432                         mutex_exit(&port->fp_mutex);
 433                         rval = DDI_FAILURE;
 434                         break;
 435                 }
 436 
 437                 mutex_enter(&port->fp_mutex);
 438                 for (cnt = 0; (port->fp_job_head) && (cnt < fp_cmd_wait_cnt);
 439                     cnt++) {
 440                         mutex_exit(&port->fp_mutex);
 441                         delay(drv_sectohz(1));
 442                         mutex_enter(&port->fp_mutex);
 443                 }
 444 
 445                 if (port->fp_job_head) {
 446                         mutex_exit(&port->fp_mutex);
 447                         rval = DDI_FAILURE;
 448                         break;
 449                 }
 450                 mutex_exit(&port->fp_mutex);
 451 
 452                 rval = fp_detach_handler(port);
 453                 break;
 454 
 455         case DDI_SUSPEND:
 456                 mutex_exit(&port->fp_mutex);
 457                 converse = FC_CMD_RESUME;
 458                 if (fctl_detach_ulps(port, FC_CMD_SUSPEND,
 459                     &modlinkage) != FC_SUCCESS) {
 460                         rval = DDI_FAILURE;
 461                         break;
 462                 }
 463                 if ((rval = fp_suspend_handler(port)) != DDI_SUCCESS) {
 464                         (void) callb_generic_cpr(&port->fp_cpr_info,
 465                             CB_CODE_CPR_RESUME);
 466                 }
 467                 break;
 468 
 469         default:
 470                 mutex_exit(&port->fp_mutex);
 471                 break;
 472         }
 473 
 474         /*
 475          * Use softint to perform reattach.  Mark fp_ulp_attach so we
 476          * don't attempt to do this repeatedly on behalf of some persistent
 477          * caller.
 478          */
 479         if (rval != DDI_SUCCESS) {
 480                 mutex_enter(&port->fp_mutex);
 481                 port->fp_ulp_attach = 1;
 482 
 483                 /*
 484                  * If the port is in the low power mode then there is
 485                  * possibility that fca too could be in low power mode.
 486                  * Try to raise the power before calling attach ulps.
 487                  */
 488 
 489                 if ((port->fp_soft_state & FP_SOFT_POWER_DOWN) &&
 490                     (!(port->fp_soft_state & FP_SOFT_NO_PMCOMP))) {
 491                         mutex_exit(&port->fp_mutex);
 492                         (void) pm_raise_power(port->fp_port_dip,
 493                             FP_PM_COMPONENT, FP_PM_PORT_UP);
 494                 } else {
 495                         mutex_exit(&port->fp_mutex);
 496                 }
 497 
 498 
 499                 fp_attach_ulps(port, converse);
 500 
 501                 mutex_enter(&port->fp_mutex);
 502                 while (port->fp_ulp_attach) {
 503                         cv_wait(&port->fp_attach_cv, &port->fp_mutex);
 504                 }
 505 
 506                 port->fp_soft_state &= ~FP_DETACH_INPROGRESS;
 507 
 508                 /*
 509                  * Mark state as detach failed so asynchronous ULP attach
 510                  * events (downstream, not the ones we're initiating with
 511                  * the call to fp_attach_ulps) are not honored.  We're
 512                  * really still in pending detach.
 513                  */
 514                 port->fp_soft_state |= FP_DETACH_FAILED;
 515 
 516                 mutex_exit(&port->fp_mutex);
 517         }
 518 
 519         return (rval);
 520 }
 521 
 522 
 523 /*
 524  * fp_getinfo:
 525  *   Given the device number, return either the
 526  *   dev_info_t pointer or the instance number.
 527  */
 528 
 529 /* ARGSUSED */
 530 static int
 531 fp_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
 532 {
 533         int             rval;
 534         minor_t         instance;
 535         fc_local_port_t *port;
 536 
 537         rval = DDI_SUCCESS;
 538         instance = getminor((dev_t)arg);
 539 
 540         switch (cmd) {
 541         case DDI_INFO_DEVT2DEVINFO:
 542                 if ((port = ddi_get_soft_state(fp_driver_softstate,
 543                     instance)) == NULL) {
 544                         rval = DDI_FAILURE;
 545                         break;
 546                 }
 547                 *result = (void *)port->fp_port_dip;
 548                 break;
 549 
 550         case DDI_INFO_DEVT2INSTANCE:
 551                 *result = (void *)(uintptr_t)instance;
 552                 break;
 553 
 554         default:
 555                 rval = DDI_FAILURE;
 556                 break;
 557         }
 558 
 559         return (rval);
 560 }
 561 
 562 
 563 /*
 564  * Entry point for power up and power down request from kernel
 565  */
 566 static int
 567 fp_power(dev_info_t *dip, int comp, int level)
 568 {
 569         int             rval = DDI_FAILURE;
 570         fc_local_port_t *port;
 571 
 572         port = ddi_get_soft_state(fp_driver_softstate, ddi_get_instance(dip));
 573         if (port == NULL || comp != FP_PM_COMPONENT) {
 574                 return (rval);
 575         }
 576 
 577         switch (level) {
 578         case FP_PM_PORT_UP:
 579                 rval = DDI_SUCCESS;
 580 
 581                 /*
 582                  * If the port is DDI_SUSPENDed, let the DDI_RESUME
 583                  * code complete the rediscovery.
 584                  */
 585                 mutex_enter(&port->fp_mutex);
 586                 if (port->fp_soft_state & FP_SOFT_SUSPEND) {
 587                         port->fp_soft_state &= ~FP_SOFT_POWER_DOWN;
 588                         port->fp_pm_level = FP_PM_PORT_UP;
 589                         mutex_exit(&port->fp_mutex);
 590                         fctl_attach_ulps(port, FC_CMD_POWER_UP, &modlinkage);
 591                         break;
 592                 }
 593 
 594                 if (port->fp_soft_state & FP_SOFT_POWER_DOWN) {
 595                         ASSERT(port->fp_pm_level == FP_PM_PORT_DOWN);
 596 
 597                         port->fp_pm_level = FP_PM_PORT_UP;
 598                         rval = fp_power_up(port);
 599                         if (rval != DDI_SUCCESS) {
 600                                 port->fp_pm_level = FP_PM_PORT_DOWN;
 601                         }
 602                 } else {
 603                         port->fp_pm_level = FP_PM_PORT_UP;
 604                 }
 605                 mutex_exit(&port->fp_mutex);
 606                 break;
 607 
 608         case FP_PM_PORT_DOWN:
 609                 mutex_enter(&port->fp_mutex);
 610 
 611                 ASSERT(!(port->fp_soft_state & FP_SOFT_NO_PMCOMP));
 612                 if (port->fp_soft_state & FP_SOFT_NO_PMCOMP) {
 613                         /*
 614                          * PM framework goofed up. We have don't
 615                          * have any PM components. Let's never go down.
 616                          */
 617                         mutex_exit(&port->fp_mutex);
 618                         break;
 619 
 620                 }
 621 
 622                 if (port->fp_ulp_attach) {
 623                         /* We shouldn't let the power go down */
 624                         mutex_exit(&port->fp_mutex);
 625                         break;
 626                 }
 627 
 628                 /*
 629                  * Not a whole lot to do if we are detaching
 630                  */
 631                 if (port->fp_soft_state & FP_SOFT_IN_DETACH) {
 632                         port->fp_pm_level = FP_PM_PORT_DOWN;
 633                         mutex_exit(&port->fp_mutex);
 634                         rval = DDI_SUCCESS;
 635                         break;
 636                 }
 637 
 638                 if (!port->fp_pm_busy && !port->fp_pm_busy_nocomp) {
 639                         port->fp_pm_level = FP_PM_PORT_DOWN;
 640 
 641                         rval = fp_power_down(port);
 642                         if (rval != DDI_SUCCESS) {
 643                                 port->fp_pm_level = FP_PM_PORT_UP;
 644                                 ASSERT(!(port->fp_soft_state &
 645                                     FP_SOFT_POWER_DOWN));
 646                         } else {
 647                                 ASSERT(port->fp_soft_state &
 648                                     FP_SOFT_POWER_DOWN);
 649                         }
 650                 }
 651                 mutex_exit(&port->fp_mutex);
 652                 break;
 653 
 654         default:
 655                 break;
 656         }
 657 
 658         return (rval);
 659 }
 660 
 661 
 662 /*
 663  * Open FC port devctl node
 664  */
 665 static int
 666 fp_open(dev_t *devp, int flag, int otype, cred_t *credp)
 667 {
 668         int             instance;
 669         fc_local_port_t *port;
 670 
 671         if (otype != OTYP_CHR) {
 672                 return (EINVAL);
 673         }
 674 
 675         /*
 676          * This is not a toy to play with. Allow only powerful
 677          * users (hopefully knowledgeable) to access the port
 678          * (A hacker potentially could download a sick binary
 679          * file into FCA)
 680          */
 681         if (drv_priv(credp)) {
 682                 return (EPERM);
 683         }
 684 
 685         instance = (int)getminor(*devp);
 686 
 687         port = ddi_get_soft_state(fp_driver_softstate, instance);
 688         if (port == NULL) {
 689                 return (ENXIO);
 690         }
 691 
 692         mutex_enter(&port->fp_mutex);
 693         if (port->fp_flag & FP_EXCL) {
 694                 /*
 695                  * It is already open for exclusive access.
 696                  * So shut the door on this caller.
 697                  */
 698                 mutex_exit(&port->fp_mutex);
 699                 return (EBUSY);
 700         }
 701 
 702         if (flag & FEXCL) {
 703                 if (port->fp_flag & FP_OPEN) {
 704                         /*
 705                          * Exclusive operation not possible
 706                          * as it is already opened
 707                          */
 708                         mutex_exit(&port->fp_mutex);
 709                         return (EBUSY);
 710                 }
 711                 port->fp_flag |= FP_EXCL;
 712         }
 713         port->fp_flag |= FP_OPEN;
 714         mutex_exit(&port->fp_mutex);
 715 
 716         return (0);
 717 }
 718 
 719 
 720 /*
 721  * The driver close entry point is called on the last close()
 722  * of a device. So it is perfectly alright to just clobber the
 723  * open flag and reset it to idle (instead of having to reset
 724  * each flag bits). For any confusion, check out close(9E).
 725  */
 726 
 727 /* ARGSUSED */
 728 static int
 729 fp_close(dev_t dev, int flag, int otype, cred_t *credp)
 730 {
 731         int             instance;
 732         fc_local_port_t *port;
 733 
 734         if (otype != OTYP_CHR) {
 735                 return (EINVAL);
 736         }
 737 
 738         instance = (int)getminor(dev);
 739 
 740         port = ddi_get_soft_state(fp_driver_softstate, instance);
 741         if (port == NULL) {
 742                 return (ENXIO);
 743         }
 744 
 745         mutex_enter(&port->fp_mutex);
 746         if ((port->fp_flag & FP_OPEN) == 0) {
 747                 mutex_exit(&port->fp_mutex);
 748                 return (ENODEV);
 749         }
 750         port->fp_flag = FP_IDLE;
 751         mutex_exit(&port->fp_mutex);
 752 
 753         return (0);
 754 }
 755 
 756 /*
 757  * Handle IOCTL requests
 758  */
 759 
 760 /* ARGSUSED */
 761 static int
 762 fp_ioctl(dev_t dev, int cmd, intptr_t data, int mode, cred_t *credp, int *rval)
 763 {
 764         int             instance;
 765         int             ret = 0;
 766         fcio_t          fcio;
 767         fc_local_port_t *port;
 768 
 769         instance = (int)getminor(dev);
 770 
 771         port = ddi_get_soft_state(fp_driver_softstate, instance);
 772         if (port == NULL) {
 773                 return (ENXIO);
 774         }
 775 
 776         mutex_enter(&port->fp_mutex);
 777         if ((port->fp_flag & FP_OPEN) == 0) {
 778                 mutex_exit(&port->fp_mutex);
 779                 return (ENXIO);
 780         }
 781 
 782         if (port->fp_soft_state & FP_SOFT_SUSPEND) {
 783                 mutex_exit(&port->fp_mutex);
 784                 return (ENXIO);
 785         }
 786 
 787         mutex_exit(&port->fp_mutex);
 788 
 789         /* this will raise power if necessary */
 790         ret = fctl_busy_port(port);
 791         if (ret != 0) {
 792                 return (ret);
 793         }
 794 
 795         ASSERT(port->fp_pm_level == FP_PM_PORT_UP);
 796 
 797 
 798         switch (cmd) {
 799         case FCIO_CMD: {
 800 #ifdef  _MULTI_DATAMODEL
 801                 switch (ddi_model_convert_from(mode & FMODELS)) {
 802                 case DDI_MODEL_ILP32: {
 803                         struct fcio32 fcio32;
 804 
 805                         if (ddi_copyin((void *)data, (void *)&fcio32,
 806                             sizeof (struct fcio32), mode)) {
 807                                 ret = EFAULT;
 808                                 break;
 809                         }
 810                         fcio.fcio_xfer = fcio32.fcio_xfer;
 811                         fcio.fcio_cmd = fcio32.fcio_cmd;
 812                         fcio.fcio_flags = fcio32.fcio_flags;
 813                         fcio.fcio_cmd_flags = fcio32.fcio_cmd_flags;
 814                         fcio.fcio_ilen = (size_t)fcio32.fcio_ilen;
 815                         fcio.fcio_ibuf =
 816                             (caddr_t)(uintptr_t)fcio32.fcio_ibuf;
 817                         fcio.fcio_olen = (size_t)fcio32.fcio_olen;
 818                         fcio.fcio_obuf =
 819                             (caddr_t)(uintptr_t)fcio32.fcio_obuf;
 820                         fcio.fcio_alen = (size_t)fcio32.fcio_alen;
 821                         fcio.fcio_abuf =
 822                             (caddr_t)(uintptr_t)fcio32.fcio_abuf;
 823                         fcio.fcio_errno = fcio32.fcio_errno;
 824                         break;
 825                 }
 826 
 827                 case DDI_MODEL_NONE:
 828                         if (ddi_copyin((void *)data, (void *)&fcio,
 829                             sizeof (fcio_t), mode)) {
 830                                 ret = EFAULT;
 831                         }
 832                         break;
 833                 }
 834 #else   /* _MULTI_DATAMODEL */
 835                 if (ddi_copyin((void *)data, (void *)&fcio,
 836                     sizeof (fcio_t), mode)) {
 837                         ret = EFAULT;
 838                         break;
 839                 }
 840 #endif  /* _MULTI_DATAMODEL */
 841                 if (!ret) {
 842                         ret = fp_fciocmd(port, data, mode, &fcio);
 843                 }
 844                 break;
 845         }
 846 
 847         default:
 848                 ret = fctl_ulp_port_ioctl(port, dev, cmd, data,
 849                     mode, credp, rval);
 850         }
 851 
 852         fctl_idle_port(port);
 853 
 854         return (ret);
 855 }
 856 
 857 
 858 /*
 859  * Init Symbolic Port Name and Node Name
 860  * LV will try to get symbolic names from FCA driver
 861  * and register these to name server,
 862  * if LV fails to get these,
 863  * LV will register its default symbolic names to name server.
 864  * The Default symbolic node name format is :
 865  *      <hostname>:<hba driver name>(instance)
 866  * The Default symbolic port name format is :
 867  *      <fp path name>
 868  */
 869 static void
 870 fp_init_symbolic_names(fc_local_port_t *port)
 871 {
 872         const char *vendorname = ddi_driver_name(port->fp_fca_dip);
 873         char *sym_name;
 874         char fcaname[50] = {0};
 875         int hostnlen, fcanlen;
 876 
 877         if (port->fp_sym_node_namelen == 0) {
 878                 hostnlen = strlen(utsname.nodename);
 879                 (void) snprintf(fcaname, sizeof (fcaname),
 880                     "%s%d", vendorname, ddi_get_instance(port->fp_fca_dip));
 881                 fcanlen = strlen(fcaname);
 882 
 883                 sym_name = kmem_zalloc(hostnlen + fcanlen + 2, KM_SLEEP);
 884                 (void) sprintf(sym_name, "%s:%s", utsname.nodename, fcaname);
 885                 port->fp_sym_node_namelen = strlen(sym_name);
 886                 if (port->fp_sym_node_namelen >= FCHBA_SYMB_NAME_LEN) {
 887                         port->fp_sym_node_namelen = FCHBA_SYMB_NAME_LEN;
 888                 }
 889                 (void) strncpy(port->fp_sym_node_name, sym_name,
 890                     port->fp_sym_node_namelen);
 891                 kmem_free(sym_name, hostnlen + fcanlen + 2);
 892         }
 893 
 894         if (port->fp_sym_port_namelen == 0) {
 895                 char *pathname = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
 896 
 897                 (void) ddi_pathname(port->fp_port_dip, pathname);
 898                 port->fp_sym_port_namelen = strlen(pathname);
 899                 if (port->fp_sym_port_namelen >= FCHBA_SYMB_NAME_LEN) {
 900                         port->fp_sym_port_namelen = FCHBA_SYMB_NAME_LEN;
 901                 }
 902                 (void) strncpy(port->fp_sym_port_name, pathname,
 903                     port->fp_sym_port_namelen);
 904                 kmem_free(pathname, MAXPATHLEN);
 905         }
 906 }
 907 
 908 
 909 /*
 910  * Perform port attach
 911  */
 912 static int
 913 fp_attach_handler(dev_info_t *dip)
 914 {
 915         int                     rval;
 916         int                     instance;
 917         int                     port_num;
 918         int                     port_len;
 919         char                    name[30];
 920         char                    i_pwwn[17];
 921         fp_cmd_t                *pkt;
 922         uint32_t                ub_count;
 923         fc_local_port_t         *port;
 924         job_request_t           *job;
 925         fc_local_port_t *phyport = NULL;
 926         int portpro1;
 927         char pwwn[17], nwwn[17];
 928 
 929         instance = ddi_get_instance(dip);
 930         port_len = sizeof (port_num);
 931         rval = ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF,
 932             DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "port",
 933             (caddr_t)&port_num, &port_len);
 934         if (rval != DDI_SUCCESS) {
 935                 cmn_err(CE_WARN, "fp(%d): No port property in devinfo",
 936                     instance);
 937                 return (DDI_FAILURE);
 938         }
 939 
 940         if (ddi_create_minor_node(dip, "devctl", S_IFCHR, instance,
 941             DDI_NT_NEXUS, 0) != DDI_SUCCESS) {
 942                 cmn_err(CE_WARN, "fp(%d): failed to create devctl minor node",
 943                     instance);
 944                 return (DDI_FAILURE);
 945         }
 946 
 947         if (ddi_create_minor_node(dip, "fc", S_IFCHR, instance,
 948             DDI_NT_FC_ATTACHMENT_POINT, 0) != DDI_SUCCESS) {
 949                 cmn_err(CE_WARN, "fp(%d): failed to create fc attachment"
 950                     " point minor node", instance);
 951                 ddi_remove_minor_node(dip, NULL);
 952                 return (DDI_FAILURE);
 953         }
 954 
 955         if (ddi_soft_state_zalloc(fp_driver_softstate, instance)
 956             != DDI_SUCCESS) {
 957                 cmn_err(CE_WARN, "fp(%d): failed to alloc soft state",
 958                     instance);
 959                 ddi_remove_minor_node(dip, NULL);
 960                 return (DDI_FAILURE);
 961         }
 962         port = ddi_get_soft_state(fp_driver_softstate, instance);
 963 
 964         (void) sprintf(port->fp_ibuf, "fp(%d)", instance);
 965 
 966         port->fp_instance = instance;
 967         port->fp_ulp_attach = 1;
 968         port->fp_port_num = port_num;
 969         port->fp_verbose = fp_verbosity;
 970         port->fp_options = fp_options;
 971 
 972         port->fp_fca_dip = ddi_get_parent(dip);
 973         port->fp_port_dip = dip;
 974         port->fp_fca_tran = (fc_fca_tran_t *)
 975             ddi_get_driver_private(port->fp_fca_dip);
 976 
 977         port->fp_task = port->fp_last_task = FP_TASK_IDLE;
 978 
 979         /*
 980          * Init the starting value of fp_rscn_count. Note that if
 981          * FC_INVALID_RSCN_COUNT is 0 (which is what it currently is), the
 982          * actual # of RSCNs will be (fp_rscn_count - 1)
 983          */
 984         port->fp_rscn_count = FC_INVALID_RSCN_COUNT + 1;
 985 
 986         mutex_init(&port->fp_mutex, NULL, MUTEX_DRIVER, NULL);
 987         cv_init(&port->fp_cv, NULL, CV_DRIVER, NULL);
 988         cv_init(&port->fp_attach_cv, NULL, CV_DRIVER, NULL);
 989 
 990         (void) sprintf(name, "fp%d_cache", instance);
 991 
 992         if ((portpro1 = ddi_prop_get_int(DDI_DEV_T_ANY,
 993             dip, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
 994             "phyport-instance", -1)) != -1) {
 995                 phyport = ddi_get_soft_state(fp_driver_softstate, portpro1);
 996                 fc_wwn_to_str(&phyport->fp_service_params.nport_ww_name, pwwn);
 997                 fc_wwn_to_str(&phyport->fp_service_params.node_ww_name, nwwn);
 998                 port->fp_npiv_type = FC_NPIV_PORT;
 999         }
1000 
1001         /*
1002          * Allocate the pool of fc_packet_t structs to be used with
1003          * this fp instance.
1004          */
1005         port->fp_pkt_cache = kmem_cache_create(name,
1006             (port->fp_fca_tran->fca_pkt_size) + sizeof (fp_cmd_t), 8,
1007             fp_cache_constructor, fp_cache_destructor, NULL, (void *)port,
1008             NULL, 0);
1009         port->fp_out_fpcmds = 0;
1010         if (port->fp_pkt_cache == NULL) {
1011                 goto cache_alloc_failed;
1012         }
1013 
1014 
1015         /*
1016          * Allocate the d_id and pwwn hash tables for all remote ports
1017          * connected to this local port.
1018          */
1019         port->fp_did_table = kmem_zalloc(did_table_size *
1020             sizeof (struct d_id_hash), KM_SLEEP);
1021 
1022         port->fp_pwwn_table = kmem_zalloc(pwwn_table_size *
1023             sizeof (struct pwwn_hash), KM_SLEEP);
1024 
1025         port->fp_taskq = taskq_create("fp_ulp_callback", 1,
1026             MINCLSYSPRI, 1, 16, 0);
1027 
1028         /* Indicate that don't have the pm components yet */
1029         port->fp_soft_state |=       FP_SOFT_NO_PMCOMP;
1030 
1031         /*
1032          * Bind the callbacks with the FCA driver. This will open the gate
1033          * for asynchronous callbacks, so after this call the fp_mutex
1034          * must be held when updating the fc_local_port_t struct.
1035          *
1036          * This is done _before_ setting up the job thread so we can avoid
1037          * cleaning up after the thread_create() in the error path. This
1038          * also means fp will be operating with fp_els_resp_pkt set to NULL.
1039          */
1040         if (fp_bind_callbacks(port) != DDI_SUCCESS) {
1041                 goto bind_callbacks_failed;
1042         }
1043 
1044         if (phyport) {
1045                 mutex_enter(&phyport->fp_mutex);
1046                 if (phyport->fp_port_next) {
1047                         phyport->fp_port_next->fp_port_prev = port;
1048                         port->fp_port_next =  phyport->fp_port_next;
1049                         phyport->fp_port_next = port;
1050                         port->fp_port_prev = phyport;
1051                 } else {
1052                         phyport->fp_port_next = port;
1053                         phyport->fp_port_prev = port;
1054                         port->fp_port_next =  phyport;
1055                         port->fp_port_prev = phyport;
1056                 }
1057                 mutex_exit(&phyport->fp_mutex);
1058         }
1059 
1060         /*
1061          * Init Symbolic Names
1062          */
1063         fp_init_symbolic_names(port);
1064 
1065         pkt = fp_alloc_pkt(port, sizeof (la_els_logi_t), sizeof (la_els_logi_t),
1066             KM_SLEEP, NULL);
1067 
1068         if (pkt == NULL) {
1069                 cmn_err(CE_WARN, "fp(%d): failed to allocate ELS packet",
1070                     instance);
1071                 goto alloc_els_packet_failed;
1072         }
1073 
1074         (void) thread_create(NULL, 0, fp_job_handler, port, 0, &p0, TS_RUN,
1075             v.v_maxsyspri - 2);
1076 
1077         fc_wwn_to_str(&port->fp_service_params.nport_ww_name, i_pwwn);
1078         if (ddi_prop_update_string(DDI_DEV_T_NONE, dip, "initiator-port",
1079             i_pwwn) != DDI_PROP_SUCCESS) {
1080                 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
1081                     "fp(%d): Updating 'initiator-port' property"
1082                     " on fp dev_info node failed", instance);
1083         }
1084 
1085         fc_wwn_to_str(&port->fp_service_params.node_ww_name, i_pwwn);
1086         if (ddi_prop_update_string(DDI_DEV_T_NONE, dip, "initiator-node",
1087             i_pwwn) != DDI_PROP_SUCCESS) {
1088                 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
1089                     "fp(%d): Updating 'initiator-node' property"
1090                     " on fp dev_info node failed", instance);
1091         }
1092 
1093         mutex_enter(&port->fp_mutex);
1094         port->fp_els_resp_pkt = pkt;
1095         mutex_exit(&port->fp_mutex);
1096 
1097         /*
1098          * Determine the count of unsolicited buffers this FCA can support
1099          */
1100         fp_retrieve_caps(port);
1101 
1102         /*
1103          * Allocate unsolicited buffer tokens
1104          */
1105         if (port->fp_ub_count) {
1106                 ub_count = port->fp_ub_count;
1107                 port->fp_ub_tokens = kmem_zalloc(ub_count *
1108                     sizeof (*port->fp_ub_tokens), KM_SLEEP);
1109                 /*
1110                  * Do not fail the attach if unsolicited buffer allocation
1111                  * fails; Just try to get along with whatever the FCA can do.
1112                  */
1113                 if (fc_ulp_uballoc(port, &ub_count, fp_unsol_buf_size,
1114                     FC_TYPE_EXTENDED_LS, port->fp_ub_tokens) !=
1115                     FC_SUCCESS || ub_count != port->fp_ub_count) {
1116                         cmn_err(CE_WARN, "fp(%d): failed to allocate "
1117                             " Unsolicited buffers. proceeding with attach...",
1118                             instance);
1119                         kmem_free(port->fp_ub_tokens,
1120                             sizeof (*port->fp_ub_tokens) * port->fp_ub_count);
1121                         port->fp_ub_tokens = NULL;
1122                 }
1123         }
1124 
1125         fp_load_ulp_modules(dip, port);
1126 
1127         /*
1128          * Enable DDI_SUSPEND and DDI_RESUME for this instance.
1129          */
1130         (void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
1131             "pm-hardware-state", "needs-suspend-resume",
1132             strlen("needs-suspend-resume") + 1);
1133 
1134         /*
1135          * fctl maintains a list of all port handles, so
1136          * help fctl add this one to its list now.
1137          */
1138         mutex_enter(&port->fp_mutex);
1139         fctl_add_port(port);
1140 
1141         /*
1142          * If a state change is already in progress, set the bind state t
1143          * OFFLINE as well, so further state change callbacks into ULPs
1144          * will pass the appropriate states
1145          */
1146         if (FC_PORT_STATE_MASK(port->fp_bind_state) == FC_STATE_OFFLINE ||
1147             port->fp_statec_busy) {
1148                 port->fp_bind_state = FC_STATE_OFFLINE;
1149                 mutex_exit(&port->fp_mutex);
1150 
1151                 fp_startup_done((opaque_t)port, FC_PKT_SUCCESS);
1152         } else {
1153                 /*
1154                  * Without dropping the mutex, ensure that the port
1155                  * startup happens ahead of state change callback
1156                  * processing
1157                  */
1158                 ASSERT(port->fp_job_tail == NULL && port->fp_job_head == NULL);
1159 
1160                 port->fp_last_task = port->fp_task;
1161                 port->fp_task = FP_TASK_PORT_STARTUP;
1162 
1163                 job = fctl_alloc_job(JOB_PORT_STARTUP, JOB_TYPE_FCTL_ASYNC,
1164                     fp_startup_done, (opaque_t)port, KM_SLEEP);
1165 
1166                 port->fp_job_head = port->fp_job_tail = job;
1167 
1168                 cv_signal(&port->fp_cv);
1169 
1170                 mutex_exit(&port->fp_mutex);
1171         }
1172 
1173         mutex_enter(&port->fp_mutex);
1174         while (port->fp_ulp_attach) {
1175                 cv_wait(&port->fp_attach_cv, &port->fp_mutex);
1176         }
1177         mutex_exit(&port->fp_mutex);
1178 
1179         if (ddi_prop_update_string_array(DDI_DEV_T_NONE, dip,
1180             "pm-components", fp_pm_comps,
1181             sizeof (fp_pm_comps) / sizeof (fp_pm_comps[0])) !=
1182             DDI_PROP_SUCCESS) {
1183                 FP_TRACE(FP_NHEAD2(9, 0), "Failed to create PM"
1184                     " components property, PM disabled on this port.");
1185                 mutex_enter(&port->fp_mutex);
1186                 port->fp_pm_level = FP_PM_PORT_UP;
1187                 mutex_exit(&port->fp_mutex);
1188         } else {
1189                 if (pm_raise_power(dip, FP_PM_COMPONENT,
1190                     FP_PM_PORT_UP) != DDI_SUCCESS) {
1191                         FP_TRACE(FP_NHEAD2(9, 0), "Failed to raise"
1192                             " power level");
1193                         mutex_enter(&port->fp_mutex);
1194                         port->fp_pm_level = FP_PM_PORT_UP;
1195                         mutex_exit(&port->fp_mutex);
1196                 }
1197 
1198                 /*
1199                  * Don't unset the FP_SOFT_NO_PMCOMP flag until after
1200                  * the call to pm_raise_power.  The PM framework can't
1201                  * handle multiple threads calling into it during attach.
1202                  */
1203 
1204                 mutex_enter(&port->fp_mutex);
1205                 port->fp_soft_state &=   ~FP_SOFT_NO_PMCOMP;
1206                 mutex_exit(&port->fp_mutex);
1207         }
1208 
1209         ddi_report_dev(dip);
1210 
1211         fp_log_port_event(port, ESC_SUNFC_PORT_ATTACH);
1212 
1213         return (DDI_SUCCESS);
1214 
1215         /*
1216          * Unwind any/all preceeding allocations in the event of an error.
1217          */
1218 
1219 alloc_els_packet_failed:
1220 
1221         if (port->fp_fca_handle != NULL) {
1222                 port->fp_fca_tran->fca_unbind_port(port->fp_fca_handle);
1223                 port->fp_fca_handle = NULL;
1224         }
1225 
1226         if (port->fp_ub_tokens != NULL) {
1227                 (void) fc_ulp_ubfree(port, port->fp_ub_count,
1228                     port->fp_ub_tokens);
1229                 kmem_free(port->fp_ub_tokens,
1230                     port->fp_ub_count * sizeof (*port->fp_ub_tokens));
1231                 port->fp_ub_tokens = NULL;
1232         }
1233 
1234         if (port->fp_els_resp_pkt != NULL) {
1235                 fp_free_pkt(port->fp_els_resp_pkt);
1236                 port->fp_els_resp_pkt = NULL;
1237         }
1238 
1239 bind_callbacks_failed:
1240 
1241         if (port->fp_taskq != NULL) {
1242                 taskq_destroy(port->fp_taskq);
1243         }
1244 
1245         if (port->fp_pwwn_table != NULL) {
1246                 kmem_free(port->fp_pwwn_table,
1247                     pwwn_table_size * sizeof (struct pwwn_hash));
1248                 port->fp_pwwn_table = NULL;
1249         }
1250 
1251         if (port->fp_did_table != NULL) {
1252                 kmem_free(port->fp_did_table,
1253                     did_table_size * sizeof (struct d_id_hash));
1254                 port->fp_did_table = NULL;
1255         }
1256 
1257         if (port->fp_pkt_cache != NULL) {
1258                 kmem_cache_destroy(port->fp_pkt_cache);
1259                 port->fp_pkt_cache = NULL;
1260         }
1261 
1262 cache_alloc_failed:
1263 
1264         cv_destroy(&port->fp_attach_cv);
1265         cv_destroy(&port->fp_cv);
1266         mutex_destroy(&port->fp_mutex);
1267         ddi_remove_minor_node(port->fp_port_dip, NULL);
1268         ddi_soft_state_free(fp_driver_softstate, instance);
1269         ddi_prop_remove_all(dip);
1270 
1271         return (DDI_FAILURE);
1272 }
1273 
1274 
1275 /*
1276  * Handle DDI_RESUME request
1277  */
1278 static int
1279 fp_resume_handler(dev_info_t *dip)
1280 {
1281         int             rval;
1282         fc_local_port_t *port;
1283 
1284         port = ddi_get_soft_state(fp_driver_softstate, ddi_get_instance(dip));
1285 
1286         ASSERT(port != NULL);
1287 
1288 #ifdef  DEBUG
1289         mutex_enter(&port->fp_mutex);
1290         ASSERT(port->fp_soft_state & FP_SOFT_SUSPEND);
1291         mutex_exit(&port->fp_mutex);
1292 #endif
1293 
1294         /*
1295          * If the port was power suspended, raise the power level
1296          */
1297         mutex_enter(&port->fp_mutex);
1298         if ((port->fp_soft_state & FP_SOFT_POWER_DOWN) &&
1299             (!(port->fp_soft_state & FP_SOFT_NO_PMCOMP))) {
1300                 ASSERT(port->fp_pm_level == FP_PM_PORT_DOWN);
1301 
1302                 mutex_exit(&port->fp_mutex);
1303                 if (pm_raise_power(dip, FP_PM_COMPONENT,
1304                     FP_PM_PORT_UP) != DDI_SUCCESS) {
1305                         FP_TRACE(FP_NHEAD2(9, 0),
1306                             "Failed to raise the power level");
1307                         return (DDI_FAILURE);
1308                 }
1309                 mutex_enter(&port->fp_mutex);
1310         }
1311         port->fp_soft_state &= ~FP_SOFT_SUSPEND;
1312         mutex_exit(&port->fp_mutex);
1313 
1314         /*
1315          * All the discovery is initiated and handled by per-port thread.
1316          * Further all the discovery is done in handled in callback mode
1317          * (not polled mode); In a specific case such as this, the discovery
1318          * is required to happen in polled mode. The easiest way out is
1319          * to bail out port thread and get started. Come back and fix this
1320          * to do on demand discovery initiated by ULPs. ULPs such as FCP
1321          * will do on-demand discovery during pre-power-up busctl handling
1322          * which will only be possible when SCSA provides a new HBA vector
1323          * for sending down the PM busctl requests.
1324          */
1325         (void) callb_generic_cpr(&port->fp_cpr_info, CB_CODE_CPR_RESUME);
1326 
1327         rval = fp_resume_all(port, FC_CMD_RESUME);
1328         if (rval != DDI_SUCCESS) {
1329                 mutex_enter(&port->fp_mutex);
1330                 port->fp_soft_state |= FP_SOFT_SUSPEND;
1331                 mutex_exit(&port->fp_mutex);
1332                 (void) callb_generic_cpr(&port->fp_cpr_info,
1333                     CB_CODE_CPR_CHKPT);
1334         }
1335 
1336         return (rval);
1337 }
1338 
1339 /*
1340  * Perform FC Port power on initialization
1341  */
1342 static int
1343 fp_power_up(fc_local_port_t *port)
1344 {
1345         int     rval;
1346 
1347         ASSERT(MUTEX_HELD(&port->fp_mutex));
1348 
1349         ASSERT((port->fp_soft_state & FP_SOFT_SUSPEND) == 0);
1350         ASSERT(port->fp_soft_state & FP_SOFT_POWER_DOWN);
1351 
1352         port->fp_soft_state &= ~FP_SOFT_POWER_DOWN;
1353 
1354         mutex_exit(&port->fp_mutex);
1355 
1356         rval = fp_resume_all(port, FC_CMD_POWER_UP);
1357         if (rval != DDI_SUCCESS) {
1358                 mutex_enter(&port->fp_mutex);
1359                 port->fp_soft_state |= FP_SOFT_POWER_DOWN;
1360         } else {
1361                 mutex_enter(&port->fp_mutex);
1362         }
1363 
1364         return (rval);
1365 }
1366 
1367 
1368 /*
1369  * It is important to note that the power may possibly be removed between
1370  * SUSPEND and the ensuing RESUME operation. In such a context the underlying
1371  * FC port hardware would have gone through an OFFLINE to ONLINE transition
1372  * (hardware state). In this case, the port driver may need to rediscover the
1373  * topology, perform LOGINs, register with the name server again and perform
1374  * any such port initialization procedures. To perform LOGINs, the driver could
1375  * use the port device handle to see if a LOGIN needs to be performed and use
1376  * the D_ID and WWN in it. The LOGINs may fail (if the hardware is reconfigured
1377  * or removed) which will be reflected in the map the ULPs will see.
1378  */
1379 static int
1380 fp_resume_all(fc_local_port_t *port, fc_attach_cmd_t cmd)
1381 {
1382 
1383         ASSERT(!MUTEX_HELD(&port->fp_mutex));
1384 
1385         if (fp_bind_callbacks(port) != DDI_SUCCESS) {
1386                 return (DDI_FAILURE);
1387         }
1388 
1389         mutex_enter(&port->fp_mutex);
1390 
1391         /*
1392          * If there are commands queued for delayed retry, instead of
1393          * working the hard way to figure out which ones are good for
1394          * restart and which ones not (ELSs are definitely not good
1395          * as the port will have to go through a new spin of rediscovery
1396          * now), so just flush them out.
1397          */
1398         if (port->fp_restore & FP_RESTORE_WAIT_TIMEOUT) {
1399                 fp_cmd_t        *cmd;
1400 
1401                 port->fp_restore &= ~FP_RESTORE_WAIT_TIMEOUT;
1402 
1403                 mutex_exit(&port->fp_mutex);
1404                 while ((cmd = fp_deque_cmd(port)) != NULL) {
1405                         cmd->cmd_pkt.pkt_state = FC_PKT_TRAN_ERROR;
1406                         fp_iodone(cmd);
1407                 }
1408                 mutex_enter(&port->fp_mutex);
1409         }
1410 
1411         if (FC_PORT_STATE_MASK(port->fp_bind_state) == FC_STATE_OFFLINE) {
1412                 if ((port->fp_restore & FP_RESTORE_OFFLINE_TIMEOUT) ||
1413                     port->fp_dev_count) {
1414                         port->fp_restore &= ~FP_RESTORE_OFFLINE_TIMEOUT;
1415                         port->fp_offline_tid = timeout(fp_offline_timeout,
1416                             (caddr_t)port, fp_offline_ticks);
1417                 }
1418                 if (port->fp_job_head) {
1419                         cv_signal(&port->fp_cv);
1420                 }
1421                 mutex_exit(&port->fp_mutex);
1422                 fctl_attach_ulps(port, cmd, &modlinkage);
1423         } else {
1424                 struct job_request *job;
1425 
1426                 /*
1427                  * If an OFFLINE timer was running at the time of
1428                  * suspending, there is no need to restart it as
1429                  * the port is ONLINE now.
1430                  */
1431                 port->fp_restore &= ~FP_RESTORE_OFFLINE_TIMEOUT;
1432                 if (port->fp_statec_busy == 0) {
1433                         port->fp_soft_state |= FP_SOFT_IN_STATEC_CB;
1434                 }
1435                 port->fp_statec_busy++;
1436                 mutex_exit(&port->fp_mutex);
1437 
1438                 job = fctl_alloc_job(JOB_PORT_ONLINE,
1439                     JOB_CANCEL_ULP_NOTIFICATION, NULL, NULL, KM_SLEEP);
1440                 fctl_enque_job(port, job);
1441 
1442                 fctl_jobwait(job);
1443                 fctl_remove_oldies(port);
1444 
1445                 fctl_attach_ulps(port, cmd, &modlinkage);
1446                 fctl_dealloc_job(job);
1447         }
1448 
1449         return (DDI_SUCCESS);
1450 }
1451 
1452 
1453 /*
1454  * At this time, there shouldn't be any I/O requests on this port.
1455  * But the unsolicited callbacks from the underlying FCA port need
1456  * to be handled very carefully. The steps followed to handle the
1457  * DDI_DETACH are:
1458  *      +       Grab the port driver mutex, check if the unsolicited
1459  *              callback is currently under processing. If true, fail
1460  *              the DDI_DETACH request by printing a message; If false
1461  *              mark the DDI_DETACH as under progress, so that any
1462  *              further unsolicited callbacks get bounced.
1463  *      +       Perform PRLO/LOGO if necessary, cleanup all the data
1464  *              structures.
1465  *      +       Get the job_handler thread to gracefully exit.
1466  *      +       Unregister callbacks with the FCA port.
1467  *      +       Now that some peace is found, notify all the ULPs of
1468  *              DDI_DETACH request (using ulp_port_detach entry point)
1469  *      +       Free all mutexes, semaphores, conditional variables.
1470  *      +       Free the soft state, return success.
1471  *
1472  * Important considerations:
1473  *              Port driver de-registers state change and unsolicited
1474  *              callbacks before taking up the task of notifying ULPs
1475  *              and performing PRLO and LOGOs.
1476  *
1477  *              A port may go offline at the time PRLO/LOGO is being
1478  *              requested. It is expected of all FCA drivers to fail
1479  *              such requests either immediately with a FC_OFFLINE
1480  *              return code to fc_fca_transport() or return the packet
1481  *              asynchronously with pkt state set to FC_PKT_PORT_OFFLINE
1482  */
1483 static int
1484 fp_detach_handler(fc_local_port_t *port)
1485 {
1486         job_request_t   *job;
1487         uint32_t        delay_count;
1488         fc_orphan_t     *orp, *tmporp;
1489 
1490         /*
1491          * In a Fabric topology with many host ports connected to
1492          * a switch, another detaching instance of fp might have
1493          * triggered a LOGO (which is an unsolicited request to
1494          * this instance). So in order to be able to successfully
1495          * detach by taking care of such cases a delay of about
1496          * 30 seconds is introduced.
1497          */
1498         delay_count = 0;
1499         mutex_enter(&port->fp_mutex);
1500         if (port->fp_out_fpcmds != 0) {
1501                 /*
1502                  * At this time we can only check fp internal commands, because
1503                  * sd/ssd/scsi_vhci should have finsihed all their commands,
1504                  * fcp/fcip/fcsm should have finished all their commands.
1505                  *
1506                  * It seems that all fp internal commands are asynchronous now.
1507                  */
1508                 port->fp_soft_state &= ~FP_DETACH_INPROGRESS;
1509                 mutex_exit(&port->fp_mutex);
1510 
1511                 cmn_err(CE_WARN, "fp(%d): %d fp_cmd(s) is/are in progress"
1512                     " Failing detach", port->fp_instance, port->fp_out_fpcmds);
1513                 return (DDI_FAILURE);
1514         }
1515 
1516         while ((port->fp_soft_state &
1517             (FP_SOFT_IN_STATEC_CB | FP_SOFT_IN_UNSOL_CB)) &&
1518             (delay_count < 30)) {
1519                 mutex_exit(&port->fp_mutex);
1520                 delay_count++;
1521                 delay(drv_sectohz(1));
1522                 mutex_enter(&port->fp_mutex);
1523         }
1524 
1525         if (port->fp_soft_state &
1526             (FP_SOFT_IN_STATEC_CB | FP_SOFT_IN_UNSOL_CB)) {
1527                 port->fp_soft_state &= ~FP_DETACH_INPROGRESS;
1528                 mutex_exit(&port->fp_mutex);
1529 
1530                 cmn_err(CE_WARN, "fp(%d): FCA callback in progress: "
1531                     " Failing detach", port->fp_instance);
1532                 return (DDI_FAILURE);
1533         }
1534 
1535         port->fp_soft_state |= FP_SOFT_IN_DETACH;
1536         port->fp_soft_state &= ~FP_DETACH_INPROGRESS;
1537         mutex_exit(&port->fp_mutex);
1538 
1539         /*
1540          * If we're powered down, we need to raise power prior to submitting
1541          * the JOB_PORT_SHUTDOWN job.  Otherwise, the job handler will never
1542          * process the shutdown job.
1543          */
1544         if (fctl_busy_port(port) != 0) {
1545                 cmn_err(CE_WARN, "fp(%d): fctl_busy_port failed",
1546                     port->fp_instance);
1547                 mutex_enter(&port->fp_mutex);
1548                 port->fp_soft_state &= ~FP_SOFT_IN_DETACH;
1549                 mutex_exit(&port->fp_mutex);
1550                 return (DDI_FAILURE);
1551         }
1552 
1553         /*
1554          * This will deallocate data structs and cause the "job" thread
1555          * to exit, in preparation for DDI_DETACH on the instance.
1556          * This can sleep for an arbitrary duration, since it waits for
1557          * commands over the wire, timeout(9F) callbacks, etc.
1558          *
1559          * CAUTION: There is still a race here, where the "job" thread
1560          * can still be executing code even tho the fctl_jobwait() call
1561          * below has returned to us.  In theory the fp driver could even be
1562          * modunloaded even tho the job thread isn't done executing.
1563          * without creating the race condition.
1564          */
1565         job = fctl_alloc_job(JOB_PORT_SHUTDOWN, 0, NULL,
1566             (opaque_t)port, KM_SLEEP);
1567         fctl_enque_job(port, job);
1568         fctl_jobwait(job);
1569         fctl_dealloc_job(job);
1570 
1571 
1572         (void) pm_lower_power(port->fp_port_dip, FP_PM_COMPONENT,
1573             FP_PM_PORT_DOWN);
1574 
1575         if (port->fp_taskq) {
1576                 taskq_destroy(port->fp_taskq);
1577         }
1578 
1579         ddi_prop_remove_all(port->fp_port_dip);
1580 
1581         ddi_remove_minor_node(port->fp_port_dip, NULL);
1582 
1583         fctl_remove_port(port);
1584 
1585         fp_free_pkt(port->fp_els_resp_pkt);
1586 
1587         if (port->fp_ub_tokens) {
1588                 if (fc_ulp_ubfree(port, port->fp_ub_count,
1589                     port->fp_ub_tokens) != FC_SUCCESS) {
1590                         cmn_err(CE_WARN, "fp(%d): couldn't free "
1591                             " unsolicited buffers", port->fp_instance);
1592                 }
1593                 kmem_free(port->fp_ub_tokens,
1594                     sizeof (*port->fp_ub_tokens) * port->fp_ub_count);
1595                 port->fp_ub_tokens = NULL;
1596         }
1597 
1598         if (port->fp_pkt_cache != NULL) {
1599                 kmem_cache_destroy(port->fp_pkt_cache);
1600         }
1601 
1602         port->fp_fca_tran->fca_unbind_port(port->fp_fca_handle);
1603 
1604         mutex_enter(&port->fp_mutex);
1605         if (port->fp_did_table) {
1606                 kmem_free(port->fp_did_table, did_table_size *
1607                     sizeof (struct d_id_hash));
1608         }
1609 
1610         if (port->fp_pwwn_table) {
1611                 kmem_free(port->fp_pwwn_table, pwwn_table_size *
1612                     sizeof (struct pwwn_hash));
1613         }
1614         orp = port->fp_orphan_list;
1615         while (orp) {
1616                 tmporp = orp;
1617                 orp = orp->orp_next;
1618                 kmem_free(tmporp, sizeof (*orp));
1619         }
1620 
1621         mutex_exit(&port->fp_mutex);
1622 
1623         fp_log_port_event(port, ESC_SUNFC_PORT_DETACH);
1624 
1625         mutex_destroy(&port->fp_mutex);
1626         cv_destroy(&port->fp_attach_cv);
1627         cv_destroy(&port->fp_cv);
1628         ddi_soft_state_free(fp_driver_softstate, port->fp_instance);
1629 
1630         return (DDI_SUCCESS);
1631 }
1632 
1633 
1634 /*
1635  * Steps to perform DDI_SUSPEND operation on a FC port
1636  *
1637  *      - If already suspended return DDI_FAILURE
1638  *      - If already power-suspended return DDI_SUCCESS
1639  *      - If an unsolicited callback or state change handling is in
1640  *          in progress, throw a warning message, return DDI_FAILURE
1641  *      - Cancel timeouts
1642  *      - SUSPEND the job_handler thread (means do nothing as it is
1643  *          taken care of by the CPR frame work)
1644  */
1645 static int
1646 fp_suspend_handler(fc_local_port_t *port)
1647 {
1648         uint32_t        delay_count;
1649 
1650         mutex_enter(&port->fp_mutex);
1651 
1652         /*
1653          * The following should never happen, but
1654          * let the driver be more defensive here
1655          */
1656         if (port->fp_soft_state & FP_SOFT_SUSPEND) {
1657                 mutex_exit(&port->fp_mutex);
1658                 return (DDI_FAILURE);
1659         }
1660 
1661         /*
1662          * If the port is already power suspended, there
1663          * is nothing else to do, So return DDI_SUCCESS,
1664          * but mark the SUSPEND bit in the soft state
1665          * before leaving.
1666          */
1667         if (port->fp_soft_state & FP_SOFT_POWER_DOWN) {
1668                 port->fp_soft_state |= FP_SOFT_SUSPEND;
1669                 mutex_exit(&port->fp_mutex);
1670                 return (DDI_SUCCESS);
1671         }
1672 
1673         /*
1674          * Check if an unsolicited callback or state change handling is
1675          * in progress. If true, fail the suspend operation; also throw
1676          * a warning message notifying the failure. Note that Sun PCI
1677          * hotplug spec recommends messages in cases of failure (but
1678          * not flooding the console)
1679          *
1680          * Busy waiting for a short interval (500 millisecond ?) to see
1681          * if the callback processing completes may be another idea. Since
1682          * most of the callback processing involves a lot of work, it
1683          * is safe to just fail the SUSPEND operation. It is definitely
1684          * not bad to fail the SUSPEND operation if the driver is busy.
1685          */
1686         delay_count = 0;
1687         while ((port->fp_soft_state & (FP_SOFT_IN_STATEC_CB |
1688             FP_SOFT_IN_UNSOL_CB)) && (delay_count < 30)) {
1689                 mutex_exit(&port->fp_mutex);
1690                 delay_count++;
1691                 delay(drv_sectohz(1));
1692                 mutex_enter(&port->fp_mutex);
1693         }
1694 
1695         if (port->fp_soft_state & (FP_SOFT_IN_STATEC_CB |
1696             FP_SOFT_IN_UNSOL_CB)) {
1697                 mutex_exit(&port->fp_mutex);
1698                 cmn_err(CE_WARN, "fp(%d): FCA callback in progress: "
1699                     " Failing suspend", port->fp_instance);
1700                 return (DDI_FAILURE);
1701         }
1702 
1703         /*
1704          * Check of FC port thread is busy
1705          */
1706         if (port->fp_job_head) {
1707                 mutex_exit(&port->fp_mutex);
1708                 FP_TRACE(FP_NHEAD2(9, 0),
1709                     "FC port thread is busy: Failing suspend");
1710                 return (DDI_FAILURE);
1711         }
1712         port->fp_soft_state |= FP_SOFT_SUSPEND;
1713 
1714         fp_suspend_all(port);
1715         mutex_exit(&port->fp_mutex);
1716 
1717         return (DDI_SUCCESS);
1718 }
1719 
1720 
1721 /*
1722  * Prepare for graceful power down of a FC port
1723  */
1724 static int
1725 fp_power_down(fc_local_port_t *port)
1726 {
1727         ASSERT(MUTEX_HELD(&port->fp_mutex));
1728 
1729         /*
1730          * Power down request followed by a DDI_SUSPEND should
1731          * never happen; If it does return DDI_SUCCESS
1732          */
1733         if (port->fp_soft_state & FP_SOFT_SUSPEND) {
1734                 port->fp_soft_state |= FP_SOFT_POWER_DOWN;
1735                 return (DDI_SUCCESS);
1736         }
1737 
1738         /*
1739          * If the port is already power suspended, there
1740          * is nothing else to do, So return DDI_SUCCESS,
1741          */
1742         if (port->fp_soft_state & FP_SOFT_POWER_DOWN) {
1743                 return (DDI_SUCCESS);
1744         }
1745 
1746         /*
1747          * Check if an unsolicited callback or state change handling
1748          * is in progress. If true, fail the PM suspend operation.
1749          * But don't print a message unless the verbosity of the
1750          * driver desires otherwise.
1751          */
1752         if ((port->fp_soft_state & FP_SOFT_IN_STATEC_CB) ||
1753             (port->fp_soft_state & FP_SOFT_IN_UNSOL_CB)) {
1754                 FP_TRACE(FP_NHEAD2(9, 0),
1755                     "Unsolicited callback in progress: Failing power down");
1756                 return (DDI_FAILURE);
1757         }
1758 
1759         /*
1760          * Check of FC port thread is busy
1761          */
1762         if (port->fp_job_head) {
1763                 FP_TRACE(FP_NHEAD2(9, 0),
1764                     "FC port thread is busy: Failing power down");
1765                 return (DDI_FAILURE);
1766         }
1767         port->fp_soft_state |= FP_SOFT_POWER_DOWN;
1768 
1769         /*
1770          * check if the ULPs are ready for power down
1771          */
1772         mutex_exit(&port->fp_mutex);
1773         if (fctl_detach_ulps(port, FC_CMD_POWER_DOWN,
1774             &modlinkage) != FC_SUCCESS) {
1775                 mutex_enter(&port->fp_mutex);
1776                 port->fp_soft_state &= ~FP_SOFT_POWER_DOWN;
1777                 mutex_exit(&port->fp_mutex);
1778 
1779                 /*
1780                  * Power back up the obedient ULPs that went down
1781                  */
1782                 fp_attach_ulps(port, FC_CMD_POWER_UP);
1783 
1784                 FP_TRACE(FP_NHEAD2(9, 0),
1785                     "ULP(s) busy, detach_ulps failed. Failing power down");
1786                 mutex_enter(&port->fp_mutex);
1787                 return (DDI_FAILURE);
1788         }
1789         mutex_enter(&port->fp_mutex);
1790 
1791         fp_suspend_all(port);
1792 
1793         return (DDI_SUCCESS);
1794 }
1795 
1796 
1797 /*
1798  * Suspend the entire FC port
1799  */
1800 static void
1801 fp_suspend_all(fc_local_port_t *port)
1802 {
1803         int                     index;
1804         struct pwwn_hash        *head;
1805         fc_remote_port_t        *pd;
1806 
1807         ASSERT(MUTEX_HELD(&port->fp_mutex));
1808 
1809         if (port->fp_wait_tid != 0) {
1810                 timeout_id_t    tid;
1811 
1812                 tid = port->fp_wait_tid;
1813                 port->fp_wait_tid = (timeout_id_t)NULL;
1814                 mutex_exit(&port->fp_mutex);
1815                 (void) untimeout(tid);
1816                 mutex_enter(&port->fp_mutex);
1817                 port->fp_restore |= FP_RESTORE_WAIT_TIMEOUT;
1818         }
1819 
1820         if (port->fp_offline_tid) {
1821                 timeout_id_t    tid;
1822 
1823                 tid = port->fp_offline_tid;
1824                 port->fp_offline_tid = (timeout_id_t)NULL;
1825                 mutex_exit(&port->fp_mutex);
1826                 (void) untimeout(tid);
1827                 mutex_enter(&port->fp_mutex);
1828                 port->fp_restore |= FP_RESTORE_OFFLINE_TIMEOUT;
1829         }
1830         mutex_exit(&port->fp_mutex);
1831         port->fp_fca_tran->fca_unbind_port(port->fp_fca_handle);
1832         mutex_enter(&port->fp_mutex);
1833 
1834         /*
1835          * Mark all devices as OLD, and reset the LOGIN state as well
1836          * (this will force the ULPs to perform a LOGIN after calling
1837          * fc_portgetmap() during RESUME/PM_RESUME)
1838          */
1839         for (index = 0; index < pwwn_table_size; index++) {
1840                 head = &port->fp_pwwn_table[index];
1841                 pd = head->pwwn_head;
1842                 while (pd != NULL) {
1843                         mutex_enter(&pd->pd_mutex);
1844                         fp_remote_port_offline(pd);
1845                         fctl_delist_did_table(port, pd);
1846                         pd->pd_state = PORT_DEVICE_VALID;
1847                         pd->pd_login_count = 0;
1848                         mutex_exit(&pd->pd_mutex);
1849                         pd = pd->pd_wwn_hnext;
1850                 }
1851         }
1852 }
1853 
1854 
1855 /*
1856  * fp_cache_constructor: Constructor function for kmem_cache_create(9F).
1857  * Performs intializations for fc_packet_t structs.
1858  * Returns 0 for success or -1 for failure.
1859  *
1860  * This function allocates DMA handles for both command and responses.
1861  * Most of the ELSs used have both command and responses so it is strongly
1862  * desired to move them to cache constructor routine.
1863  *
1864  * Context: Can sleep iff called with KM_SLEEP flag.
1865  */
1866 static int
1867 fp_cache_constructor(void *buf, void *cdarg, int kmflags)
1868 {
1869         int             (*cb) (caddr_t);
1870         fc_packet_t     *pkt;
1871         fp_cmd_t        *cmd = (fp_cmd_t *)buf;
1872         fc_local_port_t *port = (fc_local_port_t *)cdarg;
1873 
1874         cb = (kmflags == KM_SLEEP) ? DDI_DMA_SLEEP : DDI_DMA_DONTWAIT;
1875 
1876         cmd->cmd_next = NULL;
1877         cmd->cmd_flags = 0;
1878         cmd->cmd_dflags = 0;
1879         cmd->cmd_job = NULL;
1880         cmd->cmd_port = port;
1881         pkt = &cmd->cmd_pkt;
1882 
1883         if (!(port->fp_soft_state & FP_SOFT_FCA_IS_NODMA)) {
1884                 if (ddi_dma_alloc_handle(port->fp_fca_dip,
1885                     port->fp_fca_tran->fca_dma_attr, cb, NULL,
1886                     &pkt->pkt_cmd_dma) != DDI_SUCCESS) {
1887                         return (-1);
1888                 }
1889 
1890                 if (ddi_dma_alloc_handle(port->fp_fca_dip,
1891                     port->fp_fca_tran->fca_dma_attr, cb, NULL,
1892                     &pkt->pkt_resp_dma) != DDI_SUCCESS) {
1893                         ddi_dma_free_handle(&pkt->pkt_cmd_dma);
1894                         return (-1);
1895                 }
1896         } else {
1897                 pkt->pkt_cmd_dma = 0;
1898                 pkt->pkt_resp_dma = 0;
1899         }
1900 
1901         pkt->pkt_cmd_acc = pkt->pkt_resp_acc = NULL;
1902         pkt->pkt_cmd_cookie_cnt = pkt->pkt_resp_cookie_cnt =
1903             pkt->pkt_data_cookie_cnt = 0;
1904         pkt->pkt_cmd_cookie = pkt->pkt_resp_cookie =
1905             pkt->pkt_data_cookie = NULL;
1906         pkt->pkt_fca_private = (caddr_t)buf + sizeof (fp_cmd_t);
1907 
1908         return (0);
1909 }
1910 
1911 
1912 /*
1913  * fp_cache_destructor: Destructor function for kmem_cache_create().
1914  * Performs un-intializations for fc_packet_t structs.
1915  */
1916 /* ARGSUSED */
1917 static void
1918 fp_cache_destructor(void *buf, void *cdarg)
1919 {
1920         fp_cmd_t        *cmd = (fp_cmd_t *)buf;
1921         fc_packet_t     *pkt;
1922 
1923         pkt = &cmd->cmd_pkt;
1924         if (pkt->pkt_cmd_dma) {
1925                 ddi_dma_free_handle(&pkt->pkt_cmd_dma);
1926         }
1927 
1928         if (pkt->pkt_resp_dma) {
1929                 ddi_dma_free_handle(&pkt->pkt_resp_dma);
1930         }
1931 }
1932 
1933 
1934 /*
1935  * Packet allocation for ELS and any other port driver commands
1936  *
1937  * Some ELSs like FLOGI and PLOGI are critical for topology and
1938  * device discovery and a system's inability to allocate memory
1939  * or DVMA resources while performing some of these critical ELSs
1940  * cause a lot of problem. While memory allocation failures are
1941  * rare, DVMA resource failures are common as the applications
1942  * are becoming more and more powerful on huge servers.  So it
1943  * is desirable to have a framework support to reserve a fragment
1944  * of DVMA. So until this is fixed the correct way, the suffering
1945  * is huge whenever a LIP happens at a time DVMA resources are
1946  * drained out completely - So an attempt needs to be made to
1947  * KM_SLEEP while requesting for these resources, hoping that
1948  * the requests won't hang forever.
1949  *
1950  * The fc_remote_port_t argument is stored into the pkt_pd field in the
1951  * fc_packet_t struct prior to the fc_ulp_init_packet() call.  This
1952  * ensures that the pd_ref_count for the fc_remote_port_t is valid.
1953  * If there is no fc_remote_port_t associated with the fc_packet_t, then
1954  * fp_alloc_pkt() must be called with pd set to NULL.
1955  *
1956  * fp/fctl will resue fp_cmd_t somewhere, and change pkt_cmdlen/rsplen,
1957  * actually, it's a design fault. But there's no problem for physical
1958  * FCAs. But it will cause memory leak or panic for virtual FCAs like fcoei.
1959  *
1960  * For FCAs that don't support DMA, such as fcoei, we will use
1961  * pkt_fctl_rsvd1/rsvd2 to keep the real cmd_len/resp_len.
1962  */
1963 
1964 static fp_cmd_t *
1965 fp_alloc_pkt(fc_local_port_t *port, int cmd_len, int resp_len, int kmflags,
1966     fc_remote_port_t *pd)
1967 {
1968         int             rval;
1969         ulong_t         real_len;
1970         fp_cmd_t        *cmd;
1971         fc_packet_t     *pkt;
1972         int             (*cb) (caddr_t);
1973         ddi_dma_cookie_t        pkt_cookie;
1974         ddi_dma_cookie_t        *cp;
1975         uint32_t                cnt;
1976 
1977         ASSERT(!MUTEX_HELD(&port->fp_mutex));
1978 
1979         cb = (kmflags == KM_SLEEP) ? DDI_DMA_SLEEP : DDI_DMA_DONTWAIT;
1980 
1981         cmd = (fp_cmd_t *)kmem_cache_alloc(port->fp_pkt_cache, kmflags);
1982         if (cmd == NULL) {
1983                 return (cmd);
1984         }
1985 
1986         cmd->cmd_ulp_pkt = NULL;
1987         cmd->cmd_flags = 0;
1988         pkt = &cmd->cmd_pkt;
1989         ASSERT(cmd->cmd_dflags == 0);
1990 
1991         pkt->pkt_datalen = 0;
1992         pkt->pkt_data = NULL;
1993         pkt->pkt_state = 0;
1994         pkt->pkt_action = 0;
1995         pkt->pkt_reason = 0;
1996         pkt->pkt_expln = 0;
1997         pkt->pkt_cmd = NULL;
1998         pkt->pkt_resp = NULL;
1999         pkt->pkt_fctl_rsvd1 = NULL;
2000         pkt->pkt_fctl_rsvd2 = NULL;
2001 
2002         /*
2003          * Init pkt_pd with the given pointer; this must be done _before_
2004          * the call to fc_ulp_init_packet().
2005          */
2006         pkt->pkt_pd = pd;
2007 
2008         /* Now call the FCA driver to init its private, per-packet fields */
2009         if (fc_ulp_init_packet((opaque_t)port, pkt, kmflags) != FC_SUCCESS) {
2010                 goto alloc_pkt_failed;
2011         }
2012 
2013         if (cmd_len && !(port->fp_soft_state & FP_SOFT_FCA_IS_NODMA)) {
2014                 ASSERT(pkt->pkt_cmd_dma != NULL);
2015 
2016                 rval = ddi_dma_mem_alloc(pkt->pkt_cmd_dma, cmd_len,
2017                     port->fp_fca_tran->fca_acc_attr, DDI_DMA_CONSISTENT,
2018                     cb, NULL, (caddr_t *)&pkt->pkt_cmd, &real_len,
2019                     &pkt->pkt_cmd_acc);
2020 
2021                 if (rval != DDI_SUCCESS) {
2022                         goto alloc_pkt_failed;
2023                 }
2024                 cmd->cmd_dflags |= FP_CMD_VALID_DMA_MEM;
2025 
2026                 if (real_len < cmd_len) {
2027                         goto alloc_pkt_failed;
2028                 }
2029 
2030                 rval = ddi_dma_addr_bind_handle(pkt->pkt_cmd_dma, NULL,
2031                     pkt->pkt_cmd, real_len, DDI_DMA_WRITE |
2032                     DDI_DMA_CONSISTENT, cb, NULL,
2033                     &pkt_cookie, &pkt->pkt_cmd_cookie_cnt);
2034 
2035                 if (rval != DDI_DMA_MAPPED) {
2036                         goto alloc_pkt_failed;
2037                 }
2038 
2039                 cmd->cmd_dflags |= FP_CMD_VALID_DMA_BIND;
2040 
2041                 if (pkt->pkt_cmd_cookie_cnt >
2042                     port->fp_fca_tran->fca_dma_attr->dma_attr_sgllen) {
2043                         goto alloc_pkt_failed;
2044                 }
2045 
2046                 ASSERT(pkt->pkt_cmd_cookie_cnt != 0);
2047 
2048                 cp = pkt->pkt_cmd_cookie = (ddi_dma_cookie_t *)kmem_alloc(
2049                     pkt->pkt_cmd_cookie_cnt * sizeof (pkt_cookie),
2050                     KM_NOSLEEP);
2051 
2052                 if (cp == NULL) {
2053                         goto alloc_pkt_failed;
2054                 }
2055 
2056                 *cp = pkt_cookie;
2057                 cp++;
2058                 for (cnt = 1; cnt < pkt->pkt_cmd_cookie_cnt; cnt++, cp++) {
2059                         ddi_dma_nextcookie(pkt->pkt_cmd_dma, &pkt_cookie);
2060                         *cp = pkt_cookie;
2061                 }
2062         } else if (cmd_len != 0) {
2063                 pkt->pkt_cmd = kmem_alloc(cmd_len, KM_SLEEP);
2064                 pkt->pkt_fctl_rsvd1 = (opaque_t)(uintptr_t)cmd_len;
2065         }
2066 
2067         if (resp_len && !(port->fp_soft_state & FP_SOFT_FCA_IS_NODMA)) {
2068                 ASSERT(pkt->pkt_resp_dma != NULL);
2069 
2070                 rval = ddi_dma_mem_alloc(pkt->pkt_resp_dma, resp_len,
2071                     port->fp_fca_tran->fca_acc_attr,
2072                     DDI_DMA_CONSISTENT, cb, NULL,
2073                     (caddr_t *)&pkt->pkt_resp, &real_len,
2074                     &pkt->pkt_resp_acc);
2075 
2076                 if (rval != DDI_SUCCESS) {
2077                         goto alloc_pkt_failed;
2078                 }
2079                 cmd->cmd_dflags |= FP_RESP_VALID_DMA_MEM;
2080 
2081                 if (real_len < resp_len) {
2082                         goto alloc_pkt_failed;
2083                 }
2084 
2085                 rval = ddi_dma_addr_bind_handle(pkt->pkt_resp_dma, NULL,
2086                     pkt->pkt_resp, real_len, DDI_DMA_READ |
2087                     DDI_DMA_CONSISTENT, cb, NULL,
2088                     &pkt_cookie, &pkt->pkt_resp_cookie_cnt);
2089 
2090                 if (rval != DDI_DMA_MAPPED) {
2091                         goto alloc_pkt_failed;
2092                 }
2093 
2094                 cmd->cmd_dflags |= FP_RESP_VALID_DMA_BIND;
2095 
2096                 if (pkt->pkt_resp_cookie_cnt >
2097                     port->fp_fca_tran->fca_dma_attr->dma_attr_sgllen) {
2098                         goto alloc_pkt_failed;
2099                 }
2100 
2101                 ASSERT(pkt->pkt_cmd_cookie_cnt != 0);
2102 
2103                 cp = pkt->pkt_resp_cookie = (ddi_dma_cookie_t *)kmem_alloc(
2104                     pkt->pkt_resp_cookie_cnt * sizeof (pkt_cookie),
2105                     KM_NOSLEEP);
2106 
2107                 if (cp == NULL) {
2108                         goto alloc_pkt_failed;
2109                 }
2110 
2111                 *cp = pkt_cookie;
2112                 cp++;
2113                 for (cnt = 1; cnt < pkt->pkt_resp_cookie_cnt; cnt++, cp++) {
2114                         ddi_dma_nextcookie(pkt->pkt_resp_dma, &pkt_cookie);
2115                         *cp = pkt_cookie;
2116                 }
2117         } else if (resp_len != 0) {
2118                 pkt->pkt_resp = kmem_alloc(resp_len, KM_SLEEP);
2119                 pkt->pkt_fctl_rsvd2 = (opaque_t)(uintptr_t)resp_len;
2120         }
2121 
2122         pkt->pkt_cmdlen = cmd_len;
2123         pkt->pkt_rsplen = resp_len;
2124         pkt->pkt_ulp_private = cmd;
2125 
2126         return (cmd);
2127 
2128 alloc_pkt_failed:
2129 
2130         fp_free_dma(cmd);
2131 
2132         if (pkt->pkt_cmd_cookie != NULL) {
2133                 kmem_free(pkt->pkt_cmd_cookie,
2134                     pkt->pkt_cmd_cookie_cnt * sizeof (ddi_dma_cookie_t));
2135                 pkt->pkt_cmd_cookie = NULL;
2136         }
2137 
2138         if (pkt->pkt_resp_cookie != NULL) {
2139                 kmem_free(pkt->pkt_resp_cookie,
2140                     pkt->pkt_resp_cookie_cnt * sizeof (ddi_dma_cookie_t));
2141                 pkt->pkt_resp_cookie = NULL;
2142         }
2143 
2144         if (port->fp_soft_state & FP_SOFT_FCA_IS_NODMA) {
2145                 if (pkt->pkt_cmd) {
2146                         kmem_free(pkt->pkt_cmd, cmd_len);
2147                 }
2148 
2149                 if (pkt->pkt_resp) {
2150                         kmem_free(pkt->pkt_resp, resp_len);
2151                 }
2152         }
2153 
2154         kmem_cache_free(port->fp_pkt_cache, cmd);
2155 
2156         return (NULL);
2157 }
2158 
2159 
2160 /*
2161  * Free FC packet
2162  */
2163 static void
2164 fp_free_pkt(fp_cmd_t *cmd)
2165 {
2166         fc_local_port_t *port;
2167         fc_packet_t     *pkt;
2168 
2169         ASSERT(!MUTEX_HELD(&cmd->cmd_port->fp_mutex));
2170 
2171         cmd->cmd_next = NULL;
2172         cmd->cmd_job = NULL;
2173         pkt = &cmd->cmd_pkt;
2174         pkt->pkt_ulp_private = 0;
2175         pkt->pkt_tran_flags = 0;
2176         pkt->pkt_tran_type = 0;
2177         port = cmd->cmd_port;
2178 
2179         if (pkt->pkt_cmd_cookie != NULL) {
2180                 kmem_free(pkt->pkt_cmd_cookie, pkt->pkt_cmd_cookie_cnt *
2181                     sizeof (ddi_dma_cookie_t));
2182                 pkt->pkt_cmd_cookie = NULL;
2183         }
2184 
2185         if (pkt->pkt_resp_cookie != NULL) {
2186                 kmem_free(pkt->pkt_resp_cookie, pkt->pkt_resp_cookie_cnt *
2187                     sizeof (ddi_dma_cookie_t));
2188                 pkt->pkt_resp_cookie = NULL;
2189         }
2190 
2191         if (port->fp_soft_state & FP_SOFT_FCA_IS_NODMA) {
2192                 if (pkt->pkt_cmd) {
2193                         kmem_free(pkt->pkt_cmd,
2194                             (uint32_t)(uintptr_t)pkt->pkt_fctl_rsvd1);
2195                 }
2196 
2197                 if (pkt->pkt_resp) {
2198                         kmem_free(pkt->pkt_resp,
2199                             (uint32_t)(uintptr_t)pkt->pkt_fctl_rsvd2);
2200                 }
2201         }
2202 
2203         fp_free_dma(cmd);
2204         (void) fc_ulp_uninit_packet((opaque_t)port, pkt);
2205         kmem_cache_free(port->fp_pkt_cache, (void *)cmd);
2206 }
2207 
2208 
2209 /*
2210  * Release DVMA resources
2211  */
2212 static void
2213 fp_free_dma(fp_cmd_t *cmd)
2214 {
2215         fc_packet_t *pkt = &cmd->cmd_pkt;
2216 
2217         pkt->pkt_cmdlen = 0;
2218         pkt->pkt_rsplen = 0;
2219         pkt->pkt_tran_type = 0;
2220         pkt->pkt_tran_flags = 0;
2221 
2222         if (cmd->cmd_dflags & FP_CMD_VALID_DMA_BIND) {
2223                 (void) ddi_dma_unbind_handle(pkt->pkt_cmd_dma);
2224         }
2225 
2226         if (cmd->cmd_dflags & FP_CMD_VALID_DMA_MEM) {
2227                 if (pkt->pkt_cmd_acc) {
2228                         ddi_dma_mem_free(&pkt->pkt_cmd_acc);
2229                 }
2230         }
2231 
2232         if (cmd->cmd_dflags & FP_RESP_VALID_DMA_BIND) {
2233                 (void) ddi_dma_unbind_handle(pkt->pkt_resp_dma);
2234         }
2235 
2236         if (cmd->cmd_dflags & FP_RESP_VALID_DMA_MEM) {
2237                 if (pkt->pkt_resp_acc) {
2238                         ddi_dma_mem_free(&pkt->pkt_resp_acc);
2239                 }
2240         }
2241         cmd->cmd_dflags = 0;
2242 }
2243 
2244 
2245 /*
2246  * Dedicated thread to perform various activities.  One thread for
2247  * each fc_local_port_t (driver soft state) instance.
2248  * Note, this effectively works out to one thread for each local
2249  * port, but there are also some Solaris taskq threads in use on a per-local
2250  * port basis; these also need to be taken into consideration.
2251  */
2252 static void
2253 fp_job_handler(fc_local_port_t *port)
2254 {
2255         int                     rval;
2256         uint32_t                *d_id;
2257         fc_remote_port_t        *pd;
2258         job_request_t           *job;
2259 
2260 #ifndef __lock_lint
2261         /*
2262          * Solaris-internal stuff for proper operation of kernel threads
2263          * with Solaris CPR.
2264          */
2265         CALLB_CPR_INIT(&port->fp_cpr_info, &port->fp_mutex,
2266             callb_generic_cpr, "fp_job_handler");
2267 #endif
2268 
2269 
2270         /* Loop forever waiting for work to do */
2271         for (;;) {
2272 
2273                 mutex_enter(&port->fp_mutex);
2274 
2275                 /*
2276                  * Sleep if no work to do right now, or if we want
2277                  * to suspend or power-down.
2278                  */
2279                 while (port->fp_job_head == NULL ||
2280                     (port->fp_soft_state & (FP_SOFT_POWER_DOWN |
2281                     FP_SOFT_SUSPEND))) {
2282                         CALLB_CPR_SAFE_BEGIN(&port->fp_cpr_info);
2283                         cv_wait(&port->fp_cv, &port->fp_mutex);
2284                         CALLB_CPR_SAFE_END(&port->fp_cpr_info, &port->fp_mutex);
2285                 }
2286 
2287                 /*
2288                  * OK, we've just been woken up, so retrieve the next entry
2289                  * from the head of the job queue for this local port.
2290                  */
2291                 job = fctl_deque_job(port);
2292 
2293                 /*
2294                  * Handle all the fp driver's supported job codes here
2295                  * in this big honkin' switch.
2296                  */
2297                 switch (job->job_code) {
2298                 case JOB_PORT_SHUTDOWN:
2299                         /*
2300                          * fp_port_shutdown() is only called from here. This
2301                          * will prepare the local port instance (softstate)
2302                          * for detaching.  This cancels timeout callbacks,
2303                          * executes LOGOs with remote ports, cleans up tables,
2304                          * and deallocates data structs.
2305                          */
2306                         fp_port_shutdown(port, job);
2307 
2308                         /*
2309                          * This will exit the job thread.
2310                          */
2311 #ifndef __lock_lint
2312                         CALLB_CPR_EXIT(&(port->fp_cpr_info));
2313 #else
2314                         mutex_exit(&port->fp_mutex);
2315 #endif
2316                         fctl_jobdone(job);
2317                         thread_exit();
2318 
2319                         /* NOTREACHED */
2320 
2321                 case JOB_ATTACH_ULP: {
2322                         /*
2323                          * This job is spawned in response to a ULP calling
2324                          * fc_ulp_add().
2325                          */
2326 
2327                         boolean_t do_attach_ulps = B_TRUE;
2328 
2329                         /*
2330                          * If fp is detaching, we don't want to call
2331                          * fp_startup_done as this asynchronous
2332                          * notification may interfere with the re-attach.
2333                          */
2334 
2335                         if (port->fp_soft_state & (FP_DETACH_INPROGRESS |
2336                             FP_SOFT_IN_DETACH | FP_DETACH_FAILED)) {
2337                                 do_attach_ulps = B_FALSE;
2338                         } else {
2339                                 /*
2340                                  * We are going to force the transport
2341                                  * to attach to the ULPs, so set
2342                                  * fp_ulp_attach.  This will keep any
2343                                  * potential detach from occurring until
2344                                  * we are done.
2345                                  */
2346                                 port->fp_ulp_attach = 1;
2347                         }
2348 
2349                         mutex_exit(&port->fp_mutex);
2350 
2351                         /*
2352                          * NOTE: Since we just dropped the mutex, there is now
2353                          * a race window where the fp_soft_state check above
2354                          * could change here.  This race is covered because an
2355                          * additional check was added in the functions hidden
2356                          * under fp_startup_done().
2357                          */
2358                         if (do_attach_ulps == B_TRUE) {
2359                                 /*
2360                                  * This goes thru a bit of a convoluted call
2361                                  * chain before spawning off a DDI taskq
2362                                  * request to perform the actual attach
2363                                  * operations. Blocking can occur at a number
2364                                  * of points.
2365                                  */
2366                                 fp_startup_done((opaque_t)port, FC_PKT_SUCCESS);
2367                         }
2368                         job->job_result = FC_SUCCESS;
2369                         fctl_jobdone(job);
2370                         break;
2371                 }
2372 
2373                 case JOB_ULP_NOTIFY: {
2374                         /*
2375                          * Pass state change notifications up to any/all
2376                          * registered ULPs.
2377                          */
2378                         uint32_t statec;
2379 
2380                         statec = job->job_ulp_listlen;
2381                         if (statec == FC_STATE_RESET_REQUESTED) {
2382                                 port->fp_last_task = port->fp_task;
2383                                 port->fp_task = FP_TASK_OFFLINE;
2384                                 fp_port_offline(port, 0);
2385                                 port->fp_task = port->fp_last_task;
2386                                 port->fp_last_task = FP_TASK_IDLE;
2387                         }
2388 
2389                         if (--port->fp_statec_busy == 0) {
2390                                 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
2391                         }
2392 
2393                         mutex_exit(&port->fp_mutex);
2394 
2395                         job->job_result = fp_ulp_notify(port, statec, KM_SLEEP);
2396                         fctl_jobdone(job);
2397                         break;
2398                 }
2399 
2400                 case JOB_PLOGI_ONE:
2401                         /*
2402                          * Issue a PLOGI to a single remote port. Multiple
2403                          * PLOGIs to different remote ports may occur in
2404                          * parallel.
2405                          * This can create the fc_remote_port_t if it does not
2406                          * already exist.
2407                          */
2408 
2409                         mutex_exit(&port->fp_mutex);
2410                         d_id = (uint32_t *)job->job_private;
2411                         pd = fctl_get_remote_port_by_did(port, *d_id);
2412 
2413                         if (pd) {
2414                                 mutex_enter(&pd->pd_mutex);
2415                                 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
2416                                         pd->pd_login_count++;
2417                                         mutex_exit(&pd->pd_mutex);
2418                                         job->job_result = FC_SUCCESS;
2419                                         fctl_jobdone(job);
2420                                         break;
2421                                 }
2422                                 mutex_exit(&pd->pd_mutex);
2423                         } else {
2424                                 mutex_enter(&port->fp_mutex);
2425                                 if (FC_IS_TOP_SWITCH(port->fp_topology)) {
2426                                         mutex_exit(&port->fp_mutex);
2427                                         pd = fp_create_remote_port_by_ns(port,
2428                                             *d_id, KM_SLEEP);
2429                                         if (pd == NULL) {
2430                                                 job->job_result = FC_FAILURE;
2431                                                 fctl_jobdone(job);
2432                                                 break;
2433                                         }
2434                                 } else {
2435                                         mutex_exit(&port->fp_mutex);
2436                                 }
2437                         }
2438 
2439                         job->job_flags |= JOB_TYPE_FP_ASYNC;
2440                         job->job_counter = 1;
2441 
2442                         rval = fp_port_login(port, *d_id, job,
2443                             FP_CMD_PLOGI_RETAIN, KM_SLEEP, pd, NULL);
2444 
2445                         if (rval != FC_SUCCESS) {
2446                                 job->job_result = rval;
2447                                 fctl_jobdone(job);
2448                         }
2449                         break;
2450 
2451                 case JOB_LOGO_ONE: {
2452                         /*
2453                          * Issue a PLOGO to a single remote port. Multiple
2454                          * PLOGOs to different remote ports may occur in
2455                          * parallel.
2456                          */
2457                         fc_remote_port_t *pd;
2458 
2459 #ifndef __lock_lint
2460                         ASSERT(job->job_counter > 0);
2461 #endif
2462 
2463                         pd = (fc_remote_port_t *)job->job_ulp_pkts;
2464 
2465                         mutex_enter(&pd->pd_mutex);
2466                         if (pd->pd_state != PORT_DEVICE_LOGGED_IN) {
2467                                 mutex_exit(&pd->pd_mutex);
2468                                 job->job_result = FC_LOGINREQ;
2469                                 mutex_exit(&port->fp_mutex);
2470                                 fctl_jobdone(job);
2471                                 break;
2472                         }
2473                         if (pd->pd_login_count > 1) {
2474                                 pd->pd_login_count--;
2475                                 mutex_exit(&pd->pd_mutex);
2476                                 job->job_result = FC_SUCCESS;
2477                                 mutex_exit(&port->fp_mutex);
2478                                 fctl_jobdone(job);
2479                                 break;
2480                         }
2481                         mutex_exit(&pd->pd_mutex);
2482                         mutex_exit(&port->fp_mutex);
2483                         job->job_flags |= JOB_TYPE_FP_ASYNC;
2484                         (void) fp_logout(port, pd, job);
2485                         break;
2486                 }
2487 
2488                 case JOB_FCIO_LOGIN:
2489                         /*
2490                          * PLOGI initiated at ioctl request.
2491                          */
2492                         mutex_exit(&port->fp_mutex);
2493                         job->job_result =
2494                             fp_fcio_login(port, job->job_private, job);
2495                         fctl_jobdone(job);
2496                         break;
2497 
2498                 case JOB_FCIO_LOGOUT:
2499                         /*
2500                          * PLOGO initiated at ioctl request.
2501                          */
2502                         mutex_exit(&port->fp_mutex);
2503                         job->job_result =
2504                             fp_fcio_logout(port, job->job_private, job);
2505                         fctl_jobdone(job);
2506                         break;
2507 
2508                 case JOB_PORT_GETMAP:
2509                 case JOB_PORT_GETMAP_PLOGI_ALL: {
2510                         port->fp_last_task = port->fp_task;
2511                         port->fp_task = FP_TASK_GETMAP;
2512 
2513                         switch (port->fp_topology) {
2514                         case FC_TOP_PRIVATE_LOOP:
2515                                 job->job_counter = 1;
2516 
2517                                 fp_get_loopmap(port, job);
2518                                 mutex_exit(&port->fp_mutex);
2519                                 fp_jobwait(job);
2520                                 fctl_fillout_map(port,
2521                                     (fc_portmap_t **)job->job_private,
2522                                     (uint32_t *)job->job_arg, 1, 0, 0);
2523                                 fctl_jobdone(job);
2524                                 mutex_enter(&port->fp_mutex);
2525                                 break;
2526 
2527                         case FC_TOP_PUBLIC_LOOP:
2528                         case FC_TOP_FABRIC:
2529                                 mutex_exit(&port->fp_mutex);
2530                                 job->job_counter = 1;
2531 
2532                                 job->job_result = fp_ns_getmap(port,
2533                                     job, (fc_portmap_t **)job->job_private,
2534                                     (uint32_t *)job->job_arg,
2535                                     FCTL_GAN_START_ID);
2536                                 fctl_jobdone(job);
2537                                 mutex_enter(&port->fp_mutex);
2538                                 break;
2539 
2540                         case FC_TOP_PT_PT:
2541                                 mutex_exit(&port->fp_mutex);
2542                                 fctl_fillout_map(port,
2543                                     (fc_portmap_t **)job->job_private,
2544                                     (uint32_t *)job->job_arg, 1, 0, 0);
2545                                 fctl_jobdone(job);
2546                                 mutex_enter(&port->fp_mutex);
2547                                 break;
2548 
2549                         default:
2550                                 mutex_exit(&port->fp_mutex);
2551                                 fctl_jobdone(job);
2552                                 mutex_enter(&port->fp_mutex);
2553                                 break;
2554                         }
2555                         port->fp_task = port->fp_last_task;
2556                         port->fp_last_task = FP_TASK_IDLE;
2557                         mutex_exit(&port->fp_mutex);
2558                         break;
2559                 }
2560 
2561                 case JOB_PORT_OFFLINE: {
2562                         fp_log_port_event(port, ESC_SUNFC_PORT_OFFLINE);
2563 
2564                         port->fp_last_task = port->fp_task;
2565                         port->fp_task = FP_TASK_OFFLINE;
2566 
2567                         if (port->fp_statec_busy > 2) {
2568                                 job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION;
2569                                 fp_port_offline(port, 0);
2570                                 if (--port->fp_statec_busy == 0) {
2571                                         port->fp_soft_state &=
2572                                             ~FP_SOFT_IN_STATEC_CB;
2573                                 }
2574                         } else {
2575                                 fp_port_offline(port, 1);
2576                         }
2577 
2578                         port->fp_task = port->fp_last_task;
2579                         port->fp_last_task = FP_TASK_IDLE;
2580 
2581                         mutex_exit(&port->fp_mutex);
2582 
2583                         fctl_jobdone(job);
2584                         break;
2585                 }
2586 
2587                 case JOB_PORT_STARTUP: {
2588                         if ((rval = fp_port_startup(port, job)) != FC_SUCCESS) {
2589                                 if (port->fp_statec_busy > 1) {
2590                                         mutex_exit(&port->fp_mutex);
2591                                         break;
2592                                 }
2593                                 mutex_exit(&port->fp_mutex);
2594 
2595                                 FP_TRACE(FP_NHEAD2(9, rval),
2596                                     "Topology discovery failed");
2597                                 break;
2598                         }
2599 
2600                         /*
2601                          * Attempt building device handles in case
2602                          * of private Loop.
2603                          */
2604                         if (port->fp_topology == FC_TOP_PRIVATE_LOOP) {
2605                                 job->job_counter = 1;
2606 
2607                                 fp_get_loopmap(port, job);
2608                                 mutex_exit(&port->fp_mutex);
2609                                 fp_jobwait(job);
2610                                 mutex_enter(&port->fp_mutex);
2611                                 if (port->fp_lilp_map.lilp_magic < MAGIC_LIRP) {
2612                                         ASSERT(port->fp_total_devices == 0);
2613                                         port->fp_total_devices =
2614                                             port->fp_dev_count;
2615                                 }
2616                         } else if (FC_IS_TOP_SWITCH(port->fp_topology)) {
2617                                 /*
2618                                  * Hack to avoid state changes going up early
2619                                  */
2620                                 port->fp_statec_busy++;
2621                                 port->fp_soft_state |= FP_SOFT_IN_STATEC_CB;
2622 
2623                                 job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION;
2624                                 fp_fabric_online(port, job);
2625                                 job->job_flags &= ~JOB_CANCEL_ULP_NOTIFICATION;
2626                         }
2627                         mutex_exit(&port->fp_mutex);
2628                         fctl_jobdone(job);
2629                         break;
2630                 }
2631 
2632                 case JOB_PORT_ONLINE: {
2633                         char            *newtop;
2634                         char            *oldtop;
2635                         uint32_t        old_top;
2636 
2637                         fp_log_port_event(port, ESC_SUNFC_PORT_ONLINE);
2638 
2639                         /*
2640                          * Bail out early if there are a lot of
2641                          * state changes in the pipeline
2642                          */
2643                         if (port->fp_statec_busy > 1) {
2644                                 --port->fp_statec_busy;
2645                                 mutex_exit(&port->fp_mutex);
2646                                 fctl_jobdone(job);
2647                                 break;
2648                         }
2649 
2650                         switch (old_top = port->fp_topology) {
2651                         case FC_TOP_PRIVATE_LOOP:
2652                                 oldtop = "Private Loop";
2653                                 break;
2654 
2655                         case FC_TOP_PUBLIC_LOOP:
2656                                 oldtop = "Public Loop";
2657                                 break;
2658 
2659                         case FC_TOP_PT_PT:
2660                                 oldtop = "Point to Point";
2661                                 break;
2662 
2663                         case FC_TOP_FABRIC:
2664                                 oldtop = "Fabric";
2665                                 break;
2666 
2667                         default:
2668                                 oldtop = NULL;
2669                                 break;
2670                         }
2671 
2672                         port->fp_last_task = port->fp_task;
2673                         port->fp_task = FP_TASK_ONLINE;
2674 
2675                         if ((rval = fp_port_startup(port, job)) != FC_SUCCESS) {
2676 
2677                                 port->fp_task = port->fp_last_task;
2678                                 port->fp_last_task = FP_TASK_IDLE;
2679 
2680                                 if (port->fp_statec_busy > 1) {
2681                                         --port->fp_statec_busy;
2682                                         mutex_exit(&port->fp_mutex);
2683                                         break;
2684                                 }
2685 
2686                                 port->fp_state = FC_STATE_OFFLINE;
2687 
2688                                 FP_TRACE(FP_NHEAD2(9, rval),
2689                                     "Topology discovery failed");
2690 
2691                                 if (--port->fp_statec_busy == 0) {
2692                                         port->fp_soft_state &=
2693                                             ~FP_SOFT_IN_STATEC_CB;
2694                                 }
2695 
2696                                 if (port->fp_offline_tid == NULL) {
2697                                         port->fp_offline_tid =
2698                                             timeout(fp_offline_timeout,
2699                                             (caddr_t)port, fp_offline_ticks);
2700                                 }
2701 
2702                                 mutex_exit(&port->fp_mutex);
2703                                 break;
2704                         }
2705 
2706                         switch (port->fp_topology) {
2707                         case FC_TOP_PRIVATE_LOOP:
2708                                 newtop = "Private Loop";
2709                                 break;
2710 
2711                         case FC_TOP_PUBLIC_LOOP:
2712                                 newtop = "Public Loop";
2713                                 break;
2714 
2715                         case FC_TOP_PT_PT:
2716                                 newtop = "Point to Point";
2717                                 break;
2718 
2719                         case FC_TOP_FABRIC:
2720                                 newtop = "Fabric";
2721                                 break;
2722 
2723                         default:
2724                                 newtop = NULL;
2725                                 break;
2726                         }
2727 
2728                         if (oldtop && newtop && strcmp(oldtop, newtop)) {
2729                                 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
2730                                     "Change in FC Topology old = %s new = %s",
2731                                     oldtop, newtop);
2732                         }
2733 
2734                         switch (port->fp_topology) {
2735                         case FC_TOP_PRIVATE_LOOP: {
2736                                 int orphan = (old_top == FC_TOP_FABRIC ||
2737                                     old_top == FC_TOP_PUBLIC_LOOP) ? 1 : 0;
2738 
2739                                 mutex_exit(&port->fp_mutex);
2740                                 fp_loop_online(port, job, orphan);
2741                                 break;
2742                         }
2743 
2744                         case FC_TOP_PUBLIC_LOOP:
2745                                 /* FALLTHROUGH */
2746                         case FC_TOP_FABRIC:
2747                                 fp_fabric_online(port, job);
2748                                 mutex_exit(&port->fp_mutex);
2749                                 break;
2750 
2751                         case FC_TOP_PT_PT:
2752                                 fp_p2p_online(port, job);
2753                                 mutex_exit(&port->fp_mutex);
2754                                 break;
2755 
2756                         default:
2757                                 if (--port->fp_statec_busy != 0) {
2758                                         /*
2759                                          * Watch curiously at what the next
2760                                          * state transition can do.
2761                                          */
2762                                         mutex_exit(&port->fp_mutex);
2763                                         break;
2764                                 }
2765 
2766                                 FP_TRACE(FP_NHEAD2(9, 0),
2767                                     "Topology Unknown, Offlining the port..");
2768 
2769                                 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
2770                                 port->fp_state = FC_STATE_OFFLINE;
2771 
2772                                 if (port->fp_offline_tid == NULL) {
2773                                         port->fp_offline_tid =
2774                                             timeout(fp_offline_timeout,
2775                                             (caddr_t)port, fp_offline_ticks);
2776                                 }
2777                                 mutex_exit(&port->fp_mutex);
2778                                 break;
2779                         }
2780 
2781                         mutex_enter(&port->fp_mutex);
2782 
2783                         port->fp_task = port->fp_last_task;
2784                         port->fp_last_task = FP_TASK_IDLE;
2785 
2786                         mutex_exit(&port->fp_mutex);
2787 
2788                         fctl_jobdone(job);
2789                         break;
2790                 }
2791 
2792                 case JOB_PLOGI_GROUP: {
2793                         mutex_exit(&port->fp_mutex);
2794                         fp_plogi_group(port, job);
2795                         break;
2796                 }
2797 
2798                 case JOB_UNSOL_REQUEST: {
2799                         mutex_exit(&port->fp_mutex);
2800                         fp_handle_unsol_buf(port,
2801                             (fc_unsol_buf_t *)job->job_private, job);
2802                         fctl_dealloc_job(job);
2803                         break;
2804                 }
2805 
2806                 case JOB_NS_CMD: {
2807                         fctl_ns_req_t *ns_cmd;
2808 
2809                         mutex_exit(&port->fp_mutex);
2810 
2811                         job->job_flags |= JOB_TYPE_FP_ASYNC;
2812                         ns_cmd = (fctl_ns_req_t *)job->job_private;
2813                         if (ns_cmd->ns_cmd_code < NS_GA_NXT ||
2814                             ns_cmd->ns_cmd_code > NS_DA_ID) {
2815                                 job->job_result = FC_BADCMD;
2816                                 fctl_jobdone(job);
2817                                 break;
2818                         }
2819 
2820                         if (FC_IS_CMD_A_REG(ns_cmd->ns_cmd_code)) {
2821                                 if (ns_cmd->ns_pd != NULL) {
2822                                         job->job_result = FC_BADOBJECT;
2823                                         fctl_jobdone(job);
2824                                         break;
2825                                 }
2826 
2827                                 job->job_counter = 1;
2828 
2829                                 rval = fp_ns_reg(port, ns_cmd->ns_pd,
2830                                     ns_cmd->ns_cmd_code, job, 0, KM_SLEEP);
2831 
2832                                 if (rval != FC_SUCCESS) {
2833                                         job->job_result = rval;
2834                                         fctl_jobdone(job);
2835                                 }
2836                                 break;
2837                         }
2838                         job->job_result = FC_SUCCESS;
2839                         job->job_counter = 1;
2840 
2841                         rval = fp_ns_query(port, ns_cmd, job, 0, KM_SLEEP);
2842                         if (rval != FC_SUCCESS) {
2843                                 fctl_jobdone(job);
2844                         }
2845                         break;
2846                 }
2847 
2848                 case JOB_LINK_RESET: {
2849                         la_wwn_t *pwwn;
2850                         uint32_t topology;
2851 
2852                         pwwn = (la_wwn_t *)job->job_private;
2853                         ASSERT(pwwn != NULL);
2854 
2855                         topology = port->fp_topology;
2856                         mutex_exit(&port->fp_mutex);
2857 
2858                         if (fctl_is_wwn_zero(pwwn) == FC_SUCCESS ||
2859                             topology == FC_TOP_PRIVATE_LOOP) {
2860                                 job->job_flags |= JOB_TYPE_FP_ASYNC;
2861                                 rval = port->fp_fca_tran->fca_reset(
2862                                     port->fp_fca_handle, FC_FCA_LINK_RESET);
2863                                 job->job_result = rval;
2864                                 fp_jobdone(job);
2865                         } else {
2866                                 ASSERT((job->job_flags &
2867                                     JOB_TYPE_FP_ASYNC) == 0);
2868 
2869                                 if (FC_IS_TOP_SWITCH(topology)) {
2870                                         rval = fp_remote_lip(port, pwwn,
2871                                             KM_SLEEP, job);
2872                                 } else {
2873                                         rval = FC_FAILURE;
2874                                 }
2875                                 if (rval != FC_SUCCESS) {
2876                                         job->job_result = rval;
2877                                 }
2878                                 fctl_jobdone(job);
2879                         }
2880                         break;
2881                 }
2882 
2883                 default:
2884                         mutex_exit(&port->fp_mutex);
2885                         job->job_result = FC_BADCMD;
2886                         fctl_jobdone(job);
2887                         break;
2888                 }
2889         }
2890         /* NOTREACHED */
2891 }
2892 
2893 
2894 /*
2895  * Perform FC port bring up initialization
2896  */
2897 static int
2898 fp_port_startup(fc_local_port_t *port, job_request_t *job)
2899 {
2900         int             rval;
2901         uint32_t        state;
2902         uint32_t        src_id;
2903         fc_lilpmap_t    *lilp_map;
2904 
2905         ASSERT(MUTEX_HELD(&port->fp_mutex));
2906         ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
2907 
2908         FP_DTRACE(FP_NHEAD1(2, 0), "Entering fp_port_startup;"
2909             " port=%p, job=%p", port, job);
2910 
2911         port->fp_topology = FC_TOP_UNKNOWN;
2912         port->fp_port_id.port_id = 0;
2913         state = FC_PORT_STATE_MASK(port->fp_state);
2914 
2915         if (state == FC_STATE_OFFLINE) {
2916                 port->fp_port_type.port_type = FC_NS_PORT_UNKNOWN;
2917                 job->job_result = FC_OFFLINE;
2918                 mutex_exit(&port->fp_mutex);
2919                 fctl_jobdone(job);
2920                 mutex_enter(&port->fp_mutex);
2921                 return (FC_OFFLINE);
2922         }
2923 
2924         if (state == FC_STATE_LOOP) {
2925                 port->fp_port_type.port_type = FC_NS_PORT_NL;
2926                 mutex_exit(&port->fp_mutex);
2927 
2928                 lilp_map = &port->fp_lilp_map;
2929                 if ((rval = fp_get_lilpmap(port, lilp_map)) != FC_SUCCESS) {
2930                         job->job_result = FC_FAILURE;
2931                         fctl_jobdone(job);
2932 
2933                         FP_TRACE(FP_NHEAD1(9, rval),
2934                             "LILP map Invalid or not present");
2935                         mutex_enter(&port->fp_mutex);
2936                         return (FC_FAILURE);
2937                 }
2938 
2939                 if (lilp_map->lilp_length == 0) {
2940                         job->job_result = FC_NO_MAP;
2941                         fctl_jobdone(job);
2942                         fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
2943                             "LILP map length zero");
2944                         mutex_enter(&port->fp_mutex);
2945                         return (FC_NO_MAP);
2946                 }
2947                 src_id = lilp_map->lilp_myalpa & 0xFF;
2948         } else {
2949                 fc_remote_port_t        *pd;
2950                 fc_fca_pm_t             pm;
2951                 fc_fca_p2p_info_t       p2p_info;
2952                 int                     pd_recepient;
2953 
2954                 /*
2955                  * Get P2P remote port info if possible
2956                  */
2957                 bzero((caddr_t)&pm, sizeof (pm));
2958 
2959                 pm.pm_cmd_flags = FC_FCA_PM_READ;
2960                 pm.pm_cmd_code = FC_PORT_GET_P2P_INFO;
2961                 pm.pm_data_len = sizeof (fc_fca_p2p_info_t);
2962                 pm.pm_data_buf = (caddr_t)&p2p_info;
2963 
2964                 rval = port->fp_fca_tran->fca_port_manage(
2965                     port->fp_fca_handle, &pm);
2966 
2967                 if (rval == FC_SUCCESS) {
2968                         port->fp_port_id.port_id = p2p_info.fca_d_id;
2969                         port->fp_port_type.port_type = FC_NS_PORT_N;
2970                         port->fp_topology = FC_TOP_PT_PT;
2971                         port->fp_total_devices = 1;
2972                         pd_recepient = fctl_wwn_cmp(
2973                             &port->fp_service_params.nport_ww_name,
2974                             &p2p_info.pwwn) < 0 ?
2975                             PD_PLOGI_RECEPIENT : PD_PLOGI_INITIATOR;
2976                         mutex_exit(&port->fp_mutex);
2977                         pd = fctl_create_remote_port(port,
2978                             &p2p_info.nwwn,
2979                             &p2p_info.pwwn,
2980                             p2p_info.d_id,
2981                             pd_recepient, KM_NOSLEEP);
2982                         FP_DTRACE(FP_NHEAD1(2, 0), "Exiting fp_port_startup;"
2983                             " P2P port=%p pd=%p fp %x pd %x", port, pd,
2984                             port->fp_port_id.port_id, p2p_info.d_id);
2985                         mutex_enter(&port->fp_mutex);
2986                         return (FC_SUCCESS);
2987                 }
2988                 port->fp_port_type.port_type = FC_NS_PORT_N;
2989                 mutex_exit(&port->fp_mutex);
2990                 src_id = 0;
2991         }
2992 
2993         job->job_counter = 1;
2994         job->job_result = FC_SUCCESS;
2995 
2996         if ((rval = fp_fabric_login(port, src_id, job, FP_CMD_PLOGI_DONT_CARE,
2997             KM_SLEEP)) != FC_SUCCESS) {
2998                 port->fp_port_type.port_type = FC_NS_PORT_UNKNOWN;
2999                 job->job_result = FC_FAILURE;
3000                 fctl_jobdone(job);
3001 
3002                 mutex_enter(&port->fp_mutex);
3003                 if (port->fp_statec_busy <= 1) {
3004                         mutex_exit(&port->fp_mutex);
3005                         fp_printf(port, CE_NOTE, FP_LOG_ONLY, rval, NULL,
3006                             "Couldn't transport FLOGI");
3007                         mutex_enter(&port->fp_mutex);
3008                 }
3009                 return (FC_FAILURE);
3010         }
3011 
3012         fp_jobwait(job);
3013 
3014         mutex_enter(&port->fp_mutex);
3015         if (job->job_result == FC_SUCCESS) {
3016                 if (FC_IS_TOP_SWITCH(port->fp_topology)) {
3017                         mutex_exit(&port->fp_mutex);
3018                         fp_ns_init(port, job, KM_SLEEP);
3019                         mutex_enter(&port->fp_mutex);
3020                 }
3021         } else {
3022                 if (state == FC_STATE_LOOP) {
3023                         port->fp_topology = FC_TOP_PRIVATE_LOOP;
3024                         port->fp_port_id.port_id =
3025                             port->fp_lilp_map.lilp_myalpa & 0xFF;
3026                 }
3027         }
3028 
3029         FP_DTRACE(FP_NHEAD1(2, 0), "Exiting fp_port_startup; port=%p, job=%p",
3030             port, job);
3031 
3032         return (FC_SUCCESS);
3033 }
3034 
3035 
3036 /*
3037  * Perform ULP invocations following FC port startup
3038  */
3039 /* ARGSUSED */
3040 static void
3041 fp_startup_done(opaque_t arg, uchar_t result)
3042 {
3043         fc_local_port_t *port = arg;
3044 
3045         fp_attach_ulps(port, FC_CMD_ATTACH);
3046 
3047         FP_DTRACE(FP_NHEAD1(2, 0), "fp_startup almost complete; port=%p", port);
3048 }
3049 
3050 
3051 /*
3052  * Perform ULP port attach
3053  */
3054 static void
3055 fp_ulp_port_attach(void *arg)
3056 {
3057         fp_soft_attach_t *att = (fp_soft_attach_t *)arg;
3058         fc_local_port_t  *port = att->att_port;
3059 
3060         FP_DTRACE(FP_NHEAD1(1, 0), "port attach of"
3061             " ULPs begin; port=%p, cmd=%x", port, att->att_cmd);
3062 
3063         fctl_attach_ulps(att->att_port, att->att_cmd, &modlinkage);
3064 
3065         if (att->att_need_pm_idle == B_TRUE) {
3066                 fctl_idle_port(port);
3067         }
3068 
3069         FP_DTRACE(FP_NHEAD1(1, 0), "port attach of"
3070             " ULPs end; port=%p, cmd=%x", port, att->att_cmd);
3071 
3072         mutex_enter(&att->att_port->fp_mutex);
3073         att->att_port->fp_ulp_attach = 0;
3074 
3075         port->fp_task = port->fp_last_task;
3076         port->fp_last_task = FP_TASK_IDLE;
3077 
3078         cv_signal(&att->att_port->fp_attach_cv);
3079 
3080         mutex_exit(&att->att_port->fp_mutex);
3081 
3082         kmem_free(att, sizeof (fp_soft_attach_t));
3083 }
3084 
3085 /*
3086  * Entry point to funnel all requests down to FCAs
3087  */
3088 static int
3089 fp_sendcmd(fc_local_port_t *port, fp_cmd_t *cmd, opaque_t fca_handle)
3090 {
3091         int rval;
3092 
3093         mutex_enter(&port->fp_mutex);
3094         if (port->fp_statec_busy > 1 || (cmd->cmd_ulp_pkt != NULL &&
3095             (port->fp_statec_busy || FC_PORT_STATE_MASK(port->fp_state) ==
3096             FC_STATE_OFFLINE))) {
3097                 /*
3098                  * This means there is more than one state change
3099                  * at this point of time - Since they are processed
3100                  * serially, any processing of the current one should
3101                  * be failed, failed and move up in processing the next
3102                  */
3103                 cmd->cmd_pkt.pkt_state = FC_PKT_ELS_IN_PROGRESS;
3104                 cmd->cmd_pkt.pkt_reason = FC_REASON_OFFLINE;
3105                 if (cmd->cmd_job) {
3106                         /*
3107                          * A state change that is going to be invalidated
3108                          * by another one already in the port driver's queue
3109                          * need not go up to all ULPs. This will minimize
3110                          * needless processing and ripples in ULP modules
3111                          */
3112                         cmd->cmd_job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION;
3113                 }
3114                 mutex_exit(&port->fp_mutex);
3115                 return (FC_STATEC_BUSY);
3116         }
3117 
3118         if (FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) {
3119                 cmd->cmd_pkt.pkt_state = FC_PKT_PORT_OFFLINE;
3120                 cmd->cmd_pkt.pkt_reason = FC_REASON_OFFLINE;
3121                 mutex_exit(&port->fp_mutex);
3122 
3123                 return (FC_OFFLINE);
3124         }
3125         mutex_exit(&port->fp_mutex);
3126 
3127         rval = cmd->cmd_transport(fca_handle, &cmd->cmd_pkt);
3128         if (rval != FC_SUCCESS) {
3129                 if (rval == FC_TRAN_BUSY) {
3130                         cmd->cmd_retry_interval = fp_retry_delay;
3131                         rval = fp_retry_cmd(&cmd->cmd_pkt);
3132                         if (rval == FC_FAILURE) {
3133                                 cmd->cmd_pkt.pkt_state = FC_PKT_TRAN_BSY;
3134                         }
3135                 }
3136         } else {
3137                 mutex_enter(&port->fp_mutex);
3138                 port->fp_out_fpcmds++;
3139                 mutex_exit(&port->fp_mutex);
3140         }
3141 
3142         return (rval);
3143 }
3144 
3145 
3146 /*
3147  * Each time a timeout kicks in, walk the wait queue, decrement the
3148  * the retry_interval, when the retry_interval becomes less than
3149  * or equal to zero, re-transport the command: If the re-transport
3150  * fails with BUSY, enqueue the command in the wait queue.
3151  *
3152  * In order to prevent looping forever because of commands enqueued
3153  * from within this function itself, save the current tail pointer
3154  * (in cur_tail) and exit the loop after serving this command.
3155  */
3156 static void
3157 fp_resendcmd(void *port_handle)
3158 {
3159         int             rval;
3160         fc_local_port_t *port;
3161         fp_cmd_t        *cmd;
3162         fp_cmd_t        *cur_tail;
3163 
3164         port = port_handle;
3165         mutex_enter(&port->fp_mutex);
3166         cur_tail = port->fp_wait_tail;
3167         mutex_exit(&port->fp_mutex);
3168 
3169         while ((cmd = fp_deque_cmd(port)) != NULL) {
3170                 cmd->cmd_retry_interval -= fp_retry_ticker;
3171                 /* Check if we are detaching */
3172                 if (port->fp_soft_state &
3173                     (FP_SOFT_IN_DETACH | FP_DETACH_INPROGRESS)) {
3174                         cmd->cmd_pkt.pkt_state = FC_PKT_TRAN_ERROR;
3175                         cmd->cmd_pkt.pkt_reason = 0;
3176                         fp_iodone(cmd);
3177                 } else if (cmd->cmd_retry_interval <= 0) {
3178                         rval = cmd->cmd_transport(port->fp_fca_handle,
3179                             &cmd->cmd_pkt);
3180 
3181                         if (rval != FC_SUCCESS) {
3182                                 if (cmd->cmd_pkt.pkt_state == FC_PKT_TRAN_BSY) {
3183                                         if (--cmd->cmd_retry_count) {
3184                                                 fp_enque_cmd(port, cmd);
3185                                                 if (cmd == cur_tail) {
3186                                                         break;
3187                                                 }
3188                                                 continue;
3189                                         }
3190                                         cmd->cmd_pkt.pkt_state =
3191                                             FC_PKT_TRAN_BSY;
3192                                 } else {
3193                                         cmd->cmd_pkt.pkt_state =
3194                                             FC_PKT_TRAN_ERROR;
3195                                 }
3196                                 cmd->cmd_pkt.pkt_reason = 0;
3197                                 fp_iodone(cmd);
3198                         } else {
3199                                 mutex_enter(&port->fp_mutex);
3200                                 port->fp_out_fpcmds++;
3201                                 mutex_exit(&port->fp_mutex);
3202                         }
3203                 } else {
3204                         fp_enque_cmd(port, cmd);
3205                 }
3206 
3207                 if (cmd == cur_tail) {
3208                         break;
3209                 }
3210         }
3211 
3212         mutex_enter(&port->fp_mutex);
3213         if (port->fp_wait_head) {
3214                 timeout_id_t tid;
3215 
3216                 mutex_exit(&port->fp_mutex);
3217                 tid = timeout(fp_resendcmd, (caddr_t)port,
3218                     fp_retry_ticks);
3219                 mutex_enter(&port->fp_mutex);
3220                 port->fp_wait_tid = tid;
3221         } else {
3222                 port->fp_wait_tid = NULL;
3223         }
3224         mutex_exit(&port->fp_mutex);
3225 }
3226 
3227 
3228 /*
3229  * Handle Local, Fabric, N_Port, Transport (whatever that means) BUSY here.
3230  *
3231  * Yes, as you can see below, cmd_retry_count is used here too.  That means
3232  * the retries for BUSY are less if there were transport failures (transport
3233  * failure means fca_transport failure). The goal is not to exceed overall
3234  * retries set in the cmd_retry_count (whatever may be the reason for retry)
3235  *
3236  * Return Values:
3237  *      FC_SUCCESS
3238  *      FC_FAILURE
3239  */
3240 static int
3241 fp_retry_cmd(fc_packet_t *pkt)
3242 {
3243         fp_cmd_t *cmd;
3244 
3245         cmd = pkt->pkt_ulp_private;
3246 
3247         if (--cmd->cmd_retry_count) {
3248                 fp_enque_cmd(cmd->cmd_port, cmd);
3249                 return (FC_SUCCESS);
3250         } else {
3251                 return (FC_FAILURE);
3252         }
3253 }
3254 
3255 
3256 /*
3257  * Queue up FC packet for deferred retry
3258  */
3259 static void
3260 fp_enque_cmd(fc_local_port_t *port, fp_cmd_t *cmd)
3261 {
3262         timeout_id_t tid;
3263 
3264         ASSERT(!MUTEX_HELD(&port->fp_mutex));
3265 
3266 #ifdef  DEBUG
3267         fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, &cmd->cmd_pkt,
3268             "Retrying ELS for %x", cmd->cmd_pkt.pkt_cmd_fhdr.d_id);
3269 #endif
3270 
3271         mutex_enter(&port->fp_mutex);
3272         if (port->fp_wait_tail) {
3273                 port->fp_wait_tail->cmd_next = cmd;
3274                 port->fp_wait_tail = cmd;
3275         } else {
3276                 ASSERT(port->fp_wait_head == NULL);
3277                 port->fp_wait_head = port->fp_wait_tail = cmd;
3278                 if (port->fp_wait_tid == NULL) {
3279                         mutex_exit(&port->fp_mutex);
3280                         tid = timeout(fp_resendcmd, (caddr_t)port,
3281                             fp_retry_ticks);
3282                         mutex_enter(&port->fp_mutex);
3283                         port->fp_wait_tid = tid;
3284                 }
3285         }
3286         mutex_exit(&port->fp_mutex);
3287 }
3288 
3289 
3290 /*
3291  * Handle all RJT codes
3292  */
3293 static int
3294 fp_handle_reject(fc_packet_t *pkt)
3295 {
3296         int             rval = FC_FAILURE;
3297         uchar_t         next_class;
3298         fp_cmd_t        *cmd;
3299         fc_local_port_t *port;
3300 
3301         cmd = pkt->pkt_ulp_private;
3302         port = cmd->cmd_port;
3303 
3304         switch (pkt->pkt_state) {
3305         case FC_PKT_FABRIC_RJT:
3306         case FC_PKT_NPORT_RJT:
3307                 if (pkt->pkt_reason == FC_REASON_CLASS_NOT_SUPP) {
3308                         next_class = fp_get_nextclass(cmd->cmd_port,
3309                             FC_TRAN_CLASS(pkt->pkt_tran_flags));
3310 
3311                         if (next_class == FC_TRAN_CLASS_INVALID) {
3312                                 return (rval);
3313                         }
3314                         pkt->pkt_tran_flags = FC_TRAN_INTR | next_class;
3315                         pkt->pkt_tran_type = FC_PKT_EXCHANGE;
3316 
3317                         rval = fp_sendcmd(cmd->cmd_port, cmd,
3318                             cmd->cmd_port->fp_fca_handle);
3319 
3320                         if (rval != FC_SUCCESS) {
3321                                 pkt->pkt_state = FC_PKT_TRAN_ERROR;
3322                         }
3323                 }
3324                 break;
3325 
3326         case FC_PKT_LS_RJT:
3327         case FC_PKT_BA_RJT:
3328                 if ((pkt->pkt_reason == FC_REASON_LOGICAL_ERROR) ||
3329                     (pkt->pkt_reason == FC_REASON_LOGICAL_BSY)) {
3330                         cmd->cmd_retry_interval = fp_retry_delay;
3331                         rval = fp_retry_cmd(pkt);
3332                 }
3333                 break;
3334 
3335         case FC_PKT_FS_RJT:
3336                 if ((pkt->pkt_reason == FC_REASON_FS_LOGICAL_BUSY) ||
3337                     ((pkt->pkt_reason == FC_REASON_FS_CMD_UNABLE) &&
3338                     (pkt->pkt_expln == 0x00))) {
3339                         cmd->cmd_retry_interval = fp_retry_delay;
3340                         rval = fp_retry_cmd(pkt);
3341                 }
3342                 break;
3343 
3344         case FC_PKT_LOCAL_RJT:
3345                 if (pkt->pkt_reason == FC_REASON_QFULL) {
3346                         cmd->cmd_retry_interval = fp_retry_delay;
3347                         rval = fp_retry_cmd(pkt);
3348                 }
3349                 break;
3350 
3351         default:
3352                 FP_TRACE(FP_NHEAD1(1, 0),
3353                     "fp_handle_reject(): Invalid pkt_state");
3354                 break;
3355         }
3356 
3357         return (rval);
3358 }
3359 
3360 
3361 /*
3362  * Return the next class of service supported by the FCA
3363  */
3364 static uchar_t
3365 fp_get_nextclass(fc_local_port_t *port, uchar_t cur_class)
3366 {
3367         uchar_t next_class;
3368 
3369         ASSERT(!MUTEX_HELD(&port->fp_mutex));
3370 
3371         switch (cur_class) {
3372         case FC_TRAN_CLASS_INVALID:
3373                 if (port->fp_cos & FC_NS_CLASS1) {
3374                         next_class = FC_TRAN_CLASS1;
3375                         break;
3376                 }
3377                 /* FALLTHROUGH */
3378 
3379         case FC_TRAN_CLASS1:
3380                 if (port->fp_cos & FC_NS_CLASS2) {
3381                         next_class = FC_TRAN_CLASS2;
3382                         break;
3383                 }
3384                 /* FALLTHROUGH */
3385 
3386         case FC_TRAN_CLASS2:
3387                 if (port->fp_cos & FC_NS_CLASS3) {
3388                         next_class = FC_TRAN_CLASS3;
3389                         break;
3390                 }
3391                 /* FALLTHROUGH */
3392 
3393         case FC_TRAN_CLASS3:
3394         default:
3395                 next_class = FC_TRAN_CLASS_INVALID;
3396                 break;
3397         }
3398 
3399         return (next_class);
3400 }
3401 
3402 
3403 /*
3404  * Determine if a class of service is supported by the FCA
3405  */
3406 static int
3407 fp_is_class_supported(uint32_t cos, uchar_t tran_class)
3408 {
3409         int rval;
3410 
3411         switch (tran_class) {
3412         case FC_TRAN_CLASS1:
3413                 if (cos & FC_NS_CLASS1) {
3414                         rval = FC_SUCCESS;
3415                 } else {
3416                         rval = FC_FAILURE;
3417                 }
3418                 break;
3419 
3420         case FC_TRAN_CLASS2:
3421                 if (cos & FC_NS_CLASS2) {
3422                         rval = FC_SUCCESS;
3423                 } else {
3424                         rval = FC_FAILURE;
3425                 }
3426                 break;
3427 
3428         case FC_TRAN_CLASS3:
3429                 if (cos & FC_NS_CLASS3) {
3430                         rval = FC_SUCCESS;
3431                 } else {
3432                         rval = FC_FAILURE;
3433                 }
3434                 break;
3435 
3436         default:
3437                 rval = FC_FAILURE;
3438                 break;
3439         }
3440 
3441         return (rval);
3442 }
3443 
3444 
3445 /*
3446  * Dequeue FC packet for retry
3447  */
3448 static fp_cmd_t *
3449 fp_deque_cmd(fc_local_port_t *port)
3450 {
3451         fp_cmd_t *cmd;
3452 
3453         ASSERT(!MUTEX_HELD(&port->fp_mutex));
3454 
3455         mutex_enter(&port->fp_mutex);
3456 
3457         if (port->fp_wait_head == NULL) {
3458                 /*
3459                  * To avoid races, NULL the fp_wait_tid as
3460                  * we are about to exit the timeout thread.
3461                  */
3462                 port->fp_wait_tid = NULL;
3463                 mutex_exit(&port->fp_mutex);
3464                 return (NULL);
3465         }
3466 
3467         cmd = port->fp_wait_head;
3468         port->fp_wait_head = cmd->cmd_next;
3469         cmd->cmd_next = NULL;
3470 
3471         if (port->fp_wait_head == NULL) {
3472                 port->fp_wait_tail = NULL;
3473         }
3474         mutex_exit(&port->fp_mutex);
3475 
3476         return (cmd);
3477 }
3478 
3479 
3480 /*
3481  * Wait for job completion
3482  */
3483 static void
3484 fp_jobwait(job_request_t *job)
3485 {
3486         sema_p(&job->job_port_sema);
3487 }
3488 
3489 
3490 /*
3491  * Convert FC packet state to FC errno
3492  */
3493 int
3494 fp_state_to_rval(uchar_t state)
3495 {
3496         int count;
3497 
3498         for (count = 0; count < sizeof (fp_xlat) /
3499             sizeof (fp_xlat[0]); count++) {
3500                 if (fp_xlat[count].xlat_state == state) {
3501                         return (fp_xlat[count].xlat_rval);
3502                 }
3503         }
3504 
3505         return (FC_FAILURE);
3506 }
3507 
3508 
3509 /*
3510  * For Synchronous I/O requests, the caller is
3511  * expected to do fctl_jobdone(if necessary)
3512  *
3513  * We want to preserve at least one failure in the
3514  * job_result if it happens.
3515  *
3516  */
3517 static void
3518 fp_iodone(fp_cmd_t *cmd)
3519 {
3520         fc_packet_t             *ulp_pkt = cmd->cmd_ulp_pkt;
3521         job_request_t           *job = cmd->cmd_job;
3522         fc_remote_port_t        *pd = cmd->cmd_pkt.pkt_pd;
3523 
3524         ASSERT(job != NULL);
3525         ASSERT(cmd->cmd_port != NULL);
3526         ASSERT(&cmd->cmd_pkt != NULL);
3527 
3528         mutex_enter(&job->job_mutex);
3529         if (job->job_result == FC_SUCCESS) {
3530                 job->job_result = fp_state_to_rval(cmd->cmd_pkt.pkt_state);
3531         }
3532         mutex_exit(&job->job_mutex);
3533 
3534         if (pd) {
3535                 mutex_enter(&pd->pd_mutex);
3536                 pd->pd_flags = PD_IDLE;
3537                 mutex_exit(&pd->pd_mutex);
3538         }
3539 
3540         if (ulp_pkt) {
3541                 if (pd && cmd->cmd_flags & FP_CMD_DELDEV_ON_ERROR &&
3542                     FP_IS_PKT_ERROR(ulp_pkt)) {
3543                         fc_local_port_t         *port;
3544                         fc_remote_node_t        *node;
3545 
3546                         port = cmd->cmd_port;
3547 
3548                         mutex_enter(&pd->pd_mutex);
3549                         pd->pd_state = PORT_DEVICE_INVALID;
3550                         pd->pd_ref_count--;
3551                         node = pd->pd_remote_nodep;
3552                         mutex_exit(&pd->pd_mutex);
3553 
3554                         ASSERT(node != NULL);
3555                         ASSERT(port != NULL);
3556 
3557                         if (fctl_destroy_remote_port(port, pd) == 0) {
3558                                 fctl_destroy_remote_node(node);
3559                         }
3560 
3561                         ulp_pkt->pkt_pd = NULL;
3562                 }
3563 
3564                 ulp_pkt->pkt_comp(ulp_pkt);
3565         }
3566 
3567         fp_free_pkt(cmd);
3568         fp_jobdone(job);
3569 }
3570 
3571 
3572 /*
3573  * Job completion handler
3574  */
3575 static void
3576 fp_jobdone(job_request_t *job)
3577 {
3578         mutex_enter(&job->job_mutex);
3579         ASSERT(job->job_counter > 0);
3580 
3581         if (--job->job_counter != 0) {
3582                 mutex_exit(&job->job_mutex);
3583                 return;
3584         }
3585 
3586         if (job->job_ulp_pkts) {
3587                 ASSERT(job->job_ulp_listlen > 0);
3588                 kmem_free(job->job_ulp_pkts,
3589                     sizeof (fc_packet_t *) * job->job_ulp_listlen);
3590         }
3591 
3592         if (job->job_flags & JOB_TYPE_FP_ASYNC) {
3593                 mutex_exit(&job->job_mutex);
3594                 fctl_jobdone(job);
3595         } else {
3596                 mutex_exit(&job->job_mutex);
3597                 sema_v(&job->job_port_sema);
3598         }
3599 }
3600 
3601 
3602 /*
3603  * Try to perform shutdown of a port during a detach. No return
3604  * value since the detach should not fail because the port shutdown
3605  * failed.
3606  */
3607 static void
3608 fp_port_shutdown(fc_local_port_t *port, job_request_t *job)
3609 {
3610         int                     index;
3611         int                     count;
3612         int                     flags;
3613         fp_cmd_t                *cmd;
3614         struct pwwn_hash        *head;
3615         fc_remote_port_t        *pd;
3616 
3617         ASSERT(MUTEX_HELD(&port->fp_mutex));
3618 
3619         job->job_result = FC_SUCCESS;
3620 
3621         if (port->fp_taskq) {
3622                 /*
3623                  * We must release the mutex here to ensure that other
3624                  * potential jobs can complete their processing.  Many
3625                  * also need this mutex.
3626                  */
3627                 mutex_exit(&port->fp_mutex);
3628                 taskq_wait(port->fp_taskq);
3629                 mutex_enter(&port->fp_mutex);
3630         }
3631 
3632         if (port->fp_offline_tid) {
3633                 timeout_id_t tid;
3634 
3635                 tid = port->fp_offline_tid;
3636                 port->fp_offline_tid = NULL;
3637                 mutex_exit(&port->fp_mutex);
3638                 (void) untimeout(tid);
3639                 mutex_enter(&port->fp_mutex);
3640         }
3641 
3642         if (port->fp_wait_tid) {
3643                 timeout_id_t tid;
3644 
3645                 tid = port->fp_wait_tid;
3646                 port->fp_wait_tid = NULL;
3647                 mutex_exit(&port->fp_mutex);
3648                 (void) untimeout(tid);
3649         } else {
3650                 mutex_exit(&port->fp_mutex);
3651         }
3652 
3653         /*
3654          * While we cancel the timeout, let's also return the
3655          * the outstanding requests back to the callers.
3656          */
3657         while ((cmd = fp_deque_cmd(port)) != NULL) {
3658                 ASSERT(cmd->cmd_job != NULL);
3659                 cmd->cmd_job->job_result = FC_OFFLINE;
3660                 fp_iodone(cmd);
3661         }
3662 
3663         /*
3664          * Gracefully LOGO with all the devices logged in.
3665          */
3666         mutex_enter(&port->fp_mutex);
3667 
3668         for (count = index = 0; index < pwwn_table_size; index++) {
3669                 head = &port->fp_pwwn_table[index];
3670                 pd = head->pwwn_head;
3671                 while (pd != NULL) {
3672                         mutex_enter(&pd->pd_mutex);
3673                         if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
3674                                 count++;
3675                         }
3676                         mutex_exit(&pd->pd_mutex);
3677                         pd = pd->pd_wwn_hnext;
3678                 }
3679         }
3680 
3681         if (job->job_flags & JOB_TYPE_FP_ASYNC) {
3682                 flags = job->job_flags;
3683                 job->job_flags &= ~JOB_TYPE_FP_ASYNC;
3684         } else {
3685                 flags = 0;
3686         }
3687         if (count) {
3688                 job->job_counter = count;
3689 
3690                 for (index = 0; index < pwwn_table_size; index++) {
3691                         head = &port->fp_pwwn_table[index];
3692                         pd = head->pwwn_head;
3693                         while (pd != NULL) {
3694                                 mutex_enter(&pd->pd_mutex);
3695                                 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
3696                                         ASSERT(pd->pd_login_count > 0);
3697                                         /*
3698                                          * Force the counter to ONE in order
3699                                          * for us to really send LOGO els.
3700                                          */
3701                                         pd->pd_login_count = 1;
3702                                         mutex_exit(&pd->pd_mutex);
3703                                         mutex_exit(&port->fp_mutex);
3704                                         (void) fp_logout(port, pd, job);
3705                                         mutex_enter(&port->fp_mutex);
3706                                 } else {
3707                                         mutex_exit(&pd->pd_mutex);
3708                                 }
3709                                 pd = pd->pd_wwn_hnext;
3710                         }
3711                 }
3712                 mutex_exit(&port->fp_mutex);
3713                 fp_jobwait(job);
3714         } else {
3715                 mutex_exit(&port->fp_mutex);
3716         }
3717 
3718         if (job->job_result != FC_SUCCESS) {
3719                 FP_TRACE(FP_NHEAD1(9, 0),
3720                     "Can't logout all devices. Proceeding with"
3721                     " port shutdown");
3722                 job->job_result = FC_SUCCESS;
3723         }
3724 
3725         fctl_destroy_all_remote_ports(port);
3726 
3727         mutex_enter(&port->fp_mutex);
3728         if (FC_IS_TOP_SWITCH(port->fp_topology)) {
3729                 mutex_exit(&port->fp_mutex);
3730                 fp_ns_fini(port, job);
3731         } else {
3732                 mutex_exit(&port->fp_mutex);
3733         }
3734 
3735         if (flags) {
3736                 job->job_flags = flags;
3737         }
3738 
3739         mutex_enter(&port->fp_mutex);
3740 
3741 }
3742 
3743 
3744 /*
3745  * Build the port driver's data structures based on the AL_PA list
3746  */
3747 static void
3748 fp_get_loopmap(fc_local_port_t *port, job_request_t *job)
3749 {
3750         int                     rval;
3751         int                     flag;
3752         int                     count;
3753         uint32_t                d_id;
3754         fc_remote_port_t        *pd;
3755         fc_lilpmap_t            *lilp_map;
3756 
3757         ASSERT(MUTEX_HELD(&port->fp_mutex));
3758 
3759         if (FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) {
3760                 job->job_result = FC_OFFLINE;
3761                 mutex_exit(&port->fp_mutex);
3762                 fp_jobdone(job);
3763                 mutex_enter(&port->fp_mutex);
3764                 return;
3765         }
3766 
3767         if (port->fp_lilp_map.lilp_length == 0) {
3768                 mutex_exit(&port->fp_mutex);
3769                 job->job_result = FC_NO_MAP;
3770                 fp_jobdone(job);
3771                 mutex_enter(&port->fp_mutex);
3772                 return;
3773         }
3774         mutex_exit(&port->fp_mutex);
3775 
3776         lilp_map = &port->fp_lilp_map;
3777         job->job_counter = lilp_map->lilp_length;
3778 
3779         if (job->job_code == JOB_PORT_GETMAP_PLOGI_ALL) {
3780                 flag = FP_CMD_PLOGI_RETAIN;
3781         } else {
3782                 flag = FP_CMD_PLOGI_DONT_CARE;
3783         }
3784 
3785         for (count = 0; count < lilp_map->lilp_length; count++) {
3786                 d_id = lilp_map->lilp_alpalist[count];
3787 
3788                 if (d_id == (lilp_map->lilp_myalpa & 0xFF)) {
3789                         fp_jobdone(job);
3790                         continue;
3791                 }
3792 
3793                 pd = fctl_get_remote_port_by_did(port, d_id);
3794                 if (pd) {
3795                         mutex_enter(&pd->pd_mutex);
3796                         if (flag == FP_CMD_PLOGI_DONT_CARE ||
3797                             pd->pd_state == PORT_DEVICE_LOGGED_IN) {
3798                                 mutex_exit(&pd->pd_mutex);
3799                                 fp_jobdone(job);
3800                                 continue;
3801                         }
3802                         mutex_exit(&pd->pd_mutex);
3803                 }
3804 
3805                 rval = fp_port_login(port, d_id, job, flag,
3806                     KM_SLEEP, pd, NULL);
3807                 if (rval != FC_SUCCESS) {
3808                         fp_jobdone(job);
3809                 }
3810         }
3811 
3812         mutex_enter(&port->fp_mutex);
3813 }
3814 
3815 
3816 /*
3817  * Perform loop ONLINE processing
3818  */
3819 static void
3820 fp_loop_online(fc_local_port_t *port, job_request_t *job, int orphan)
3821 {
3822         int                     count;
3823         int                     rval;
3824         uint32_t                d_id;
3825         uint32_t                listlen;
3826         fc_lilpmap_t            *lilp_map;
3827         fc_remote_port_t        *pd;
3828         fc_portmap_t            *changelist;
3829 
3830         ASSERT(!MUTEX_HELD(&port->fp_mutex));
3831 
3832         FP_TRACE(FP_NHEAD1(1, 0), "fp_loop_online begin; port=%p, job=%p",
3833             port, job);
3834 
3835         lilp_map = &port->fp_lilp_map;
3836 
3837         if (lilp_map->lilp_length) {
3838                 mutex_enter(&port->fp_mutex);
3839                 if (port->fp_soft_state & FP_SOFT_IN_FCA_RESET) {
3840                         port->fp_soft_state &= ~FP_SOFT_IN_FCA_RESET;
3841                         mutex_exit(&port->fp_mutex);
3842                         delay(drv_usectohz(PLDA_RR_TOV * 1000 * 1000));
3843                 } else {
3844                         mutex_exit(&port->fp_mutex);
3845                 }
3846 
3847                 job->job_counter = lilp_map->lilp_length;
3848 
3849                 for (count = 0; count < lilp_map->lilp_length; count++) {
3850                         d_id = lilp_map->lilp_alpalist[count];
3851 
3852                         if (d_id == (lilp_map->lilp_myalpa & 0xFF)) {
3853                                 fp_jobdone(job);
3854                                 continue;
3855                         }
3856 
3857                         pd = fctl_get_remote_port_by_did(port, d_id);
3858                         if (pd != NULL) {
3859 #ifdef  DEBUG
3860                                 mutex_enter(&pd->pd_mutex);
3861                                 if (pd->pd_recepient == PD_PLOGI_INITIATOR) {
3862                                         ASSERT(pd->pd_type != PORT_DEVICE_OLD);
3863                                 }
3864                                 mutex_exit(&pd->pd_mutex);
3865 #endif
3866                                 fp_jobdone(job);
3867                                 continue;
3868                         }
3869 
3870                         rval = fp_port_login(port, d_id, job,
3871                             FP_CMD_PLOGI_DONT_CARE, KM_SLEEP, pd, NULL);
3872 
3873                         if (rval != FC_SUCCESS) {
3874                                 fp_jobdone(job);
3875                         }
3876                 }
3877                 fp_jobwait(job);
3878         }
3879         listlen = 0;
3880         changelist = NULL;
3881 
3882         if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) {
3883                 mutex_enter(&port->fp_mutex);
3884                 ASSERT(port->fp_statec_busy > 0);
3885                 if (port->fp_statec_busy == 1) {
3886                         mutex_exit(&port->fp_mutex);
3887                         fctl_fillout_map(port, &changelist, &listlen,
3888                             1, 0, orphan);
3889 
3890                         mutex_enter(&port->fp_mutex);
3891                         if (port->fp_lilp_map.lilp_magic < MAGIC_LIRP) {
3892                                 ASSERT(port->fp_total_devices == 0);
3893                                 port->fp_total_devices = port->fp_dev_count;
3894                         }
3895                 } else {
3896                         job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION;
3897                 }
3898                 mutex_exit(&port->fp_mutex);
3899         }
3900 
3901         if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) {
3902                 (void) fp_ulp_statec_cb(port, FC_STATE_ONLINE, changelist,
3903                     listlen, listlen, KM_SLEEP);
3904         } else {
3905                 mutex_enter(&port->fp_mutex);
3906                 if (--port->fp_statec_busy == 0) {
3907                         port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
3908                 }
3909                 ASSERT(changelist == NULL && listlen == 0);
3910                 mutex_exit(&port->fp_mutex);
3911         }
3912 
3913         FP_TRACE(FP_NHEAD1(1, 0), "fp_loop_online end; port=%p, job=%p",
3914             port, job);
3915 }
3916 
3917 
3918 /*
3919  * Get an Arbitrated Loop map from the underlying FCA
3920  */
3921 static int
3922 fp_get_lilpmap(fc_local_port_t *port, fc_lilpmap_t *lilp_map)
3923 {
3924         int rval;
3925 
3926         FP_TRACE(FP_NHEAD1(1, 0), "fp_get_lilpmap Begin; port=%p, map=%p",
3927             port, lilp_map);
3928 
3929         bzero((caddr_t)lilp_map, sizeof (fc_lilpmap_t));
3930         rval = port->fp_fca_tran->fca_getmap(port->fp_fca_handle, lilp_map);
3931         lilp_map->lilp_magic &= 0xFF;    /* Ignore upper byte */
3932 
3933         if (rval != FC_SUCCESS) {
3934                 rval = FC_NO_MAP;
3935         } else if (lilp_map->lilp_length == 0 &&
3936             (lilp_map->lilp_magic >= MAGIC_LISM &&
3937             lilp_map->lilp_magic < MAGIC_LIRP)) {
3938                 uchar_t lilp_length;
3939 
3940                 /*
3941                  * Since the map length is zero, provide all
3942                  * the valid AL_PAs for NL_ports discovery.
3943                  */
3944                 lilp_length = sizeof (fp_valid_alpas) /
3945                     sizeof (fp_valid_alpas[0]);
3946                 lilp_map->lilp_length = lilp_length;
3947                 bcopy(fp_valid_alpas, lilp_map->lilp_alpalist,
3948                     lilp_length);
3949         } else {
3950                 rval = fp_validate_lilp_map(lilp_map);
3951 
3952                 if (rval == FC_SUCCESS) {
3953                         mutex_enter(&port->fp_mutex);
3954                         port->fp_total_devices = lilp_map->lilp_length - 1;
3955                         mutex_exit(&port->fp_mutex);
3956                 }
3957         }
3958 
3959         mutex_enter(&port->fp_mutex);
3960         if (rval != FC_SUCCESS && !(port->fp_soft_state & FP_SOFT_BAD_LINK)) {
3961                 port->fp_soft_state |= FP_SOFT_BAD_LINK;
3962                 mutex_exit(&port->fp_mutex);
3963 
3964                 if (port->fp_fca_tran->fca_reset(port->fp_fca_handle,
3965                     FC_FCA_RESET_CORE) != FC_SUCCESS) {
3966                         FP_TRACE(FP_NHEAD1(9, 0),
3967                             "FCA reset failed after LILP map was found"
3968                             " to be invalid");
3969                 }
3970         } else if (rval == FC_SUCCESS) {
3971                 port->fp_soft_state &= ~FP_SOFT_BAD_LINK;
3972                 mutex_exit(&port->fp_mutex);
3973         } else {
3974                 mutex_exit(&port->fp_mutex);
3975         }
3976 
3977         FP_TRACE(FP_NHEAD1(1, 0), "fp_get_lilpmap End; port=%p, map=%p", port,
3978             lilp_map);
3979 
3980         return (rval);
3981 }
3982 
3983 
3984 /*
3985  * Perform Fabric Login:
3986  *
3987  * Return Values:
3988  *              FC_SUCCESS
3989  *              FC_FAILURE
3990  *              FC_NOMEM
3991  *              FC_TRANSPORT_ERROR
3992  *              and a lot others defined in fc_error.h
3993  */
3994 static int
3995 fp_fabric_login(fc_local_port_t *port, uint32_t s_id, job_request_t *job,
3996     int flag, int sleep)
3997 {
3998         int             rval;
3999         fp_cmd_t        *cmd;
4000         uchar_t         class;
4001 
4002         ASSERT(!MUTEX_HELD(&port->fp_mutex));
4003 
4004         FP_TRACE(FP_NHEAD1(1, 0), "fp_fabric_login Begin; port=%p, job=%p",
4005             port, job);
4006 
4007         class = fp_get_nextclass(port, FC_TRAN_CLASS_INVALID);
4008         if (class == FC_TRAN_CLASS_INVALID) {
4009                 return (FC_ELS_BAD);
4010         }
4011 
4012         cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t),
4013             sizeof (la_els_logi_t), sleep, NULL);
4014         if (cmd == NULL) {
4015                 return (FC_NOMEM);
4016         }
4017 
4018         cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class;
4019         cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
4020         cmd->cmd_flags = flag;
4021         cmd->cmd_retry_count = fp_retry_count;
4022         cmd->cmd_ulp_pkt = NULL;
4023 
4024         fp_xlogi_init(port, cmd, s_id, 0xFFFFFE, fp_flogi_intr,
4025             job, LA_ELS_FLOGI);
4026 
4027         rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
4028         if (rval != FC_SUCCESS) {
4029                 fp_free_pkt(cmd);
4030         }
4031 
4032         FP_TRACE(FP_NHEAD1(1, 0), "fp_fabric_login End; port=%p, job=%p",
4033             port, job);
4034 
4035         return (rval);
4036 }
4037 
4038 
4039 /*
4040  * In some scenarios such as private loop device discovery period
4041  * the fc_remote_port_t data structure isn't allocated. The allocation
4042  * is done when the PLOGI is successful. In some other scenarios
4043  * such as Fabric topology, the fc_remote_port_t is already created
4044  * and initialized with appropriate values (as the NS provides
4045  * them)
4046  */
4047 static int
4048 fp_port_login(fc_local_port_t *port, uint32_t d_id, job_request_t *job,
4049     int cmd_flag, int sleep, fc_remote_port_t *pd, fc_packet_t *ulp_pkt)
4050 {
4051         uchar_t class;
4052         fp_cmd_t *cmd;
4053         uint32_t src_id;
4054         fc_remote_port_t *tmp_pd;
4055         int relogin;
4056         int found = 0;
4057 
4058 #ifdef  DEBUG
4059         if (pd == NULL) {
4060                 ASSERT(fctl_get_remote_port_by_did(port, d_id) == NULL);
4061         }
4062 #endif
4063         ASSERT(job->job_counter > 0);
4064 
4065         class = fp_get_nextclass(port, FC_TRAN_CLASS_INVALID);
4066         if (class == FC_TRAN_CLASS_INVALID) {
4067                 return (FC_ELS_BAD);
4068         }
4069 
4070         mutex_enter(&port->fp_mutex);
4071         tmp_pd = fctl_lookup_pd_by_did(port, d_id);
4072         mutex_exit(&port->fp_mutex);
4073 
4074         relogin = 1;
4075         if (tmp_pd) {
4076                 mutex_enter(&tmp_pd->pd_mutex);
4077                 if ((tmp_pd->pd_aux_flags & PD_DISABLE_RELOGIN) &&
4078                     !(tmp_pd->pd_aux_flags & PD_LOGGED_OUT)) {
4079                         tmp_pd->pd_state = PORT_DEVICE_LOGGED_IN;
4080                         relogin = 0;
4081                 }
4082                 mutex_exit(&tmp_pd->pd_mutex);
4083         }
4084 
4085         if (!relogin) {
4086                 mutex_enter(&tmp_pd->pd_mutex);
4087                 if (tmp_pd->pd_state == PORT_DEVICE_LOGGED_IN) {
4088                         cmd_flag |= FP_CMD_PLOGI_RETAIN;
4089                 }
4090                 mutex_exit(&tmp_pd->pd_mutex);
4091 
4092                 cmd = fp_alloc_pkt(port, sizeof (la_els_adisc_t),
4093                     sizeof (la_els_adisc_t), sleep, tmp_pd);
4094                 if (cmd == NULL) {
4095                         return (FC_NOMEM);
4096                 }
4097 
4098                 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class;
4099                 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
4100                 cmd->cmd_flags = cmd_flag;
4101                 cmd->cmd_retry_count = fp_retry_count;
4102                 cmd->cmd_ulp_pkt = ulp_pkt;
4103 
4104                 mutex_enter(&port->fp_mutex);
4105                 mutex_enter(&tmp_pd->pd_mutex);
4106                 fp_adisc_init(cmd, job);
4107                 mutex_exit(&tmp_pd->pd_mutex);
4108                 mutex_exit(&port->fp_mutex);
4109 
4110                 cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_adisc_t);
4111                 cmd->cmd_pkt.pkt_rsplen = sizeof (la_els_adisc_t);
4112 
4113         } else {
4114                 cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t),
4115                     sizeof (la_els_logi_t), sleep, pd);
4116                 if (cmd == NULL) {
4117                         return (FC_NOMEM);
4118                 }
4119 
4120                 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class;
4121                 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
4122                 cmd->cmd_flags = cmd_flag;
4123                 cmd->cmd_retry_count = fp_retry_count;
4124                 cmd->cmd_ulp_pkt = ulp_pkt;
4125 
4126                 mutex_enter(&port->fp_mutex);
4127                 src_id = port->fp_port_id.port_id;
4128                 mutex_exit(&port->fp_mutex);
4129 
4130                 fp_xlogi_init(port, cmd, src_id, d_id, fp_plogi_intr,
4131                     job, LA_ELS_PLOGI);
4132         }
4133 
4134         if (pd) {
4135                 mutex_enter(&pd->pd_mutex);
4136                 pd->pd_flags = PD_ELS_IN_PROGRESS;
4137                 mutex_exit(&pd->pd_mutex);
4138         }
4139 
4140         /* npiv check to make sure we don't log into ourself */
4141         if (relogin &&
4142             ((port->fp_npiv_type == FC_NPIV_PORT) ||
4143             (port->fp_npiv_flag == FC_NPIV_ENABLE))) {
4144                 if ((d_id & 0xffff00) ==
4145                     (port->fp_port_id.port_id & 0xffff00)) {
4146                         found = 1;
4147                 }
4148         }
4149 
4150         if (found ||
4151             (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS)) {
4152                 if (found) {
4153                         fc_packet_t *pkt = &cmd->cmd_pkt;
4154                         pkt->pkt_state = FC_PKT_NPORT_RJT;
4155                 }
4156                 if (pd) {
4157                         mutex_enter(&pd->pd_mutex);
4158                         pd->pd_flags = PD_IDLE;
4159                         mutex_exit(&pd->pd_mutex);
4160                 }
4161 
4162                 if (ulp_pkt) {
4163                         fc_packet_t *pkt = &cmd->cmd_pkt;
4164 
4165                         ulp_pkt->pkt_state = pkt->pkt_state;
4166                         ulp_pkt->pkt_reason = pkt->pkt_reason;
4167                         ulp_pkt->pkt_action = pkt->pkt_action;
4168                         ulp_pkt->pkt_expln = pkt->pkt_expln;
4169                 }
4170 
4171                 fp_iodone(cmd);
4172         }
4173 
4174         return (FC_SUCCESS);
4175 }
4176 
4177 
4178 /*
4179  * Register the LOGIN parameters with a port device
4180  */
4181 static void
4182 fp_register_login(ddi_acc_handle_t *handle, fc_remote_port_t *pd,
4183     la_els_logi_t *acc, uchar_t class)
4184 {
4185         fc_remote_node_t        *node;
4186 
4187         ASSERT(pd != NULL);
4188 
4189         mutex_enter(&pd->pd_mutex);
4190         node = pd->pd_remote_nodep;
4191         if (pd->pd_login_count == 0) {
4192                 pd->pd_login_count++;
4193         }
4194 
4195         if (handle) {
4196                 FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)&pd->pd_csp,
4197                     (uint8_t *)&acc->common_service,
4198                     sizeof (acc->common_service), DDI_DEV_AUTOINCR);
4199                 FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)&pd->pd_clsp1,
4200                     (uint8_t *)&acc->class_1, sizeof (acc->class_1),
4201                     DDI_DEV_AUTOINCR);
4202                 FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)&pd->pd_clsp2,
4203                     (uint8_t *)&acc->class_2, sizeof (acc->class_2),
4204                     DDI_DEV_AUTOINCR);
4205                 FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)&pd->pd_clsp3,
4206                     (uint8_t *)&acc->class_3, sizeof (acc->class_3),
4207                     DDI_DEV_AUTOINCR);
4208         } else {
4209                 pd->pd_csp = acc->common_service;
4210                 pd->pd_clsp1 = acc->class_1;
4211                 pd->pd_clsp2 = acc->class_2;
4212                 pd->pd_clsp3 = acc->class_3;
4213         }
4214 
4215         pd->pd_state = PORT_DEVICE_LOGGED_IN;
4216         pd->pd_login_class = class;
4217         mutex_exit(&pd->pd_mutex);
4218 
4219 #ifndef __lock_lint
4220         ASSERT(fctl_get_remote_port_by_did(pd->pd_port,
4221             pd->pd_port_id.port_id) == pd);
4222 #endif
4223 
4224         mutex_enter(&node->fd_mutex);
4225         if (handle) {
4226                 FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)node->fd_vv,
4227                     (uint8_t *)acc->vendor_version, sizeof (node->fd_vv),
4228                     DDI_DEV_AUTOINCR);
4229         } else {
4230                 bcopy(acc->vendor_version, node->fd_vv, sizeof (node->fd_vv));
4231         }
4232         mutex_exit(&node->fd_mutex);
4233 }
4234 
4235 
4236 /*
4237  * Mark the remote port as OFFLINE
4238  */
4239 static void
4240 fp_remote_port_offline(fc_remote_port_t *pd)
4241 {
4242         ASSERT(MUTEX_HELD(&pd->pd_mutex));
4243         if (pd->pd_login_count &&
4244             ((pd->pd_aux_flags & PD_DISABLE_RELOGIN) == 0)) {
4245                 bzero((caddr_t)&pd->pd_csp, sizeof (struct common_service));
4246                 bzero((caddr_t)&pd->pd_clsp1, sizeof (struct service_param));
4247                 bzero((caddr_t)&pd->pd_clsp2, sizeof (struct service_param));
4248                 bzero((caddr_t)&pd->pd_clsp3, sizeof (struct service_param));
4249                 pd->pd_login_class = 0;
4250         }
4251         pd->pd_type = PORT_DEVICE_OLD;
4252         pd->pd_flags = PD_IDLE;
4253         fctl_tc_reset(&pd->pd_logo_tc);
4254 }
4255 
4256 
4257 /*
4258  * Deregistration of a port device
4259  */
4260 static void
4261 fp_unregister_login(fc_remote_port_t *pd)
4262 {
4263         fc_remote_node_t *node;
4264 
4265         ASSERT(pd != NULL);
4266 
4267         mutex_enter(&pd->pd_mutex);
4268         pd->pd_login_count = 0;
4269         bzero((caddr_t)&pd->pd_csp, sizeof (struct common_service));
4270         bzero((caddr_t)&pd->pd_clsp1, sizeof (struct service_param));
4271         bzero((caddr_t)&pd->pd_clsp2, sizeof (struct service_param));
4272         bzero((caddr_t)&pd->pd_clsp3, sizeof (struct service_param));
4273 
4274         pd->pd_state = PORT_DEVICE_VALID;
4275         pd->pd_login_class = 0;
4276         node = pd->pd_remote_nodep;
4277         mutex_exit(&pd->pd_mutex);
4278 
4279         mutex_enter(&node->fd_mutex);
4280         bzero(node->fd_vv, sizeof (node->fd_vv));
4281         mutex_exit(&node->fd_mutex);
4282 }
4283 
4284 
4285 /*
4286  * Handle OFFLINE state of an FCA port
4287  */
4288 static void
4289 fp_port_offline(fc_local_port_t *port, int notify)
4290 {
4291         int                     index;
4292         int                     statec;
4293         timeout_id_t            tid;
4294         struct pwwn_hash        *head;
4295         fc_remote_port_t        *pd;
4296 
4297         ASSERT(MUTEX_HELD(&port->fp_mutex));
4298 
4299         for (index = 0; index < pwwn_table_size; index++) {
4300                 head = &port->fp_pwwn_table[index];
4301                 pd = head->pwwn_head;
4302                 while (pd != NULL) {
4303                         mutex_enter(&pd->pd_mutex);
4304                         fp_remote_port_offline(pd);
4305                         fctl_delist_did_table(port, pd);
4306                         mutex_exit(&pd->pd_mutex);
4307                         pd = pd->pd_wwn_hnext;
4308                 }
4309         }
4310         port->fp_total_devices = 0;
4311 
4312         statec = 0;
4313         if (notify) {
4314                 /*
4315                  * Decrement the statec busy counter as we
4316                  * are almost done with handling the state
4317                  * change
4318                  */
4319                 ASSERT(port->fp_statec_busy > 0);
4320                 if (--port->fp_statec_busy == 0) {
4321                         port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
4322                 }
4323                 mutex_exit(&port->fp_mutex);
4324                 (void) fp_ulp_statec_cb(port, FC_STATE_OFFLINE, NULL,
4325                     0, 0, KM_SLEEP);
4326                 mutex_enter(&port->fp_mutex);
4327 
4328                 if (port->fp_statec_busy) {
4329                         statec++;
4330                 }
4331         } else if (port->fp_statec_busy > 1) {
4332                 statec++;
4333         }
4334 
4335         if ((tid = port->fp_offline_tid) != NULL) {
4336                 mutex_exit(&port->fp_mutex);
4337                 (void) untimeout(tid);
4338                 mutex_enter(&port->fp_mutex);
4339         }
4340 
4341         if (!statec) {
4342                 port->fp_offline_tid = timeout(fp_offline_timeout,
4343                     (caddr_t)port, fp_offline_ticks);
4344         }
4345 }
4346 
4347 
4348 /*
4349  * Offline devices and send up a state change notification to ULPs
4350  */
4351 static void
4352 fp_offline_timeout(void *port_handle)
4353 {
4354         int             ret;
4355         fc_local_port_t *port = port_handle;
4356         uint32_t        listlen = 0;
4357         fc_portmap_t    *changelist = NULL;
4358 
4359         mutex_enter(&port->fp_mutex);
4360 
4361         if ((FC_PORT_STATE_MASK(port->fp_state) != FC_STATE_OFFLINE) ||
4362             (port->fp_soft_state &
4363             (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN)) ||
4364             port->fp_dev_count == 0 || port->fp_statec_busy) {
4365                 port->fp_offline_tid = NULL;
4366                 mutex_exit(&port->fp_mutex);
4367                 return;
4368         }
4369 
4370         mutex_exit(&port->fp_mutex);
4371 
4372         FP_TRACE(FP_NHEAD2(9, 0), "OFFLINE timeout");
4373 
4374         if (port->fp_options & FP_CORE_ON_OFFLINE_TIMEOUT) {
4375                 if ((ret = port->fp_fca_tran->fca_reset(port->fp_fca_handle,
4376                     FC_FCA_CORE)) != FC_SUCCESS) {
4377                         FP_TRACE(FP_NHEAD1(9, ret),
4378                             "Failed to force adapter dump");
4379                 } else {
4380                         FP_TRACE(FP_NHEAD1(9, 0),
4381                             "Forced adapter dump successfully");
4382                 }
4383         } else if (port->fp_options & FP_RESET_CORE_ON_OFFLINE_TIMEOUT) {
4384                 if ((ret = port->fp_fca_tran->fca_reset(port->fp_fca_handle,
4385                     FC_FCA_RESET_CORE)) != FC_SUCCESS) {
4386                         FP_TRACE(FP_NHEAD1(9, ret),
4387                             "Failed to force adapter dump and reset");
4388                 } else {
4389                         FP_TRACE(FP_NHEAD1(9, 0),
4390                             "Forced adapter dump and reset successfully");
4391                 }
4392         }
4393 
4394         fctl_fillout_map(port, &changelist, &listlen, 1, 0, 0);
4395         (void) fp_ulp_statec_cb(port, FC_STATE_OFFLINE, changelist,
4396             listlen, listlen, KM_SLEEP);
4397 
4398         mutex_enter(&port->fp_mutex);
4399         port->fp_offline_tid = NULL;
4400         mutex_exit(&port->fp_mutex);
4401 }
4402 
4403 
4404 /*
4405  * Perform general purpose ELS request initialization
4406  */
4407 static void
4408 fp_els_init(fp_cmd_t *cmd, uint32_t s_id, uint32_t d_id,
4409     void (*comp) (), job_request_t *job)
4410 {
4411         fc_packet_t *pkt;
4412 
4413         pkt = &cmd->cmd_pkt;
4414         cmd->cmd_job = job;
4415 
4416         pkt->pkt_cmd_fhdr.r_ctl = R_CTL_ELS_REQ;
4417         pkt->pkt_cmd_fhdr.d_id = d_id;
4418         pkt->pkt_cmd_fhdr.s_id = s_id;
4419         pkt->pkt_cmd_fhdr.type = FC_TYPE_EXTENDED_LS;
4420         pkt->pkt_cmd_fhdr.f_ctl = F_CTL_SEQ_INITIATIVE | F_CTL_FIRST_SEQ;
4421         pkt->pkt_cmd_fhdr.seq_id = 0;
4422         pkt->pkt_cmd_fhdr.df_ctl  = 0;
4423         pkt->pkt_cmd_fhdr.seq_cnt = 0;
4424         pkt->pkt_cmd_fhdr.ox_id = 0xffff;
4425         pkt->pkt_cmd_fhdr.rx_id = 0xffff;
4426         pkt->pkt_cmd_fhdr.ro = 0;
4427         pkt->pkt_cmd_fhdr.rsvd = 0;
4428         pkt->pkt_comp = comp;
4429         pkt->pkt_timeout = FP_ELS_TIMEOUT;
4430 }
4431 
4432 
4433 /*
4434  * Initialize PLOGI/FLOGI ELS request
4435  */
4436 static void
4437 fp_xlogi_init(fc_local_port_t *port, fp_cmd_t *cmd, uint32_t s_id,
4438     uint32_t d_id, void (*intr) (), job_request_t *job, uchar_t ls_code)
4439 {
4440         ls_code_t       payload;
4441 
4442         fp_els_init(cmd, s_id, d_id, intr, job);
4443         cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
4444 
4445         payload.ls_code = ls_code;
4446         payload.mbz = 0;
4447 
4448         FC_SET_CMD(port, cmd->cmd_pkt.pkt_cmd_acc,
4449             (uint8_t *)&port->fp_service_params,
4450             (uint8_t *)cmd->cmd_pkt.pkt_cmd, sizeof (port->fp_service_params),
4451             DDI_DEV_AUTOINCR);
4452 
4453         FC_SET_CMD(port, cmd->cmd_pkt.pkt_cmd_acc, (uint8_t *)&payload,
4454             (uint8_t *)cmd->cmd_pkt.pkt_cmd, sizeof (payload),
4455             DDI_DEV_AUTOINCR);
4456 }
4457 
4458 
4459 /*
4460  * Initialize LOGO ELS request
4461  */
4462 static void
4463 fp_logo_init(fc_remote_port_t *pd, fp_cmd_t *cmd, job_request_t *job)
4464 {
4465         fc_local_port_t *port;
4466         fc_packet_t     *pkt;
4467         la_els_logo_t   payload;
4468 
4469         port = pd->pd_port;
4470         pkt = &cmd->cmd_pkt;
4471         ASSERT(MUTEX_HELD(&port->fp_mutex));
4472         ASSERT(MUTEX_HELD(&pd->pd_mutex));
4473 
4474         fp_els_init(cmd, port->fp_port_id.port_id, pd->pd_port_id.port_id,
4475             fp_logo_intr, job);
4476 
4477         cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
4478 
4479         pkt->pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
4480         pkt->pkt_tran_type = FC_PKT_EXCHANGE;
4481 
4482         payload.ls_code.ls_code = LA_ELS_LOGO;
4483         payload.ls_code.mbz = 0;
4484         payload.nport_ww_name = port->fp_service_params.nport_ww_name;
4485         payload.nport_id = port->fp_port_id;
4486 
4487         FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
4488             (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
4489 }
4490 
4491 /*
4492  * Initialize RNID ELS request
4493  */
4494 static void
4495 fp_rnid_init(fp_cmd_t *cmd, uint16_t flag, job_request_t *job)
4496 {
4497         fc_local_port_t *port;
4498         fc_packet_t     *pkt;
4499         la_els_rnid_t   payload;
4500         fc_remote_port_t        *pd;
4501 
4502         pkt = &cmd->cmd_pkt;
4503         pd = pkt->pkt_pd;
4504         port = pd->pd_port;
4505 
4506         ASSERT(MUTEX_HELD(&port->fp_mutex));
4507         ASSERT(MUTEX_HELD(&pd->pd_mutex));
4508 
4509         fp_els_init(cmd, port->fp_port_id.port_id, pd->pd_port_id.port_id,
4510             fp_rnid_intr, job);
4511 
4512         cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
4513         pkt->pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
4514         pkt->pkt_tran_type = FC_PKT_EXCHANGE;
4515 
4516         payload.ls_code.ls_code = LA_ELS_RNID;
4517         payload.ls_code.mbz = 0;
4518         payload.data_format = flag;
4519 
4520         FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
4521             (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
4522 }
4523 
4524 /*
4525  * Initialize RLS ELS request
4526  */
4527 static void
4528 fp_rls_init(fp_cmd_t *cmd, job_request_t *job)
4529 {
4530         fc_local_port_t *port;
4531         fc_packet_t     *pkt;
4532         la_els_rls_t    payload;
4533         fc_remote_port_t        *pd;
4534 
4535         pkt = &cmd->cmd_pkt;
4536         pd = pkt->pkt_pd;
4537         port = pd->pd_port;
4538 
4539         ASSERT(MUTEX_HELD(&port->fp_mutex));
4540         ASSERT(MUTEX_HELD(&pd->pd_mutex));
4541 
4542         fp_els_init(cmd, port->fp_port_id.port_id, pd->pd_port_id.port_id,
4543             fp_rls_intr, job);
4544 
4545         cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
4546         pkt->pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
4547         pkt->pkt_tran_type = FC_PKT_EXCHANGE;
4548 
4549         payload.ls_code.ls_code = LA_ELS_RLS;
4550         payload.ls_code.mbz = 0;
4551         payload.rls_portid = port->fp_port_id;
4552 
4553         FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
4554             (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
4555 }
4556 
4557 
4558 /*
4559  * Initialize an ADISC ELS request
4560  */
4561 static void
4562 fp_adisc_init(fp_cmd_t *cmd, job_request_t *job)
4563 {
4564         fc_local_port_t *port;
4565         fc_packet_t     *pkt;
4566         la_els_adisc_t  payload;
4567         fc_remote_port_t        *pd;
4568 
4569         pkt = &cmd->cmd_pkt;
4570         pd = pkt->pkt_pd;
4571         port = pd->pd_port;
4572 
4573         ASSERT(MUTEX_HELD(&pd->pd_mutex));
4574         ASSERT(MUTEX_HELD(&pd->pd_port->fp_mutex));
4575 
4576         fp_els_init(cmd, port->fp_port_id.port_id, pd->pd_port_id.port_id,
4577             fp_adisc_intr, job);
4578 
4579         cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
4580         pkt->pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
4581         pkt->pkt_tran_type = FC_PKT_EXCHANGE;
4582 
4583         payload.ls_code.ls_code = LA_ELS_ADISC;
4584         payload.ls_code.mbz = 0;
4585         payload.nport_id = port->fp_port_id;
4586         payload.port_wwn = port->fp_service_params.nport_ww_name;
4587         payload.node_wwn = port->fp_service_params.node_ww_name;
4588         payload.hard_addr = port->fp_hard_addr;
4589 
4590         FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
4591             (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
4592 }
4593 
4594 
4595 /*
4596  * Send up a state change notification to ULPs.
4597  * Spawns a call to fctl_ulp_statec_cb in a taskq thread.
4598  */
4599 static int
4600 fp_ulp_statec_cb(fc_local_port_t *port, uint32_t state,
4601     fc_portmap_t *changelist, uint32_t listlen, uint32_t alloc_len, int sleep)
4602 {
4603         fc_port_clist_t         *clist;
4604         fc_remote_port_t        *pd;
4605         int                     count;
4606 
4607         ASSERT(!MUTEX_HELD(&port->fp_mutex));
4608 
4609         clist = kmem_zalloc(sizeof (*clist), sleep);
4610         if (clist == NULL) {
4611                 kmem_free(changelist, alloc_len * sizeof (*changelist));
4612                 return (FC_NOMEM);
4613         }
4614 
4615         clist->clist_state = state;
4616 
4617         mutex_enter(&port->fp_mutex);
4618         clist->clist_flags = port->fp_topology;
4619         mutex_exit(&port->fp_mutex);
4620 
4621         clist->clist_port = (opaque_t)port;
4622         clist->clist_len = listlen;
4623         clist->clist_size = alloc_len;
4624         clist->clist_map = changelist;
4625 
4626         /*
4627          * Bump the reference count of each fc_remote_port_t in this changelist.
4628          * This is necessary since these devices will be sitting in a taskq
4629          * and referenced later.  When the state change notification is
4630          * complete, the reference counts will be decremented.
4631          */
4632         for (count = 0; count < clist->clist_len; count++) {
4633                 pd = clist->clist_map[count].map_pd;
4634 
4635                 if (pd != NULL) {
4636                         mutex_enter(&pd->pd_mutex);
4637                         ASSERT((pd->pd_ref_count >= 0) ||
4638                             (pd->pd_aux_flags & PD_GIVEN_TO_ULPS));
4639                         pd->pd_ref_count++;
4640 
4641                         if (clist->clist_map[count].map_state !=
4642                             PORT_DEVICE_INVALID) {
4643                                 pd->pd_aux_flags |= PD_GIVEN_TO_ULPS;
4644                         }
4645 
4646                         mutex_exit(&pd->pd_mutex);
4647                 }
4648         }
4649 
4650 #ifdef  DEBUG
4651         /*
4652          * Sanity check for presence of OLD devices in the hash lists
4653          */
4654         if (clist->clist_size) {
4655                 ASSERT(clist->clist_map != NULL);
4656                 for (count = 0; count < clist->clist_len; count++) {
4657                         if (clist->clist_map[count].map_state ==
4658                             PORT_DEVICE_INVALID) {
4659                                 la_wwn_t        pwwn;
4660                                 fc_portid_t     d_id;
4661 
4662                                 pd = clist->clist_map[count].map_pd;
4663                                 ASSERT(pd != NULL);
4664 
4665                                 mutex_enter(&pd->pd_mutex);
4666                                 pwwn = pd->pd_port_name;
4667                                 d_id = pd->pd_port_id;
4668                                 mutex_exit(&pd->pd_mutex);
4669 
4670                                 pd = fctl_get_remote_port_by_pwwn(port, &pwwn);
4671                                 ASSERT(pd != clist->clist_map[count].map_pd);
4672 
4673                                 pd = fctl_get_remote_port_by_did(port,
4674                                     d_id.port_id);
4675                                 ASSERT(pd != clist->clist_map[count].map_pd);
4676                         }
4677                 }
4678         }
4679 #endif
4680 
4681         mutex_enter(&port->fp_mutex);
4682 
4683         if (state == FC_STATE_ONLINE) {
4684                 if (--port->fp_statec_busy == 0) {
4685                         port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
4686                 }
4687         }
4688         mutex_exit(&port->fp_mutex);
4689 
4690         (void) taskq_dispatch(port->fp_taskq, fctl_ulp_statec_cb,
4691             clist, KM_SLEEP);
4692 
4693         FP_TRACE(FP_NHEAD1(4, 0), "fp_ulp_statec fired; Port=%p,"
4694             "state=%x, len=%d", port, state, listlen);
4695 
4696         return (FC_SUCCESS);
4697 }
4698 
4699 
4700 /*
4701  * Send up a FC_STATE_DEVICE_CHANGE state notification to ULPs
4702  */
4703 static int
4704 fp_ulp_devc_cb(fc_local_port_t *port, fc_portmap_t *changelist,
4705     uint32_t listlen, uint32_t alloc_len, int sleep, int sync)
4706 {
4707         int             ret;
4708         fc_port_clist_t *clist;
4709 
4710         ASSERT(!MUTEX_HELD(&port->fp_mutex));
4711 
4712         clist = kmem_zalloc(sizeof (*clist), sleep);
4713         if (clist == NULL) {
4714                 kmem_free(changelist, alloc_len * sizeof (*changelist));
4715                 return (FC_NOMEM);
4716         }
4717 
4718         clist->clist_state = FC_STATE_DEVICE_CHANGE;
4719 
4720         mutex_enter(&port->fp_mutex);
4721         clist->clist_flags = port->fp_topology;
4722         mutex_exit(&port->fp_mutex);
4723 
4724         clist->clist_port = (opaque_t)port;
4725         clist->clist_len = listlen;
4726         clist->clist_size = alloc_len;
4727         clist->clist_map = changelist;
4728 
4729         /* Send sysevents for target state changes */
4730 
4731         if (clist->clist_size) {
4732                 int                     count;
4733                 fc_remote_port_t        *pd;
4734 
4735                 ASSERT(clist->clist_map != NULL);
4736                 for (count = 0; count < clist->clist_len; count++) {
4737                         pd = clist->clist_map[count].map_pd;
4738 
4739                         /*
4740                          * Bump reference counts on all fc_remote_port_t
4741                          * structs in this list.  We don't know when the task
4742                          * will fire, and we don't need these fc_remote_port_t
4743                          * structs going away behind our back.
4744                          */
4745                         if (pd) {
4746                                 mutex_enter(&pd->pd_mutex);
4747                                 ASSERT((pd->pd_ref_count >= 0) ||
4748                                     (pd->pd_aux_flags & PD_GIVEN_TO_ULPS));
4749                                 pd->pd_ref_count++;
4750                                 mutex_exit(&pd->pd_mutex);
4751                         }
4752 
4753                         if (clist->clist_map[count].map_state ==
4754                             PORT_DEVICE_VALID) {
4755                                 if (clist->clist_map[count].map_type ==
4756                                     PORT_DEVICE_NEW) {
4757                                         /* Update our state change counter */
4758                                         mutex_enter(&port->fp_mutex);
4759                                         port->fp_last_change++;
4760                                         mutex_exit(&port->fp_mutex);
4761 
4762                                         /* Additions */
4763                                         fp_log_target_event(port,
4764                                             ESC_SUNFC_TARGET_ADD,
4765                                             clist->clist_map[count].map_pwwn,
4766                                             clist->clist_map[count].map_did.
4767                                             port_id);
4768                                 }
4769 
4770                         } else if ((clist->clist_map[count].map_type ==
4771                             PORT_DEVICE_OLD) &&
4772                             (clist->clist_map[count].map_state ==
4773                             PORT_DEVICE_INVALID)) {
4774                                 /* Update our state change counter */
4775                                 mutex_enter(&port->fp_mutex);
4776                                 port->fp_last_change++;
4777                                 mutex_exit(&port->fp_mutex);
4778 
4779                                 /*
4780                                  * For removals, we don't decrement
4781                                  * pd_ref_count until after the ULP's
4782                                  * state change callback function has
4783                                  * completed.
4784                                  */
4785 
4786                                 /* Removals */
4787                                 fp_log_target_event(port,
4788                                     ESC_SUNFC_TARGET_REMOVE,
4789                                     clist->clist_map[count].map_pwwn,
4790                                     clist->clist_map[count].map_did.port_id);
4791                         }
4792 
4793                         if (clist->clist_map[count].map_state !=
4794                             PORT_DEVICE_INVALID) {
4795                                 /*
4796                                  * Indicate that the ULPs are now aware of
4797                                  * this device.
4798                                  */
4799 
4800                                 mutex_enter(&pd->pd_mutex);
4801                                 pd->pd_aux_flags |= PD_GIVEN_TO_ULPS;
4802                                 mutex_exit(&pd->pd_mutex);
4803                         }
4804 
4805 #ifdef  DEBUG
4806                         /*
4807                          * Sanity check for OLD devices in the hash lists
4808                          */
4809                         if (pd && clist->clist_map[count].map_state ==
4810                             PORT_DEVICE_INVALID) {
4811                                 la_wwn_t        pwwn;
4812                                 fc_portid_t     d_id;
4813 
4814                                 mutex_enter(&pd->pd_mutex);
4815                                 pwwn = pd->pd_port_name;
4816                                 d_id = pd->pd_port_id;
4817                                 mutex_exit(&pd->pd_mutex);
4818 
4819                                 /*
4820                                  * This overwrites the 'pd' local variable.
4821                                  * Beware of this if 'pd' ever gets
4822                                  * referenced below this block.
4823                                  */
4824                                 pd = fctl_get_remote_port_by_pwwn(port, &pwwn);
4825                                 ASSERT(pd != clist->clist_map[count].map_pd);
4826 
4827                                 pd = fctl_get_remote_port_by_did(port,
4828                                     d_id.port_id);
4829                                 ASSERT(pd != clist->clist_map[count].map_pd);
4830                         }
4831 #endif
4832                 }
4833         }
4834 
4835         if (sync) {
4836                 clist->clist_wait = 1;
4837                 mutex_init(&clist->clist_mutex, NULL, MUTEX_DRIVER, NULL);
4838                 cv_init(&clist->clist_cv, NULL, CV_DRIVER, NULL);
4839         }
4840 
4841         ret = taskq_dispatch(port->fp_taskq, fctl_ulp_statec_cb, clist, sleep);
4842         if (sync && ret) {
4843                 mutex_enter(&clist->clist_mutex);
4844                 while (clist->clist_wait) {
4845                         cv_wait(&clist->clist_cv, &clist->clist_mutex);
4846                 }
4847                 mutex_exit(&clist->clist_mutex);
4848 
4849                 mutex_destroy(&clist->clist_mutex);
4850                 cv_destroy(&clist->clist_cv);
4851                 kmem_free(clist, sizeof (*clist));
4852         }
4853 
4854         if (!ret) {
4855                 FP_TRACE(FP_NHEAD1(4, 0), "fp_ulp_devc dispatch failed; "
4856                     "port=%p", port);
4857                 kmem_free(clist->clist_map,
4858                     sizeof (*(clist->clist_map)) * clist->clist_size);
4859                 kmem_free(clist, sizeof (*clist));
4860         } else {
4861                 FP_TRACE(FP_NHEAD1(4, 0), "fp_ulp_devc fired; port=%p, len=%d",
4862                     port, listlen);
4863         }
4864 
4865         return (FC_SUCCESS);
4866 }
4867 
4868 
4869 /*
4870  * Perform PLOGI to the group of devices for ULPs
4871  */
4872 static void
4873 fp_plogi_group(fc_local_port_t *port, job_request_t *job)
4874 {
4875         int                     offline;
4876         int                     count;
4877         int                     rval;
4878         uint32_t                listlen;
4879         uint32_t                done;
4880         uint32_t                d_id;
4881         fc_remote_node_t        *node;
4882         fc_remote_port_t        *pd;
4883         fc_remote_port_t        *tmp_pd;
4884         fc_packet_t             *ulp_pkt;
4885         la_els_logi_t           *els_data;
4886         ls_code_t               ls_code;
4887 
4888         FP_TRACE(FP_NHEAD1(1, 0), "fp_plogi_group begin; port=%p, job=%p",
4889             port, job);
4890 
4891         done = 0;
4892         listlen = job->job_ulp_listlen;
4893         job->job_counter = job->job_ulp_listlen;
4894 
4895         mutex_enter(&port->fp_mutex);
4896         offline = (port->fp_statec_busy ||
4897             FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) ? 1 : 0;
4898         mutex_exit(&port->fp_mutex);
4899 
4900         for (count = 0; count < listlen; count++) {
4901                 ASSERT(job->job_ulp_pkts[count]->pkt_rsplen >=
4902                     sizeof (la_els_logi_t));
4903 
4904                 ulp_pkt = job->job_ulp_pkts[count];
4905                 pd = ulp_pkt->pkt_pd;
4906                 d_id = ulp_pkt->pkt_cmd_fhdr.d_id;
4907 
4908                 if (offline) {
4909                         done++;
4910 
4911                         ulp_pkt->pkt_state = FC_PKT_PORT_OFFLINE;
4912                         ulp_pkt->pkt_reason = FC_REASON_OFFLINE;
4913                         ulp_pkt->pkt_pd = NULL;
4914                         ulp_pkt->pkt_comp(ulp_pkt);
4915 
4916                         job->job_ulp_pkts[count] = NULL;
4917 
4918                         fp_jobdone(job);
4919                         continue;
4920                 }
4921 
4922                 if (pd == NULL) {
4923                         pd = fctl_get_remote_port_by_did(port, d_id);
4924                         if (pd == NULL) {
4925                                 /* reset later */
4926                                 ulp_pkt->pkt_state = FC_PKT_FAILURE;
4927                                 continue;
4928                         }
4929                         mutex_enter(&pd->pd_mutex);
4930                         if (pd->pd_flags == PD_ELS_IN_PROGRESS) {
4931                                 mutex_exit(&pd->pd_mutex);
4932                                 ulp_pkt->pkt_state = FC_PKT_ELS_IN_PROGRESS;
4933                                 done++;
4934                                 ulp_pkt->pkt_comp(ulp_pkt);
4935                                 job->job_ulp_pkts[count] = NULL;
4936                                 fp_jobdone(job);
4937                         } else {
4938                                 ulp_pkt->pkt_state = FC_PKT_FAILURE;
4939                                 mutex_exit(&pd->pd_mutex);
4940                         }
4941                         continue;
4942                 }
4943 
4944                 switch (ulp_pkt->pkt_state) {
4945                 case FC_PKT_ELS_IN_PROGRESS:
4946                         ulp_pkt->pkt_reason = FC_REASON_OFFLINE;
4947                         /* FALLTHRU */
4948                 case FC_PKT_LOCAL_RJT:
4949                         done++;
4950                         ulp_pkt->pkt_comp(ulp_pkt);
4951                         job->job_ulp_pkts[count] = NULL;
4952                         fp_jobdone(job);
4953                         continue;
4954                 default:
4955                         break;
4956                 }
4957 
4958                 /*
4959                  * Validate the pd corresponding to the d_id passed
4960                  * by the ULPs
4961                  */
4962                 tmp_pd = fctl_get_remote_port_by_did(port, d_id);
4963                 if ((tmp_pd == NULL) || (pd != tmp_pd)) {
4964                         done++;
4965                         ulp_pkt->pkt_state = FC_PKT_FAILURE;
4966                         ulp_pkt->pkt_reason = FC_REASON_NO_CONNECTION;
4967                         ulp_pkt->pkt_pd = NULL;
4968                         ulp_pkt->pkt_comp(ulp_pkt);
4969                         job->job_ulp_pkts[count] = NULL;
4970                         fp_jobdone(job);
4971                         continue;
4972                 }
4973 
4974                 FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_group contd; "
4975                     "port=%p, pd=%p", port, pd);
4976 
4977                 mutex_enter(&pd->pd_mutex);
4978 
4979                 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
4980                         done++;
4981                         els_data = (la_els_logi_t *)ulp_pkt->pkt_resp;
4982 
4983                         ls_code.ls_code = LA_ELS_ACC;
4984                         ls_code.mbz = 0;
4985 
4986                         FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
4987                             (uint8_t *)&ls_code, (uint8_t *)&els_data->ls_code,
4988                             sizeof (ls_code_t), DDI_DEV_AUTOINCR);
4989 
4990                         FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
4991                             (uint8_t *)&pd->pd_csp,
4992                             (uint8_t *)&els_data->common_service,
4993                             sizeof (pd->pd_csp), DDI_DEV_AUTOINCR);
4994 
4995                         FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
4996                             (uint8_t *)&pd->pd_port_name,
4997                             (uint8_t *)&els_data->nport_ww_name,
4998                             sizeof (pd->pd_port_name), DDI_DEV_AUTOINCR);
4999 
5000                         FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
5001                             (uint8_t *)&pd->pd_clsp1,
5002                             (uint8_t *)&els_data->class_1,
5003                             sizeof (pd->pd_clsp1), DDI_DEV_AUTOINCR);
5004 
5005                         FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
5006                             (uint8_t *)&pd->pd_clsp2,
5007                             (uint8_t *)&els_data->class_2,
5008                             sizeof (pd->pd_clsp2), DDI_DEV_AUTOINCR);
5009 
5010                         FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
5011                             (uint8_t *)&pd->pd_clsp3,
5012                             (uint8_t *)&els_data->class_3,
5013                             sizeof (pd->pd_clsp3), DDI_DEV_AUTOINCR);
5014 
5015                         node = pd->pd_remote_nodep;
5016                         pd->pd_login_count++;
5017                         pd->pd_flags = PD_IDLE;
5018                         ulp_pkt->pkt_pd = pd;
5019                         mutex_exit(&pd->pd_mutex);
5020 
5021                         mutex_enter(&node->fd_mutex);
5022                         FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
5023                             (uint8_t *)&node->fd_node_name,
5024                             (uint8_t *)(&els_data->node_ww_name),
5025                             sizeof (node->fd_node_name), DDI_DEV_AUTOINCR);
5026 
5027                         FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
5028                             (uint8_t *)&node->fd_vv,
5029                             (uint8_t *)(&els_data->vendor_version),
5030                             sizeof (node->fd_vv), DDI_DEV_AUTOINCR);
5031 
5032                         mutex_exit(&node->fd_mutex);
5033                         ulp_pkt->pkt_state = FC_PKT_SUCCESS;
5034                 } else {
5035 
5036                         ulp_pkt->pkt_state = FC_PKT_FAILURE; /* reset later */
5037                         mutex_exit(&pd->pd_mutex);
5038                 }
5039 
5040                 if (ulp_pkt->pkt_state != FC_PKT_FAILURE) {
5041                         ulp_pkt->pkt_comp(ulp_pkt);
5042                         job->job_ulp_pkts[count] = NULL;
5043                         fp_jobdone(job);
5044                 }
5045         }
5046 
5047         if (done == listlen) {
5048                 fp_jobwait(job);
5049                 fctl_jobdone(job);
5050                 return;
5051         }
5052 
5053         job->job_counter = listlen - done;
5054 
5055         for (count = 0; count < listlen; count++) {
5056                 int cmd_flags;
5057 
5058                 if ((ulp_pkt = job->job_ulp_pkts[count]) == NULL) {
5059                         continue;
5060                 }
5061 
5062                 ASSERT(ulp_pkt->pkt_state == FC_PKT_FAILURE);
5063 
5064                 cmd_flags = FP_CMD_PLOGI_RETAIN;
5065 
5066                 d_id = ulp_pkt->pkt_cmd_fhdr.d_id;
5067                 ASSERT(d_id != 0);
5068 
5069                 pd = fctl_get_remote_port_by_did(port, d_id);
5070 
5071                 /*
5072                  * We need to properly adjust the port device
5073                  * reference counter before we assign the pd
5074                  * to the ULP packets port device pointer.
5075                  */
5076                 if (pd != NULL && ulp_pkt->pkt_pd == NULL) {
5077                         mutex_enter(&pd->pd_mutex);
5078                         pd->pd_ref_count++;
5079                         mutex_exit(&pd->pd_mutex);
5080                         FP_TRACE(FP_NHEAD1(3, 0),
5081                             "fp_plogi_group: DID = 0x%x using new pd %p \
5082                             old pd NULL\n", d_id, pd);
5083                 } else if (pd != NULL && ulp_pkt->pkt_pd != NULL &&
5084                     ulp_pkt->pkt_pd != pd) {
5085                         mutex_enter(&pd->pd_mutex);
5086                         pd->pd_ref_count++;
5087                         mutex_exit(&pd->pd_mutex);
5088                         mutex_enter(&ulp_pkt->pkt_pd->pd_mutex);
5089                         ulp_pkt->pkt_pd->pd_ref_count--;
5090                         mutex_exit(&ulp_pkt->pkt_pd->pd_mutex);
5091                         FP_TRACE(FP_NHEAD1(3, 0),
5092                             "fp_plogi_group: DID = 0x%x pkt_pd %p != pd %p\n",
5093                             d_id, ulp_pkt->pkt_pd, pd);
5094                 } else if (pd == NULL && ulp_pkt->pkt_pd != NULL) {
5095                         mutex_enter(&ulp_pkt->pkt_pd->pd_mutex);
5096                         ulp_pkt->pkt_pd->pd_ref_count--;
5097                         mutex_exit(&ulp_pkt->pkt_pd->pd_mutex);
5098                         FP_TRACE(FP_NHEAD1(3, 0),
5099                             "fp_plogi_group: DID = 0x%x pd is NULL and \
5100                             pkt_pd = %p\n", d_id, ulp_pkt->pkt_pd);
5101                 }
5102 
5103                 ulp_pkt->pkt_pd = pd;
5104 
5105                 if (pd != NULL) {
5106                         mutex_enter(&pd->pd_mutex);
5107                         d_id = pd->pd_port_id.port_id;
5108                         pd->pd_flags = PD_ELS_IN_PROGRESS;
5109                         mutex_exit(&pd->pd_mutex);
5110                 } else {
5111                         d_id = ulp_pkt->pkt_cmd_fhdr.d_id;
5112 #ifdef  DEBUG
5113                         pd = fctl_get_remote_port_by_did(port, d_id);
5114                         ASSERT(pd == NULL);
5115 #endif
5116                         /*
5117                          * In the Fabric topology, use NS to create
5118                          * port device, and if that fails still try
5119                          * with PLOGI - which will make yet another
5120                          * attempt to create after successful PLOGI
5121                          */
5122                         mutex_enter(&port->fp_mutex);
5123                         if (FC_IS_TOP_SWITCH(port->fp_topology)) {
5124                                 mutex_exit(&port->fp_mutex);
5125                                 pd = fp_create_remote_port_by_ns(port,
5126                                     d_id, KM_SLEEP);
5127                                 if (pd) {
5128                                         cmd_flags |= FP_CMD_DELDEV_ON_ERROR;
5129 
5130                                         mutex_enter(&pd->pd_mutex);
5131                                         pd->pd_flags = PD_ELS_IN_PROGRESS;
5132                                         mutex_exit(&pd->pd_mutex);
5133 
5134                                         FP_TRACE(FP_NHEAD1(3, 0),
5135                                             "fp_plogi_group;"
5136                                             " NS created PD port=%p, job=%p,"
5137                                             " pd=%p", port, job, pd);
5138                                 }
5139                         } else {
5140                                 mutex_exit(&port->fp_mutex);
5141                         }
5142                         if ((ulp_pkt->pkt_pd == NULL) && (pd != NULL)) {
5143                                 FP_TRACE(FP_NHEAD1(3, 0),
5144                                     "fp_plogi_group;"
5145                                     "ulp_pkt's pd is NULL, get a pd %p",
5146                                     pd);
5147                                 mutex_enter(&pd->pd_mutex);
5148                                 pd->pd_ref_count++;
5149                                 mutex_exit(&pd->pd_mutex);
5150                         }
5151                         ulp_pkt->pkt_pd = pd;
5152                 }
5153 
5154                 rval = fp_port_login(port, d_id, job, cmd_flags,
5155                     KM_SLEEP, pd, ulp_pkt);
5156 
5157                 if (rval == FC_SUCCESS) {
5158                         continue;
5159                 }
5160 
5161                 if (rval == FC_STATEC_BUSY) {
5162                         ulp_pkt->pkt_state = FC_PKT_PORT_OFFLINE;
5163                         ulp_pkt->pkt_reason = FC_REASON_OFFLINE;
5164                 } else {
5165                         ulp_pkt->pkt_state = FC_PKT_FAILURE;
5166                 }
5167 
5168                 if (pd) {
5169                         mutex_enter(&pd->pd_mutex);
5170                         pd->pd_flags = PD_IDLE;
5171                         mutex_exit(&pd->pd_mutex);
5172                 }
5173 
5174                 if (cmd_flags & FP_CMD_DELDEV_ON_ERROR) {
5175                         ASSERT(pd != NULL);
5176 
5177                         FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_group: NS created,"
5178                             " PD removed; port=%p, job=%p", port, job);
5179 
5180                         mutex_enter(&pd->pd_mutex);
5181                         pd->pd_ref_count--;
5182                         node = pd->pd_remote_nodep;
5183                         mutex_exit(&pd->pd_mutex);
5184 
5185                         ASSERT(node != NULL);
5186 
5187                         if (fctl_destroy_remote_port(port, pd) == 0) {
5188                                 fctl_destroy_remote_node(node);
5189                         }
5190                         ulp_pkt->pkt_pd = NULL;
5191                 }
5192                 ulp_pkt->pkt_comp(ulp_pkt);
5193                 fp_jobdone(job);
5194         }
5195 
5196         fp_jobwait(job);
5197         fctl_jobdone(job);
5198 
5199         FP_TRACE(FP_NHEAD1(1, 0), "fp_plogi_group end: port=%p, job=%p",
5200             port, job);
5201 }
5202 
5203 
5204 /*
5205  * Name server request initialization
5206  */
5207 static void
5208 fp_ns_init(fc_local_port_t *port, job_request_t *job, int sleep)
5209 {
5210         int rval;
5211         int count;
5212         int size;
5213 
5214         ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
5215 
5216         job->job_counter = 1;
5217         job->job_result = FC_SUCCESS;
5218 
5219         rval = fp_port_login(port, 0xFFFFFC, job, FP_CMD_PLOGI_RETAIN,
5220             KM_SLEEP, NULL, NULL);
5221 
5222         if (rval != FC_SUCCESS) {
5223                 mutex_enter(&port->fp_mutex);
5224                 port->fp_topology = FC_TOP_NO_NS;
5225                 mutex_exit(&port->fp_mutex);
5226                 return;
5227         }
5228 
5229         fp_jobwait(job);
5230 
5231         if (job->job_result != FC_SUCCESS) {
5232                 mutex_enter(&port->fp_mutex);
5233                 port->fp_topology = FC_TOP_NO_NS;
5234                 mutex_exit(&port->fp_mutex);
5235                 return;
5236         }
5237 
5238         /*
5239          * At this time, we'll do NS registration for objects in the
5240          * ns_reg_cmds (see top of this file) array.
5241          *
5242          * Each time a ULP module registers with the transport, the
5243          * appropriate fc4 bit is set fc4 types and registered with
5244          * the NS for this support. Also, ULPs and FC admin utilities
5245          * may do registration for objects like IP address, symbolic
5246          * port/node name, Initial process associator at run time.
5247          */
5248         size = sizeof (ns_reg_cmds) / sizeof (ns_reg_cmds[0]);
5249         job->job_counter = size;
5250         job->job_result = FC_SUCCESS;
5251 
5252         for (count = 0; count < size; count++) {
5253                 if (fp_ns_reg(port, NULL, ns_reg_cmds[count],
5254                     job, 0, sleep) != FC_SUCCESS) {
5255                         fp_jobdone(job);
5256                 }
5257         }
5258         if (size) {
5259                 fp_jobwait(job);
5260         }
5261 
5262         job->job_result = FC_SUCCESS;
5263 
5264         (void) fp_ns_get_devcount(port, job, 0, KM_SLEEP);
5265 
5266         if (port->fp_dev_count < FP_MAX_DEVICES) {
5267                 (void) fp_ns_get_devcount(port, job, 1, KM_SLEEP);
5268         }
5269 
5270         job->job_counter = 1;
5271 
5272         if (fp_ns_scr(port, job, FC_SCR_FULL_REGISTRATION,
5273             sleep) == FC_SUCCESS) {
5274                 fp_jobwait(job);
5275         }
5276 }
5277 
5278 
5279 /*
5280  * Name server finish:
5281  *      Unregister for RSCNs
5282  *      Unregister all the host port objects in the Name Server
5283  *      Perform LOGO with the NS;
5284  */
5285 static void
5286 fp_ns_fini(fc_local_port_t *port, job_request_t *job)
5287 {
5288         fp_cmd_t        *cmd;
5289         uchar_t         class;
5290         uint32_t        s_id;
5291         fc_packet_t     *pkt;
5292         la_els_logo_t   payload;
5293 
5294         ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
5295 
5296         job->job_counter = 1;
5297 
5298         if (fp_ns_scr(port, job, FC_SCR_CLEAR_REGISTRATION, KM_SLEEP) !=
5299             FC_SUCCESS) {
5300                 fp_jobdone(job);
5301         }
5302         fp_jobwait(job);
5303 
5304         job->job_counter = 1;
5305 
5306         if (fp_ns_reg(port, NULL, NS_DA_ID, job, 0, KM_SLEEP) != FC_SUCCESS) {
5307                 fp_jobdone(job);
5308         }
5309         fp_jobwait(job);
5310 
5311         job->job_counter = 1;
5312 
5313         cmd = fp_alloc_pkt(port, sizeof (la_els_logo_t),
5314             FP_PORT_IDENTIFIER_LEN, KM_SLEEP, NULL);
5315         pkt = &cmd->cmd_pkt;
5316 
5317         mutex_enter(&port->fp_mutex);
5318         class = port->fp_ns_login_class;
5319         s_id = port->fp_port_id.port_id;
5320         payload.nport_id = port->fp_port_id;
5321         mutex_exit(&port->fp_mutex);
5322 
5323         cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class;
5324         cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
5325         cmd->cmd_flags = FP_CMD_PLOGI_DONT_CARE;
5326         cmd->cmd_retry_count = 1;
5327         cmd->cmd_ulp_pkt = NULL;
5328 
5329         if (port->fp_npiv_type == FC_NPIV_PORT) {
5330                 fp_els_init(cmd, s_id, 0xFFFFFE, fp_logo_intr, job);
5331         } else {
5332                 fp_els_init(cmd, s_id, 0xFFFFFC, fp_logo_intr, job);
5333         }
5334 
5335         cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
5336 
5337         payload.ls_code.ls_code = LA_ELS_LOGO;
5338         payload.ls_code.mbz = 0;
5339         payload.nport_ww_name = port->fp_service_params.nport_ww_name;
5340 
5341         FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
5342             (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
5343 
5344         if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
5345                 fp_iodone(cmd);
5346         }
5347         fp_jobwait(job);
5348 }
5349 
5350 
5351 /*
5352  * NS Registration function.
5353  *
5354  *      It should be seriously noted that FC-GS-2 currently doesn't support
5355  *      an Object Registration by a D_ID other than the owner of the object.
5356  *      What we are aiming at currently is to at least allow Symbolic Node/Port
5357  *      Name registration for any N_Port Identifier by the host software.
5358  *
5359  *      Anyway, if the second argument (fc_remote_port_t *) is NULL, this
5360  *      function treats the request as Host NS Object.
5361  */
5362 static int
5363 fp_ns_reg(fc_local_port_t *port, fc_remote_port_t *pd, uint16_t cmd_code,
5364     job_request_t *job, int polled, int sleep)
5365 {
5366         int             rval;
5367         fc_portid_t     s_id;
5368         fc_packet_t     *pkt;
5369         fp_cmd_t        *cmd;
5370 
5371         if (pd == NULL) {
5372                 mutex_enter(&port->fp_mutex);
5373                 s_id = port->fp_port_id;
5374                 mutex_exit(&port->fp_mutex);
5375         } else {
5376                 mutex_enter(&pd->pd_mutex);
5377                 s_id = pd->pd_port_id;
5378                 mutex_exit(&pd->pd_mutex);
5379         }
5380 
5381         if (polled) {
5382                 job->job_counter = 1;
5383         }
5384 
5385         switch (cmd_code) {
5386         case NS_RPN_ID:
5387         case NS_RNN_ID: {
5388                 ns_rxn_req_t rxn;
5389 
5390                 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
5391                     sizeof (ns_rxn_req_t), sizeof (fc_reg_resp_t), sleep, NULL);
5392                 if (cmd == NULL) {
5393                         return (FC_NOMEM);
5394                 }
5395                 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5396                 pkt = &cmd->cmd_pkt;
5397 
5398                 if (pd == NULL) {
5399                         rxn.rxn_xname = ((cmd_code == NS_RPN_ID) ?
5400                             (port->fp_service_params.nport_ww_name) :
5401                             (port->fp_service_params.node_ww_name));
5402                 } else {
5403                         if (cmd_code == NS_RPN_ID) {
5404                                 mutex_enter(&pd->pd_mutex);
5405                                 rxn.rxn_xname = pd->pd_port_name;
5406                                 mutex_exit(&pd->pd_mutex);
5407                         } else {
5408                                 fc_remote_node_t *node;
5409 
5410                                 mutex_enter(&pd->pd_mutex);
5411                                 node = pd->pd_remote_nodep;
5412                                 mutex_exit(&pd->pd_mutex);
5413 
5414                                 mutex_enter(&node->fd_mutex);
5415                                 rxn.rxn_xname = node->fd_node_name;
5416                                 mutex_exit(&node->fd_mutex);
5417                         }
5418                 }
5419                 rxn.rxn_port_id = s_id;
5420 
5421                 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rxn,
5422                     (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
5423                     sizeof (rxn), DDI_DEV_AUTOINCR);
5424 
5425                 break;
5426         }
5427 
5428         case NS_RCS_ID: {
5429                 ns_rcos_t rcos;
5430 
5431                 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
5432                     sizeof (ns_rcos_t), sizeof (fc_reg_resp_t), sleep, NULL);
5433                 if (cmd == NULL) {
5434                         return (FC_NOMEM);
5435                 }
5436                 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5437                 pkt = &cmd->cmd_pkt;
5438 
5439                 if (pd == NULL) {
5440                         rcos.rcos_cos = port->fp_cos;
5441                 } else {
5442                         mutex_enter(&pd->pd_mutex);
5443                         rcos.rcos_cos = pd->pd_cos;
5444                         mutex_exit(&pd->pd_mutex);
5445                 }
5446                 rcos.rcos_port_id = s_id;
5447 
5448                 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rcos,
5449                     (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
5450                     sizeof (rcos), DDI_DEV_AUTOINCR);
5451 
5452                 break;
5453         }
5454 
5455         case NS_RFT_ID: {
5456                 ns_rfc_type_t rfc;
5457 
5458                 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
5459                     sizeof (ns_rfc_type_t), sizeof (fc_reg_resp_t), sleep,
5460                     NULL);
5461                 if (cmd == NULL) {
5462                         return (FC_NOMEM);
5463                 }
5464                 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5465                 pkt = &cmd->cmd_pkt;
5466 
5467                 if (pd == NULL) {
5468                         mutex_enter(&port->fp_mutex);
5469                         bcopy(port->fp_fc4_types, rfc.rfc_types,
5470                             sizeof (port->fp_fc4_types));
5471                         mutex_exit(&port->fp_mutex);
5472                 } else {
5473                         mutex_enter(&pd->pd_mutex);
5474                         bcopy(pd->pd_fc4types, rfc.rfc_types,
5475                             sizeof (pd->pd_fc4types));
5476                         mutex_exit(&pd->pd_mutex);
5477                 }
5478                 rfc.rfc_port_id = s_id;
5479 
5480                 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rfc,
5481                     (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
5482                     sizeof (rfc), DDI_DEV_AUTOINCR);
5483 
5484                 break;
5485         }
5486 
5487         case NS_RSPN_ID: {
5488                 uchar_t         name_len;
5489                 int             pl_size;
5490                 fc_portid_t     spn;
5491 
5492                 if (pd == NULL) {
5493                         mutex_enter(&port->fp_mutex);
5494                         name_len = port->fp_sym_port_namelen;
5495                         mutex_exit(&port->fp_mutex);
5496                 } else {
5497                         mutex_enter(&pd->pd_mutex);
5498                         name_len = pd->pd_spn_len;
5499                         mutex_exit(&pd->pd_mutex);
5500                 }
5501 
5502                 pl_size = sizeof (fc_portid_t) + name_len + 1;
5503 
5504                 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) + pl_size,
5505                     sizeof (fc_reg_resp_t), sleep, NULL);
5506                 if (cmd == NULL) {
5507                         return (FC_NOMEM);
5508                 }
5509 
5510                 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5511 
5512                 pkt = &cmd->cmd_pkt;
5513 
5514                 spn = s_id;
5515 
5516                 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&spn, (uint8_t *)
5517                     (pkt->pkt_cmd + sizeof (fc_ct_header_t)), sizeof (spn),
5518                     DDI_DEV_AUTOINCR);
5519                 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&name_len,
5520                     (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)
5521                     + sizeof (fc_portid_t)), 1, DDI_DEV_AUTOINCR);
5522 
5523                 if (pd == NULL) {
5524                         mutex_enter(&port->fp_mutex);
5525                         FC_SET_CMD(port, pkt->pkt_cmd_acc,
5526                             (uint8_t *)port->fp_sym_port_name, (uint8_t *)
5527                             (pkt->pkt_cmd + sizeof (fc_ct_header_t) +
5528                             sizeof (spn) + 1), name_len, DDI_DEV_AUTOINCR);
5529                         mutex_exit(&port->fp_mutex);
5530                 } else {
5531                         mutex_enter(&pd->pd_mutex);
5532                         FC_SET_CMD(port, pkt->pkt_cmd_acc,
5533                             (uint8_t *)pd->pd_spn,
5534                             (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t) +
5535                             sizeof (spn) + 1), name_len, DDI_DEV_AUTOINCR);
5536                         mutex_exit(&pd->pd_mutex);
5537                 }
5538                 break;
5539         }
5540 
5541         case NS_RPT_ID: {
5542                 ns_rpt_t rpt;
5543 
5544                 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
5545                     sizeof (ns_rpt_t), sizeof (fc_reg_resp_t), sleep, NULL);
5546                 if (cmd == NULL) {
5547                         return (FC_NOMEM);
5548                 }
5549                 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5550                 pkt = &cmd->cmd_pkt;
5551 
5552                 if (pd == NULL) {
5553                         rpt.rpt_type = port->fp_port_type;
5554                 } else {
5555                         mutex_enter(&pd->pd_mutex);
5556                         rpt.rpt_type = pd->pd_porttype;
5557                         mutex_exit(&pd->pd_mutex);
5558                 }
5559                 rpt.rpt_port_id = s_id;
5560 
5561                 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rpt,
5562                     (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
5563                     sizeof (rpt), DDI_DEV_AUTOINCR);
5564 
5565                 break;
5566         }
5567 
5568         case NS_RIP_NN: {
5569                 ns_rip_t rip;
5570 
5571                 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
5572                     sizeof (ns_rip_t), sizeof (fc_reg_resp_t), sleep, NULL);
5573                 if (cmd == NULL) {
5574                         return (FC_NOMEM);
5575                 }
5576                 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5577                 pkt = &cmd->cmd_pkt;
5578 
5579                 if (pd == NULL) {
5580                         rip.rip_node_name =
5581                             port->fp_service_params.node_ww_name;
5582                         bcopy(port->fp_ip_addr, rip.rip_ip_addr,
5583                             sizeof (port->fp_ip_addr));
5584                 } else {
5585                         fc_remote_node_t *node;
5586 
5587                         /*
5588                          * The most correct implementation should have the IP
5589                          * address in the fc_remote_node_t structure; I believe
5590                          * Node WWN and IP address should have one to one
5591                          * correlation (but guess what this is changing in
5592                          * FC-GS-2 latest draft)
5593                          */
5594                         mutex_enter(&pd->pd_mutex);
5595                         node = pd->pd_remote_nodep;
5596                         bcopy(pd->pd_ip_addr, rip.rip_ip_addr,
5597                             sizeof (pd->pd_ip_addr));
5598                         mutex_exit(&pd->pd_mutex);
5599 
5600                         mutex_enter(&node->fd_mutex);
5601                         rip.rip_node_name = node->fd_node_name;
5602                         mutex_exit(&node->fd_mutex);
5603                 }
5604 
5605                 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rip,
5606                     (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
5607                     sizeof (rip), DDI_DEV_AUTOINCR);
5608 
5609                 break;
5610         }
5611 
5612         case NS_RIPA_NN: {
5613                 ns_ipa_t ipa;
5614 
5615                 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
5616                     sizeof (ns_ipa_t), sizeof (fc_reg_resp_t), sleep, NULL);
5617                 if (cmd == NULL) {
5618                         return (FC_NOMEM);
5619                 }
5620                 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5621                 pkt = &cmd->cmd_pkt;
5622 
5623                 if (pd == NULL) {
5624                         ipa.ipa_node_name =
5625                             port->fp_service_params.node_ww_name;
5626                         bcopy(port->fp_ipa, ipa.ipa_value,
5627                             sizeof (port->fp_ipa));
5628                 } else {
5629                         fc_remote_node_t *node;
5630 
5631                         mutex_enter(&pd->pd_mutex);
5632                         node = pd->pd_remote_nodep;
5633                         mutex_exit(&pd->pd_mutex);
5634 
5635                         mutex_enter(&node->fd_mutex);
5636                         ipa.ipa_node_name = node->fd_node_name;
5637                         bcopy(node->fd_ipa, ipa.ipa_value,
5638                             sizeof (node->fd_ipa));
5639                         mutex_exit(&node->fd_mutex);
5640                 }
5641 
5642                 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&ipa,
5643                     (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
5644                     sizeof (ipa), DDI_DEV_AUTOINCR);
5645 
5646                 break;
5647         }
5648 
5649         case NS_RSNN_NN: {
5650                 uchar_t                 name_len;
5651                 int                     pl_size;
5652                 la_wwn_t                snn;
5653                 fc_remote_node_t        *node = NULL;
5654 
5655                 if (pd == NULL) {
5656                         mutex_enter(&port->fp_mutex);
5657                         name_len = port->fp_sym_node_namelen;
5658                         mutex_exit(&port->fp_mutex);
5659                 } else {
5660                         mutex_enter(&pd->pd_mutex);
5661                         node = pd->pd_remote_nodep;
5662                         mutex_exit(&pd->pd_mutex);
5663 
5664                         mutex_enter(&node->fd_mutex);
5665                         name_len = node->fd_snn_len;
5666                         mutex_exit(&node->fd_mutex);
5667                 }
5668 
5669                 pl_size = sizeof (la_wwn_t) + name_len + 1;
5670 
5671                 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
5672                     pl_size, sizeof (fc_reg_resp_t), sleep, NULL);
5673                 if (cmd == NULL) {
5674                         return (FC_NOMEM);
5675                 }
5676                 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5677 
5678                 pkt = &cmd->cmd_pkt;
5679 
5680                 bcopy(&port->fp_service_params.node_ww_name,
5681                     &snn, sizeof (la_wwn_t));
5682 
5683                 if (pd == NULL) {
5684                         mutex_enter(&port->fp_mutex);
5685                         FC_SET_CMD(port, pkt->pkt_cmd_acc,
5686                             (uint8_t *)port->fp_sym_node_name, (uint8_t *)
5687                             (pkt->pkt_cmd + sizeof (fc_ct_header_t) +
5688                             sizeof (snn) + 1), name_len, DDI_DEV_AUTOINCR);
5689                         mutex_exit(&port->fp_mutex);
5690                 } else {
5691                         ASSERT(node != NULL);
5692                         mutex_enter(&node->fd_mutex);
5693                         FC_SET_CMD(port, pkt->pkt_cmd_acc,
5694                             (uint8_t *)node->fd_snn,
5695                             (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t) +
5696                             sizeof (snn) + 1), name_len, DDI_DEV_AUTOINCR);
5697                         mutex_exit(&node->fd_mutex);
5698                 }
5699 
5700                 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&snn,
5701                     (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
5702                     sizeof (snn), DDI_DEV_AUTOINCR);
5703                 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&name_len,
5704                     (uint8_t *)(pkt->pkt_cmd
5705                     + sizeof (fc_ct_header_t) + sizeof (snn)),
5706                     1, DDI_DEV_AUTOINCR);
5707 
5708                 break;
5709         }
5710 
5711         case NS_DA_ID: {
5712                 ns_remall_t rall;
5713                 char tmp[4] = {0};
5714                 char *ptr;
5715 
5716                 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
5717                     sizeof (ns_remall_t), sizeof (fc_reg_resp_t), sleep, NULL);
5718 
5719                 if (cmd == NULL) {
5720                         return (FC_NOMEM);
5721                 }
5722 
5723                 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job);
5724                 pkt = &cmd->cmd_pkt;
5725 
5726                 ptr = (char *)(&s_id);
5727                 tmp[3] = *ptr++;
5728                 tmp[2] = *ptr++;
5729                 tmp[1] = *ptr++;
5730                 tmp[0] = *ptr;
5731 #if defined(_BIT_FIELDS_LTOH)
5732                 bcopy((caddr_t)tmp, (caddr_t)(&rall.rem_port_id), 4);
5733 #else
5734                 rall.rem_port_id = s_id;
5735 #endif
5736                 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rall,
5737                     (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
5738                     sizeof (rall), DDI_DEV_AUTOINCR);
5739 
5740                 break;
5741         }
5742 
5743         default:
5744                 return (FC_FAILURE);
5745         }
5746 
5747         rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
5748 
5749         if (rval != FC_SUCCESS) {
5750                 job->job_result = rval;
5751                 fp_iodone(cmd);
5752         }
5753 
5754         if (polled) {
5755                 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
5756                 fp_jobwait(job);
5757         } else {
5758                 rval = FC_SUCCESS;
5759         }
5760 
5761         return (rval);
5762 }
5763 
5764 
5765 /*
5766  * Common interrupt handler
5767  */
5768 static int
5769 fp_common_intr(fc_packet_t *pkt, int iodone)
5770 {
5771         int             rval = FC_FAILURE;
5772         fp_cmd_t        *cmd;
5773         fc_local_port_t *port;
5774 
5775         cmd = pkt->pkt_ulp_private;
5776         port = cmd->cmd_port;
5777 
5778         /*
5779          * Fail fast the upper layer requests if
5780          * a state change has occurred amidst.
5781          */
5782         mutex_enter(&port->fp_mutex);
5783         if (cmd->cmd_ulp_pkt != NULL && port->fp_statec_busy) {
5784                 mutex_exit(&port->fp_mutex);
5785                 cmd->cmd_ulp_pkt->pkt_state = FC_PKT_PORT_OFFLINE;
5786                 cmd->cmd_ulp_pkt->pkt_reason = FC_REASON_OFFLINE;
5787         } else if (!(port->fp_soft_state &
5788             (FP_SOFT_IN_DETACH | FP_DETACH_INPROGRESS))) {
5789                 mutex_exit(&port->fp_mutex);
5790 
5791                 switch (pkt->pkt_state) {
5792                 case FC_PKT_LOCAL_BSY:
5793                 case FC_PKT_FABRIC_BSY:
5794                 case FC_PKT_NPORT_BSY:
5795                 case FC_PKT_TIMEOUT:
5796                         cmd->cmd_retry_interval = (pkt->pkt_state ==
5797                             FC_PKT_TIMEOUT) ? 0 : fp_retry_delay;
5798                         rval = fp_retry_cmd(pkt);
5799                         break;
5800 
5801                 case FC_PKT_FABRIC_RJT:
5802                 case FC_PKT_NPORT_RJT:
5803                 case FC_PKT_LOCAL_RJT:
5804                 case FC_PKT_LS_RJT:
5805                 case FC_PKT_FS_RJT:
5806                 case FC_PKT_BA_RJT:
5807                         rval = fp_handle_reject(pkt);
5808                         break;
5809 
5810                 default:
5811                         if (pkt->pkt_resp_resid) {
5812                                 cmd->cmd_retry_interval = 0;
5813                                 rval = fp_retry_cmd(pkt);
5814                         }
5815                         break;
5816                 }
5817         } else {
5818                 mutex_exit(&port->fp_mutex);
5819         }
5820 
5821         if (rval != FC_SUCCESS && iodone) {
5822                 fp_iodone(cmd);
5823                 rval = FC_SUCCESS;
5824         }
5825 
5826         return (rval);
5827 }
5828 
5829 
5830 /*
5831  * Some not so long winding theory on point to point topology:
5832  *
5833  *      In the ACC payload, if the D_ID is ZERO and the common service
5834  *      parameters indicate N_Port, then the topology is POINT TO POINT.
5835  *
5836  *      In a point to point topology with an N_Port, during Fabric Login,
5837  *      the destination N_Port will check with our WWN and decide if it
5838  *      needs to issue PLOGI or not. That means, FLOGI could potentially
5839  *      trigger an unsolicited PLOGI from an N_Port. The Unsolicited
5840  *      PLOGI creates the device handles.
5841  *
5842  *      Assuming that the host port WWN is greater than the other N_Port
5843  *      WWN, then we become the master (be aware that this isn't the word
5844  *      used in the FC standards) and initiate the PLOGI.
5845  *
5846  */
5847 static void
5848 fp_flogi_intr(fc_packet_t *pkt)
5849 {
5850         int                     state;
5851         int                     f_port;
5852         uint32_t                s_id;
5853         uint32_t                d_id;
5854         fp_cmd_t                *cmd;
5855         fc_local_port_t         *port;
5856         la_wwn_t                *swwn;
5857         la_wwn_t                dwwn;
5858         la_wwn_t                nwwn;
5859         fc_remote_port_t        *pd;
5860         la_els_logi_t           *acc;
5861         com_svc_t               csp;
5862         ls_code_t               resp;
5863 
5864         cmd = pkt->pkt_ulp_private;
5865         port = cmd->cmd_port;
5866 
5867         mutex_enter(&port->fp_mutex);
5868         port->fp_out_fpcmds--;
5869         mutex_exit(&port->fp_mutex);
5870 
5871         FP_TRACE(FP_NHEAD1(1, 0), "fp_flogi_intr; port=%p, pkt=%p, state=%x",
5872             port, pkt, pkt->pkt_state);
5873 
5874         if (FP_IS_PKT_ERROR(pkt)) {
5875                 (void) fp_common_intr(pkt, 1);
5876                 return;
5877         }
5878 
5879         /*
5880          * Currently, we don't need to swap bytes here because qlc is faking the
5881          * response for us and so endianness is getting taken care of. But we
5882          * have to fix this and generalize this at some point
5883          */
5884         acc = (la_els_logi_t *)pkt->pkt_resp;
5885 
5886         FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp, (uint8_t *)acc,
5887             sizeof (resp), DDI_DEV_AUTOINCR);
5888 
5889         ASSERT(resp.ls_code == LA_ELS_ACC);
5890         if (resp.ls_code != LA_ELS_ACC) {
5891                 (void) fp_common_intr(pkt, 1);
5892                 return;
5893         }
5894 
5895         FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&csp,
5896             (uint8_t *)&acc->common_service, sizeof (csp), DDI_DEV_AUTOINCR);
5897 
5898         f_port = FP_IS_F_PORT(csp.cmn_features) ? 1 : 0;
5899 
5900         ASSERT(!MUTEX_HELD(&port->fp_mutex));
5901 
5902         mutex_enter(&port->fp_mutex);
5903         state = FC_PORT_STATE_MASK(port->fp_state);
5904         mutex_exit(&port->fp_mutex);
5905 
5906         if (f_port == 0) {
5907                 if (state != FC_STATE_LOOP) {
5908                         swwn = &port->fp_service_params.nport_ww_name;
5909 
5910                         FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&dwwn,
5911                             (uint8_t *)&acc->nport_ww_name, sizeof (la_wwn_t),
5912                             DDI_DEV_AUTOINCR);
5913 
5914                         FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&nwwn,
5915                             (uint8_t *)&acc->node_ww_name, sizeof (la_wwn_t),
5916                             DDI_DEV_AUTOINCR);
5917 
5918                         mutex_enter(&port->fp_mutex);
5919 
5920                         port->fp_topology = FC_TOP_PT_PT;
5921                         port->fp_total_devices = 1;
5922                         if (fctl_wwn_cmp(swwn, &dwwn) >= 0) {
5923                                 port->fp_ptpt_master = 1;
5924                                 /*
5925                                  * Let us choose 'X' as S_ID and 'Y'
5926                                  * as D_ID and that'll work; hopefully
5927                                  * If not, it will get changed.
5928                                  */
5929                                 s_id = port->fp_instance + FP_DEFAULT_SID;
5930                                 d_id = port->fp_instance + FP_DEFAULT_DID;
5931                                 port->fp_port_id.port_id = s_id;
5932                                 mutex_exit(&port->fp_mutex);
5933 
5934                                 FP_TRACE(FP_NHEAD1(1, 0), "fp_flogi_intr: fp %x"
5935                                     "pd %x", port->fp_port_id.port_id, d_id);
5936                                 pd = fctl_create_remote_port(port,
5937                                     &nwwn, &dwwn, d_id, PD_PLOGI_INITIATOR,
5938                                     KM_NOSLEEP);
5939                                 if (pd == NULL) {
5940                                         fp_printf(port, CE_NOTE, FP_LOG_ONLY,
5941                                             0, NULL, "couldn't create device"
5942                                             " d_id=%X", d_id);
5943                                         fp_iodone(cmd);
5944                                         return;
5945                                 }
5946 
5947                                 cmd->cmd_pkt.pkt_tran_flags =
5948                                     pkt->pkt_tran_flags;
5949                                 cmd->cmd_pkt.pkt_tran_type = pkt->pkt_tran_type;
5950                                 cmd->cmd_flags = FP_CMD_PLOGI_RETAIN;
5951                                 cmd->cmd_retry_count = fp_retry_count;
5952 
5953                                 fp_xlogi_init(port, cmd, s_id, d_id,
5954                                     fp_plogi_intr, cmd->cmd_job, LA_ELS_PLOGI);
5955 
5956                                 (&cmd->cmd_pkt)->pkt_pd = pd;
5957 
5958                                 /*
5959                                  * We've just created this fc_remote_port_t, and
5960                                  * we're about to use it to send a PLOGI, so
5961                                  * bump the reference count right now.  When
5962                                  * the packet is freed, the reference count will
5963                                  * be decremented.  The ULP may also start using
5964                                  * it, so mark it as given away as well.
5965                                  */
5966                                 pd->pd_ref_count++;
5967                                 pd->pd_aux_flags |= PD_GIVEN_TO_ULPS;
5968 
5969                                 if (fp_sendcmd(port, cmd,
5970                                     port->fp_fca_handle) == FC_SUCCESS) {
5971                                         return;
5972                                 }
5973                         } else {
5974                                 /*
5975                                  * The device handles will be created when the
5976                                  * unsolicited PLOGI is completed successfully
5977                                  */
5978                                 port->fp_ptpt_master = 0;
5979                                 mutex_exit(&port->fp_mutex);
5980                         }
5981                 }
5982                 pkt->pkt_state = FC_PKT_FAILURE;
5983         } else {
5984                 if (f_port) {
5985                         mutex_enter(&port->fp_mutex);
5986                         if (state == FC_STATE_LOOP) {
5987                                 port->fp_topology = FC_TOP_PUBLIC_LOOP;
5988                         } else {
5989                                 port->fp_topology = FC_TOP_FABRIC;
5990 
5991                                 FC_GET_RSP(port, pkt->pkt_resp_acc,
5992                                     (uint8_t *)&port->fp_fabric_name,
5993                                     (uint8_t *)&acc->node_ww_name,
5994                                     sizeof (la_wwn_t),
5995                                     DDI_DEV_AUTOINCR);
5996                         }
5997                         port->fp_port_id.port_id = pkt->pkt_resp_fhdr.d_id;
5998                         mutex_exit(&port->fp_mutex);
5999                 } else {
6000                         pkt->pkt_state = FC_PKT_FAILURE;
6001                 }
6002         }
6003         fp_iodone(cmd);
6004 }
6005 
6006 
6007 /*
6008  * Handle solicited PLOGI response
6009  */
6010 static void
6011 fp_plogi_intr(fc_packet_t *pkt)
6012 {
6013         int                     nl_port;
6014         int                     bailout;
6015         uint32_t                d_id;
6016         fp_cmd_t                *cmd;
6017         la_els_logi_t           *acc;
6018         fc_local_port_t         *port;
6019         fc_remote_port_t        *pd;
6020         la_wwn_t                nwwn;
6021         la_wwn_t                pwwn;
6022         ls_code_t               resp;
6023 
6024         nl_port = 0;
6025         cmd = pkt->pkt_ulp_private;
6026         port = cmd->cmd_port;
6027         d_id = pkt->pkt_cmd_fhdr.d_id;
6028 
6029 #ifndef __lock_lint
6030         ASSERT(cmd->cmd_job && cmd->cmd_job->job_counter);
6031 #endif
6032 
6033         FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_intr: port=%p, job=%p, d_id=%x,"
6034             " jcount=%d pkt=%p, state=%x", port, cmd->cmd_job, d_id,
6035             cmd->cmd_job->job_counter, pkt, pkt->pkt_state);
6036 
6037         /*
6038          * Bail out early on ULP initiated requests if the
6039          * state change has occurred
6040          */
6041         mutex_enter(&port->fp_mutex);
6042         port->fp_out_fpcmds--;
6043         bailout = ((port->fp_statec_busy ||
6044             FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) &&
6045             cmd->cmd_ulp_pkt) ? 1 : 0;
6046         mutex_exit(&port->fp_mutex);
6047 
6048         if (FP_IS_PKT_ERROR(pkt) || bailout) {
6049                 int skip_msg = 0;
6050                 int giveup = 0;
6051 
6052                 if (cmd->cmd_ulp_pkt) {
6053                         cmd->cmd_ulp_pkt->pkt_state = pkt->pkt_state;
6054                         cmd->cmd_ulp_pkt->pkt_reason = pkt->pkt_reason;
6055                         cmd->cmd_ulp_pkt->pkt_action = pkt->pkt_action;
6056                         cmd->cmd_ulp_pkt->pkt_expln = pkt->pkt_expln;
6057                 }
6058 
6059                 /*
6060                  * If an unsolicited cross login already created
6061                  * a device speed up the discovery by not retrying
6062                  * the command mindlessly.
6063                  */
6064                 if (pkt->pkt_pd == NULL &&
6065                     fctl_get_remote_port_by_did(port, d_id) != NULL) {
6066                         fp_iodone(cmd);
6067                         return;
6068                 }
6069 
6070                 if (pkt->pkt_pd != NULL) {
6071                         giveup = (pkt->pkt_pd->pd_recepient ==
6072                             PD_PLOGI_RECEPIENT) ? 1 : 0;
6073                         if (giveup) {
6074                                 /*
6075                                  * This pd is marked as plogi
6076                                  * recipient, stop retrying
6077                                  */
6078                                 FP_TRACE(FP_NHEAD1(3, 0),
6079                                     "fp_plogi_intr: stop retry as"
6080                                     " a cross login was accepted"
6081                                     " from d_id=%x, port=%p.",
6082                                     d_id, port);
6083                                 fp_iodone(cmd);
6084                                 return;
6085                         }
6086                 }
6087 
6088                 if (fp_common_intr(pkt, 0) == FC_SUCCESS) {
6089                         return;
6090                 }
6091 
6092                 if ((pd = fctl_get_remote_port_by_did(port, d_id)) != NULL) {
6093                         mutex_enter(&pd->pd_mutex);
6094                         if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
6095                                 skip_msg++;
6096                         }
6097                         mutex_exit(&pd->pd_mutex);
6098                 }
6099 
6100                 mutex_enter(&port->fp_mutex);
6101                 if (!bailout && !(skip_msg && port->fp_statec_busy) &&
6102                     port->fp_statec_busy <= 1 &&
6103                     pkt->pkt_reason != FC_REASON_FCAL_OPN_FAIL) {
6104                         mutex_exit(&port->fp_mutex);
6105                         /*
6106                          * In case of Login Collisions, JNI HBAs returns the
6107                          * FC pkt back to the Initiator with the state set to
6108                          * FC_PKT_LS_RJT and reason to FC_REASON_LOGICAL_ERROR.
6109                          * QLC HBAs handles such cases in the FW and doesnot
6110                          * return the LS_RJT with Logical error when
6111                          * login collision happens.
6112                          */
6113                         if ((pkt->pkt_state != FC_PKT_LS_RJT) ||
6114                             (pkt->pkt_reason != FC_REASON_LOGICAL_ERROR)) {
6115                                 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, pkt,
6116                                     "PLOGI to %x failed", d_id);
6117                         }
6118                         FP_TRACE(FP_NHEAD2(9, 0),
6119                             "PLOGI to %x failed. state=%x reason=%x.",
6120                             d_id, pkt->pkt_state, pkt->pkt_reason);
6121                 } else {
6122                         mutex_exit(&port->fp_mutex);
6123                 }
6124 
6125                 fp_iodone(cmd);
6126                 return;
6127         }
6128 
6129         acc = (la_els_logi_t *)pkt->pkt_resp;
6130 
6131         FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp, (uint8_t *)acc,
6132             sizeof (resp), DDI_DEV_AUTOINCR);
6133 
6134         ASSERT(resp.ls_code == LA_ELS_ACC);
6135         if (resp.ls_code != LA_ELS_ACC) {
6136                 (void) fp_common_intr(pkt, 1);
6137                 return;
6138         }
6139 
6140         if (d_id == FS_NAME_SERVER || d_id == FS_FABRIC_CONTROLLER) {
6141                 mutex_enter(&port->fp_mutex);
6142                 port->fp_ns_login_class = FC_TRAN_CLASS(pkt->pkt_tran_flags);
6143                 mutex_exit(&port->fp_mutex);
6144                 fp_iodone(cmd);
6145                 return;
6146         }
6147 
6148         ASSERT(acc == (la_els_logi_t *)pkt->pkt_resp);
6149 
6150         FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&pwwn,
6151             (uint8_t *)&acc->nport_ww_name, sizeof (la_wwn_t),
6152             DDI_DEV_AUTOINCR);
6153 
6154         FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&nwwn,
6155             (uint8_t *)&acc->node_ww_name, sizeof (la_wwn_t),
6156             DDI_DEV_AUTOINCR);
6157 
6158         ASSERT(fctl_is_wwn_zero(&pwwn) == FC_FAILURE);
6159         ASSERT(fctl_is_wwn_zero(&nwwn) == FC_FAILURE);
6160 
6161         if ((pd = pkt->pkt_pd) == NULL) {
6162                 pd = fctl_get_remote_port_by_pwwn(port, &pwwn);
6163                 if (pd == NULL) {
6164                         FP_TRACE(FP_NHEAD2(1, 0), "fp_plogi_intr: fp %x pd %x",
6165                             port->fp_port_id.port_id, d_id);
6166                         pd = fctl_create_remote_port(port, &nwwn, &pwwn, d_id,
6167                             PD_PLOGI_INITIATOR, KM_NOSLEEP);
6168                         if (pd == NULL) {
6169                                 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
6170                                     "couldn't create port device handles"
6171                                     " d_id=%x", d_id);
6172                                 fp_iodone(cmd);
6173                                 return;
6174                         }
6175                 } else {
6176                         fc_remote_port_t *tmp_pd;
6177 
6178                         tmp_pd = fctl_get_remote_port_by_did(port, d_id);
6179                         if (tmp_pd != NULL) {
6180                                 fp_iodone(cmd);
6181                                 return;
6182                         }
6183 
6184                         mutex_enter(&port->fp_mutex);
6185                         mutex_enter(&pd->pd_mutex);
6186                         if ((pd->pd_state == PORT_DEVICE_LOGGED_IN) ||
6187                             (pd->pd_aux_flags & PD_LOGGED_OUT)) {
6188                                 cmd->cmd_flags |= FP_CMD_PLOGI_RETAIN;
6189                         }
6190 
6191                         if (pd->pd_type == PORT_DEVICE_OLD) {
6192                                 if (pd->pd_port_id.port_id != d_id) {
6193                                         fctl_delist_did_table(port, pd);
6194                                         pd->pd_type = PORT_DEVICE_CHANGED;
6195                                         pd->pd_port_id.port_id = d_id;
6196                                 } else {
6197                                         pd->pd_type = PORT_DEVICE_NOCHANGE;
6198                                 }
6199                         }
6200 
6201                         if (pd->pd_aux_flags & PD_IN_DID_QUEUE) {
6202                                 char ww_name[17];
6203 
6204                                 fc_wwn_to_str(&pd->pd_port_name, ww_name);
6205 
6206                                 mutex_exit(&pd->pd_mutex);
6207                                 mutex_exit(&port->fp_mutex);
6208                                 FP_TRACE(FP_NHEAD2(9, 0),
6209                                     "Possible Duplicate name or address"
6210                                     " identifiers in the PLOGI response"
6211                                     " D_ID=%x, PWWN=%s: Please check the"
6212                                     " configuration", d_id, ww_name);
6213                                 fp_iodone(cmd);
6214                                 return;
6215                         }
6216                         fctl_enlist_did_table(port, pd);
6217                         pd->pd_aux_flags &= ~PD_LOGGED_OUT;
6218                         mutex_exit(&pd->pd_mutex);
6219                         mutex_exit(&port->fp_mutex);
6220                 }
6221         } else {
6222                 fc_remote_port_t *tmp_pd, *new_wwn_pd;
6223 
6224                 tmp_pd = fctl_get_remote_port_by_did(port, d_id);
6225                 new_wwn_pd = fctl_get_remote_port_by_pwwn(port, &pwwn);
6226 
6227                 mutex_enter(&port->fp_mutex);
6228                 mutex_enter(&pd->pd_mutex);
6229                 if (fctl_wwn_cmp(&pd->pd_port_name, &pwwn) == 0) {
6230                         FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_intr: d_id=%x,"
6231                             " pd_state=%x pd_type=%x", d_id, pd->pd_state,
6232                             pd->pd_type);
6233                         if ((pd->pd_state == PORT_DEVICE_LOGGED_IN &&
6234                             pd->pd_type == PORT_DEVICE_OLD) ||
6235                             (pd->pd_aux_flags & PD_LOGGED_OUT)) {
6236                                 pd->pd_type = PORT_DEVICE_NOCHANGE;
6237                         } else if (pd->pd_state != PORT_DEVICE_LOGGED_IN) {
6238                                 pd->pd_type = PORT_DEVICE_NEW;
6239                         }
6240                 } else {
6241                         char    old_name[17];
6242                         char    new_name[17];
6243 
6244                         fc_wwn_to_str(&pd->pd_port_name, old_name);
6245                         fc_wwn_to_str(&pwwn, new_name);
6246 
6247                         FP_TRACE(FP_NHEAD1(9, 0),
6248                             "fp_plogi_intr: PWWN of a device with D_ID=%x "
6249                             "changed. New PWWN = %s, OLD PWWN = %s ; tmp_pd:%p "
6250                             "pd:%p new_wwn_pd:%p, cmd_ulp_pkt:%p, bailout:0x%x",
6251                             d_id, new_name, old_name, tmp_pd, pd, new_wwn_pd,
6252                             cmd->cmd_ulp_pkt, bailout);
6253 
6254                         FP_TRACE(FP_NHEAD2(9, 0),
6255                             "PWWN of a device with D_ID=%x changed."
6256                             " New PWWN = %s, OLD PWWN = %s", d_id,
6257                             new_name, old_name);
6258 
6259                         if (cmd->cmd_ulp_pkt && !bailout) {
6260                                 fc_remote_node_t        *rnodep;
6261                                 fc_portmap_t    *changelist;
6262                                 fc_portmap_t    *listptr;
6263                                 int             len = 1;
6264                                 /* # entries in changelist */
6265 
6266                                 fctl_delist_pwwn_table(port, pd);
6267 
6268                                 /*
6269                                  * Lets now check if there already is a pd with
6270                                  * this new WWN in the table. If so, we'll mark
6271                                  * it as invalid
6272                                  */
6273 
6274                                 if (new_wwn_pd) {
6275                                         /*
6276                                          * There is another pd with in the pwwn
6277                                          * table with the same WWN that we got
6278                                          * in the PLOGI payload. We have to get
6279                                          * it out of the pwwn table, update the
6280                                          * pd's state (fp_fillout_old_map does
6281                                          * this for us) and add it to the
6282                                          * changelist that goes up to ULPs.
6283                                          *
6284                                          * len is length of changelist and so
6285                                          * increment it.
6286                                          */
6287                                         len++;
6288 
6289                                         if (tmp_pd != pd) {
6290                                                 /*
6291                                                  * Odd case where pwwn and did
6292                                                  * tables are out of sync but
6293                                                  * we will handle that too. See
6294                                                  * more comments below.
6295                                                  *
6296                                                  * One more device that ULPs
6297                                                  * should know about and so len
6298                                                  * gets incremented again.
6299                                                  */
6300                                                 len++;
6301                                         }
6302 
6303                                         listptr = changelist = kmem_zalloc(len *
6304                                             sizeof (*changelist), KM_SLEEP);
6305 
6306                                         mutex_enter(&new_wwn_pd->pd_mutex);
6307                                         rnodep = new_wwn_pd->pd_remote_nodep;
6308                                         mutex_exit(&new_wwn_pd->pd_mutex);
6309 
6310                                         /*
6311                                          * Hold the fd_mutex since
6312                                          * fctl_copy_portmap_held expects it.
6313                                          * Preserve lock hierarchy by grabbing
6314                                          * fd_mutex before pd_mutex
6315                                          */
6316                                         if (rnodep) {
6317                                                 mutex_enter(&rnodep->fd_mutex);
6318                                         }
6319                                         mutex_enter(&new_wwn_pd->pd_mutex);
6320                                         fp_fillout_old_map_held(listptr++,
6321                                             new_wwn_pd, 0);
6322                                         mutex_exit(&new_wwn_pd->pd_mutex);
6323                                         if (rnodep) {
6324                                                 mutex_exit(&rnodep->fd_mutex);
6325                                         }
6326 
6327                                         /*
6328                                          * Safety check :
6329                                          * Lets ensure that the pwwn and did
6330                                          * tables are in sync. Ideally, we
6331                                          * should not find that these two pd's
6332                                          * are different.
6333                                          */
6334                                         if (tmp_pd != pd) {
6335                                                 mutex_enter(&tmp_pd->pd_mutex);
6336                                                 rnodep =
6337                                                     tmp_pd->pd_remote_nodep;
6338                                                 mutex_exit(&tmp_pd->pd_mutex);
6339 
6340                                                 /* As above grab fd_mutex */
6341                                                 if (rnodep) {
6342                                                         mutex_enter(&rnodep->
6343                                                             fd_mutex);
6344                                                 }
6345                                                 mutex_enter(&tmp_pd->pd_mutex);
6346 
6347                                                 fp_fillout_old_map_held(
6348                                                     listptr++, tmp_pd, 0);
6349 
6350                                                 mutex_exit(&tmp_pd->pd_mutex);
6351                                                 if (rnodep) {
6352                                                         mutex_exit(&rnodep->
6353                                                             fd_mutex);
6354                                                 }
6355 
6356                                                 /*
6357                                                  * Now add "pd" (not tmp_pd)
6358                                                  * to fp_did_table to sync it up
6359                                                  * with fp_pwwn_table
6360                                                  *
6361                                                  * pd->pd_mutex is already held
6362                                                  * at this point
6363                                                  */
6364                                                 fctl_enlist_did_table(port, pd);
6365                                         }
6366                                 } else {
6367                                         listptr = changelist = kmem_zalloc(
6368                                             sizeof (*changelist), KM_SLEEP);
6369                                 }
6370 
6371                                 ASSERT(changelist != NULL);
6372 
6373                                 fp_fillout_changed_map(listptr, pd, &d_id,
6374                                     &pwwn);
6375                                 fctl_enlist_pwwn_table(port, pd);
6376 
6377                                 mutex_exit(&pd->pd_mutex);
6378                                 mutex_exit(&port->fp_mutex);
6379 
6380                                 fp_iodone(cmd);
6381 
6382                                 (void) fp_ulp_devc_cb(port, changelist, len,
6383                                     len, KM_NOSLEEP, 0);
6384 
6385                                 return;
6386                         }
6387                 }
6388 
6389                 if (pd->pd_porttype.port_type == FC_NS_PORT_NL) {
6390                         nl_port = 1;
6391                 }
6392                 if (pd->pd_aux_flags & PD_DISABLE_RELOGIN) {
6393                         pd->pd_aux_flags &= ~PD_LOGGED_OUT;
6394                 }
6395 
6396                 mutex_exit(&pd->pd_mutex);
6397                 mutex_exit(&port->fp_mutex);
6398 
6399                 if (tmp_pd == NULL) {
6400                         mutex_enter(&port->fp_mutex);
6401                         mutex_enter(&pd->pd_mutex);
6402                         if (pd->pd_aux_flags & PD_IN_DID_QUEUE) {
6403                                 char ww_name[17];
6404 
6405                                 fc_wwn_to_str(&pd->pd_port_name, ww_name);
6406                                 mutex_exit(&pd->pd_mutex);
6407                                 mutex_exit(&port->fp_mutex);
6408                                 FP_TRACE(FP_NHEAD2(9, 0),
6409                                     "Possible Duplicate name or address"
6410                                     " identifiers in the PLOGI response"
6411                                     " D_ID=%x, PWWN=%s: Please check the"
6412                                     " configuration", d_id, ww_name);
6413                                 fp_iodone(cmd);
6414                                 return;
6415                         }
6416                         fctl_enlist_did_table(port, pd);
6417                         pd->pd_aux_flags &= ~PD_LOGGED_OUT;
6418                         mutex_exit(&pd->pd_mutex);
6419                         mutex_exit(&port->fp_mutex);
6420                 }
6421         }
6422         fp_register_login(&pkt->pkt_resp_acc, pd, acc,
6423             FC_TRAN_CLASS(pkt->pkt_tran_flags));
6424 
6425         if (cmd->cmd_ulp_pkt) {
6426                 cmd->cmd_ulp_pkt->pkt_state = pkt->pkt_state;
6427                 cmd->cmd_ulp_pkt->pkt_action = pkt->pkt_action;
6428                 cmd->cmd_ulp_pkt->pkt_expln = pkt->pkt_expln;
6429                 if (cmd->cmd_ulp_pkt->pkt_pd == NULL) {
6430                         if (pd != NULL) {
6431                                 FP_TRACE(FP_NHEAD1(9, 0),
6432                                     "fp_plogi_intr;"
6433                                     "ulp_pkt's pd is NULL, get a pd %p",
6434                                     pd);
6435                                 mutex_enter(&pd->pd_mutex);
6436                                 pd->pd_ref_count++;
6437                                 mutex_exit(&pd->pd_mutex);
6438                         }
6439                         cmd->cmd_ulp_pkt->pkt_pd = pd;
6440                 }
6441                 bcopy((caddr_t)&pkt->pkt_resp_fhdr,
6442                     (caddr_t)&cmd->cmd_ulp_pkt->pkt_resp_fhdr,
6443                     sizeof (fc_frame_hdr_t));
6444                 bcopy((caddr_t)pkt->pkt_resp,
6445                     (caddr_t)cmd->cmd_ulp_pkt->pkt_resp,
6446                     sizeof (la_els_logi_t));
6447         }
6448 
6449         mutex_enter(&port->fp_mutex);
6450         if (port->fp_topology == FC_TOP_PRIVATE_LOOP || nl_port) {
6451                 mutex_enter(&pd->pd_mutex);
6452 
6453                 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
6454                 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
6455                 cmd->cmd_retry_count = fp_retry_count;
6456 
6457                 /*
6458                  * If the fc_remote_port_t pointer is not set in the given
6459                  * fc_packet_t, then this fc_remote_port_t must have just
6460                  * been created.  Save the pointer and also increment the
6461                  * fc_remote_port_t reference count.
6462                  */
6463                 if (pkt->pkt_pd == NULL) {
6464                         pkt->pkt_pd = pd;
6465                         pd->pd_ref_count++;  /* It's in use! */
6466                 }
6467 
6468                 fp_adisc_init(cmd, cmd->cmd_job);
6469 
6470                 pkt->pkt_cmdlen = sizeof (la_els_adisc_t);
6471                 pkt->pkt_rsplen = sizeof (la_els_adisc_t);
6472 
6473                 mutex_exit(&pd->pd_mutex);
6474                 mutex_exit(&port->fp_mutex);
6475 
6476                 if (fp_sendcmd(port, cmd, port->fp_fca_handle) == FC_SUCCESS) {
6477                         return;
6478                 }
6479         } else {
6480                 mutex_exit(&port->fp_mutex);
6481         }
6482 
6483         if ((cmd->cmd_flags & FP_CMD_PLOGI_RETAIN) == 0) {
6484                 mutex_enter(&port->fp_mutex);
6485                 mutex_enter(&pd->pd_mutex);
6486 
6487                 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
6488                 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
6489                 cmd->cmd_retry_count = fp_retry_count;
6490 
6491                 fp_logo_init(pd, cmd, cmd->cmd_job);
6492 
6493                 pkt->pkt_cmdlen = sizeof (la_els_logo_t);
6494                 pkt->pkt_rsplen = FP_PORT_IDENTIFIER_LEN;
6495 
6496                 mutex_exit(&pd->pd_mutex);
6497                 mutex_exit(&port->fp_mutex);
6498 
6499                 if (fp_sendcmd(port, cmd, port->fp_fca_handle) == FC_SUCCESS) {
6500                         return;
6501                 }
6502 
6503         }
6504         fp_iodone(cmd);
6505 }
6506 
6507 
6508 /*
6509  * Handle solicited ADISC response
6510  */
6511 static void
6512 fp_adisc_intr(fc_packet_t *pkt)
6513 {
6514         int                     rval;
6515         int                     bailout;
6516         fp_cmd_t                *cmd, *logi_cmd;
6517         fc_local_port_t         *port;
6518         fc_remote_port_t        *pd;
6519         la_els_adisc_t          *acc;
6520         ls_code_t               resp;
6521         fc_hardaddr_t           ha;
6522         fc_portmap_t            *changelist;
6523         int                     initiator, adiscfail = 0;
6524 
6525         pd = pkt->pkt_pd;
6526         cmd = pkt->pkt_ulp_private;
6527         port = cmd->cmd_port;
6528 
6529 #ifndef __lock_lint
6530         ASSERT(cmd->cmd_job && cmd->cmd_job->job_counter);
6531 #endif
6532 
6533         ASSERT(pd != NULL && port != NULL && cmd != NULL);
6534 
6535         mutex_enter(&port->fp_mutex);
6536         port->fp_out_fpcmds--;
6537         bailout = ((port->fp_statec_busy ||
6538             FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) &&
6539             cmd->cmd_ulp_pkt) ? 1 : 0;
6540         mutex_exit(&port->fp_mutex);
6541 
6542         if (bailout) {
6543                 fp_iodone(cmd);
6544                 return;
6545         }
6546 
6547         if (pkt->pkt_state == FC_PKT_SUCCESS && pkt->pkt_resp_resid == 0) {
6548                 acc = (la_els_adisc_t *)pkt->pkt_resp;
6549 
6550                 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp,
6551                     (uint8_t *)acc, sizeof (resp), DDI_DEV_AUTOINCR);
6552 
6553                 if (resp.ls_code == LA_ELS_ACC) {
6554                         int     is_private;
6555 
6556                         FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&ha,
6557                             (uint8_t *)&acc->hard_addr, sizeof (ha),
6558                             DDI_DEV_AUTOINCR);
6559 
6560                         mutex_enter(&port->fp_mutex);
6561 
6562                         is_private =
6563                             (port->fp_topology == FC_TOP_PRIVATE_LOOP) ? 1 : 0;
6564 
6565                         mutex_enter(&pd->pd_mutex);
6566                         if ((pd->pd_aux_flags & PD_IN_DID_QUEUE) == 0) {
6567                                 fctl_enlist_did_table(port, pd);
6568                         }
6569                         mutex_exit(&pd->pd_mutex);
6570 
6571                         mutex_exit(&port->fp_mutex);
6572 
6573                         mutex_enter(&pd->pd_mutex);
6574                         if (pd->pd_type != PORT_DEVICE_NEW) {
6575                                 if (is_private && (pd->pd_hard_addr.hard_addr !=
6576                                     ha.hard_addr)) {
6577                                         pd->pd_type = PORT_DEVICE_CHANGED;
6578                                 } else {
6579                                         pd->pd_type = PORT_DEVICE_NOCHANGE;
6580                                 }
6581                         }
6582 
6583                         if (is_private && (ha.hard_addr &&
6584                             pd->pd_port_id.port_id != ha.hard_addr)) {
6585                                 char ww_name[17];
6586 
6587                                 fc_wwn_to_str(&pd->pd_port_name, ww_name);
6588 
6589                                 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
6590                                     "NL_Port Identifier %x doesn't match"
6591                                     " with Hard Address %x, Will use Port"
6592                                     " WWN %s", pd->pd_port_id.port_id,
6593                                     ha.hard_addr, ww_name);
6594 
6595                                 pd->pd_hard_addr.hard_addr = 0;
6596                         } else {
6597                                 pd->pd_hard_addr.hard_addr = ha.hard_addr;
6598                         }
6599                         mutex_exit(&pd->pd_mutex);
6600                 } else {
6601                         if (fp_common_intr(pkt, 0) == FC_SUCCESS) {
6602                                 return;
6603                         }
6604                 }
6605         } else {
6606                 if (fp_common_intr(pkt, 0) == FC_SUCCESS) {
6607                         return;
6608                 }
6609 
6610                 mutex_enter(&port->fp_mutex);
6611                 if (port->fp_statec_busy <= 1) {
6612                         mutex_exit(&port->fp_mutex);
6613                         if (pkt->pkt_state == FC_PKT_LS_RJT &&
6614                             pkt->pkt_reason == FC_REASON_CMD_UNABLE) {
6615                                 uchar_t class;
6616                                 int cmd_flag;
6617                                 uint32_t src_id;
6618 
6619                                 class = fp_get_nextclass(port,
6620                                     FC_TRAN_CLASS_INVALID);
6621                                 if (class == FC_TRAN_CLASS_INVALID) {
6622                                         fp_iodone(cmd);
6623                                         return;
6624                                 }
6625 
6626                                 FP_TRACE(FP_NHEAD1(1, 0), "ADISC re-login; "
6627                                     "fp_state=0x%x, pkt_state=0x%x, "
6628                                     "reason=0x%x, class=0x%x",
6629                                     port->fp_state, pkt->pkt_state,
6630                                     pkt->pkt_reason, class);
6631                                 cmd_flag = FP_CMD_PLOGI_RETAIN;
6632 
6633                                 logi_cmd = fp_alloc_pkt(port,
6634                                     sizeof (la_els_logi_t),
6635                                     sizeof (la_els_logi_t), KM_SLEEP, pd);
6636                                 if (logi_cmd == NULL) {
6637                                         fp_iodone(cmd);
6638                                         return;
6639                                 }
6640 
6641                                 logi_cmd->cmd_pkt.pkt_tran_flags =
6642                                     FC_TRAN_INTR | class;
6643                                 logi_cmd->cmd_pkt.pkt_tran_type =
6644                                     FC_PKT_EXCHANGE;
6645                                 logi_cmd->cmd_flags = cmd_flag;
6646                                 logi_cmd->cmd_retry_count = fp_retry_count;
6647                                 logi_cmd->cmd_ulp_pkt = NULL;
6648 
6649                                 mutex_enter(&port->fp_mutex);
6650                                 src_id = port->fp_port_id.port_id;
6651                                 mutex_exit(&port->fp_mutex);
6652 
6653                                 fp_xlogi_init(port, logi_cmd, src_id,
6654                                     pkt->pkt_cmd_fhdr.d_id, fp_plogi_intr,
6655                                     cmd->cmd_job, LA_ELS_PLOGI);
6656                                 if (pd) {
6657                                         mutex_enter(&pd->pd_mutex);
6658                                         pd->pd_flags = PD_ELS_IN_PROGRESS;
6659                                         mutex_exit(&pd->pd_mutex);
6660                                 }
6661 
6662                                 if (fp_sendcmd(port, logi_cmd,
6663                                     port->fp_fca_handle) == FC_SUCCESS) {
6664                                         fp_free_pkt(cmd);
6665                                         return;
6666                                 } else {
6667                                         fp_free_pkt(logi_cmd);
6668                                 }
6669                         } else {
6670                                 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, pkt,
6671                                     "ADISC to %x failed, cmd_flags=%x",
6672                                     pkt->pkt_cmd_fhdr.d_id, cmd->cmd_flags);
6673                                 cmd->cmd_flags &= ~FP_CMD_PLOGI_RETAIN;
6674                                 adiscfail = 1;
6675                         }
6676                 } else {
6677                         mutex_exit(&port->fp_mutex);
6678                 }
6679         }
6680 
6681         if (cmd->cmd_ulp_pkt) {
6682                 cmd->cmd_ulp_pkt->pkt_state = pkt->pkt_state;
6683                 cmd->cmd_ulp_pkt->pkt_action = pkt->pkt_action;
6684                 cmd->cmd_ulp_pkt->pkt_expln = pkt->pkt_expln;
6685                 if (cmd->cmd_ulp_pkt->pkt_pd == NULL) {
6686                         cmd->cmd_ulp_pkt->pkt_pd = pd;
6687                         FP_TRACE(FP_NHEAD1(9, 0),
6688                             "fp_adisc__intr;"
6689                             "ulp_pkt's pd is NULL, get a pd %p",
6690                             pd);
6691 
6692                 }
6693                 bcopy((caddr_t)&pkt->pkt_resp_fhdr,
6694                     (caddr_t)&cmd->cmd_ulp_pkt->pkt_resp_fhdr,
6695                     sizeof (fc_frame_hdr_t));
6696                 bcopy((caddr_t)pkt->pkt_resp,
6697                     (caddr_t)cmd->cmd_ulp_pkt->pkt_resp,
6698                     sizeof (la_els_adisc_t));
6699         }
6700 
6701         if ((cmd->cmd_flags & FP_CMD_PLOGI_RETAIN) == 0) {
6702                 FP_TRACE(FP_NHEAD1(9, 0),
6703                     "fp_adisc_intr: Perform LOGO.cmd_flags=%x, "
6704                     "fp_retry_count=%x, ulp_pkt=%p",
6705                     cmd->cmd_flags, fp_retry_count, cmd->cmd_ulp_pkt);
6706 
6707                 mutex_enter(&port->fp_mutex);
6708                 mutex_enter(&pd->pd_mutex);
6709 
6710                 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
6711                 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
6712                 cmd->cmd_retry_count = fp_retry_count;
6713 
6714                 fp_logo_init(pd, cmd, cmd->cmd_job);
6715 
6716                 pkt->pkt_cmdlen = sizeof (la_els_logo_t);
6717                 pkt->pkt_rsplen = FP_PORT_IDENTIFIER_LEN;
6718 
6719                 mutex_exit(&pd->pd_mutex);
6720                 mutex_exit(&port->fp_mutex);
6721 
6722                 rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
6723                 if (adiscfail) {
6724                         mutex_enter(&pd->pd_mutex);
6725                         initiator =
6726                             ((pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0);
6727                         pd->pd_state = PORT_DEVICE_VALID;
6728                         pd->pd_aux_flags |= PD_LOGGED_OUT;
6729                         if (pd->pd_aux_flags & PD_DISABLE_RELOGIN) {
6730                                 pd->pd_type = PORT_DEVICE_NEW;
6731                         } else {
6732                                 pd->pd_type = PORT_DEVICE_NOCHANGE;
6733                         }
6734                         mutex_exit(&pd->pd_mutex);
6735 
6736                         changelist =
6737                             kmem_zalloc(sizeof (*changelist), KM_SLEEP);
6738 
6739                         if (initiator) {
6740                                 fp_unregister_login(pd);
6741                                 fctl_copy_portmap(changelist, pd);
6742                         } else {
6743                                 fp_fillout_old_map(changelist, pd, 0);
6744                         }
6745 
6746                         FP_TRACE(FP_NHEAD1(9, 0),
6747                             "fp_adisc_intr: Dev change notification "
6748                             "to ULP port=%p, pd=%p, map_type=%x map_state=%x "
6749                             "map_flags=%x initiator=%d", port, pd,
6750                             changelist->map_type, changelist->map_state,
6751                             changelist->map_flags, initiator);
6752 
6753                         (void) fp_ulp_devc_cb(port, changelist,
6754                             1, 1, KM_SLEEP, 0);
6755                 }
6756                 if (rval == FC_SUCCESS) {
6757                         return;
6758                 }
6759         }
6760         fp_iodone(cmd);
6761 }
6762 
6763 
6764 /*
6765  * Handle solicited LOGO response
6766  */
6767 static void
6768 fp_logo_intr(fc_packet_t *pkt)
6769 {
6770         ls_code_t       resp;
6771         fc_local_port_t *port = ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port;
6772 
6773         mutex_enter(&((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_mutex);
6774         ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_out_fpcmds--;
6775         mutex_exit(&((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_mutex);
6776 
6777         FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp,
6778             (uint8_t *)pkt->pkt_resp, sizeof (resp), DDI_DEV_AUTOINCR);
6779 
6780         if (FP_IS_PKT_ERROR(pkt)) {
6781                 (void) fp_common_intr(pkt, 1);
6782                 return;
6783         }
6784 
6785         ASSERT(resp.ls_code == LA_ELS_ACC);
6786         if (resp.ls_code != LA_ELS_ACC) {
6787                 (void) fp_common_intr(pkt, 1);
6788                 return;
6789         }
6790 
6791         if (pkt->pkt_pd != NULL) {
6792                 fp_unregister_login(pkt->pkt_pd);
6793         }
6794 
6795         fp_iodone(pkt->pkt_ulp_private);
6796 }
6797 
6798 
6799 /*
6800  * Handle solicited RNID response
6801  */
6802 static void
6803 fp_rnid_intr(fc_packet_t *pkt)
6804 {
6805         ls_code_t               resp;
6806         job_request_t           *job;
6807         fp_cmd_t                *cmd;
6808         la_els_rnid_acc_t       *acc;
6809         fc_local_port_t *port = ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port;
6810 
6811         FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp,
6812             (uint8_t *)pkt->pkt_resp, sizeof (resp), DDI_DEV_AUTOINCR);
6813         cmd = pkt->pkt_ulp_private;
6814 
6815         mutex_enter(&cmd->cmd_port->fp_mutex);
6816         cmd->cmd_port->fp_out_fpcmds--;
6817         mutex_exit(&cmd->cmd_port->fp_mutex);
6818 
6819         job = cmd->cmd_job;
6820         ASSERT(job->job_private != NULL);
6821 
6822         /* If failure or LS_RJT then retry the packet, if needed */
6823         if (pkt->pkt_state != FC_PKT_SUCCESS || resp.ls_code != LA_ELS_ACC) {
6824                 (void) fp_common_intr(pkt, 1);
6825                 return;
6826         }
6827 
6828         /* Save node_id memory allocated in ioctl code */
6829         acc = (la_els_rnid_acc_t *)pkt->pkt_resp;
6830 
6831         FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)job->job_private,
6832             (uint8_t *)acc, sizeof (la_els_rnid_acc_t), DDI_DEV_AUTOINCR);
6833 
6834         /* wakeup the ioctl thread and free the pkt */
6835         fp_iodone(cmd);
6836 }
6837 
6838 
6839 /*
6840  * Handle solicited RLS response
6841  */
6842 static void
6843 fp_rls_intr(fc_packet_t *pkt)
6844 {
6845         ls_code_t               resp;
6846         job_request_t           *job;
6847         fp_cmd_t                *cmd;
6848         la_els_rls_acc_t        *acc;
6849         fc_local_port_t *port = ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port;
6850 
6851         FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp,
6852             (uint8_t *)pkt->pkt_resp, sizeof (resp), DDI_DEV_AUTOINCR);
6853         cmd = pkt->pkt_ulp_private;
6854 
6855         mutex_enter(&cmd->cmd_port->fp_mutex);
6856         cmd->cmd_port->fp_out_fpcmds--;
6857         mutex_exit(&cmd->cmd_port->fp_mutex);
6858 
6859         job = cmd->cmd_job;
6860         ASSERT(job->job_private != NULL);
6861 
6862         /* If failure or LS_RJT then retry the packet, if needed */
6863         if (FP_IS_PKT_ERROR(pkt) || resp.ls_code != LA_ELS_ACC) {
6864                 (void) fp_common_intr(pkt, 1);
6865                 return;
6866         }
6867 
6868         /* Save link error status block in memory allocated in ioctl code */
6869         acc = (la_els_rls_acc_t *)pkt->pkt_resp;
6870 
6871         FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)job->job_private,
6872             (uint8_t *)&acc->rls_link_params, sizeof (fc_rls_acc_t),
6873             DDI_DEV_AUTOINCR);
6874 
6875         /* wakeup the ioctl thread and free the pkt */
6876         fp_iodone(cmd);
6877 }
6878 
6879 
6880 /*
6881  * A solicited command completion interrupt (mostly for commands
6882  * that require almost no post processing such as SCR ELS)
6883  */
6884 static void
6885 fp_intr(fc_packet_t *pkt)
6886 {
6887         mutex_enter(&((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_mutex);
6888         ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_out_fpcmds--;
6889         mutex_exit(&((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_mutex);
6890 
6891         if (FP_IS_PKT_ERROR(pkt)) {
6892                 (void) fp_common_intr(pkt, 1);
6893                 return;
6894         }
6895         fp_iodone(pkt->pkt_ulp_private);
6896 }
6897 
6898 
6899 /*
6900  * Handle the underlying port's state change
6901  */
6902 static void
6903 fp_statec_cb(opaque_t port_handle, uint32_t state)
6904 {
6905         fc_local_port_t *port = port_handle;
6906         job_request_t   *job;
6907 
6908         /*
6909          * If it is not possible to process the callbacks
6910          * just drop the callback on the floor; Don't bother
6911          * to do something that isn't safe at this time
6912          */
6913         mutex_enter(&port->fp_mutex);
6914         if ((port->fp_soft_state &
6915             (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN)) ||
6916             (FC_PORT_STATE_MASK(port->fp_state) == FC_PORT_STATE_MASK(state))) {
6917                 mutex_exit(&port->fp_mutex);
6918                 return;
6919         }
6920 
6921         if (port->fp_statec_busy == 0) {
6922                 port->fp_soft_state |= FP_SOFT_IN_STATEC_CB;
6923 #ifdef  DEBUG
6924         } else {
6925                 ASSERT(port->fp_soft_state & FP_SOFT_IN_STATEC_CB);
6926 #endif
6927         }
6928 
6929         port->fp_statec_busy++;
6930 
6931         /*
6932          * For now, force the trusted method of device authentication (by
6933          * PLOGI) when LIPs do not involve OFFLINE to ONLINE transition.
6934          */
6935         if (FC_PORT_STATE_MASK(state) == FC_STATE_LIP ||
6936             FC_PORT_STATE_MASK(state) == FC_STATE_LIP_LBIT_SET) {
6937                 state = FC_PORT_SPEED_MASK(port->fp_state) | FC_STATE_LOOP;
6938                 fp_port_offline(port, 0);
6939         }
6940         mutex_exit(&port->fp_mutex);
6941 
6942         switch (FC_PORT_STATE_MASK(state)) {
6943         case FC_STATE_OFFLINE:
6944                 job = fctl_alloc_job(JOB_PORT_OFFLINE,
6945                     JOB_TYPE_FCTL_ASYNC, NULL, NULL, KM_NOSLEEP);
6946                 if (job == NULL) {
6947                         fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
6948                             " fp_statec_cb() couldn't submit a job "
6949                             " to the thread: failing..");
6950                         mutex_enter(&port->fp_mutex);
6951                         if (--port->fp_statec_busy == 0) {
6952                                 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
6953                         }
6954                         mutex_exit(&port->fp_mutex);
6955                         return;
6956                 }
6957                 mutex_enter(&port->fp_mutex);
6958                 /*
6959                  * Zero out this field so that we do not retain
6960                  * the fabric name as its no longer valid
6961                  */
6962                 bzero(&port->fp_fabric_name, sizeof (la_wwn_t));
6963                 port->fp_state = state;
6964                 mutex_exit(&port->fp_mutex);
6965 
6966                 fctl_enque_job(port, job);
6967                 break;
6968 
6969         case FC_STATE_ONLINE:
6970         case FC_STATE_LOOP:
6971                 mutex_enter(&port->fp_mutex);
6972                 port->fp_state = state;
6973 
6974                 if (port->fp_offline_tid) {
6975                         timeout_id_t tid;
6976 
6977                         tid = port->fp_offline_tid;
6978                         port->fp_offline_tid = NULL;
6979                         mutex_exit(&port->fp_mutex);
6980                         (void) untimeout(tid);
6981                 } else {
6982                         mutex_exit(&port->fp_mutex);
6983                 }
6984 
6985                 job = fctl_alloc_job(JOB_PORT_ONLINE,
6986                     JOB_TYPE_FCTL_ASYNC, NULL, NULL, KM_NOSLEEP);
6987                 if (job == NULL) {
6988                         fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
6989                             "fp_statec_cb() couldn't submit a job "
6990                             "to the thread: failing..");
6991 
6992                         mutex_enter(&port->fp_mutex);
6993                         if (--port->fp_statec_busy == 0) {
6994                                 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
6995                         }
6996                         mutex_exit(&port->fp_mutex);
6997                         return;
6998                 }
6999                 fctl_enque_job(port, job);
7000                 break;
7001 
7002         case FC_STATE_RESET_REQUESTED:
7003                 mutex_enter(&port->fp_mutex);
7004                 port->fp_state = FC_STATE_OFFLINE;
7005                 port->fp_soft_state |= FP_SOFT_IN_FCA_RESET;
7006                 mutex_exit(&port->fp_mutex);
7007                 /* FALLTHROUGH */
7008 
7009         case FC_STATE_RESET:
7010                 job = fctl_alloc_job(JOB_ULP_NOTIFY,
7011                     JOB_TYPE_FCTL_ASYNC, NULL, NULL, KM_NOSLEEP);
7012                 if (job == NULL) {
7013                         fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
7014                             "fp_statec_cb() couldn't submit a job"
7015                             " to the thread: failing..");
7016 
7017                         mutex_enter(&port->fp_mutex);
7018                         if (--port->fp_statec_busy == 0) {
7019                                 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
7020                         }
7021                         mutex_exit(&port->fp_mutex);
7022                         return;
7023                 }
7024 
7025                 /* squeeze into some field in the job structure */
7026                 job->job_ulp_listlen = FC_PORT_STATE_MASK(state);
7027                 fctl_enque_job(port, job);
7028                 break;
7029 
7030         case FC_STATE_TARGET_PORT_RESET:
7031                 (void) fp_ulp_notify(port, state, KM_NOSLEEP);
7032                 /* FALLTHROUGH */
7033 
7034         case FC_STATE_NAMESERVICE:
7035                 /* FALLTHROUGH */
7036 
7037         default:
7038                 mutex_enter(&port->fp_mutex);
7039                 if (--port->fp_statec_busy == 0) {
7040                         port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
7041                 }
7042                 mutex_exit(&port->fp_mutex);
7043                 break;
7044         }
7045 }
7046 
7047 
7048 /*
7049  * Register with the Name Server for RSCNs
7050  */
7051 static int
7052 fp_ns_scr(fc_local_port_t *port, job_request_t *job, uchar_t scr_func,
7053     int sleep)
7054 {
7055         uint32_t        s_id;
7056         uchar_t         class;
7057         fc_scr_req_t    payload;
7058         fp_cmd_t        *cmd;
7059         fc_packet_t     *pkt;
7060 
7061         mutex_enter(&port->fp_mutex);
7062         s_id = port->fp_port_id.port_id;
7063         class = port->fp_ns_login_class;
7064         mutex_exit(&port->fp_mutex);
7065 
7066         cmd = fp_alloc_pkt(port, sizeof (fc_scr_req_t),
7067             sizeof (fc_scr_resp_t), sleep, NULL);
7068         if (cmd == NULL) {
7069                 return (FC_NOMEM);
7070         }
7071 
7072         cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class;
7073         cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
7074         cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
7075         cmd->cmd_retry_count = fp_retry_count;
7076         cmd->cmd_ulp_pkt = NULL;
7077 
7078         pkt = &cmd->cmd_pkt;
7079         cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
7080 
7081         fp_els_init(cmd, s_id, 0xFFFFFD, fp_intr, job);
7082 
7083         payload.ls_code.ls_code = LA_ELS_SCR;
7084         payload.ls_code.mbz = 0;
7085         payload.scr_rsvd = 0;
7086         payload.scr_func = scr_func;
7087 
7088         FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
7089             (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
7090 
7091         job->job_counter = 1;
7092 
7093         if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
7094                 fp_iodone(cmd);
7095         }
7096 
7097         return (FC_SUCCESS);
7098 }
7099 
7100 
7101 /*
7102  * There are basically two methods to determine the total number of
7103  * devices out in the NS database; Reading the details of the two
7104  * methods described below, it shouldn't be hard to identify which
7105  * of the two methods is better.
7106  *
7107  *      Method 1.
7108  *              Iteratively issue GANs until all ports identifiers are walked
7109  *
7110  *      Method 2.
7111  *              Issue GID_PT (get port Identifiers) with Maximum residual
7112  *              field in the request CT HEADER set to accommodate only the
7113  *              CT HEADER in the response frame. And if FC-GS2 has been
7114  *              carefully read, the NS here has a chance to FS_ACC the
7115  *              request and indicate the residual size in the FS_ACC.
7116  *
7117  *      Method 2 is wonderful, although it's not mandatory for the NS
7118  *      to update the Maximum/Residual Field as can be seen in 4.3.1.6
7119  *      (note with particular care the use of the auxiliary verb 'may')
7120  *
7121  */
7122 static int
7123 fp_ns_get_devcount(fc_local_port_t *port, job_request_t *job, int create,
7124     int sleep)
7125 {
7126         int             flags;
7127         int             rval;
7128         uint32_t        src_id;
7129         fctl_ns_req_t   *ns_cmd;
7130 
7131         ASSERT(!MUTEX_HELD(&port->fp_mutex));
7132 
7133         mutex_enter(&port->fp_mutex);
7134         src_id = port->fp_port_id.port_id;
7135         mutex_exit(&port->fp_mutex);
7136 
7137         if (!create && (port->fp_options & FP_NS_SMART_COUNT)) {
7138                 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pt_t),
7139                     sizeof (ns_resp_gid_pt_t), 0,
7140                     (FCTL_NS_GET_DEV_COUNT | FCTL_NS_NO_DATA_BUF), sleep);
7141 
7142                 if (ns_cmd == NULL) {
7143                         return (FC_NOMEM);
7144                 }
7145 
7146                 ns_cmd->ns_cmd_code = NS_GID_PT;
7147                 ((ns_req_gid_pt_t *)(ns_cmd->ns_cmd_buf))->port_type.port_type
7148                     = FC_NS_PORT_NX;    /* All port types */
7149                 ((ns_req_gid_pt_t *)(ns_cmd->ns_cmd_buf))->port_type.rsvd = 0;
7150 
7151         } else {
7152                 uint32_t ns_flags;
7153 
7154                 ns_flags = FCTL_NS_GET_DEV_COUNT | FCTL_NS_NO_DATA_BUF;
7155                 if (create) {
7156                         ns_flags |= FCTL_NS_CREATE_DEVICE;
7157                 }
7158                 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t),
7159                     sizeof (ns_resp_gan_t), sizeof (int), ns_flags, sleep);
7160 
7161                 if (ns_cmd == NULL) {
7162                         return (FC_NOMEM);
7163                 }
7164                 ns_cmd->ns_gan_index = 0;
7165                 ns_cmd->ns_gan_sid = FCTL_GAN_START_ID;
7166                 ns_cmd->ns_cmd_code = NS_GA_NXT;
7167                 ns_cmd->ns_gan_max = 0xFFFF;
7168 
7169                 ((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.port_id = src_id;
7170                 ((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.priv_lilp_posit = 0;
7171         }
7172 
7173         flags = job->job_flags;
7174         job->job_flags &= ~JOB_TYPE_FP_ASYNC;
7175         job->job_counter = 1;
7176 
7177         rval = fp_ns_query(port, ns_cmd, job, 1, sleep);
7178         job->job_flags = flags;
7179 
7180         if (!create && (port->fp_options & FP_NS_SMART_COUNT)) {
7181                 uint16_t max_resid;
7182 
7183                 /*
7184                  * Revert to scanning the NS if NS_GID_PT isn't
7185                  * helping us figure out total number of devices.
7186                  */
7187                 if (job->job_result != FC_SUCCESS ||
7188                     ns_cmd->ns_resp_hdr.ct_cmdrsp != FS_ACC_IU) {
7189                         mutex_enter(&port->fp_mutex);
7190                         port->fp_options &= ~FP_NS_SMART_COUNT;
7191                         mutex_exit(&port->fp_mutex);
7192 
7193                         fctl_free_ns_cmd(ns_cmd);
7194                         return (fp_ns_get_devcount(port, job, create, sleep));
7195                 }
7196 
7197                 mutex_enter(&port->fp_mutex);
7198                 port->fp_total_devices = 1;
7199                 max_resid = ns_cmd->ns_resp_hdr.ct_aiusize;
7200                 if (max_resid) {
7201                         /*
7202                          * Since port identifier is 4 bytes and max_resid
7203                          * is also in WORDS, max_resid simply indicates
7204                          * the total number of port identifiers not
7205                          * transferred
7206                          */
7207                         port->fp_total_devices += max_resid;
7208                 }
7209                 mutex_exit(&port->fp_mutex);
7210         }
7211         mutex_enter(&port->fp_mutex);
7212         port->fp_total_devices = *((int *)ns_cmd->ns_data_buf);
7213         mutex_exit(&port->fp_mutex);
7214         fctl_free_ns_cmd(ns_cmd);
7215 
7216         return (rval);
7217 }
7218 
7219 /*
7220  * One heck of a function to serve userland.
7221  */
7222 static int
7223 fp_fciocmd(fc_local_port_t *port, intptr_t data, int mode, fcio_t *fcio)
7224 {
7225         int             rval = 0;
7226         int             jcode;
7227         uint32_t        ret;
7228         uchar_t         open_flag;
7229         fcio_t          *kfcio;
7230         job_request_t   *job;
7231         boolean_t       use32 = B_FALSE;
7232 
7233 #ifdef _MULTI_DATAMODEL
7234         switch (ddi_model_convert_from(mode & FMODELS)) {
7235         case DDI_MODEL_ILP32:
7236                 use32 = B_TRUE;
7237                 break;
7238 
7239         case DDI_MODEL_NONE:
7240         default:
7241                 break;
7242         }
7243 #endif
7244 
7245         mutex_enter(&port->fp_mutex);
7246         if (port->fp_soft_state & (FP_SOFT_IN_STATEC_CB |
7247             FP_SOFT_IN_UNSOL_CB)) {
7248                 fcio->fcio_errno = FC_STATEC_BUSY;
7249                 mutex_exit(&port->fp_mutex);
7250                 rval = EAGAIN;
7251                 if (fp_fcio_copyout(fcio, data, mode)) {
7252                         rval = EFAULT;
7253                 }
7254                 return (rval);
7255         }
7256         open_flag = port->fp_flag;
7257         mutex_exit(&port->fp_mutex);
7258 
7259         if (fp_check_perms(open_flag, fcio->fcio_cmd) != FC_SUCCESS) {
7260                 fcio->fcio_errno = FC_FAILURE;
7261                 rval = EACCES;
7262                 if (fp_fcio_copyout(fcio, data, mode)) {
7263                         rval = EFAULT;
7264                 }
7265                 return (rval);
7266         }
7267 
7268         /*
7269          * If an exclusive open was demanded during open, don't let
7270          * either innocuous or devil threads to share the file
7271          * descriptor and fire down exclusive access commands
7272          */
7273         mutex_enter(&port->fp_mutex);
7274         if (port->fp_flag & FP_EXCL) {
7275                 if (port->fp_flag & FP_EXCL_BUSY) {
7276                         mutex_exit(&port->fp_mutex);
7277                         fcio->fcio_errno = FC_FAILURE;
7278                         return (EBUSY);
7279                 }
7280                 port->fp_flag |= FP_EXCL_BUSY;
7281         }
7282         mutex_exit(&port->fp_mutex);
7283 
7284         fcio->fcio_errno = FC_SUCCESS;
7285 
7286         switch (fcio->fcio_cmd) {
7287         case FCIO_GET_HOST_PARAMS: {
7288                 fc_port_dev_t   *val;
7289                 fc_port_dev32_t *val32;
7290                 int             index;
7291                 int             lilp_device_count;
7292                 fc_lilpmap_t    *lilp_map;
7293                 uchar_t         *alpa_list;
7294 
7295                 if (use32 == B_TRUE) {
7296                         if (fcio->fcio_olen != sizeof (*val32) ||
7297                             fcio->fcio_xfer != FCIO_XFER_READ) {
7298                                 rval = EINVAL;
7299                                 break;
7300                         }
7301                 } else {
7302                         if (fcio->fcio_olen != sizeof (*val) ||
7303                             fcio->fcio_xfer != FCIO_XFER_READ) {
7304                                 rval = EINVAL;
7305                                 break;
7306                         }
7307                 }
7308 
7309                 val = kmem_zalloc(sizeof (*val), KM_SLEEP);
7310 
7311                 mutex_enter(&port->fp_mutex);
7312                 val->dev_did = port->fp_port_id;
7313                 val->dev_hard_addr = port->fp_hard_addr;
7314                 val->dev_pwwn = port->fp_service_params.nport_ww_name;
7315                 val->dev_nwwn = port->fp_service_params.node_ww_name;
7316                 val->dev_state = port->fp_state;
7317 
7318                 lilp_map = &port->fp_lilp_map;
7319                 alpa_list = &lilp_map->lilp_alpalist[0];
7320                 lilp_device_count = lilp_map->lilp_length;
7321                 for (index = 0; index < lilp_device_count; index++) {
7322                         uint32_t d_id;
7323 
7324                         d_id = alpa_list[index];
7325                         if (d_id == port->fp_port_id.port_id) {
7326                                 break;
7327                         }
7328                 }
7329                 val->dev_did.priv_lilp_posit = (uint8_t)(index & 0xff);
7330 
7331                 bcopy(port->fp_fc4_types, val->dev_type,
7332                     sizeof (port->fp_fc4_types));
7333                 mutex_exit(&port->fp_mutex);
7334 
7335                 if (use32 == B_TRUE) {
7336                         val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP);
7337 
7338                         val32->dev_did = val->dev_did;
7339                         val32->dev_hard_addr = val->dev_hard_addr;
7340                         val32->dev_pwwn = val->dev_pwwn;
7341                         val32->dev_nwwn = val->dev_nwwn;
7342                         val32->dev_state = val->dev_state;
7343                         val32->dev_did.priv_lilp_posit =
7344                             val->dev_did.priv_lilp_posit;
7345 
7346                         bcopy(val->dev_type, val32->dev_type,
7347                             sizeof (port->fp_fc4_types));
7348 
7349                         if (fp_copyout((void *)val32, (void *)fcio->fcio_obuf,
7350                             fcio->fcio_olen, mode) == 0) {
7351                                 if (fp_fcio_copyout(fcio, data, mode)) {
7352                                         rval = EFAULT;
7353                                 }
7354                         } else {
7355                                 rval = EFAULT;
7356                         }
7357 
7358                         kmem_free(val32, sizeof (*val32));
7359                 } else {
7360                         if (fp_copyout((void *)val, (void *)fcio->fcio_obuf,
7361                             fcio->fcio_olen, mode) == 0) {
7362                                 if (fp_fcio_copyout(fcio, data, mode)) {
7363                                         rval = EFAULT;
7364                                 }
7365                         } else {
7366                                 rval = EFAULT;
7367                         }
7368                 }
7369 
7370                 /* need to free "val" here */
7371                 kmem_free(val, sizeof (*val));
7372                 break;
7373         }
7374 
7375         case FCIO_GET_OTHER_ADAPTER_PORTS: {
7376                 uint32_t    index;
7377                 char        *tmpPath;
7378                 fc_local_port_t   *tmpPort;
7379 
7380                 if (fcio->fcio_olen < MAXPATHLEN ||
7381                     fcio->fcio_ilen != sizeof (uint32_t)) {
7382                         rval = EINVAL;
7383                         break;
7384                 }
7385                 if (ddi_copyin(fcio->fcio_ibuf, &index, sizeof (index), mode)) {
7386                         rval = EFAULT;
7387                         break;
7388                 }
7389 
7390                 tmpPort = fctl_get_adapter_port_by_index(port, index);
7391                 if (tmpPort == NULL) {
7392                         FP_TRACE(FP_NHEAD1(9, 0),
7393                             "User supplied index out of range");
7394                         fcio->fcio_errno = FC_BADPORT;
7395                         rval = EFAULT;
7396                         if (fp_fcio_copyout(fcio, data, mode)) {
7397                                 rval = EFAULT;
7398                         }
7399                         break;
7400                 }
7401 
7402                 tmpPath = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
7403                 (void) ddi_pathname(tmpPort->fp_port_dip, tmpPath);
7404                 if (fp_copyout((void *)tmpPath, (void *)fcio->fcio_obuf,
7405                     MAXPATHLEN, mode) == 0) {
7406                         if (fp_fcio_copyout(fcio, data, mode)) {
7407                                 rval = EFAULT;
7408                         }
7409                 } else {
7410                         rval = EFAULT;
7411                 }
7412                 kmem_free(tmpPath, MAXPATHLEN);
7413                 break;
7414         }
7415 
7416         case FCIO_NPIV_GET_ADAPTER_ATTRIBUTES:
7417         case FCIO_GET_ADAPTER_ATTRIBUTES: {
7418                 fc_hba_adapter_attributes_t     *val;
7419                 fc_hba_adapter_attributes32_t   *val32;
7420 
7421                 if (use32 == B_TRUE) {
7422                         if (fcio->fcio_olen < sizeof (*val32) ||
7423                             fcio->fcio_xfer != FCIO_XFER_READ) {
7424                                 rval = EINVAL;
7425                                 break;
7426                         }
7427                 } else {
7428                         if (fcio->fcio_olen < sizeof (*val) ||
7429                             fcio->fcio_xfer != FCIO_XFER_READ) {
7430                                 rval = EINVAL;
7431                                 break;
7432                         }
7433                 }
7434 
7435                 val = kmem_zalloc(sizeof (*val), KM_SLEEP);
7436                 val->version = FC_HBA_ADAPTER_ATTRIBUTES_VERSION;
7437                 mutex_enter(&port->fp_mutex);
7438                 bcopy(port->fp_hba_port_attrs.manufacturer,
7439                     val->Manufacturer,
7440                     sizeof (val->Manufacturer));
7441                 bcopy(port->fp_hba_port_attrs.serial_number,
7442                     val->SerialNumber,
7443                     sizeof (val->SerialNumber));
7444                 bcopy(port->fp_hba_port_attrs.model,
7445                     val->Model,
7446                     sizeof (val->Model));
7447                 bcopy(port->fp_hba_port_attrs.model_description,
7448                     val->ModelDescription,
7449                     sizeof (val->ModelDescription));
7450                 bcopy(port->fp_sym_node_name, val->NodeSymbolicName,
7451                     port->fp_sym_node_namelen);
7452                 bcopy(port->fp_hba_port_attrs.hardware_version,
7453                     val->HardwareVersion,
7454                     sizeof (val->HardwareVersion));
7455                 bcopy(port->fp_hba_port_attrs.option_rom_version,
7456                     val->OptionROMVersion,
7457                     sizeof (val->OptionROMVersion));
7458                 bcopy(port->fp_hba_port_attrs.firmware_version,
7459                     val->FirmwareVersion,
7460                     sizeof (val->FirmwareVersion));
7461                 val->VendorSpecificID =
7462                     port->fp_hba_port_attrs.vendor_specific_id;
7463                 bcopy(&port->fp_service_params.node_ww_name.raw_wwn,
7464                     &val->NodeWWN.raw_wwn,
7465                     sizeof (val->NodeWWN.raw_wwn));
7466 
7467 
7468                 bcopy(port->fp_hba_port_attrs.driver_name,
7469                     val->DriverName,
7470                     sizeof (val->DriverName));
7471                 bcopy(port->fp_hba_port_attrs.driver_version,
7472                     val->DriverVersion,
7473                     sizeof (val->DriverVersion));
7474                 mutex_exit(&port->fp_mutex);
7475 
7476                 if (fcio->fcio_cmd == FCIO_GET_ADAPTER_ATTRIBUTES) {
7477                         val->NumberOfPorts = fctl_count_fru_ports(port, 0);
7478                 } else {
7479                         val->NumberOfPorts = fctl_count_fru_ports(port, 1);
7480                 }
7481 
7482                 if (use32 == B_TRUE) {
7483                         val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP);
7484                         val32->version = val->version;
7485                         bcopy(val->Manufacturer, val32->Manufacturer,
7486                             sizeof (val->Manufacturer));
7487                         bcopy(val->SerialNumber, val32->SerialNumber,
7488                             sizeof (val->SerialNumber));
7489                         bcopy(val->Model, val32->Model,
7490                             sizeof (val->Model));
7491                         bcopy(val->ModelDescription, val32->ModelDescription,
7492                             sizeof (val->ModelDescription));
7493                         bcopy(val->NodeSymbolicName, val32->NodeSymbolicName,
7494                             sizeof (val->NodeSymbolicName));
7495                         bcopy(val->HardwareVersion, val32->HardwareVersion,
7496                             sizeof (val->HardwareVersion));
7497                         bcopy(val->OptionROMVersion, val32->OptionROMVersion,
7498                             sizeof (val->OptionROMVersion));
7499                         bcopy(val->FirmwareVersion, val32->FirmwareVersion,
7500                             sizeof (val->FirmwareVersion));
7501                         val32->VendorSpecificID = val->VendorSpecificID;
7502                         bcopy(&val->NodeWWN.raw_wwn, &val32->NodeWWN.raw_wwn,
7503                             sizeof (val->NodeWWN.raw_wwn));
7504                         bcopy(val->DriverName, val32->DriverName,
7505                             sizeof (val->DriverName));
7506                         bcopy(val->DriverVersion, val32->DriverVersion,
7507                             sizeof (val->DriverVersion));
7508 
7509                         val32->NumberOfPorts = val->NumberOfPorts;
7510 
7511                         if (fp_copyout((void *)val32, (void *)fcio->fcio_obuf,
7512                             fcio->fcio_olen, mode) == 0) {
7513                                 if (fp_fcio_copyout(fcio, data, mode)) {
7514                                         rval = EFAULT;
7515                                 }
7516                         } else {
7517                                 rval = EFAULT;
7518                         }
7519 
7520                         kmem_free(val32, sizeof (*val32));
7521                 } else {
7522                         if (fp_copyout((void *)val, (void *)fcio->fcio_obuf,
7523                             fcio->fcio_olen, mode) == 0) {
7524                                 if (fp_fcio_copyout(fcio, data, mode)) {
7525                                         rval = EFAULT;
7526                                 }
7527                         } else {
7528                                 rval = EFAULT;
7529                         }
7530                 }
7531 
7532                 kmem_free(val, sizeof (*val));
7533                 break;
7534         }
7535 
7536         case FCIO_GET_NPIV_ATTRIBUTES: {
7537                 fc_hba_npiv_attributes_t *attrs;
7538 
7539                 attrs = kmem_zalloc(sizeof (*attrs), KM_SLEEP);
7540                 mutex_enter(&port->fp_mutex);
7541                 bcopy(&port->fp_service_params.node_ww_name.raw_wwn,
7542                     &attrs->NodeWWN.raw_wwn,
7543                     sizeof (attrs->NodeWWN.raw_wwn));
7544                 bcopy(&port->fp_service_params.nport_ww_name.raw_wwn,
7545                     &attrs->PortWWN.raw_wwn,
7546                     sizeof (attrs->PortWWN.raw_wwn));
7547                 mutex_exit(&port->fp_mutex);
7548                 if (fp_copyout((void *)attrs, (void *)fcio->fcio_obuf,
7549                     fcio->fcio_olen, mode) == 0) {
7550                         if (fp_fcio_copyout(fcio, data, mode)) {
7551                                 rval = EFAULT;
7552                         }
7553                 } else {
7554                         rval = EFAULT;
7555                 }
7556                 kmem_free(attrs, sizeof (*attrs));
7557                 break;
7558         }
7559 
7560         case FCIO_DELETE_NPIV_PORT: {
7561                 fc_local_port_t *tmpport;
7562                 char    ww_pname[17];
7563                 la_wwn_t        vwwn[1];
7564 
7565                 FP_TRACE(FP_NHEAD1(1, 0), "Delete NPIV Port");
7566                 if (ddi_copyin(fcio->fcio_ibuf,
7567                     &vwwn, sizeof (la_wwn_t), mode)) {
7568                         rval = EFAULT;
7569                         break;
7570                 }
7571 
7572                 fc_wwn_to_str(&vwwn[0], ww_pname);
7573                 FP_TRACE(FP_NHEAD1(3, 0),
7574                     "Delete NPIV Port %s", ww_pname);
7575                 tmpport = fc_delete_npiv_port(port, &vwwn[0]);
7576                 if (tmpport == NULL) {
7577                         FP_TRACE(FP_NHEAD1(3, 0),
7578                             "Delete NPIV Port : no found");
7579                         rval = EFAULT;
7580                 } else {
7581                         fc_local_port_t *nextport = tmpport->fp_port_next;
7582                         fc_local_port_t *prevport = tmpport->fp_port_prev;
7583                         int portlen, portindex, ret;
7584 
7585                         portlen = sizeof (portindex);
7586                         ret = ddi_prop_op(DDI_DEV_T_ANY,
7587                             tmpport->fp_port_dip, PROP_LEN_AND_VAL_BUF,
7588                             DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "port",
7589                             (caddr_t)&portindex, &portlen);
7590                         if (ret != DDI_SUCCESS) {
7591                                 rval = EFAULT;
7592                                 break;
7593                         }
7594                         if (ndi_devi_offline(tmpport->fp_port_dip,
7595                             NDI_DEVI_REMOVE) != DDI_SUCCESS) {
7596                                 FP_TRACE(FP_NHEAD1(1, 0),
7597                                     "Delete NPIV Port failed");
7598                                 mutex_enter(&port->fp_mutex);
7599                                 tmpport->fp_npiv_state = 0;
7600                                 mutex_exit(&port->fp_mutex);
7601                                 rval = EFAULT;
7602                         } else {
7603                                 mutex_enter(&port->fp_mutex);
7604                                 nextport->fp_port_prev = prevport;
7605                                 prevport->fp_port_next = nextport;
7606                                 if (port == port->fp_port_next) {
7607                                         port->fp_port_next =
7608                                             port->fp_port_prev = NULL;
7609                                 }
7610                                 port->fp_npiv_portnum--;
7611                                 FP_TRACE(FP_NHEAD1(3, 0),
7612                                     "Delete NPIV Port %d", portindex);
7613                                 port->fp_npiv_portindex[portindex-1] = 0;
7614                                 mutex_exit(&port->fp_mutex);
7615                         }
7616                 }
7617                 break;
7618         }
7619 
7620         case FCIO_CREATE_NPIV_PORT: {
7621                 char ww_nname[17], ww_pname[17];
7622                 la_npiv_create_entry_t entrybuf;
7623                 uint32_t vportindex = 0;
7624                 int npiv_ret = 0;
7625                 char *portname, *fcaname;
7626 
7627                 portname = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
7628                 (void) ddi_pathname(port->fp_port_dip, portname);
7629                 fcaname = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
7630                 (void) ddi_pathname(port->fp_fca_dip, fcaname);
7631                 FP_TRACE(FP_NHEAD1(1, 0),
7632                     "Create NPIV port %s %s %s", portname, fcaname,
7633                     ddi_driver_name(port->fp_fca_dip));
7634                 kmem_free(portname, MAXPATHLEN);
7635                 kmem_free(fcaname, MAXPATHLEN);
7636                 if (ddi_copyin(fcio->fcio_ibuf,
7637                     &entrybuf, sizeof (la_npiv_create_entry_t), mode)) {
7638                         rval = EFAULT;
7639                         break;
7640                 }
7641 
7642                 fc_wwn_to_str(&entrybuf.VNodeWWN, ww_nname);
7643                 fc_wwn_to_str(&entrybuf.VPortWWN, ww_pname);
7644                 vportindex = entrybuf.vindex;
7645                 FP_TRACE(FP_NHEAD1(3, 0),
7646                     "Create NPIV Port %s %s %d",
7647                     ww_nname, ww_pname, vportindex);
7648 
7649                 if (fc_get_npiv_port(port, &entrybuf.VPortWWN)) {
7650                         rval = EFAULT;
7651                         break;
7652                 }
7653                 npiv_ret = fctl_fca_create_npivport(port->fp_fca_dip,
7654                     port->fp_port_dip, ww_nname, ww_pname, &vportindex);
7655                 if (npiv_ret == NDI_SUCCESS) {
7656                         mutex_enter(&port->fp_mutex);
7657                         port->fp_npiv_portnum++;
7658                         mutex_exit(&port->fp_mutex);
7659                         if (fp_copyout((void *)&vportindex,
7660                             (void *)fcio->fcio_obuf,
7661                             fcio->fcio_olen, mode) == 0) {
7662                                 if (fp_fcio_copyout(fcio, data, mode)) {
7663                                         rval = EFAULT;
7664                                 }
7665                         } else {
7666                                 rval = EFAULT;
7667                         }
7668                 } else {
7669                         rval = EFAULT;
7670                 }
7671                 FP_TRACE(FP_NHEAD1(3, 0),
7672                     "Create NPIV Port %d %d", npiv_ret, vportindex);
7673                 break;
7674         }
7675 
7676         case FCIO_GET_NPIV_PORT_LIST: {
7677                 fc_hba_npiv_port_list_t *list;
7678                 int count;
7679 
7680                 if ((fcio->fcio_xfer != FCIO_XFER_READ) ||
7681                     (fcio->fcio_olen == 0) || (fcio->fcio_obuf == 0)) {
7682                         rval = EINVAL;
7683                         break;
7684                 }
7685 
7686                 list = kmem_zalloc(fcio->fcio_olen, KM_SLEEP);
7687                 list->version = FC_HBA_LIST_VERSION;
7688 
7689                 count = (fcio->fcio_olen -
7690                     (int)sizeof (fc_hba_npiv_port_list_t))/MAXPATHLEN  + 1;
7691                 if (port->fp_npiv_portnum > count) {
7692                         list->numAdapters = port->fp_npiv_portnum;
7693                 } else {
7694                         /* build npiv port list */
7695                         count = fc_ulp_get_npiv_port_list(port,
7696                             (char *)list->hbaPaths);
7697                         if (count < 0) {
7698                                 rval = ENXIO;
7699                                 FP_TRACE(FP_NHEAD1(1, 0),
7700                                     "Build NPIV Port List error");
7701                                 kmem_free(list, fcio->fcio_olen);
7702                                 break;
7703                         }
7704                         list->numAdapters = count;
7705                 }
7706 
7707                 if (fp_copyout((void *)list, (void *)fcio->fcio_obuf,
7708                     fcio->fcio_olen, mode) == 0) {
7709                         if (fp_fcio_copyout(fcio, data, mode)) {
7710                                 FP_TRACE(FP_NHEAD1(1, 0),
7711                                     "Copy NPIV Port data error");
7712                                 rval = EFAULT;
7713                         }
7714                 } else {
7715                         FP_TRACE(FP_NHEAD1(1, 0), "Copy NPIV Port List error");
7716                         rval = EFAULT;
7717                 }
7718                 kmem_free(list, fcio->fcio_olen);
7719                 break;
7720         }
7721 
7722         case FCIO_GET_ADAPTER_PORT_NPIV_ATTRIBUTES: {
7723                 fc_hba_port_npiv_attributes_t   *val;
7724 
7725                 val = kmem_zalloc(sizeof (*val), KM_SLEEP);
7726                 val->version = FC_HBA_PORT_NPIV_ATTRIBUTES_VERSION;
7727 
7728                 mutex_enter(&port->fp_mutex);
7729                 val->npivflag = port->fp_npiv_flag;
7730                 val->lastChange = port->fp_last_change;
7731                 bcopy(&port->fp_service_params.nport_ww_name.raw_wwn,
7732                     &val->PortWWN.raw_wwn,
7733                     sizeof (val->PortWWN.raw_wwn));
7734                 bcopy(&port->fp_service_params.node_ww_name.raw_wwn,
7735                     &val->NodeWWN.raw_wwn,
7736                     sizeof (val->NodeWWN.raw_wwn));
7737                 mutex_exit(&port->fp_mutex);
7738 
7739                 val->NumberOfNPIVPorts = fc_ulp_get_npiv_port_num(port);
7740                 if (port->fp_npiv_type != FC_NPIV_PORT) {
7741                         val->MaxNumberOfNPIVPorts =
7742                             port->fp_fca_tran->fca_num_npivports;
7743                 } else {
7744                         val->MaxNumberOfNPIVPorts = 0;
7745                 }
7746 
7747                 if (fp_copyout((void *)val, (void *)fcio->fcio_obuf,
7748                     fcio->fcio_olen, mode) == 0) {
7749                         if (fp_fcio_copyout(fcio, data, mode)) {
7750                                 rval = EFAULT;
7751                         }
7752                 } else {
7753                         rval = EFAULT;
7754                 }
7755                 kmem_free(val, sizeof (*val));
7756                 break;
7757         }
7758 
7759         case FCIO_GET_ADAPTER_PORT_ATTRIBUTES: {
7760                 fc_hba_port_attributes_t        *val;
7761                 fc_hba_port_attributes32_t      *val32;
7762 
7763                 if (use32 == B_TRUE) {
7764                         if (fcio->fcio_olen < sizeof (*val32) ||
7765                             fcio->fcio_xfer != FCIO_XFER_READ) {
7766                                 rval = EINVAL;
7767                                 break;
7768                         }
7769                 } else {
7770                         if (fcio->fcio_olen < sizeof (*val) ||
7771                             fcio->fcio_xfer != FCIO_XFER_READ) {
7772                                 rval = EINVAL;
7773                                 break;
7774                         }
7775                 }
7776 
7777                 val = kmem_zalloc(sizeof (*val), KM_SLEEP);
7778                 val->version = FC_HBA_PORT_ATTRIBUTES_VERSION;
7779                 mutex_enter(&port->fp_mutex);
7780                 val->lastChange = port->fp_last_change;
7781                 val->fp_minor = port->fp_instance;
7782 
7783                 bcopy(&port->fp_service_params.nport_ww_name.raw_wwn,
7784                     &val->PortWWN.raw_wwn,
7785                     sizeof (val->PortWWN.raw_wwn));
7786                 bcopy(&port->fp_service_params.node_ww_name.raw_wwn,
7787                     &val->NodeWWN.raw_wwn,
7788                     sizeof (val->NodeWWN.raw_wwn));
7789                 bcopy(&port->fp_fabric_name, &val->FabricName.raw_wwn,
7790                     sizeof (val->FabricName.raw_wwn));
7791 
7792                 val->PortFcId = port->fp_port_id.port_id;
7793 
7794                 switch (FC_PORT_STATE_MASK(port->fp_state)) {
7795                 case FC_STATE_OFFLINE:
7796                         val->PortState = FC_HBA_PORTSTATE_OFFLINE;
7797                         break;
7798                 case FC_STATE_ONLINE:
7799                 case FC_STATE_LOOP:
7800                 case FC_STATE_NAMESERVICE:
7801                         val->PortState = FC_HBA_PORTSTATE_ONLINE;
7802                         break;
7803                 default:
7804                         val->PortState = FC_HBA_PORTSTATE_UNKNOWN;
7805                         break;
7806                 }
7807 
7808                 /* Translate from LV to FC-HBA port type codes */
7809                 switch (port->fp_port_type.port_type) {
7810                 case FC_NS_PORT_N:
7811                         val->PortType = FC_HBA_PORTTYPE_NPORT;
7812                         break;
7813                 case FC_NS_PORT_NL:
7814                         /* Actually means loop for us */
7815                         val->PortType = FC_HBA_PORTTYPE_LPORT;
7816                         break;
7817                 case FC_NS_PORT_F:
7818                         val->PortType = FC_HBA_PORTTYPE_FPORT;
7819                         break;
7820                 case FC_NS_PORT_FL:
7821                         val->PortType = FC_HBA_PORTTYPE_FLPORT;
7822                         break;
7823                 case FC_NS_PORT_E:
7824                         val->PortType = FC_HBA_PORTTYPE_EPORT;
7825                         break;
7826                 default:
7827                         val->PortType = FC_HBA_PORTTYPE_OTHER;
7828                         break;
7829                 }
7830 
7831 
7832                 /*
7833                  * If fp has decided that the topology is public loop,
7834                  * we will indicate that using the appropriate
7835                  * FC HBA API constant.
7836                  */
7837                 switch (port->fp_topology) {
7838                 case FC_TOP_PUBLIC_LOOP:
7839                         val->PortType = FC_HBA_PORTTYPE_NLPORT;
7840                         break;
7841 
7842                 case FC_TOP_PT_PT:
7843                         val->PortType = FC_HBA_PORTTYPE_PTP;
7844                         break;
7845 
7846                 case FC_TOP_UNKNOWN:
7847                         /*
7848                          * This should cover the case where nothing is connected
7849                          * to the port. Crystal+ is p'bly an exception here.
7850                          * For Crystal+, port 0 will come up as private loop
7851                          * (i.e fp_bind_state will be FC_STATE_LOOP) even when
7852                          * nothing is connected to it.
7853                          * Current plan is to let userland handle this.
7854                          */
7855                         if (port->fp_bind_state == FC_STATE_OFFLINE) {
7856                                 val->PortType = FC_HBA_PORTTYPE_UNKNOWN;
7857                         }
7858                         break;
7859 
7860                 default:
7861                         /*
7862                          * Do Nothing.
7863                          * Unused:
7864                          *   val->PortType = FC_HBA_PORTTYPE_GPORT;
7865                          */
7866                         break;
7867                 }
7868 
7869                 val->PortSupportedClassofService =
7870                     port->fp_hba_port_attrs.supported_cos;
7871                 val->PortSupportedFc4Types[0] = 0;
7872                 bcopy(port->fp_fc4_types, val->PortActiveFc4Types,
7873                     sizeof (val->PortActiveFc4Types));
7874                 bcopy(port->fp_sym_port_name, val->PortSymbolicName,
7875                     port->fp_sym_port_namelen);
7876                 val->PortSupportedSpeed =
7877                     port->fp_hba_port_attrs.supported_speed;
7878 
7879                 switch (FC_PORT_SPEED_MASK(port->fp_state)) {
7880                 case FC_STATE_1GBIT_SPEED:
7881                         val->PortSpeed = FC_HBA_PORTSPEED_1GBIT;
7882                         break;
7883                 case FC_STATE_2GBIT_SPEED:
7884                         val->PortSpeed = FC_HBA_PORTSPEED_2GBIT;
7885                         break;
7886                 case FC_STATE_4GBIT_SPEED:
7887                         val->PortSpeed = FC_HBA_PORTSPEED_4GBIT;
7888                         break;
7889                 case FC_STATE_8GBIT_SPEED:
7890                         val->PortSpeed = FC_HBA_PORTSPEED_8GBIT;
7891                         break;
7892                 case FC_STATE_10GBIT_SPEED:
7893                         val->PortSpeed = FC_HBA_PORTSPEED_10GBIT;
7894                         break;
7895                 case FC_STATE_16GBIT_SPEED:
7896                         val->PortSpeed = FC_HBA_PORTSPEED_16GBIT;
7897                         break;
7898                 default:
7899                         val->PortSpeed = FC_HBA_PORTSPEED_UNKNOWN;
7900                         break;
7901                 }
7902                 val->PortMaxFrameSize = port->fp_hba_port_attrs.max_frame_size;
7903                 val->NumberofDiscoveredPorts = port->fp_dev_count;
7904                 mutex_exit(&port->fp_mutex);
7905 
7906                 if (use32 == B_TRUE) {
7907                         val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP);
7908                         val32->version = val->version;
7909                         val32->lastChange = val->lastChange;
7910                         val32->fp_minor = val->fp_minor;
7911 
7912                         bcopy(&val->PortWWN.raw_wwn, &val32->PortWWN.raw_wwn,
7913                             sizeof (val->PortWWN.raw_wwn));
7914                         bcopy(&val->NodeWWN.raw_wwn, &val32->NodeWWN.raw_wwn,
7915                             sizeof (val->NodeWWN.raw_wwn));
7916                         val32->PortFcId = val->PortFcId;
7917                         val32->PortState = val->PortState;
7918                         val32->PortType = val->PortType;
7919 
7920                         val32->PortSupportedClassofService =
7921                             val->PortSupportedClassofService;
7922                         bcopy(val->PortActiveFc4Types,
7923                             val32->PortActiveFc4Types,
7924                             sizeof (val->PortActiveFc4Types));
7925                         bcopy(val->PortSymbolicName, val32->PortSymbolicName,
7926                             sizeof (val->PortSymbolicName));
7927                         bcopy(&val->FabricName, &val32->FabricName,
7928                             sizeof (val->FabricName.raw_wwn));
7929                         val32->PortSupportedSpeed = val->PortSupportedSpeed;
7930                         val32->PortSpeed = val->PortSpeed;
7931 
7932                         val32->PortMaxFrameSize = val->PortMaxFrameSize;
7933                         val32->NumberofDiscoveredPorts =
7934                             val->NumberofDiscoveredPorts;
7935 
7936                         if (fp_copyout((void *)val32, (void *)fcio->fcio_obuf,
7937                             fcio->fcio_olen, mode) == 0) {
7938                                 if (fp_fcio_copyout(fcio, data, mode)) {
7939                                         rval = EFAULT;
7940                                 }
7941                         } else {
7942                                 rval = EFAULT;
7943                         }
7944 
7945                         kmem_free(val32, sizeof (*val32));
7946                 } else {
7947                         if (fp_copyout((void *)val, (void *)fcio->fcio_obuf,
7948                             fcio->fcio_olen, mode) == 0) {
7949                                 if (fp_fcio_copyout(fcio, data, mode)) {
7950                                         rval = EFAULT;
7951                                 }
7952                         } else {
7953                                 rval = EFAULT;
7954                         }
7955                 }
7956 
7957                 kmem_free(val, sizeof (*val));
7958                 break;
7959         }
7960 
7961         case FCIO_GET_DISCOVERED_PORT_ATTRIBUTES: {
7962                 fc_hba_port_attributes_t        *val;
7963                 fc_hba_port_attributes32_t      *val32;
7964                 uint32_t        index = 0;
7965                 fc_remote_port_t *tmp_pd;
7966 
7967                 if (use32 == B_TRUE) {
7968                         if (fcio->fcio_olen < sizeof (*val32) ||
7969                             fcio->fcio_xfer != FCIO_XFER_READ) {
7970                                 rval = EINVAL;
7971                                 break;
7972                         }
7973                 } else {
7974                         if (fcio->fcio_olen < sizeof (*val) ||
7975                             fcio->fcio_xfer != FCIO_XFER_READ) {
7976                                 rval = EINVAL;
7977                                 break;
7978                         }
7979                 }
7980 
7981                 if (ddi_copyin(fcio->fcio_ibuf, &index, sizeof (index), mode)) {
7982                         rval = EFAULT;
7983                         break;
7984                 }
7985 
7986                 if (index >= port->fp_dev_count) {
7987                         FP_TRACE(FP_NHEAD1(9, 0),
7988                             "User supplied index out of range");
7989                         fcio->fcio_errno = FC_OUTOFBOUNDS;
7990                         rval = EINVAL;
7991                         if (fp_fcio_copyout(fcio, data, mode)) {
7992                                 rval = EFAULT;
7993                         }
7994                         break;
7995                 }
7996 
7997                 val = kmem_zalloc(sizeof (*val), KM_SLEEP);
7998                 val->version = FC_HBA_PORT_ATTRIBUTES_VERSION;
7999 
8000                 mutex_enter(&port->fp_mutex);
8001                 tmp_pd = fctl_lookup_pd_by_index(port, index);
8002 
8003                 if (tmp_pd == NULL) {
8004                         fcio->fcio_errno = FC_BADPORT;
8005                         rval = EINVAL;
8006                 } else {
8007                         val->lastChange = port->fp_last_change;
8008                         val->fp_minor = port->fp_instance;
8009 
8010                         mutex_enter(&tmp_pd->pd_mutex);
8011                         bcopy(&tmp_pd->pd_port_name.raw_wwn,
8012                             &val->PortWWN.raw_wwn,
8013                             sizeof (val->PortWWN.raw_wwn));
8014                         bcopy(&tmp_pd->pd_remote_nodep->fd_node_name.raw_wwn,
8015                             &val->NodeWWN.raw_wwn,
8016                             sizeof (val->NodeWWN.raw_wwn));
8017                         val->PortFcId = tmp_pd->pd_port_id.port_id;
8018                         bcopy(tmp_pd->pd_spn, val->PortSymbolicName,
8019                             tmp_pd->pd_spn_len);
8020                         val->PortSupportedClassofService = tmp_pd->pd_cos;
8021                         /*
8022                          * we will assume the sizeof these pd_fc4types and
8023                          * portActiveFc4Types will remain the same.  we could
8024                          * add in a check for it, but we decided it was unneeded
8025                          */
8026                         bcopy((caddr_t)tmp_pd->pd_fc4types,
8027                             val->PortActiveFc4Types,
8028                             sizeof (tmp_pd->pd_fc4types));
8029                         val->PortState =
8030                             fp_map_remote_port_state(tmp_pd->pd_state);
8031                         mutex_exit(&tmp_pd->pd_mutex);
8032 
8033                         val->PortType = FC_HBA_PORTTYPE_UNKNOWN;
8034                         val->PortSupportedFc4Types[0] = 0;
8035                         val->PortSupportedSpeed = FC_HBA_PORTSPEED_UNKNOWN;
8036                         val->PortSpeed = FC_HBA_PORTSPEED_UNKNOWN;
8037                         val->PortMaxFrameSize = 0;
8038                         val->NumberofDiscoveredPorts = 0;
8039 
8040                         if (use32 == B_TRUE) {
8041                                 val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP);
8042                                 val32->version = val->version;
8043                                 val32->lastChange = val->lastChange;
8044                                 val32->fp_minor = val->fp_minor;
8045 
8046                                 bcopy(&val->PortWWN.raw_wwn,
8047                                     &val32->PortWWN.raw_wwn,
8048                                     sizeof (val->PortWWN.raw_wwn));
8049                                 bcopy(&val->NodeWWN.raw_wwn,
8050                                     &val32->NodeWWN.raw_wwn,
8051                                     sizeof (val->NodeWWN.raw_wwn));
8052                                 val32->PortFcId = val->PortFcId;
8053                                 bcopy(val->PortSymbolicName,
8054                                     val32->PortSymbolicName,
8055                                     sizeof (val->PortSymbolicName));
8056                                 val32->PortSupportedClassofService =
8057                                     val->PortSupportedClassofService;
8058                                 bcopy(val->PortActiveFc4Types,
8059                                     val32->PortActiveFc4Types,
8060                                     sizeof (tmp_pd->pd_fc4types));
8061 
8062                                 val32->PortType = val->PortType;
8063                                 val32->PortState = val->PortState;
8064                                 val32->PortSupportedFc4Types[0] =
8065                                     val->PortSupportedFc4Types[0];
8066                                 val32->PortSupportedSpeed =
8067                                     val->PortSupportedSpeed;
8068                                 val32->PortSpeed = val->PortSpeed;
8069                                 val32->PortMaxFrameSize =
8070                                     val->PortMaxFrameSize;
8071                                 val32->NumberofDiscoveredPorts =
8072                                     val->NumberofDiscoveredPorts;
8073 
8074                                 if (fp_copyout((void *)val32,
8075                                     (void *)fcio->fcio_obuf,
8076                                     fcio->fcio_olen, mode) == 0) {
8077                                         if (fp_fcio_copyout(fcio,
8078                                             data, mode)) {
8079                                                 rval = EFAULT;
8080                                         }
8081                                 } else {
8082                                         rval = EFAULT;
8083                                 }
8084 
8085                                 kmem_free(val32, sizeof (*val32));
8086                         } else {
8087                                 if (fp_copyout((void *)val,
8088                                     (void *)fcio->fcio_obuf,
8089                                     fcio->fcio_olen, mode) == 0) {
8090                                         if (fp_fcio_copyout(fcio, data, mode)) {
8091                                                 rval = EFAULT;
8092                                         }
8093                                 } else {
8094                                         rval = EFAULT;
8095                                 }
8096                         }
8097                 }
8098 
8099                 mutex_exit(&port->fp_mutex);
8100                 kmem_free(val, sizeof (*val));
8101                 break;
8102         }
8103 
8104         case FCIO_GET_PORT_ATTRIBUTES: {
8105                 fc_hba_port_attributes_t    *val;
8106                 fc_hba_port_attributes32_t  *val32;
8107                 la_wwn_t                    wwn;
8108                 fc_remote_port_t            *tmp_pd;
8109 
8110                 if (use32 == B_TRUE) {
8111                         if (fcio->fcio_olen < sizeof (*val32) ||
8112                             fcio->fcio_xfer != FCIO_XFER_READ) {
8113                                 rval = EINVAL;
8114                                 break;
8115                         }
8116                 } else {
8117                         if (fcio->fcio_olen < sizeof (*val) ||
8118                             fcio->fcio_xfer != FCIO_XFER_READ) {
8119                                 rval = EINVAL;
8120                                 break;
8121                         }
8122                 }
8123 
8124                 if (ddi_copyin(fcio->fcio_ibuf, &wwn, sizeof (wwn), mode)) {
8125                         rval = EFAULT;
8126                         break;
8127                 }
8128 
8129                 val = kmem_zalloc(sizeof (*val), KM_SLEEP);
8130                 val->version = FC_HBA_PORT_ATTRIBUTES_VERSION;
8131 
8132                 mutex_enter(&port->fp_mutex);
8133                 tmp_pd = fctl_lookup_pd_by_wwn(port, wwn);
8134                 val->lastChange = port->fp_last_change;
8135                 val->fp_minor = port->fp_instance;
8136                 mutex_exit(&port->fp_mutex);
8137 
8138                 if (tmp_pd == NULL) {
8139                         fcio->fcio_errno = FC_BADWWN;
8140                         rval = EINVAL;
8141                 } else {
8142                         mutex_enter(&tmp_pd->pd_mutex);
8143                         bcopy(&tmp_pd->pd_port_name.raw_wwn,
8144                             &val->PortWWN.raw_wwn,
8145                             sizeof (val->PortWWN.raw_wwn));
8146                         bcopy(&tmp_pd->pd_remote_nodep->fd_node_name.raw_wwn,
8147                             &val->NodeWWN.raw_wwn,
8148                             sizeof (val->NodeWWN.raw_wwn));
8149                         val->PortFcId = tmp_pd->pd_port_id.port_id;
8150                         bcopy(tmp_pd->pd_spn, val->PortSymbolicName,
8151                             tmp_pd->pd_spn_len);
8152                         val->PortSupportedClassofService = tmp_pd->pd_cos;
8153                         val->PortType = FC_HBA_PORTTYPE_UNKNOWN;
8154                         val->PortState =
8155                             fp_map_remote_port_state(tmp_pd->pd_state);
8156                         val->PortSupportedFc4Types[0] = 0;
8157                         /*
8158                          * we will assume the sizeof these pd_fc4types and
8159                          * portActiveFc4Types will remain the same.  we could
8160                          * add in a check for it, but we decided it was unneeded
8161                          */
8162                         bcopy((caddr_t)tmp_pd->pd_fc4types,
8163                             val->PortActiveFc4Types,
8164                             sizeof (tmp_pd->pd_fc4types));
8165                         val->PortSupportedSpeed = FC_HBA_PORTSPEED_UNKNOWN;
8166                         val->PortSpeed = FC_HBA_PORTSPEED_UNKNOWN;
8167                         val->PortMaxFrameSize = 0;
8168                         val->NumberofDiscoveredPorts = 0;
8169                         mutex_exit(&tmp_pd->pd_mutex);
8170 
8171                         if (use32 == B_TRUE) {
8172                                 val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP);
8173                                 val32->version = val->version;
8174                                 val32->lastChange = val->lastChange;
8175                                 val32->fp_minor = val->fp_minor;
8176                                 bcopy(&val->PortWWN.raw_wwn,
8177                                     &val32->PortWWN.raw_wwn,
8178                                     sizeof (val->PortWWN.raw_wwn));
8179                                 bcopy(&val->NodeWWN.raw_wwn,
8180                                     &val32->NodeWWN.raw_wwn,
8181                                     sizeof (val->NodeWWN.raw_wwn));
8182                                 val32->PortFcId = val->PortFcId;
8183                                 bcopy(val->PortSymbolicName,
8184                                     val32->PortSymbolicName,
8185                                     sizeof (val->PortSymbolicName));
8186                                 val32->PortSupportedClassofService =
8187                                     val->PortSupportedClassofService;
8188                                 val32->PortType = val->PortType;
8189                                 val32->PortState = val->PortState;
8190                                 val32->PortSupportedFc4Types[0] =
8191                                     val->PortSupportedFc4Types[0];
8192                                 bcopy(val->PortActiveFc4Types,
8193                                     val32->PortActiveFc4Types,
8194                                     sizeof (tmp_pd->pd_fc4types));
8195                                 val32->PortSupportedSpeed =
8196                                     val->PortSupportedSpeed;
8197                                 val32->PortSpeed = val->PortSpeed;
8198                                 val32->PortMaxFrameSize = val->PortMaxFrameSize;
8199                                 val32->NumberofDiscoveredPorts =
8200                                     val->NumberofDiscoveredPorts;
8201 
8202                                 if (fp_copyout((void *)val32,
8203                                     (void *)fcio->fcio_obuf,
8204                                     fcio->fcio_olen, mode) == 0) {
8205                                         if (fp_fcio_copyout(fcio, data, mode)) {
8206                                                 rval = EFAULT;
8207                                         }
8208                                 } else {
8209                                         rval = EFAULT;
8210                                 }
8211 
8212                                 kmem_free(val32, sizeof (*val32));
8213                         } else {
8214                                 if (fp_copyout((void *)val,
8215                                     (void *)fcio->fcio_obuf,
8216                                     fcio->fcio_olen, mode) == 0) {
8217                                         if (fp_fcio_copyout(fcio, data, mode)) {
8218                                                 rval = EFAULT;
8219                                         }
8220                                 } else {
8221                                         rval = EFAULT;
8222                                 }
8223                         }
8224                 }
8225                 kmem_free(val, sizeof (*val));
8226                 break;
8227         }
8228 
8229         case FCIO_GET_NUM_DEVS: {
8230                 int num_devices;
8231 
8232                 if (fcio->fcio_olen != sizeof (num_devices) ||
8233                     fcio->fcio_xfer != FCIO_XFER_READ) {
8234                         rval = EINVAL;
8235                         break;
8236                 }
8237 
8238                 mutex_enter(&port->fp_mutex);
8239                 switch (port->fp_topology) {
8240                 case FC_TOP_PRIVATE_LOOP:
8241                 case FC_TOP_PT_PT:
8242                         num_devices = port->fp_total_devices;
8243                         fcio->fcio_errno = FC_SUCCESS;
8244                         break;
8245 
8246                 case FC_TOP_PUBLIC_LOOP:
8247                 case FC_TOP_FABRIC:
8248                         mutex_exit(&port->fp_mutex);
8249                         job = fctl_alloc_job(JOB_NS_CMD, 0, NULL,
8250                             NULL, KM_SLEEP);
8251                         ASSERT(job != NULL);
8252 
8253                         /*
8254                          * In FC-GS-2 the Name Server doesn't send out
8255                          * RSCNs for any Name Server Database updates
8256                          * When it is finally fixed there is no need
8257                          * to probe as below and should be removed.
8258                          */
8259                         (void) fp_ns_get_devcount(port, job, 0, KM_SLEEP);
8260                         fctl_dealloc_job(job);
8261 
8262                         mutex_enter(&port->fp_mutex);
8263                         num_devices = port->fp_total_devices;
8264                         fcio->fcio_errno = FC_SUCCESS;
8265                         break;
8266 
8267                 case FC_TOP_NO_NS:
8268                         /* FALLTHROUGH */
8269                 case FC_TOP_UNKNOWN:
8270                         /* FALLTHROUGH */
8271                 default:
8272                         num_devices = 0;
8273                         fcio->fcio_errno = FC_SUCCESS;
8274                         break;
8275                 }
8276                 mutex_exit(&port->fp_mutex);
8277 
8278                 if (fp_copyout((void *)&num_devices,
8279                     (void *)fcio->fcio_obuf, fcio->fcio_olen,
8280                     mode) == 0) {
8281                         if (fp_fcio_copyout(fcio, data, mode)) {
8282                                 rval = EFAULT;
8283                         }
8284                 } else {
8285                         rval = EFAULT;
8286                 }
8287                 break;
8288         }
8289 
8290         case FCIO_GET_DEV_LIST: {
8291                 int num_devices;
8292                 int new_count;
8293                 int map_size;
8294 
8295                 if (fcio->fcio_xfer != FCIO_XFER_READ ||
8296                     fcio->fcio_alen != sizeof (new_count)) {
8297                         rval = EINVAL;
8298                         break;
8299                 }
8300 
8301                 num_devices = fcio->fcio_olen / sizeof (fc_port_dev_t);
8302 
8303                 mutex_enter(&port->fp_mutex);
8304                 if (num_devices < port->fp_total_devices) {
8305                         fcio->fcio_errno = FC_TOOMANY;
8306                         new_count = port->fp_total_devices;
8307                         mutex_exit(&port->fp_mutex);
8308 
8309                         if (fp_copyout((void *)&new_count,
8310                             (void *)fcio->fcio_abuf,
8311                             sizeof (new_count), mode)) {
8312                                 rval = EFAULT;
8313                                 break;
8314                         }
8315 
8316                         if (fp_fcio_copyout(fcio, data, mode)) {
8317                                 rval = EFAULT;
8318                                 break;
8319                         }
8320                         rval = EINVAL;
8321                         break;
8322                 }
8323 
8324                 if (port->fp_total_devices <= 0) {
8325                         fcio->fcio_errno = FC_NO_MAP;
8326                         new_count = port->fp_total_devices;
8327                         mutex_exit(&port->fp_mutex);
8328 
8329                         if (fp_copyout((void *)&new_count,
8330                             (void *)fcio->fcio_abuf,
8331                             sizeof (new_count), mode)) {
8332                                 rval = EFAULT;
8333                                 break;
8334                         }
8335 
8336                         if (fp_fcio_copyout(fcio, data, mode)) {
8337                                 rval = EFAULT;
8338                                 break;
8339                         }
8340                         rval = EINVAL;
8341                         break;
8342                 }
8343 
8344                 switch (port->fp_topology) {
8345                 case FC_TOP_PRIVATE_LOOP:
8346                         if (fp_fillout_loopmap(port, fcio,
8347                             mode) != FC_SUCCESS) {
8348                                 rval = EFAULT;
8349                                 break;
8350                         }
8351                         if (fp_fcio_copyout(fcio, data, mode)) {
8352                                 rval = EFAULT;
8353                         }
8354                         break;
8355 
8356                 case FC_TOP_PT_PT:
8357                         if (fp_fillout_p2pmap(port, fcio,
8358                             mode) != FC_SUCCESS) {
8359                                 rval = EFAULT;
8360                                 break;
8361                         }
8362                         if (fp_fcio_copyout(fcio, data, mode)) {
8363                                 rval = EFAULT;
8364                         }
8365                         break;
8366 
8367                 case FC_TOP_PUBLIC_LOOP:
8368                 case FC_TOP_FABRIC: {
8369                         fctl_ns_req_t *ns_cmd;
8370 
8371                         map_size =
8372                             sizeof (fc_port_dev_t) * port->fp_total_devices;
8373 
8374                         mutex_exit(&port->fp_mutex);
8375 
8376                         ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t),
8377                             sizeof (ns_resp_gan_t), map_size,
8378                             (FCTL_NS_FILL_NS_MAP | FCTL_NS_BUF_IS_USERLAND),
8379                             KM_SLEEP);
8380                         ASSERT(ns_cmd != NULL);
8381 
8382                         ns_cmd->ns_gan_index = 0;
8383                         ns_cmd->ns_gan_sid = FCTL_GAN_START_ID;
8384                         ns_cmd->ns_cmd_code = NS_GA_NXT;
8385                         ns_cmd->ns_gan_max = map_size / sizeof (fc_port_dev_t);
8386 
8387                         job = fctl_alloc_job(JOB_PORT_GETMAP, 0, NULL,
8388                             NULL, KM_SLEEP);
8389                         ASSERT(job != NULL);
8390 
8391                         ret = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP);
8392 
8393                         if (ret != FC_SUCCESS ||
8394                             job->job_result != FC_SUCCESS) {
8395                                 fctl_free_ns_cmd(ns_cmd);
8396 
8397                                 fcio->fcio_errno = job->job_result;
8398                                 new_count = 0;
8399                                 if (fp_copyout((void *)&new_count,
8400                                     (void *)fcio->fcio_abuf,
8401                                     sizeof (new_count), mode)) {
8402                                         fctl_dealloc_job(job);
8403                                         mutex_enter(&port->fp_mutex);
8404                                         rval = EFAULT;
8405                                         break;
8406                                 }
8407 
8408                                 if (fp_fcio_copyout(fcio, data, mode)) {
8409                                         fctl_dealloc_job(job);
8410                                         mutex_enter(&port->fp_mutex);
8411                                         rval = EFAULT;
8412                                         break;
8413                                 }
8414                                 rval = EIO;
8415                                 mutex_enter(&port->fp_mutex);
8416                                 break;
8417                         }
8418                         fctl_dealloc_job(job);
8419 
8420                         new_count = ns_cmd->ns_gan_index;
8421                         if (fp_copyout((void *)&new_count,
8422                             (void *)fcio->fcio_abuf, sizeof (new_count),
8423                             mode)) {
8424                                 rval = EFAULT;
8425                                 fctl_free_ns_cmd(ns_cmd);
8426                                 mutex_enter(&port->fp_mutex);
8427                                 break;
8428                         }
8429 
8430                         if (fp_copyout((void *)ns_cmd->ns_data_buf,
8431                             (void *)fcio->fcio_obuf, sizeof (fc_port_dev_t) *
8432                             ns_cmd->ns_gan_index, mode)) {
8433                                 rval = EFAULT;
8434                                 fctl_free_ns_cmd(ns_cmd);
8435                                 mutex_enter(&port->fp_mutex);
8436                                 break;
8437                         }
8438                         fctl_free_ns_cmd(ns_cmd);
8439 
8440                         if (fp_fcio_copyout(fcio, data, mode)) {
8441                                 rval = EFAULT;
8442                         }
8443                         mutex_enter(&port->fp_mutex);
8444                         break;
8445                 }
8446 
8447                 case FC_TOP_NO_NS:
8448                         /* FALLTHROUGH */
8449                 case FC_TOP_UNKNOWN:
8450                         /* FALLTHROUGH */
8451                 default:
8452                         fcio->fcio_errno = FC_NO_MAP;
8453                         num_devices = port->fp_total_devices;
8454 
8455                         if (fp_copyout((void *)&new_count,
8456                             (void *)fcio->fcio_abuf,
8457                             sizeof (new_count), mode)) {
8458                                 rval = EFAULT;
8459                                 break;
8460                         }
8461 
8462                         if (fp_fcio_copyout(fcio, data, mode)) {
8463                                 rval = EFAULT;
8464                                 break;
8465                         }
8466                         rval = EINVAL;
8467                         break;
8468                 }
8469                 mutex_exit(&port->fp_mutex);
8470                 break;
8471         }
8472 
8473         case FCIO_GET_SYM_PNAME: {
8474                 rval = ENOTSUP;
8475                 break;
8476         }
8477 
8478         case FCIO_GET_SYM_NNAME: {
8479                 rval = ENOTSUP;
8480                 break;
8481         }
8482 
8483         case FCIO_SET_SYM_PNAME: {
8484                 rval = ENOTSUP;
8485                 break;
8486         }
8487 
8488         case FCIO_SET_SYM_NNAME: {
8489                 rval = ENOTSUP;
8490                 break;
8491         }
8492 
8493         case FCIO_GET_LOGI_PARAMS: {
8494                 la_wwn_t                pwwn;
8495                 la_wwn_t                *my_pwwn;
8496                 la_els_logi_t           *params;
8497                 la_els_logi32_t         *params32;
8498                 fc_remote_node_t        *node;
8499                 fc_remote_port_t        *pd;
8500 
8501                 if (fcio->fcio_ilen != sizeof (la_wwn_t) ||
8502                     (fcio->fcio_xfer & FCIO_XFER_READ) == 0 ||
8503                     (fcio->fcio_xfer & FCIO_XFER_WRITE) == 0) {
8504                         rval = EINVAL;
8505                         break;
8506                 }
8507 
8508                 if (use32 == B_TRUE) {
8509                         if (fcio->fcio_olen != sizeof (la_els_logi32_t)) {
8510                                 rval = EINVAL;
8511                                 break;
8512                         }
8513                 } else {
8514                         if (fcio->fcio_olen != sizeof (la_els_logi_t)) {
8515                                 rval = EINVAL;
8516                                 break;
8517                         }
8518                 }
8519 
8520                 if (ddi_copyin(fcio->fcio_ibuf, &pwwn, sizeof (pwwn), mode)) {
8521                         rval = EFAULT;
8522                         break;
8523                 }
8524 
8525                 pd = fctl_hold_remote_port_by_pwwn(port, &pwwn);
8526                 if (pd == NULL) {
8527                         mutex_enter(&port->fp_mutex);
8528                         my_pwwn = &port->fp_service_params.nport_ww_name;
8529                         mutex_exit(&port->fp_mutex);
8530 
8531                         if (fctl_wwn_cmp(&pwwn, my_pwwn) != 0) {
8532                                 rval = ENXIO;
8533                                 break;
8534                         }
8535 
8536                         params = kmem_zalloc(sizeof (*params), KM_SLEEP);
8537                         mutex_enter(&port->fp_mutex);
8538                         *params = port->fp_service_params;
8539                         mutex_exit(&port->fp_mutex);
8540                 } else {
8541                         params = kmem_zalloc(sizeof (*params), KM_SLEEP);
8542 
8543                         mutex_enter(&pd->pd_mutex);
8544                         params->ls_code.mbz = params->ls_code.ls_code = 0;
8545                         params->common_service = pd->pd_csp;
8546                         params->nport_ww_name = pd->pd_port_name;
8547                         params->class_1 = pd->pd_clsp1;
8548                         params->class_2 = pd->pd_clsp2;
8549                         params->class_3 = pd->pd_clsp3;
8550                         node = pd->pd_remote_nodep;
8551                         mutex_exit(&pd->pd_mutex);
8552 
8553                         bzero(params->reserved, sizeof (params->reserved));
8554 
8555                         mutex_enter(&node->fd_mutex);
8556                         bcopy(node->fd_vv, params->vendor_version,
8557                             sizeof (node->fd_vv));
8558                         params->node_ww_name = node->fd_node_name;
8559                         mutex_exit(&node->fd_mutex);
8560 
8561                         fctl_release_remote_port(pd);
8562                 }
8563 
8564                 if (use32 == B_TRUE) {
8565                         params32 = kmem_zalloc(sizeof (*params32), KM_SLEEP);
8566 
8567                         params32->ls_code.mbz = params->ls_code.mbz;
8568                         params32->common_service = params->common_service;
8569                         params32->nport_ww_name = params->nport_ww_name;
8570                         params32->class_1 = params->class_1;
8571                         params32->class_2 = params->class_2;
8572                         params32->class_3 = params->class_3;
8573                         bzero(params32->reserved, sizeof (params32->reserved));
8574                         bcopy(params->vendor_version, params32->vendor_version,
8575                             sizeof (node->fd_vv));
8576                         params32->node_ww_name = params->node_ww_name;
8577 
8578                         if (ddi_copyout((void *)params32,
8579                             (void *)fcio->fcio_obuf,
8580                             sizeof (*params32), mode)) {
8581                                 rval = EFAULT;
8582                         }
8583 
8584                         kmem_free(params32, sizeof (*params32));
8585                 } else {
8586                         if (ddi_copyout((void *)params, (void *)fcio->fcio_obuf,
8587                             sizeof (*params), mode)) {
8588                                 rval = EFAULT;
8589                         }
8590                 }
8591 
8592                 kmem_free(params, sizeof (*params));
8593                 if (fp_fcio_copyout(fcio, data, mode)) {
8594                         rval = EFAULT;
8595                 }
8596                 break;
8597         }
8598 
8599         case FCIO_DEV_LOGOUT:
8600         case FCIO_DEV_LOGIN:
8601                 if (fcio->fcio_ilen != sizeof (la_wwn_t) ||
8602                     fcio->fcio_xfer != FCIO_XFER_WRITE) {
8603                         rval = EINVAL;
8604 
8605                         if (fp_fcio_copyout(fcio, data, mode)) {
8606                                 rval = EFAULT;
8607                         }
8608                         break;
8609                 }
8610 
8611                 if (fcio->fcio_cmd == FCIO_DEV_LOGIN) {
8612                         jcode = JOB_FCIO_LOGIN;
8613                 } else {
8614                         jcode = JOB_FCIO_LOGOUT;
8615                 }
8616 
8617                 kfcio = kmem_zalloc(sizeof (*kfcio), KM_SLEEP);
8618                 bcopy(fcio, kfcio, sizeof (*fcio));
8619 
8620                 if (kfcio->fcio_ilen) {
8621                         kfcio->fcio_ibuf = kmem_zalloc(kfcio->fcio_ilen,
8622                             KM_SLEEP);
8623 
8624                         if (ddi_copyin((void *)fcio->fcio_ibuf,
8625                             (void *)kfcio->fcio_ibuf, kfcio->fcio_ilen,
8626                             mode)) {
8627                                 rval = EFAULT;
8628 
8629                                 kmem_free(kfcio->fcio_ibuf, kfcio->fcio_ilen);
8630                                 kmem_free(kfcio, sizeof (*kfcio));
8631                                 fcio->fcio_errno = job->job_result;
8632                                 if (fp_fcio_copyout(fcio, data, mode)) {
8633                                         rval = EFAULT;
8634                                 }
8635                                 break;
8636                         }
8637                 }
8638 
8639                 job = fctl_alloc_job(jcode, 0, NULL, NULL, KM_SLEEP);
8640                 job->job_private = kfcio;
8641 
8642                 fctl_enque_job(port, job);
8643                 fctl_jobwait(job);
8644 
8645                 rval = job->job_result;
8646 
8647                 fcio->fcio_errno = kfcio->fcio_errno;
8648                 if (fp_fcio_copyout(fcio, data, mode)) {
8649                         rval = EFAULT;
8650                 }
8651 
8652                 kmem_free(kfcio->fcio_ibuf, kfcio->fcio_ilen);
8653                 kmem_free(kfcio, sizeof (*kfcio));
8654                 fctl_dealloc_job(job);
8655                 break;
8656 
8657         case FCIO_GET_STATE: {
8658                 la_wwn_t                pwwn;
8659                 uint32_t                state;
8660                 fc_remote_port_t        *pd;
8661                 fctl_ns_req_t           *ns_cmd;
8662 
8663                 if (fcio->fcio_ilen != sizeof (la_wwn_t) ||
8664                     fcio->fcio_olen != sizeof (state) ||
8665                     (fcio->fcio_xfer & FCIO_XFER_WRITE) == 0 ||
8666                     (fcio->fcio_xfer & FCIO_XFER_READ) == 0) {
8667                         rval = EINVAL;
8668                         break;
8669                 }
8670 
8671                 if (ddi_copyin(fcio->fcio_ibuf, &pwwn, sizeof (pwwn), mode)) {
8672                         rval = EFAULT;
8673                         break;
8674                 }
8675                 fcio->fcio_errno = 0;
8676 
8677                 pd = fctl_hold_remote_port_by_pwwn(port, &pwwn);
8678                 if (pd == NULL) {
8679                         mutex_enter(&port->fp_mutex);
8680                         if (FC_IS_TOP_SWITCH(port->fp_topology)) {
8681                                 mutex_exit(&port->fp_mutex);
8682                                 job = fctl_alloc_job(JOB_PLOGI_ONE, 0,
8683                                     NULL, NULL, KM_SLEEP);
8684 
8685                                 job->job_counter = 1;
8686                                 job->job_result = FC_SUCCESS;
8687 
8688                                 ns_cmd = fctl_alloc_ns_cmd(
8689                                     sizeof (ns_req_gid_pn_t),
8690                                     sizeof (ns_resp_gid_pn_t),
8691                                     sizeof (ns_resp_gid_pn_t),
8692                                     FCTL_NS_BUF_IS_USERLAND, KM_SLEEP);
8693                                 ASSERT(ns_cmd != NULL);
8694 
8695                                 ns_cmd->ns_cmd_code = NS_GID_PN;
8696                                 ((ns_req_gid_pn_t *)
8697                                     (ns_cmd->ns_cmd_buf))->pwwn = pwwn;
8698 
8699                                 ret = fp_ns_query(port, ns_cmd, job,
8700                                     1, KM_SLEEP);
8701 
8702                                 if (ret != FC_SUCCESS || job->job_result !=
8703                                     FC_SUCCESS) {
8704                                         if (ret != FC_SUCCESS) {
8705                                                 fcio->fcio_errno = ret;
8706                                         } else {
8707                                                 fcio->fcio_errno =
8708                                                     job->job_result;
8709                                         }
8710                                         rval = EIO;
8711                                 } else {
8712                                         state = PORT_DEVICE_INVALID;
8713                                 }
8714                                 fctl_free_ns_cmd(ns_cmd);
8715                                 fctl_dealloc_job(job);
8716                         } else {
8717                                 mutex_exit(&port->fp_mutex);
8718                                 fcio->fcio_errno = FC_BADWWN;
8719                                 rval = ENXIO;
8720                         }
8721                 } else {
8722                         mutex_enter(&pd->pd_mutex);
8723                         state = pd->pd_state;
8724                         mutex_exit(&pd->pd_mutex);
8725 
8726                         fctl_release_remote_port(pd);
8727                 }
8728 
8729                 if (!rval) {
8730                         if (ddi_copyout((void *)&state,
8731                             (void *)fcio->fcio_obuf, sizeof (state),
8732                             mode)) {
8733                                 rval = EFAULT;
8734                         }
8735                 }
8736                 if (fp_fcio_copyout(fcio, data, mode)) {
8737                         rval = EFAULT;
8738                 }
8739                 break;
8740         }
8741 
8742         case FCIO_DEV_REMOVE: {
8743                 la_wwn_t        pwwn;
8744                 fc_portmap_t    *changelist;
8745                 fc_remote_port_t *pd;
8746 
8747                 if (fcio->fcio_ilen != sizeof (la_wwn_t) ||
8748                     fcio->fcio_xfer != FCIO_XFER_WRITE) {
8749                         rval = EINVAL;
8750                         break;
8751                 }
8752 
8753                 if (ddi_copyin(fcio->fcio_ibuf, &pwwn, sizeof (pwwn), mode)) {
8754                         rval = EFAULT;
8755                         break;
8756                 }
8757 
8758                 pd = fctl_hold_remote_port_by_pwwn(port, &pwwn);
8759                 if (pd == NULL) {
8760                         rval = ENXIO;
8761                         fcio->fcio_errno = FC_BADWWN;
8762                         if (fp_fcio_copyout(fcio, data, mode)) {
8763                                 rval = EFAULT;
8764                         }
8765                         break;
8766                 }
8767 
8768                 mutex_enter(&pd->pd_mutex);
8769                 if (pd->pd_ref_count > 1) {
8770                         mutex_exit(&pd->pd_mutex);
8771 
8772                         rval = EBUSY;
8773                         fcio->fcio_errno = FC_FAILURE;
8774                         fctl_release_remote_port(pd);
8775 
8776                         if (fp_fcio_copyout(fcio, data, mode)) {
8777                                 rval = EFAULT;
8778                         }
8779                         break;
8780                 }
8781                 mutex_exit(&pd->pd_mutex);
8782 
8783                 changelist = kmem_zalloc(sizeof (*changelist), KM_SLEEP);
8784 
8785                 fctl_copy_portmap(changelist, pd);
8786                 changelist->map_type = PORT_DEVICE_USER_LOGOUT;
8787                 (void) fp_ulp_devc_cb(port, changelist, 1, 1, KM_SLEEP, 1);
8788 
8789                 fctl_release_remote_port(pd);
8790                 break;
8791         }
8792 
8793         case FCIO_GET_FCODE_REV: {
8794                 caddr_t         fcode_rev;
8795                 fc_fca_pm_t     pm;
8796 
8797                 if (fcio->fcio_olen < FC_FCODE_REV_SIZE ||
8798                     fcio->fcio_xfer != FCIO_XFER_READ) {
8799                         rval = EINVAL;
8800                         break;
8801                 }
8802                 bzero((caddr_t)&pm, sizeof (pm));
8803 
8804                 fcode_rev = kmem_zalloc(fcio->fcio_olen, KM_SLEEP);
8805 
8806                 pm.pm_cmd_flags = FC_FCA_PM_READ;
8807                 pm.pm_cmd_code = FC_PORT_GET_FCODE_REV;
8808                 pm.pm_data_len = fcio->fcio_olen;
8809                 pm.pm_data_buf = fcode_rev;
8810 
8811                 ret = port->fp_fca_tran->fca_port_manage(
8812                     port->fp_fca_handle, &pm);
8813 
8814                 if (ret == FC_SUCCESS) {
8815                         if (ddi_copyout((void *)fcode_rev,
8816                             (void *)fcio->fcio_obuf,
8817                             fcio->fcio_olen, mode) == 0) {
8818                                 if (fp_fcio_copyout(fcio, data, mode)) {
8819                                         rval = EFAULT;
8820                                 }
8821                         } else {
8822                                 rval = EFAULT;
8823                         }
8824                 } else {
8825                         /*
8826                          * check if buffer was not large enough to obtain
8827                          * FCODE version.
8828                          */
8829                         if (pm.pm_data_len > fcio->fcio_olen) {
8830                                 rval = ENOMEM;
8831                         } else {
8832                                 rval = EIO;
8833                         }
8834                         fcio->fcio_errno = ret;
8835                         if (fp_fcio_copyout(fcio, data, mode)) {
8836                                 rval = EFAULT;
8837                         }
8838                 }
8839                 kmem_free(fcode_rev, fcio->fcio_olen);
8840                 break;
8841         }
8842 
8843         case FCIO_GET_FW_REV: {
8844                 caddr_t         fw_rev;
8845                 fc_fca_pm_t     pm;
8846 
8847                 if (fcio->fcio_olen < FC_FW_REV_SIZE ||
8848                     fcio->fcio_xfer != FCIO_XFER_READ) {
8849                         rval = EINVAL;
8850                         break;
8851                 }
8852                 bzero((caddr_t)&pm, sizeof (pm));
8853 
8854                 fw_rev = kmem_zalloc(fcio->fcio_olen, KM_SLEEP);
8855 
8856                 pm.pm_cmd_flags = FC_FCA_PM_READ;
8857                 pm.pm_cmd_code = FC_PORT_GET_FW_REV;
8858                 pm.pm_data_len = fcio->fcio_olen;
8859                 pm.pm_data_buf = fw_rev;
8860 
8861                 ret = port->fp_fca_tran->fca_port_manage(
8862                     port->fp_fca_handle, &pm);
8863 
8864                 if (ret == FC_SUCCESS) {
8865                         if (ddi_copyout((void *)fw_rev,
8866                             (void *)fcio->fcio_obuf,
8867                             fcio->fcio_olen, mode) == 0) {
8868                                 if (fp_fcio_copyout(fcio, data, mode)) {
8869                                         rval = EFAULT;
8870                                 }
8871                         } else {
8872                                 rval = EFAULT;
8873                         }
8874                 } else {
8875                         if (fp_fcio_copyout(fcio, data, mode)) {
8876                                 rval = EFAULT;
8877                         }
8878                         rval = EIO;
8879                 }
8880                 kmem_free(fw_rev, fcio->fcio_olen);
8881                 break;
8882         }
8883 
8884         case FCIO_GET_DUMP_SIZE: {
8885                 uint32_t        dump_size;
8886                 fc_fca_pm_t     pm;
8887 
8888                 if (fcio->fcio_olen != sizeof (dump_size) ||
8889                     fcio->fcio_xfer != FCIO_XFER_READ) {
8890                         rval = EINVAL;
8891                         break;
8892                 }
8893                 bzero((caddr_t)&pm, sizeof (pm));
8894                 pm.pm_cmd_flags = FC_FCA_PM_READ;
8895                 pm.pm_cmd_code = FC_PORT_GET_DUMP_SIZE;
8896                 pm.pm_data_len = sizeof (dump_size);
8897                 pm.pm_data_buf = (caddr_t)&dump_size;
8898 
8899                 ret = port->fp_fca_tran->fca_port_manage(
8900                     port->fp_fca_handle, &pm);
8901 
8902                 if (ret == FC_SUCCESS) {
8903                         if (ddi_copyout((void *)&dump_size,
8904                             (void *)fcio->fcio_obuf, sizeof (dump_size),
8905                             mode) == 0) {
8906                                 if (fp_fcio_copyout(fcio, data, mode)) {
8907                                         rval = EFAULT;
8908                                 }
8909                         } else {
8910                                 rval = EFAULT;
8911                         }
8912                 } else {
8913                         fcio->fcio_errno = ret;
8914                         rval = EIO;
8915                         if (fp_fcio_copyout(fcio, data, mode)) {
8916                                 rval = EFAULT;
8917                         }
8918                 }
8919                 break;
8920         }
8921 
8922         case FCIO_DOWNLOAD_FW: {
8923                 caddr_t         firmware;
8924                 fc_fca_pm_t     pm;
8925 
8926                 if (fcio->fcio_ilen <= 0 ||
8927                     fcio->fcio_xfer != FCIO_XFER_WRITE) {
8928                         rval = EINVAL;
8929                         break;
8930                 }
8931 
8932                 firmware = kmem_zalloc(fcio->fcio_ilen, KM_SLEEP);
8933                 if (ddi_copyin(fcio->fcio_ibuf, firmware,
8934                     fcio->fcio_ilen, mode)) {
8935                         rval = EFAULT;
8936                         kmem_free(firmware, fcio->fcio_ilen);
8937                         break;
8938                 }
8939 
8940                 bzero((caddr_t)&pm, sizeof (pm));
8941                 pm.pm_cmd_flags = FC_FCA_PM_WRITE;
8942                 pm.pm_cmd_code = FC_PORT_DOWNLOAD_FW;
8943                 pm.pm_data_len = fcio->fcio_ilen;
8944                 pm.pm_data_buf = firmware;
8945 
8946                 ret = port->fp_fca_tran->fca_port_manage(
8947                     port->fp_fca_handle, &pm);
8948 
8949                 kmem_free(firmware, fcio->fcio_ilen);
8950 
8951                 if (ret != FC_SUCCESS) {
8952                         fcio->fcio_errno = ret;
8953                         rval = EIO;
8954                         if (fp_fcio_copyout(fcio, data, mode)) {
8955                                 rval = EFAULT;
8956                         }
8957                 }
8958                 break;
8959         }
8960 
8961         case FCIO_DOWNLOAD_FCODE: {
8962                 caddr_t         fcode;
8963                 fc_fca_pm_t     pm;
8964 
8965                 if (fcio->fcio_ilen <= 0 ||
8966                     fcio->fcio_xfer != FCIO_XFER_WRITE) {
8967                         rval = EINVAL;
8968                         break;
8969                 }
8970 
8971                 fcode = kmem_zalloc(fcio->fcio_ilen, KM_SLEEP);
8972                 if (ddi_copyin(fcio->fcio_ibuf, fcode,
8973                     fcio->fcio_ilen, mode)) {
8974                         rval = EFAULT;
8975                         kmem_free(fcode, fcio->fcio_ilen);
8976                         break;
8977                 }
8978 
8979                 bzero((caddr_t)&pm, sizeof (pm));
8980                 pm.pm_cmd_flags = FC_FCA_PM_WRITE;
8981                 pm.pm_cmd_code = FC_PORT_DOWNLOAD_FCODE;
8982                 pm.pm_data_len = fcio->fcio_ilen;
8983                 pm.pm_data_buf = fcode;
8984 
8985                 ret = port->fp_fca_tran->fca_port_manage(
8986                     port->fp_fca_handle, &pm);
8987 
8988                 kmem_free(fcode, fcio->fcio_ilen);
8989 
8990                 if (ret != FC_SUCCESS) {
8991                         fcio->fcio_errno = ret;
8992                         rval = EIO;
8993                         if (fp_fcio_copyout(fcio, data, mode)) {
8994                                 rval = EFAULT;
8995                         }
8996                 }
8997                 break;
8998         }
8999 
9000         case FCIO_FORCE_DUMP:
9001                 ret = port->fp_fca_tran->fca_reset(
9002                     port->fp_fca_handle, FC_FCA_CORE);
9003 
9004                 if (ret != FC_SUCCESS) {
9005                         fcio->fcio_errno = ret;
9006                         rval = EIO;
9007                         if (fp_fcio_copyout(fcio, data, mode)) {
9008                                 rval = EFAULT;
9009                         }
9010                 }
9011                 break;
9012 
9013         case FCIO_GET_DUMP: {
9014                 caddr_t         dump;
9015                 uint32_t        dump_size;
9016                 fc_fca_pm_t     pm;
9017 
9018                 if (fcio->fcio_xfer != FCIO_XFER_READ) {
9019                         rval = EINVAL;
9020                         break;
9021                 }
9022                 bzero((caddr_t)&pm, sizeof (pm));
9023 
9024                 pm.pm_cmd_flags = FC_FCA_PM_READ;
9025                 pm.pm_cmd_code = FC_PORT_GET_DUMP_SIZE;
9026                 pm.pm_data_len = sizeof (dump_size);
9027                 pm.pm_data_buf = (caddr_t)&dump_size;
9028 
9029                 ret = port->fp_fca_tran->fca_port_manage(
9030                     port->fp_fca_handle, &pm);
9031 
9032                 if (ret != FC_SUCCESS) {
9033                         fcio->fcio_errno = ret;
9034                         rval = EIO;
9035                         if (fp_fcio_copyout(fcio, data, mode)) {
9036                                 rval = EFAULT;
9037                         }
9038                         break;
9039                 }
9040                 if (fcio->fcio_olen != dump_size) {
9041                         fcio->fcio_errno = FC_NOMEM;
9042                         rval = EINVAL;
9043                         if (fp_fcio_copyout(fcio, data, mode)) {
9044                                 rval = EFAULT;
9045                         }
9046                         break;
9047                 }
9048 
9049                 dump = kmem_zalloc(dump_size, KM_SLEEP);
9050 
9051                 bzero((caddr_t)&pm, sizeof (pm));
9052                 pm.pm_cmd_flags = FC_FCA_PM_READ;
9053                 pm.pm_cmd_code = FC_PORT_GET_DUMP;
9054                 pm.pm_data_len = dump_size;
9055                 pm.pm_data_buf = dump;
9056 
9057                 ret = port->fp_fca_tran->fca_port_manage(
9058                     port->fp_fca_handle, &pm);
9059 
9060                 if (ret == FC_SUCCESS) {
9061                         if (ddi_copyout((void *)dump, (void *)fcio->fcio_obuf,
9062                             dump_size, mode) == 0) {
9063                                 if (fp_fcio_copyout(fcio, data, mode)) {
9064                                         rval = EFAULT;
9065                                 }
9066                         } else {
9067                                 rval = EFAULT;
9068                         }
9069                 } else {
9070                         fcio->fcio_errno = ret;
9071                         rval = EIO;
9072                         if (fp_fcio_copyout(fcio, data, mode)) {
9073                                 rval = EFAULT;
9074                         }
9075                 }
9076                 kmem_free(dump, dump_size);
9077                 break;
9078         }
9079 
9080         case FCIO_GET_TOPOLOGY: {
9081                 uint32_t user_topology;
9082 
9083                 if (fcio->fcio_xfer != FCIO_XFER_READ ||
9084                     fcio->fcio_olen != sizeof (user_topology)) {
9085                         rval = EINVAL;
9086                         break;
9087                 }
9088 
9089                 mutex_enter(&port->fp_mutex);
9090                 if (FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) {
9091                         user_topology = FC_TOP_UNKNOWN;
9092                 } else {
9093                         user_topology = port->fp_topology;
9094                 }
9095                 mutex_exit(&port->fp_mutex);
9096 
9097                 if (ddi_copyout((void *)&user_topology,
9098                     (void *)fcio->fcio_obuf, sizeof (user_topology),
9099                     mode)) {
9100                         rval = EFAULT;
9101                 }
9102                 break;
9103         }
9104 
9105         case FCIO_RESET_LINK: {
9106                 la_wwn_t pwwn;
9107 
9108                 /*
9109                  * Look at the output buffer field; if this field has zero
9110                  * bytes then attempt to reset the local link/loop. If the
9111                  * fcio_ibuf field points to a WWN, see if it's an NL_Port,
9112                  * and if yes, determine the LFA and reset the remote LIP
9113                  * by LINIT ELS.
9114                  */
9115 
9116                 if (fcio->fcio_xfer != FCIO_XFER_WRITE ||
9117                     fcio->fcio_ilen != sizeof (pwwn)) {
9118                         rval = EINVAL;
9119                         break;
9120                 }
9121 
9122                 if (ddi_copyin(fcio->fcio_ibuf, &pwwn,
9123                     sizeof (pwwn), mode)) {
9124                         rval = EFAULT;
9125                         break;
9126                 }
9127 
9128                 mutex_enter(&port->fp_mutex);
9129                 if (port->fp_soft_state & FP_SOFT_IN_LINK_RESET) {
9130                         mutex_exit(&port->fp_mutex);
9131                         break;
9132                 }
9133                 port->fp_soft_state |= FP_SOFT_IN_LINK_RESET;
9134                 mutex_exit(&port->fp_mutex);
9135 
9136                 job = fctl_alloc_job(JOB_LINK_RESET, 0, NULL, NULL, KM_SLEEP);
9137                 if (job == NULL) {
9138                         rval = ENOMEM;
9139                         break;
9140                 }
9141                 job->job_counter = 1;
9142                 job->job_private = (void *)&pwwn;
9143 
9144                 fctl_enque_job(port, job);
9145                 fctl_jobwait(job);
9146 
9147                 mutex_enter(&port->fp_mutex);
9148                 port->fp_soft_state &= ~FP_SOFT_IN_LINK_RESET;
9149                 mutex_exit(&port->fp_mutex);
9150 
9151                 if (job->job_result != FC_SUCCESS) {
9152                         fcio->fcio_errno = job->job_result;
9153                         rval = EIO;
9154                         if (fp_fcio_copyout(fcio, data, mode)) {
9155                                 rval = EFAULT;
9156                         }
9157                 }
9158                 fctl_dealloc_job(job);
9159                 break;
9160         }
9161 
9162         case FCIO_RESET_HARD:
9163                 ret = port->fp_fca_tran->fca_reset(
9164                     port->fp_fca_handle, FC_FCA_RESET);
9165                 if (ret != FC_SUCCESS) {
9166                         fcio->fcio_errno = ret;
9167                         rval = EIO;
9168                         if (fp_fcio_copyout(fcio, data, mode)) {
9169                                 rval = EFAULT;
9170                         }
9171                 }
9172                 break;
9173 
9174         case FCIO_RESET_HARD_CORE:
9175                 ret = port->fp_fca_tran->fca_reset(
9176                     port->fp_fca_handle, FC_FCA_RESET_CORE);
9177                 if (ret != FC_SUCCESS) {
9178                         rval = EIO;
9179                         fcio->fcio_errno = ret;
9180                         if (fp_fcio_copyout(fcio, data, mode)) {
9181                                 rval = EFAULT;
9182                         }
9183                 }
9184                 break;
9185 
9186         case FCIO_DIAG: {
9187                 fc_fca_pm_t pm;
9188 
9189                 bzero((caddr_t)&pm, sizeof (fc_fca_pm_t));
9190 
9191                 /* Validate user buffer from ioctl call. */
9192                 if (((fcio->fcio_ilen > 0) && (fcio->fcio_ibuf == NULL)) ||
9193                     ((fcio->fcio_ilen <= 0) && (fcio->fcio_ibuf != NULL)) ||
9194                     ((fcio->fcio_alen > 0) && (fcio->fcio_abuf == NULL)) ||
9195                     ((fcio->fcio_alen <= 0) && (fcio->fcio_abuf != NULL)) ||
9196                     ((fcio->fcio_olen > 0) && (fcio->fcio_obuf == NULL)) ||
9197                     ((fcio->fcio_olen <= 0) && (fcio->fcio_obuf != NULL))) {
9198                         rval = EFAULT;
9199                         break;
9200                 }
9201 
9202                 if ((pm.pm_cmd_len = fcio->fcio_ilen) > 0) {
9203                         pm.pm_cmd_buf = kmem_zalloc(fcio->fcio_ilen, KM_SLEEP);
9204                         if (ddi_copyin(fcio->fcio_ibuf, pm.pm_cmd_buf,
9205                             fcio->fcio_ilen, mode)) {
9206                                 rval = EFAULT;
9207                                 goto fp_fcio_diag_cleanup;
9208                         }
9209                 }
9210 
9211                 if ((pm.pm_data_len = fcio->fcio_alen) > 0) {
9212                         pm.pm_data_buf = kmem_zalloc(fcio->fcio_alen, KM_SLEEP);
9213                         if (ddi_copyin(fcio->fcio_abuf, pm.pm_data_buf,
9214                             fcio->fcio_alen, mode)) {
9215                                 rval = EFAULT;
9216                                 goto fp_fcio_diag_cleanup;
9217                         }
9218                 }
9219 
9220                 if ((pm.pm_stat_len = fcio->fcio_olen) > 0) {
9221                         pm.pm_stat_buf = kmem_zalloc(fcio->fcio_olen, KM_SLEEP);
9222                 }
9223 
9224                 pm.pm_cmd_code = FC_PORT_DIAG;
9225                 pm.pm_cmd_flags = fcio->fcio_cmd_flags;
9226 
9227                 ret = port->fp_fca_tran->fca_port_manage(
9228                     port->fp_fca_handle, &pm);
9229 
9230                 if (ret != FC_SUCCESS) {
9231                         if (ret == FC_INVALID_REQUEST) {
9232                                 rval = ENOTTY;
9233                         } else {
9234                                 rval = EIO;
9235                         }
9236 
9237                         fcio->fcio_errno = ret;
9238                         if (fp_fcio_copyout(fcio, data, mode)) {
9239                                 rval = EFAULT;
9240                         }
9241                         goto fp_fcio_diag_cleanup;
9242                 }
9243 
9244                 /*
9245                  * pm_stat_len will contain the number of status bytes
9246                  * an FCA driver requires to return the complete status
9247                  * of the requested diag operation. If the user buffer
9248                  * is not large enough to hold the entire status, We
9249                  * copy only the portion of data the fits in the buffer and
9250                  * return a ENOMEM to the user application.
9251                  */
9252                 if (pm.pm_stat_len > fcio->fcio_olen) {
9253                         fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
9254                             "fp:FCIO_DIAG:status buffer too small\n");
9255 
9256                         rval = ENOMEM;
9257                         if (ddi_copyout(pm.pm_stat_buf, fcio->fcio_obuf,
9258                             fcio->fcio_olen, mode)) {
9259                                 rval = EFAULT;
9260                                 goto fp_fcio_diag_cleanup;
9261                         }
9262                 } else {
9263                         /*
9264                          * Copy only data pm_stat_len bytes of data
9265                          */
9266                         if (ddi_copyout(pm.pm_stat_buf, fcio->fcio_obuf,
9267                             pm.pm_stat_len, mode)) {
9268                                 rval = EFAULT;
9269                                 goto fp_fcio_diag_cleanup;
9270                         }
9271                 }
9272 
9273                 if (fp_fcio_copyout(fcio, data, mode)) {
9274                         rval = EFAULT;
9275                 }
9276 
9277                 fp_fcio_diag_cleanup:
9278                 if (pm.pm_cmd_buf != NULL) {
9279                         kmem_free(pm.pm_cmd_buf, fcio->fcio_ilen);
9280                 }
9281                 if (pm.pm_data_buf != NULL) {
9282                         kmem_free(pm.pm_data_buf, fcio->fcio_alen);
9283                 }
9284                 if (pm.pm_stat_buf != NULL) {
9285                         kmem_free(pm.pm_stat_buf, fcio->fcio_olen);
9286                 }
9287 
9288                 break;
9289         }
9290 
9291         case FCIO_GET_NODE_ID: {
9292                 /* validate parameters */
9293                 if (fcio->fcio_xfer != FCIO_XFER_READ ||
9294                     fcio->fcio_olen < sizeof (fc_rnid_t)) {
9295                         rval = EINVAL;
9296                         break;
9297                 }
9298 
9299                 rval = fp_get_rnid(port, data, mode, fcio);
9300 
9301                 /* ioctl handling is over */
9302                 break;
9303         }
9304 
9305         case FCIO_SEND_NODE_ID: {
9306                 la_wwn_t                pwwn;
9307 
9308                 /* validate parameters */
9309                 if (fcio->fcio_ilen != sizeof (la_wwn_t) ||
9310                     fcio->fcio_xfer != FCIO_XFER_READ) {
9311                         rval = EINVAL;
9312                         break;
9313                 }
9314 
9315                 if (ddi_copyin(fcio->fcio_ibuf, &pwwn,
9316                     sizeof (la_wwn_t), mode)) {
9317                         rval = EFAULT;
9318                         break;
9319                 }
9320 
9321                 rval = fp_send_rnid(port, data, mode, fcio, &pwwn);
9322 
9323                 /* ioctl handling is over */
9324                 break;
9325         }
9326 
9327         case FCIO_SET_NODE_ID: {
9328                 if (fcio->fcio_ilen != sizeof (fc_rnid_t) ||
9329                     (fcio->fcio_xfer != FCIO_XFER_WRITE)) {
9330                         rval = EINVAL;
9331                         break;
9332                 }
9333 
9334                 rval = fp_set_rnid(port, data, mode, fcio);
9335                 break;
9336         }
9337 
9338         case FCIO_LINK_STATUS: {
9339                 fc_portid_t             rls_req;
9340                 fc_rls_acc_t            *rls_acc;
9341                 fc_fca_pm_t             pm;
9342                 uint32_t                dest, src_id;
9343                 fp_cmd_t                *cmd;
9344                 fc_remote_port_t        *pd;
9345                 uchar_t                 pd_flags;
9346 
9347                 /* validate parameters */
9348                 if (fcio->fcio_ilen != sizeof (fc_portid_t) ||
9349                     fcio->fcio_olen != sizeof (fc_rls_acc_t) ||
9350                     fcio->fcio_xfer != FCIO_XFER_RW) {
9351                         rval = EINVAL;
9352                         break;
9353                 }
9354 
9355                 if ((fcio->fcio_cmd_flags != FCIO_CFLAGS_RLS_DEST_FPORT) &&
9356                     (fcio->fcio_cmd_flags != FCIO_CFLAGS_RLS_DEST_NPORT)) {
9357                         rval = EINVAL;
9358                         break;
9359                 }
9360 
9361                 if (ddi_copyin((void *)fcio->fcio_ibuf, (void *)&rls_req,
9362                     sizeof (fc_portid_t), mode)) {
9363                         rval = EFAULT;
9364                         break;
9365                 }
9366 
9367 
9368                 /* Determine the destination of the RLS frame */
9369                 if (fcio->fcio_cmd_flags == FCIO_CFLAGS_RLS_DEST_FPORT) {
9370                         dest = FS_FABRIC_F_PORT;
9371                 } else {
9372                         dest = rls_req.port_id;
9373                 }
9374 
9375                 mutex_enter(&port->fp_mutex);
9376                 src_id = port->fp_port_id.port_id;
9377                 mutex_exit(&port->fp_mutex);
9378 
9379                 /* If dest is zero OR same as FCA ID, then use port_manage() */
9380                 if (dest == 0 || dest == src_id) {
9381 
9382                         /* Allocate memory for link error status block */
9383                         rls_acc = kmem_zalloc(sizeof (*rls_acc), KM_SLEEP);
9384                         ASSERT(rls_acc != NULL);
9385 
9386                         /* Prepare the port management structure */
9387                         bzero((caddr_t)&pm, sizeof (pm));
9388 
9389                         pm.pm_cmd_flags = FC_FCA_PM_READ;
9390                         pm.pm_cmd_code  = FC_PORT_RLS;
9391                         pm.pm_data_len  = sizeof (*rls_acc);
9392                         pm.pm_data_buf  = (caddr_t)rls_acc;
9393 
9394                         /* Get the adapter's link error status block */
9395                         ret = port->fp_fca_tran->fca_port_manage(
9396                             port->fp_fca_handle, &pm);
9397 
9398                         if (ret == FC_SUCCESS) {
9399                                 /* xfer link status block to userland */
9400                                 if (ddi_copyout((void *)rls_acc,
9401                                     (void *)fcio->fcio_obuf,
9402                                     sizeof (*rls_acc), mode) == 0) {
9403                                         if (fp_fcio_copyout(fcio, data,
9404                                             mode)) {
9405                                                 rval = EFAULT;
9406                                         }
9407                                 } else {
9408                                         rval = EFAULT;
9409                                 }
9410                         } else {
9411                                 rval = EIO;
9412                                 fcio->fcio_errno = ret;
9413                                 if (fp_fcio_copyout(fcio, data, mode)) {
9414                                         rval = EFAULT;
9415                                 }
9416                         }
9417 
9418                         kmem_free(rls_acc, sizeof (*rls_acc));
9419 
9420                         /* ioctl handling is over */
9421                         break;
9422                 }
9423 
9424                 /*
9425                  * Send RLS to the destination port.
9426                  * Having RLS frame destination is as FPORT is not yet
9427                  * supported and will be implemented in future, if needed.
9428                  * Following call to get "pd" will fail if dest is FPORT
9429                  */
9430                 pd = fctl_hold_remote_port_by_did(port, dest);
9431                 if (pd == NULL) {
9432                         fcio->fcio_errno = FC_BADOBJECT;
9433                         rval = ENXIO;
9434                         if (fp_fcio_copyout(fcio, data, mode)) {
9435                                 rval = EFAULT;
9436                         }
9437                         break;
9438                 }
9439 
9440                 mutex_enter(&pd->pd_mutex);
9441                 if (pd->pd_state != PORT_DEVICE_LOGGED_IN) {
9442                         mutex_exit(&pd->pd_mutex);
9443                         fctl_release_remote_port(pd);
9444 
9445                         fcio->fcio_errno = FC_LOGINREQ;
9446                         rval = EINVAL;
9447                         if (fp_fcio_copyout(fcio, data, mode)) {
9448                                 rval = EFAULT;
9449                         }
9450                         break;
9451                 }
9452                 ASSERT(pd->pd_login_count >= 1);
9453                 mutex_exit(&pd->pd_mutex);
9454 
9455                 /*
9456                  * Allocate job structure and set job_code as DUMMY,
9457                  * because we will not go through the job thread.
9458                  * Instead fp_sendcmd() is called directly here.
9459                  */
9460                 job = fctl_alloc_job(JOB_DUMMY, JOB_TYPE_FP_ASYNC,
9461                     NULL, NULL, KM_SLEEP);
9462                 ASSERT(job != NULL);
9463 
9464                 job->job_counter = 1;
9465 
9466                 cmd = fp_alloc_pkt(port, sizeof (la_els_rls_t),
9467                     sizeof (la_els_rls_acc_t), KM_SLEEP, pd);
9468                 if (cmd == NULL) {
9469                         fcio->fcio_errno = FC_NOMEM;
9470                         rval = ENOMEM;
9471 
9472                         fctl_release_remote_port(pd);
9473 
9474                         fctl_dealloc_job(job);
9475                         if (fp_fcio_copyout(fcio, data, mode)) {
9476                                 rval = EFAULT;
9477                         }
9478                         break;
9479                 }
9480 
9481                 /* Allocate memory for link error status block */
9482                 rls_acc = kmem_zalloc(sizeof (*rls_acc), KM_SLEEP);
9483 
9484                 mutex_enter(&port->fp_mutex);
9485                 mutex_enter(&pd->pd_mutex);
9486 
9487                 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
9488                 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
9489                 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
9490                 cmd->cmd_retry_count = 1;
9491                 cmd->cmd_ulp_pkt = NULL;
9492 
9493                 fp_rls_init(cmd, job);
9494 
9495                 job->job_private = (void *)rls_acc;
9496 
9497                 pd_flags = pd->pd_flags;
9498                 pd->pd_flags = PD_ELS_IN_PROGRESS;
9499 
9500                 mutex_exit(&pd->pd_mutex);
9501                 mutex_exit(&port->fp_mutex);
9502 
9503                 if (fp_sendcmd(port, cmd, port->fp_fca_handle) == FC_SUCCESS) {
9504                         fctl_jobwait(job);
9505 
9506                         fcio->fcio_errno = job->job_result;
9507                         if (job->job_result == FC_SUCCESS) {
9508                                 ASSERT(pd != NULL);
9509                                 /*
9510                                  * link error status block is now available.
9511                                  * Copy it to userland
9512                                  */
9513                                 ASSERT(job->job_private == (void *)rls_acc);
9514                                 if (ddi_copyout((void *)rls_acc,
9515                                     (void *)fcio->fcio_obuf,
9516                                     sizeof (*rls_acc), mode) == 0) {
9517                                         if (fp_fcio_copyout(fcio, data,
9518                                             mode)) {
9519                                                 rval = EFAULT;
9520                                         }
9521                                 } else {
9522                                         rval = EFAULT;
9523                                 }
9524                         } else {
9525                                 rval = EIO;
9526                         }
9527                 } else {
9528                         rval = EIO;
9529                         fp_free_pkt(cmd);
9530                 }
9531 
9532                 if (rval) {
9533                         mutex_enter(&port->fp_mutex);
9534                         mutex_enter(&pd->pd_mutex);
9535                         if (pd->pd_flags == PD_ELS_IN_PROGRESS) {
9536                                 pd->pd_flags = pd_flags;
9537                         }
9538                         mutex_exit(&pd->pd_mutex);
9539                         mutex_exit(&port->fp_mutex);
9540                 }
9541 
9542                 fctl_release_remote_port(pd);
9543                 fctl_dealloc_job(job);
9544                 kmem_free(rls_acc, sizeof (*rls_acc));
9545 
9546                 if (fp_fcio_copyout(fcio, data, mode)) {
9547                         rval = EFAULT;
9548                 }
9549                 break;
9550         }
9551 
9552         case FCIO_NS: {
9553                 fc_ns_cmd_t     *ns_req;
9554                 fc_ns_cmd32_t   *ns_req32;
9555                 fctl_ns_req_t   *ns_cmd;
9556 
9557                 if (use32 == B_TRUE) {
9558                         if (fcio->fcio_ilen != sizeof (*ns_req32)) {
9559                                 rval = EINVAL;
9560                                 break;
9561                         }
9562 
9563                         ns_req = kmem_zalloc(sizeof (*ns_req), KM_SLEEP);
9564                         ns_req32 = kmem_zalloc(sizeof (*ns_req32), KM_SLEEP);
9565 
9566                         if (ddi_copyin(fcio->fcio_ibuf, ns_req32,
9567                             sizeof (*ns_req32), mode)) {
9568                                 rval = EFAULT;
9569                                 kmem_free(ns_req, sizeof (*ns_req));
9570                                 kmem_free(ns_req32, sizeof (*ns_req32));
9571                                 break;
9572                         }
9573 
9574                         ns_req->ns_flags = ns_req32->ns_flags;
9575                         ns_req->ns_cmd = ns_req32->ns_cmd;
9576                         ns_req->ns_req_len = ns_req32->ns_req_len;
9577                         ns_req->ns_req_payload = ns_req32->ns_req_payload;
9578                         ns_req->ns_resp_len = ns_req32->ns_resp_len;
9579                         ns_req->ns_resp_payload = ns_req32->ns_resp_payload;
9580                         ns_req->ns_fctl_private = ns_req32->ns_fctl_private;
9581                         ns_req->ns_resp_hdr = ns_req32->ns_resp_hdr;
9582 
9583                         kmem_free(ns_req32, sizeof (*ns_req32));
9584                 } else {
9585                         if (fcio->fcio_ilen != sizeof (*ns_req)) {
9586                                 rval = EINVAL;
9587                                 break;
9588                         }
9589 
9590                         ns_req = kmem_zalloc(sizeof (*ns_req), KM_SLEEP);
9591 
9592                         if (ddi_copyin(fcio->fcio_ibuf, ns_req,
9593                             sizeof (fc_ns_cmd_t), mode)) {
9594                                 rval = EFAULT;
9595                                 kmem_free(ns_req, sizeof (*ns_req));
9596                                 break;
9597                         }
9598                 }
9599 
9600                 if (ns_req->ns_req_len <= 0) {
9601                         rval = EINVAL;
9602                         kmem_free(ns_req, sizeof (*ns_req));
9603                         break;
9604                 }
9605 
9606                 job = fctl_alloc_job(JOB_NS_CMD, 0, NULL, NULL, KM_SLEEP);
9607                 ASSERT(job != NULL);
9608 
9609                 ns_cmd = fctl_alloc_ns_cmd(ns_req->ns_req_len,
9610                     ns_req->ns_resp_len, ns_req->ns_resp_len,
9611                     FCTL_NS_FILL_NS_MAP, KM_SLEEP);
9612                 ASSERT(ns_cmd != NULL);
9613                 ns_cmd->ns_cmd_code = ns_req->ns_cmd;
9614 
9615                 if (ns_cmd->ns_cmd_code == NS_GA_NXT) {
9616                         ns_cmd->ns_gan_max = 1;
9617                         ns_cmd->ns_gan_index = 0;
9618                         ns_cmd->ns_gan_sid = FCTL_GAN_START_ID;
9619                 }
9620 
9621                 if (ddi_copyin(ns_req->ns_req_payload,
9622                     ns_cmd->ns_cmd_buf, ns_req->ns_req_len, mode)) {
9623                         rval = EFAULT;
9624                         fctl_free_ns_cmd(ns_cmd);
9625                         fctl_dealloc_job(job);
9626                         kmem_free(ns_req, sizeof (*ns_req));
9627                         break;
9628                 }
9629 
9630                 job->job_private = (void *)ns_cmd;
9631                 fctl_enque_job(port, job);
9632                 fctl_jobwait(job);
9633                 rval = job->job_result;
9634 
9635                 if (rval == FC_SUCCESS) {
9636                         if (ns_req->ns_resp_len) {
9637                                 if (ddi_copyout(ns_cmd->ns_data_buf,
9638                                     ns_req->ns_resp_payload,
9639                                     ns_cmd->ns_data_len, mode)) {
9640                                         rval = EFAULT;
9641                                         fctl_free_ns_cmd(ns_cmd);
9642                                         fctl_dealloc_job(job);
9643                                         kmem_free(ns_req, sizeof (*ns_req));
9644                                         break;
9645                                 }
9646                         }
9647                 } else {
9648                         rval = EIO;
9649                 }
9650                 ns_req->ns_resp_hdr = ns_cmd->ns_resp_hdr;
9651                 fctl_free_ns_cmd(ns_cmd);
9652                 fctl_dealloc_job(job);
9653                 kmem_free(ns_req, sizeof (*ns_req));
9654 
9655                 if (fp_fcio_copyout(fcio, data, mode)) {
9656                         rval = EFAULT;
9657                 }
9658                 break;
9659         }
9660 
9661         default:
9662                 rval = ENOTTY;
9663                 break;
9664         }
9665 
9666         /*
9667          * If set, reset the EXCL busy bit to
9668          * receive other exclusive access commands
9669          */
9670         mutex_enter(&port->fp_mutex);
9671         if (port->fp_flag & FP_EXCL_BUSY) {
9672                 port->fp_flag &= ~FP_EXCL_BUSY;
9673         }
9674         mutex_exit(&port->fp_mutex);
9675 
9676         return (rval);
9677 }
9678 
9679 
9680 /*
9681  * This function assumes that the response length
9682  * is same regardless of data model (LP32 or LP64)
9683  * which is true for all the ioctls currently
9684  * supported.
9685  */
9686 static int
9687 fp_copyout(void *from, void *to, size_t len, int mode)
9688 {
9689         return (ddi_copyout(from, to, len, mode));
9690 }
9691 
9692 /*
9693  * This function does the set rnid
9694  */
9695 static int
9696 fp_set_rnid(fc_local_port_t *port, intptr_t data, int mode, fcio_t *fcio)
9697 {
9698         int             rval = 0;
9699         fc_rnid_t       *rnid;
9700         fc_fca_pm_t     pm;
9701 
9702         /* Allocate memory for node id block */
9703         rnid = kmem_zalloc(sizeof (fc_rnid_t), KM_SLEEP);
9704 
9705         if (ddi_copyin(fcio->fcio_ibuf, rnid, sizeof (fc_rnid_t), mode)) {
9706                 FP_TRACE(FP_NHEAD1(3, 0), "fp_set_rnid: failed = %d", EFAULT);
9707                 kmem_free(rnid, sizeof (fc_rnid_t));
9708                 return (EFAULT);
9709         }
9710 
9711         /* Prepare the port management structure */
9712         bzero((caddr_t)&pm, sizeof (pm));
9713 
9714         pm.pm_cmd_flags = FC_FCA_PM_WRITE;
9715         pm.pm_cmd_code  = FC_PORT_SET_NODE_ID;
9716         pm.pm_data_len  = sizeof (*rnid);
9717         pm.pm_data_buf  = (caddr_t)rnid;
9718 
9719         /* Get the adapter's node data */
9720         rval = port->fp_fca_tran->fca_port_manage(
9721             port->fp_fca_handle, &pm);
9722 
9723         if (rval != FC_SUCCESS) {
9724                 fcio->fcio_errno = rval;
9725                 rval = EIO;
9726                 if (fp_fcio_copyout(fcio, data, mode)) {
9727                         rval = EFAULT;
9728                 }
9729         } else {
9730                 mutex_enter(&port->fp_mutex);
9731                 /* copy to the port structure */
9732                 bcopy(rnid, &port->fp_rnid_params,
9733                     sizeof (port->fp_rnid_params));
9734                 mutex_exit(&port->fp_mutex);
9735         }
9736 
9737         kmem_free(rnid, sizeof (fc_rnid_t));
9738 
9739         if (rval != FC_SUCCESS) {
9740                 FP_TRACE(FP_NHEAD1(3, 0), "fp_set_rnid: failed = %d", rval);
9741         }
9742 
9743         return (rval);
9744 }
9745 
9746 /*
9747  * This function does the local pwwn get rnid
9748  */
9749 static int
9750 fp_get_rnid(fc_local_port_t *port, intptr_t data, int mode, fcio_t *fcio)
9751 {
9752         fc_rnid_t               *rnid;
9753         fc_fca_pm_t             pm;
9754         int                     rval = 0;
9755         uint32_t                ret;
9756 
9757         /* Allocate memory for rnid data block */
9758         rnid = kmem_zalloc(sizeof (fc_rnid_t), KM_SLEEP);
9759 
9760         mutex_enter(&port->fp_mutex);
9761         if (port->fp_rnid_init == 1) {
9762                 bcopy(&port->fp_rnid_params, rnid, sizeof (fc_rnid_t));
9763                 mutex_exit(&port->fp_mutex);
9764                 /* xfer node info to userland */
9765                 if (ddi_copyout((void *)rnid, (void *)fcio->fcio_obuf,
9766                     sizeof (*rnid), mode) == 0) {
9767                         if (fp_fcio_copyout(fcio, data, mode)) {
9768                                 rval = EFAULT;
9769                         }
9770                 } else {
9771                         rval = EFAULT;
9772                 }
9773 
9774                 kmem_free(rnid, sizeof (fc_rnid_t));
9775 
9776                 if (rval != FC_SUCCESS) {
9777                         FP_TRACE(FP_NHEAD1(3, 0), "fp_get_rnid: failed = %d",
9778                             rval);
9779                 }
9780 
9781                 return (rval);
9782         }
9783         mutex_exit(&port->fp_mutex);
9784 
9785         /* Prepare the port management structure */
9786         bzero((caddr_t)&pm, sizeof (pm));
9787 
9788         pm.pm_cmd_flags = FC_FCA_PM_READ;
9789         pm.pm_cmd_code  = FC_PORT_GET_NODE_ID;
9790         pm.pm_data_len  = sizeof (fc_rnid_t);
9791         pm.pm_data_buf  = (caddr_t)rnid;
9792 
9793         /* Get the adapter's node data */
9794         ret = port->fp_fca_tran->fca_port_manage(
9795             port->fp_fca_handle,
9796             &pm);
9797 
9798         if (ret == FC_SUCCESS) {
9799                 /* initialize in the port_info */
9800                 mutex_enter(&port->fp_mutex);
9801                 port->fp_rnid_init = 1;
9802                 bcopy(rnid, &port->fp_rnid_params, sizeof (*rnid));
9803                 mutex_exit(&port->fp_mutex);
9804 
9805                 /* xfer node info to userland */
9806                 if (ddi_copyout((void *)rnid,
9807                     (void *)fcio->fcio_obuf,
9808                     sizeof (*rnid), mode) == 0) {
9809                         if (fp_fcio_copyout(fcio, data,
9810                             mode)) {
9811                                 rval = EFAULT;
9812                         }
9813                 } else {
9814                         rval = EFAULT;
9815                 }
9816         } else {
9817                 rval = EIO;
9818                 fcio->fcio_errno = ret;
9819                 if (fp_fcio_copyout(fcio, data, mode)) {
9820                         rval = EFAULT;
9821                 }
9822         }
9823 
9824         kmem_free(rnid, sizeof (fc_rnid_t));
9825 
9826         if (rval != FC_SUCCESS) {
9827                 FP_TRACE(FP_NHEAD1(3, 0), "fp_get_rnid: failed = %d", rval);
9828         }
9829 
9830         return (rval);
9831 }
9832 
9833 static int
9834 fp_send_rnid(fc_local_port_t *port, intptr_t data, int mode, fcio_t *fcio,
9835     la_wwn_t *pwwn)
9836 {
9837         int                     rval = 0;
9838         fc_remote_port_t        *pd;
9839         fp_cmd_t                *cmd;
9840         job_request_t           *job;
9841         la_els_rnid_acc_t       *rnid_acc;
9842 
9843         pd = fctl_get_remote_port_by_pwwn(port, pwwn);
9844         if (pd == NULL) {
9845                 /*
9846                  * We can safely assume that the destination port
9847                  * is logged in. Either the user land will explicitly
9848                  * login before issuing RNID ioctl or the device would
9849                  * have been configured, meaning already logged in.
9850                  */
9851 
9852                 FP_TRACE(FP_NHEAD1(3, 0), "fp_send_rnid: failed = %d", ENXIO);
9853 
9854                 return (ENXIO);
9855         }
9856         /*
9857          * Allocate job structure and set job_code as DUMMY,
9858          * because we will not go thorugh the job thread.
9859          * Instead fp_sendcmd() is called directly here.
9860          */
9861         job = fctl_alloc_job(JOB_DUMMY, JOB_TYPE_FP_ASYNC,
9862             NULL, NULL, KM_SLEEP);
9863 
9864         ASSERT(job != NULL);
9865 
9866         job->job_counter = 1;
9867 
9868         cmd = fp_alloc_pkt(port, sizeof (la_els_rnid_t),
9869             sizeof (la_els_rnid_acc_t), KM_SLEEP, pd);
9870         if (cmd == NULL) {
9871                 fcio->fcio_errno = FC_NOMEM;
9872                 rval = ENOMEM;
9873 
9874                 fctl_dealloc_job(job);
9875                 if (fp_fcio_copyout(fcio, data, mode)) {
9876                         rval = EFAULT;
9877                 }
9878 
9879                 FP_TRACE(FP_NHEAD1(3, 0), "fp_send_rnid: failed = %d", rval);
9880 
9881                 return (rval);
9882         }
9883 
9884         /* Allocate memory for node id accept block */
9885         rnid_acc = kmem_zalloc(sizeof (la_els_rnid_acc_t), KM_SLEEP);
9886 
9887         mutex_enter(&port->fp_mutex);
9888         mutex_enter(&pd->pd_mutex);
9889 
9890         cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
9891         cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
9892         cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
9893         cmd->cmd_retry_count = 1;
9894         cmd->cmd_ulp_pkt = NULL;
9895 
9896         fp_rnid_init(cmd, fcio->fcio_cmd_flags, job);
9897 
9898         job->job_private = (void *)rnid_acc;
9899 
9900         pd->pd_flags = PD_ELS_IN_PROGRESS;
9901 
9902         mutex_exit(&pd->pd_mutex);
9903         mutex_exit(&port->fp_mutex);
9904 
9905         if (fp_sendcmd(port, cmd, port->fp_fca_handle) == FC_SUCCESS) {
9906                 fctl_jobwait(job);
9907                 fcio->fcio_errno = job->job_result;
9908                 if (job->job_result == FC_SUCCESS) {
9909                         int rnid_cnt;
9910                         ASSERT(pd != NULL);
9911                         /*
9912                          * node id block is now available.
9913                          * Copy it to userland
9914                          */
9915                         ASSERT(job->job_private == (void *)rnid_acc);
9916 
9917                         /* get the response length */
9918                         rnid_cnt = sizeof (ls_code_t) + sizeof (fc_rnid_hdr_t) +
9919                             rnid_acc->hdr.cmn_len +
9920                             rnid_acc->hdr.specific_len;
9921 
9922                         if (fcio->fcio_olen < rnid_cnt) {
9923                                 rval = EINVAL;
9924                         } else if (ddi_copyout((void *)rnid_acc,
9925                             (void *)fcio->fcio_obuf,
9926                             rnid_cnt, mode) == 0) {
9927                                 if (fp_fcio_copyout(fcio, data,
9928                                     mode)) {
9929                                         rval = EFAULT;
9930                                 }
9931                         } else {
9932                                 rval = EFAULT;
9933                         }
9934                 } else {
9935                         rval = EIO;
9936                 }
9937         } else {
9938                 rval = EIO;
9939                 if (pd) {
9940                         mutex_enter(&pd->pd_mutex);
9941                         pd->pd_flags = PD_IDLE;
9942                         mutex_exit(&pd->pd_mutex);
9943                 }
9944                 fp_free_pkt(cmd);
9945         }
9946 
9947         fctl_dealloc_job(job);
9948         kmem_free(rnid_acc, sizeof (la_els_rnid_acc_t));
9949 
9950         if (fp_fcio_copyout(fcio, data, mode)) {
9951                 rval = EFAULT;
9952         }
9953 
9954         if (rval != FC_SUCCESS) {
9955                 FP_TRACE(FP_NHEAD1(3, 0), "fp_send_rnid: failed = %d", rval);
9956         }
9957 
9958         return (rval);
9959 }
9960 
9961 /*
9962  * Copy out to userland
9963  */
9964 static int
9965 fp_fcio_copyout(fcio_t *fcio, intptr_t data, int mode)
9966 {
9967         int rval;
9968 
9969 #ifdef  _MULTI_DATAMODEL
9970         switch (ddi_model_convert_from(mode & FMODELS)) {
9971         case DDI_MODEL_ILP32: {
9972                 struct fcio32 fcio32;
9973 
9974                 fcio32.fcio_xfer = fcio->fcio_xfer;
9975                 fcio32.fcio_cmd = fcio->fcio_cmd;
9976                 fcio32.fcio_flags = fcio->fcio_flags;
9977                 fcio32.fcio_cmd_flags = fcio->fcio_cmd_flags;
9978                 fcio32.fcio_ilen = fcio->fcio_ilen;
9979                 fcio32.fcio_ibuf =
9980                     (caddr32_t)(uintptr_t)fcio->fcio_ibuf;
9981                 fcio32.fcio_olen = fcio->fcio_olen;
9982                 fcio32.fcio_obuf =
9983                     (caddr32_t)(uintptr_t)fcio->fcio_obuf;
9984                 fcio32.fcio_alen = fcio->fcio_alen;
9985                 fcio32.fcio_abuf =
9986                     (caddr32_t)(uintptr_t)fcio->fcio_abuf;
9987                 fcio32.fcio_errno = fcio->fcio_errno;
9988 
9989                 rval = ddi_copyout((void *)&fcio32, (void *)data,
9990                     sizeof (struct fcio32), mode);
9991                 break;
9992         }
9993         case DDI_MODEL_NONE:
9994                 rval = ddi_copyout((void *)fcio, (void *)data,
9995                     sizeof (fcio_t), mode);
9996                 break;
9997         }
9998 #else
9999         rval = ddi_copyout((void *)fcio, (void *)data, sizeof (fcio_t), mode);
10000 #endif
10001 
10002         return (rval);
10003 }
10004 
10005 
10006 static void
10007 fp_p2p_online(fc_local_port_t *port, job_request_t *job)
10008 {
10009         uint32_t                listlen;
10010         fc_portmap_t            *changelist;
10011 
10012         ASSERT(MUTEX_HELD(&port->fp_mutex));
10013         ASSERT(port->fp_topology == FC_TOP_PT_PT);
10014         ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
10015 
10016         listlen = 0;
10017         changelist = NULL;
10018 
10019         if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) {
10020                 if (port->fp_statec_busy > 1) {
10021                         job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION;
10022                 }
10023         }
10024         mutex_exit(&port->fp_mutex);
10025 
10026         if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) {
10027                 fctl_fillout_map(port, &changelist, &listlen, 1, 0, 0);
10028                 (void) fp_ulp_statec_cb(port, FC_STATE_ONLINE, changelist,
10029                     listlen, listlen, KM_SLEEP);
10030 
10031                 mutex_enter(&port->fp_mutex);
10032         } else {
10033                 ASSERT(changelist == NULL && listlen == 0);
10034                 mutex_enter(&port->fp_mutex);
10035                 if (--port->fp_statec_busy == 0) {
10036                         port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
10037                 }
10038         }
10039 }
10040 
10041 static int
10042 fp_fillout_p2pmap(fc_local_port_t *port, fcio_t *fcio, int mode)
10043 {
10044         int                     rval;
10045         int                     count;
10046         int                     index;
10047         int                     num_devices;
10048         fc_remote_node_t        *node;
10049         fc_port_dev_t           *devlist;
10050         struct pwwn_hash        *head;
10051         fc_remote_port_t        *pd;
10052 
10053         ASSERT(MUTEX_HELD(&port->fp_mutex));
10054 
10055         num_devices = fcio->fcio_olen / sizeof (fc_port_dev_t);
10056 
10057         devlist = kmem_zalloc(sizeof (fc_port_dev_t) * num_devices, KM_SLEEP);
10058 
10059         for (count = index = 0; index < pwwn_table_size; index++) {
10060                 head = &port->fp_pwwn_table[index];
10061                 pd = head->pwwn_head;
10062                 while (pd != NULL) {
10063                         mutex_enter(&pd->pd_mutex);
10064                         if (pd->pd_state == PORT_DEVICE_INVALID) {
10065                                 mutex_exit(&pd->pd_mutex);
10066                                 pd = pd->pd_wwn_hnext;
10067                                 continue;
10068                         }
10069 
10070                         devlist[count].dev_state = pd->pd_state;
10071                         devlist[count].dev_hard_addr = pd->pd_hard_addr;
10072                         devlist[count].dev_did = pd->pd_port_id;
10073                         devlist[count].dev_did.priv_lilp_posit =
10074                             (uint8_t)(index & 0xff);
10075                         bcopy((caddr_t)pd->pd_fc4types,
10076                             (caddr_t)devlist[count].dev_type,
10077                             sizeof (pd->pd_fc4types));
10078 
10079                         bcopy((caddr_t)&pd->pd_port_name,
10080                             (caddr_t)&devlist[count].dev_pwwn,
10081                             sizeof (la_wwn_t));
10082 
10083                         node = pd->pd_remote_nodep;
10084                         mutex_exit(&pd->pd_mutex);
10085 
10086                         if (node) {
10087                                 mutex_enter(&node->fd_mutex);
10088                                 bcopy((caddr_t)&node->fd_node_name,
10089                                     (caddr_t)&devlist[count].dev_nwwn,
10090                                     sizeof (la_wwn_t));
10091                                 mutex_exit(&node->fd_mutex);
10092                         }
10093                         count++;
10094                         if (count >= num_devices) {
10095                                 goto found;
10096                         }
10097                 }
10098         }
10099 found:
10100         if (fp_copyout((void *)&count, (void *)fcio->fcio_abuf,
10101             sizeof (count), mode)) {
10102                 rval = FC_FAILURE;
10103         } else if (fp_copyout((void *)devlist, (void *)fcio->fcio_obuf,
10104             sizeof (fc_port_dev_t) * num_devices, mode)) {
10105                 rval = FC_FAILURE;
10106         } else {
10107                 rval = FC_SUCCESS;
10108         }
10109 
10110         kmem_free(devlist, sizeof (fc_port_dev_t) * num_devices);
10111 
10112         return (rval);
10113 }
10114 
10115 
10116 /*
10117  * Handle Fabric ONLINE
10118  */
10119 static void
10120 fp_fabric_online(fc_local_port_t *port, job_request_t *job)
10121 {
10122         int                     index;
10123         int                     rval;
10124         int                     dbg_count;
10125         int                     count = 0;
10126         char                    ww_name[17];
10127         uint32_t                d_id;
10128         uint32_t                listlen;
10129         fctl_ns_req_t           *ns_cmd;
10130         struct pwwn_hash        *head;
10131         fc_remote_port_t        *pd;
10132         fc_remote_port_t        *npd;
10133         fc_portmap_t            *changelist;
10134 
10135         ASSERT(MUTEX_HELD(&port->fp_mutex));
10136         ASSERT(FC_IS_TOP_SWITCH(port->fp_topology));
10137         ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
10138 
10139         ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t),
10140             sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t),
10141             0, KM_SLEEP);
10142 
10143         ASSERT(ns_cmd != NULL);
10144 
10145         ns_cmd->ns_cmd_code = NS_GID_PN;
10146 
10147         /*
10148          * Check if orphans are showing up now
10149          */
10150         if (port->fp_orphan_count) {
10151                 fc_orphan_t     *orp;
10152                 fc_orphan_t     *norp = NULL;
10153                 fc_orphan_t     *prev = NULL;
10154 
10155                 for (orp = port->fp_orphan_list; orp; orp = norp) {
10156                         norp = orp->orp_next;
10157                         mutex_exit(&port->fp_mutex);
10158                         orp->orp_nscan++;
10159 
10160                         job->job_counter = 1;
10161                         job->job_result = FC_SUCCESS;
10162 
10163                         ((ns_req_gid_pn_t *)
10164                             (ns_cmd->ns_cmd_buf))->pwwn = orp->orp_pwwn;
10165                         ((ns_resp_gid_pn_t *)
10166                             ns_cmd->ns_data_buf)->pid.port_id = 0;
10167                         ((ns_resp_gid_pn_t *)
10168                             ns_cmd->ns_data_buf)->pid.priv_lilp_posit = 0;
10169 
10170                         rval = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP);
10171                         if (rval == FC_SUCCESS) {
10172                                 d_id =
10173                                     BE_32(*((uint32_t *)ns_cmd->ns_data_buf));
10174                                 pd = fp_create_remote_port_by_ns(port,
10175                                     d_id, KM_SLEEP);
10176 
10177                                 if (pd != NULL) {
10178                                         fc_wwn_to_str(&orp->orp_pwwn, ww_name);
10179 
10180                                         fp_printf(port, CE_WARN, FP_LOG_ONLY,
10181                                             0, NULL, "N_x Port with D_ID=%x,"
10182                                             " PWWN=%s reappeared in fabric",
10183                                             d_id, ww_name);
10184 
10185                                         mutex_enter(&port->fp_mutex);
10186                                         if (prev) {
10187                                                 prev->orp_next = orp->orp_next;
10188                                         } else {
10189                                                 ASSERT(orp ==
10190                                                     port->fp_orphan_list);
10191                                                 port->fp_orphan_list =
10192                                                     orp->orp_next;
10193                                         }
10194                                         port->fp_orphan_count--;
10195                                         mutex_exit(&port->fp_mutex);
10196                                         kmem_free(orp, sizeof (*orp));
10197                                         count++;
10198 
10199                                         mutex_enter(&pd->pd_mutex);
10200                                         pd->pd_flags = PD_ELS_MARK;
10201 
10202                                         mutex_exit(&pd->pd_mutex);
10203                                 } else {
10204                                         prev = orp;
10205                                 }
10206                         } else {
10207                                 if (orp->orp_nscan == FC_ORPHAN_SCAN_LIMIT) {
10208                                         fc_wwn_to_str(&orp->orp_pwwn, ww_name);
10209 
10210                                         fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0,
10211                                             NULL,
10212                                             " Port WWN %s removed from orphan"
10213                                             " list after %d scans", ww_name,
10214                                             orp->orp_nscan);
10215 
10216                                         mutex_enter(&port->fp_mutex);
10217                                         if (prev) {
10218                                                 prev->orp_next = orp->orp_next;
10219                                         } else {
10220                                                 ASSERT(orp ==
10221                                                     port->fp_orphan_list);
10222                                                 port->fp_orphan_list =
10223                                                     orp->orp_next;
10224                                         }
10225                                         port->fp_orphan_count--;
10226                                         mutex_exit(&port->fp_mutex);
10227 
10228                                         kmem_free(orp, sizeof (*orp));
10229                                 } else {
10230                                         prev = orp;
10231                                 }
10232                         }
10233                         mutex_enter(&port->fp_mutex);
10234                 }
10235         }
10236 
10237         /*
10238          * Walk the Port WWN hash table, reestablish LOGIN
10239          * if a LOGIN is already performed on a particular
10240          * device; Any failure to LOGIN should mark the
10241          * port device OLD.
10242          */
10243         for (index = 0; index < pwwn_table_size; index++) {
10244                 head = &port->fp_pwwn_table[index];
10245                 npd = head->pwwn_head;
10246 
10247                 while ((pd = npd) != NULL) {
10248                         la_wwn_t        *pwwn;
10249 
10250                         npd = pd->pd_wwn_hnext;
10251 
10252                         /*
10253                          * Don't count in the port devices that are new
10254                          * unless the total number of devices visible
10255                          * through this port is less than FP_MAX_DEVICES
10256                          */
10257                         mutex_enter(&pd->pd_mutex);
10258                         if (port->fp_dev_count >= FP_MAX_DEVICES ||
10259                             (port->fp_options & FP_TARGET_MODE)) {
10260                                 if (pd->pd_type == PORT_DEVICE_NEW ||
10261                                     pd->pd_flags == PD_ELS_MARK ||
10262                                     pd->pd_recepient != PD_PLOGI_INITIATOR) {
10263                                         mutex_exit(&pd->pd_mutex);
10264                                         continue;
10265                                 }
10266                         } else {
10267                                 if (pd->pd_flags == PD_ELS_MARK ||
10268                                     pd->pd_recepient != PD_PLOGI_INITIATOR) {
10269                                         mutex_exit(&pd->pd_mutex);
10270                                         continue;
10271                                 }
10272                                 pd->pd_type = PORT_DEVICE_OLD;
10273                         }
10274                         count++;
10275 
10276                         /*
10277                          * Consult with the name server about D_ID changes
10278                          */
10279                         job->job_counter = 1;
10280                         job->job_result = FC_SUCCESS;
10281 
10282                         ((ns_req_gid_pn_t *)
10283                             (ns_cmd->ns_cmd_buf))->pwwn = pd->pd_port_name;
10284                         ((ns_resp_gid_pn_t *)
10285                             ns_cmd->ns_data_buf)->pid.port_id = 0;
10286 
10287                         ((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->
10288                             pid.priv_lilp_posit = 0;
10289 
10290                         pwwn = &pd->pd_port_name;
10291                         pd->pd_flags = PD_ELS_MARK;
10292 
10293                         mutex_exit(&pd->pd_mutex);
10294                         mutex_exit(&port->fp_mutex);
10295 
10296                         rval = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP);
10297                         if (rval != FC_SUCCESS) {
10298                                 fc_wwn_to_str(pwwn, ww_name);
10299 
10300                                 mutex_enter(&pd->pd_mutex);
10301                                 d_id = pd->pd_port_id.port_id;
10302                                 pd->pd_type = PORT_DEVICE_DELETE;
10303                                 mutex_exit(&pd->pd_mutex);
10304 
10305                                 FP_TRACE(FP_NHEAD1(3, 0),
10306                                     "fp_fabric_online: PD "
10307                                     "disappeared; d_id=%x, PWWN=%s",
10308                                     d_id, ww_name);
10309 
10310                                 FP_TRACE(FP_NHEAD2(9, 0),
10311                                     "N_x Port with D_ID=%x, PWWN=%s"
10312                                     " disappeared from fabric", d_id,
10313                                     ww_name);
10314 
10315                                 mutex_enter(&port->fp_mutex);
10316                                 continue;
10317                         }
10318 
10319                         d_id = BE_32(*((uint32_t *)ns_cmd->ns_data_buf));
10320 
10321                         mutex_enter(&port->fp_mutex);
10322                         mutex_enter(&pd->pd_mutex);
10323                         if (d_id != pd->pd_port_id.port_id) {
10324                                 fctl_delist_did_table(port, pd);
10325                                 fc_wwn_to_str(pwwn, ww_name);
10326 
10327                                 FP_TRACE(FP_NHEAD2(9, 0),
10328                                     "D_ID of a device with PWWN %s changed."
10329                                     " New D_ID = %x, OLD D_ID = %x", ww_name,
10330                                     d_id, pd->pd_port_id.port_id);
10331 
10332                                 pd->pd_port_id.port_id = BE_32(d_id);
10333                                 pd->pd_type = PORT_DEVICE_CHANGED;
10334                                 fctl_enlist_did_table(port, pd);
10335                         }
10336                         mutex_exit(&pd->pd_mutex);
10337 
10338                 }
10339         }
10340 
10341         if (ns_cmd) {
10342                 fctl_free_ns_cmd(ns_cmd);
10343         }
10344 
10345         listlen = 0;
10346         changelist = NULL;
10347         if (count) {
10348                 if (port->fp_soft_state & FP_SOFT_IN_FCA_RESET) {
10349                         port->fp_soft_state &= ~FP_SOFT_IN_FCA_RESET;
10350                         mutex_exit(&port->fp_mutex);
10351                         delay(drv_usectohz(FLA_RR_TOV * 1000 * 1000));
10352                         mutex_enter(&port->fp_mutex);
10353                 }
10354 
10355                 dbg_count = 0;
10356 
10357                 job->job_counter = count;
10358 
10359                 for (index = 0; index < pwwn_table_size; index++) {
10360                         head = &port->fp_pwwn_table[index];
10361                         npd = head->pwwn_head;
10362 
10363                         while ((pd = npd) != NULL) {
10364                                 npd = pd->pd_wwn_hnext;
10365 
10366                                 mutex_enter(&pd->pd_mutex);
10367                                 if (pd->pd_flags != PD_ELS_MARK) {
10368                                         mutex_exit(&pd->pd_mutex);
10369                                         continue;
10370                                 }
10371 
10372                                 dbg_count++;
10373 
10374                                 /*
10375                                  * If it is already marked deletion, nothing
10376                                  * else to do.
10377                                  */
10378                                 if (pd->pd_type == PORT_DEVICE_DELETE) {
10379                                         pd->pd_type = PORT_DEVICE_OLD;
10380 
10381                                         mutex_exit(&pd->pd_mutex);
10382                                         mutex_exit(&port->fp_mutex);
10383                                         fp_jobdone(job);
10384                                         mutex_enter(&port->fp_mutex);
10385 
10386                                         continue;
10387                                 }
10388 
10389                                 /*
10390                                  * If it is freshly discovered out of
10391                                  * the orphan list, nothing else to do
10392                                  */
10393                                 if (pd->pd_type == PORT_DEVICE_NEW) {
10394                                         pd->pd_flags = PD_IDLE;
10395 
10396                                         mutex_exit(&pd->pd_mutex);
10397                                         mutex_exit(&port->fp_mutex);
10398                                         fp_jobdone(job);
10399                                         mutex_enter(&port->fp_mutex);
10400 
10401                                         continue;
10402                                 }
10403 
10404                                 pd->pd_flags = PD_IDLE;
10405                                 d_id = pd->pd_port_id.port_id;
10406 
10407                                 /*
10408                                  * Explicitly mark all devices OLD; successful
10409                                  * PLOGI should reset this to either NO_CHANGE
10410                                  * or CHANGED.
10411                                  */
10412                                 if (pd->pd_type != PORT_DEVICE_CHANGED) {
10413                                         pd->pd_type = PORT_DEVICE_OLD;
10414                                 }
10415 
10416                                 mutex_exit(&pd->pd_mutex);
10417                                 mutex_exit(&port->fp_mutex);
10418 
10419                                 rval = fp_port_login(port, d_id, job,
10420                                     FP_CMD_PLOGI_RETAIN, KM_SLEEP, pd, NULL);
10421 
10422                                 if (rval != FC_SUCCESS) {
10423                                         fp_jobdone(job);
10424                                 }
10425                                 mutex_enter(&port->fp_mutex);
10426                         }
10427                 }
10428                 mutex_exit(&port->fp_mutex);
10429 
10430                 ASSERT(dbg_count == count);
10431                 fp_jobwait(job);
10432 
10433                 mutex_enter(&port->fp_mutex);
10434 
10435                 ASSERT(port->fp_statec_busy > 0);
10436                 if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) {
10437                         if (port->fp_statec_busy > 1) {
10438                                 job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION;
10439                         }
10440                 }
10441                 mutex_exit(&port->fp_mutex);
10442         } else {
10443                 ASSERT(port->fp_statec_busy > 0);
10444                 if (port->fp_statec_busy > 1) {
10445                         job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION;
10446                 }
10447                 mutex_exit(&port->fp_mutex);
10448         }
10449 
10450         if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) {
10451                 fctl_fillout_map(port, &changelist, &listlen, 1, 0, 0);
10452 
10453                 (void) fp_ulp_statec_cb(port, FC_STATE_ONLINE, changelist,
10454                     listlen, listlen, KM_SLEEP);
10455 
10456                 mutex_enter(&port->fp_mutex);
10457         } else {
10458                 ASSERT(changelist == NULL && listlen == 0);
10459                 mutex_enter(&port->fp_mutex);
10460                 if (--port->fp_statec_busy == 0) {
10461                         port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB;
10462                 }
10463         }
10464 }
10465 
10466 
10467 /*
10468  * Fill out device list for userland ioctl in private loop
10469  */
10470 static int
10471 fp_fillout_loopmap(fc_local_port_t *port, fcio_t *fcio, int mode)
10472 {
10473         int                     rval;
10474         int                     count;
10475         int                     index;
10476         int                     num_devices;
10477         fc_remote_node_t        *node;
10478         fc_port_dev_t           *devlist;
10479         int                     lilp_device_count;
10480         fc_lilpmap_t            *lilp_map;
10481         uchar_t                 *alpa_list;
10482 
10483         ASSERT(MUTEX_HELD(&port->fp_mutex));
10484 
10485         num_devices = fcio->fcio_olen / sizeof (fc_port_dev_t);
10486         if (port->fp_total_devices > port->fp_dev_count &&
10487             num_devices >= port->fp_total_devices) {
10488                 job_request_t   *job;
10489 
10490                 mutex_exit(&port->fp_mutex);
10491                 job = fctl_alloc_job(JOB_PORT_GETMAP, 0, NULL, NULL, KM_SLEEP);
10492                 job->job_counter = 1;
10493 
10494                 mutex_enter(&port->fp_mutex);
10495                 fp_get_loopmap(port, job);
10496                 mutex_exit(&port->fp_mutex);
10497 
10498                 fp_jobwait(job);
10499                 fctl_dealloc_job(job);
10500         } else {
10501                 mutex_exit(&port->fp_mutex);
10502         }
10503         devlist = kmem_zalloc(sizeof (*devlist) * num_devices, KM_SLEEP);
10504 
10505         mutex_enter(&port->fp_mutex);
10506 
10507         /*
10508          * Applications are accustomed to getting the device list in
10509          * LILP map order. The HBA firmware usually returns the device
10510          * map in the LILP map order and diagnostic applications would
10511          * prefer to receive in the device list in that order too
10512          */
10513         lilp_map = &port->fp_lilp_map;
10514         alpa_list = &lilp_map->lilp_alpalist[0];
10515 
10516         /*
10517          * the length field corresponds to the offset in the LILP frame
10518          * which begins with 1. The thing to note here is that the
10519          * lilp_device_count is 1 more than fp->fp_total_devices since
10520          * the host adapter's alpa also shows up in the lilp map. We
10521          * don't however return details of the host adapter since
10522          * fctl_get_remote_port_by_did fails for the host adapter's ALPA
10523          * and applications are required to issue the FCIO_GET_HOST_PARAMS
10524          * ioctl to obtain details about the host adapter port.
10525          */
10526         lilp_device_count = lilp_map->lilp_length;
10527 
10528         for (count = index = 0; index < lilp_device_count &&
10529             count < num_devices; index++) {
10530                 uint32_t d_id;
10531                 fc_remote_port_t *pd;
10532 
10533                 d_id = alpa_list[index];
10534 
10535                 mutex_exit(&port->fp_mutex);
10536                 pd = fctl_get_remote_port_by_did(port, d_id);
10537                 mutex_enter(&port->fp_mutex);
10538 
10539                 if (pd != NULL) {
10540                         mutex_enter(&pd->pd_mutex);
10541 
10542                         if (pd->pd_state == PORT_DEVICE_INVALID) {
10543                                 mutex_exit(&pd->pd_mutex);
10544                                 continue;
10545                         }
10546 
10547                         devlist[count].dev_state = pd->pd_state;
10548                         devlist[count].dev_hard_addr = pd->pd_hard_addr;
10549                         devlist[count].dev_did = pd->pd_port_id;
10550                         devlist[count].dev_did.priv_lilp_posit =
10551                             (uint8_t)(index & 0xff);
10552                         bcopy((caddr_t)pd->pd_fc4types,
10553                             (caddr_t)devlist[count].dev_type,
10554                             sizeof (pd->pd_fc4types));
10555 
10556                         bcopy((caddr_t)&pd->pd_port_name,
10557                             (caddr_t)&devlist[count].dev_pwwn,
10558                             sizeof (la_wwn_t));
10559 
10560                         node = pd->pd_remote_nodep;
10561                         mutex_exit(&pd->pd_mutex);
10562 
10563                         if (node) {
10564                                 mutex_enter(&node->fd_mutex);
10565                                 bcopy((caddr_t)&node->fd_node_name,
10566                                     (caddr_t)&devlist[count].dev_nwwn,
10567                                     sizeof (la_wwn_t));
10568                                 mutex_exit(&node->fd_mutex);
10569                         }
10570                         count++;
10571                 }
10572         }
10573 
10574         if (fp_copyout((void *)&count, (void *)fcio->fcio_abuf,
10575             sizeof (count), mode)) {
10576                 rval = FC_FAILURE;
10577         }
10578 
10579         if (fp_copyout((void *)devlist, (void *)fcio->fcio_obuf,
10580             sizeof (fc_port_dev_t) * num_devices, mode)) {
10581                 rval = FC_FAILURE;
10582         } else {
10583                 rval = FC_SUCCESS;
10584         }
10585 
10586         kmem_free(devlist, sizeof (*devlist) * num_devices);
10587         ASSERT(MUTEX_HELD(&port->fp_mutex));
10588 
10589         return (rval);
10590 }
10591 
10592 
10593 /*
10594  * Completion function for responses to unsolicited commands
10595  */
10596 static void
10597 fp_unsol_intr(fc_packet_t *pkt)
10598 {
10599         fp_cmd_t        *cmd;
10600         fc_local_port_t *port;
10601 
10602         cmd = pkt->pkt_ulp_private;
10603         port = cmd->cmd_port;
10604 
10605         mutex_enter(&port->fp_mutex);
10606         port->fp_out_fpcmds--;
10607         mutex_exit(&port->fp_mutex);
10608 
10609         if (pkt->pkt_state != FC_PKT_SUCCESS) {
10610                 fp_printf(port, CE_WARN, FP_LOG_ONLY, 0, pkt,
10611                     "couldn't post response to unsolicited request;"
10612                     " ox_id=%x rx_id=%x", pkt->pkt_cmd_fhdr.ox_id,
10613                     pkt->pkt_resp_fhdr.rx_id);
10614         }
10615 
10616         if (cmd == port->fp_els_resp_pkt) {
10617                 mutex_enter(&port->fp_mutex);
10618                 port->fp_els_resp_pkt_busy = 0;
10619                 mutex_exit(&port->fp_mutex);
10620                 return;
10621         }
10622 
10623         fp_free_pkt(cmd);
10624 }
10625 
10626 
10627 /*
10628  * solicited LINIT ELS completion function
10629  */
10630 static void
10631 fp_linit_intr(fc_packet_t *pkt)
10632 {
10633         fp_cmd_t                *cmd;
10634         job_request_t           *job;
10635         fc_linit_resp_t         acc;
10636         fc_local_port_t *port = ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port;
10637 
10638         cmd = (fp_cmd_t *)pkt->pkt_ulp_private;
10639 
10640         mutex_enter(&cmd->cmd_port->fp_mutex);
10641         cmd->cmd_port->fp_out_fpcmds--;
10642         mutex_exit(&cmd->cmd_port->fp_mutex);
10643 
10644         if (FP_IS_PKT_ERROR(pkt)) {
10645                 (void) fp_common_intr(pkt, 1);
10646                 return;
10647         }
10648 
10649         job = cmd->cmd_job;
10650 
10651         FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&acc,
10652             (uint8_t *)pkt->pkt_resp, sizeof (acc), DDI_DEV_AUTOINCR);
10653         if (acc.status != FC_LINIT_SUCCESS) {
10654                 job->job_result = FC_FAILURE;
10655         } else {
10656                 job->job_result = FC_SUCCESS;
10657         }
10658 
10659         fp_iodone(cmd);
10660 }
10661 
10662 
10663 /*
10664  * Decode the unsolicited request; For FC-4 Device and Link data frames
10665  * notify the registered ULP of this FC-4 type right here. For Unsolicited
10666  * ELS requests, submit a request to the job_handler thread to work on it.
10667  * The intent is to act quickly on the FC-4 unsolicited link and data frames
10668  * and save much of the interrupt time processing of unsolicited ELS requests
10669  * and hand it off to the job_handler thread.
10670  */
10671 static void
10672 fp_unsol_cb(opaque_t port_handle, fc_unsol_buf_t *buf, uint32_t type)
10673 {
10674         uchar_t         r_ctl;
10675         uchar_t         ls_code;
10676         uint32_t        s_id;
10677         uint32_t        rscn_count = FC_INVALID_RSCN_COUNT;
10678         uint32_t        cb_arg;
10679         fp_cmd_t        *cmd;
10680         fc_local_port_t *port;
10681         job_request_t   *job;
10682         fc_remote_port_t        *pd;
10683 
10684         port = port_handle;
10685 
10686         FP_TRACE(FP_NHEAD1(1, 0), "fp_unsol_cb: s_id=%x,"
10687             " d_id=%x, type=%x, r_ctl=%x, f_ctl=%x"
10688             " seq_id=%x, df_ctl=%x, seq_cnt=%x, ox_id=%x, rx_id=%x"
10689             " ro=%x, buffer[0]:%x", buf->ub_frame.s_id, buf->ub_frame.d_id,
10690             buf->ub_frame.type, buf->ub_frame.r_ctl, buf->ub_frame.f_ctl,
10691             buf->ub_frame.seq_id, buf->ub_frame.df_ctl, buf->ub_frame.seq_cnt,
10692             buf->ub_frame.ox_id, buf->ub_frame.rx_id, buf->ub_frame.ro,
10693             buf->ub_buffer[0]);
10694 
10695         if (type & 0x80000000) {
10696                 /*
10697                  * Huh ? Nothing much can be done without
10698                  * a valid buffer. So just exit.
10699                  */
10700                 return;
10701         }
10702         /*
10703          * If the unsolicited interrupts arrive while it isn't
10704          * safe to handle unsolicited callbacks; Drop them, yes,
10705          * drop them on the floor
10706          */
10707         mutex_enter(&port->fp_mutex);
10708         port->fp_active_ubs++;
10709         if ((port->fp_soft_state &
10710             (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN)) ||
10711             FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) {
10712 
10713                 FP_TRACE(FP_NHEAD1(3, 0), "fp_unsol_cb: port state is "
10714                     "not ONLINE. s_id=%x, d_id=%x, type=%x, "
10715                     "seq_id=%x, ox_id=%x, rx_id=%x"
10716                     "ro=%x", buf->ub_frame.s_id, buf->ub_frame.d_id,
10717                     buf->ub_frame.type, buf->ub_frame.seq_id,
10718                     buf->ub_frame.ox_id, buf->ub_frame.rx_id, buf->ub_frame.ro);
10719 
10720                 ASSERT(port->fp_active_ubs > 0);
10721                 if (--(port->fp_active_ubs) == 0) {
10722                         port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB;
10723                 }
10724 
10725                 mutex_exit(&port->fp_mutex);
10726 
10727                 port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
10728                     1, &buf->ub_token);
10729 
10730                 return;
10731         }
10732 
10733         r_ctl = buf->ub_frame.r_ctl;
10734         s_id = buf->ub_frame.s_id;
10735         if (port->fp_active_ubs == 1) {
10736                 port->fp_soft_state |= FP_SOFT_IN_UNSOL_CB;
10737         }
10738 
10739         if (r_ctl == R_CTL_ELS_REQ && buf->ub_buffer[0] == LA_ELS_LOGO &&
10740             port->fp_statec_busy) {
10741                 mutex_exit(&port->fp_mutex);
10742                 pd = fctl_get_remote_port_by_did(port, s_id);
10743                 if (pd) {
10744                         mutex_enter(&pd->pd_mutex);
10745                         if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
10746                                 FP_TRACE(FP_NHEAD1(3, 0),
10747                                     "LOGO for LOGGED IN D_ID %x",
10748                                     buf->ub_frame.s_id);
10749                                 pd->pd_state = PORT_DEVICE_VALID;
10750                         }
10751                         mutex_exit(&pd->pd_mutex);
10752                 }
10753 
10754                 mutex_enter(&port->fp_mutex);
10755                 ASSERT(port->fp_active_ubs > 0);
10756                 if (--(port->fp_active_ubs) == 0) {
10757                         port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB;
10758                 }
10759                 mutex_exit(&port->fp_mutex);
10760 
10761                 port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
10762                     1, &buf->ub_token);
10763 
10764                 FP_TRACE(FP_NHEAD1(3, 0),
10765                     "fp_unsol_cb() bailing out LOGO for D_ID %x",
10766                     buf->ub_frame.s_id);
10767                 return;
10768         }
10769 
10770         if (port->fp_els_resp_pkt_busy == 0) {
10771                 if (r_ctl == R_CTL_ELS_REQ) {
10772                         ls_code = buf->ub_buffer[0];
10773 
10774                         switch (ls_code) {
10775                         case LA_ELS_PLOGI:
10776                         case LA_ELS_FLOGI:
10777                                 port->fp_els_resp_pkt_busy = 1;
10778                                 mutex_exit(&port->fp_mutex);
10779                                 fp_i_handle_unsol_els(port, buf);
10780 
10781                                 mutex_enter(&port->fp_mutex);
10782                                 ASSERT(port->fp_active_ubs > 0);
10783                                 if (--(port->fp_active_ubs) == 0) {
10784                                         port->fp_soft_state &=
10785                                             ~FP_SOFT_IN_UNSOL_CB;
10786                                 }
10787                                 mutex_exit(&port->fp_mutex);
10788                                 port->fp_fca_tran->fca_ub_release(
10789                                     port->fp_fca_handle, 1, &buf->ub_token);
10790 
10791                                 return;
10792                         case LA_ELS_RSCN:
10793                                 if (++(port)->fp_rscn_count ==
10794                                     FC_INVALID_RSCN_COUNT) {
10795                                         ++(port)->fp_rscn_count;
10796                                 }
10797                                 rscn_count = port->fp_rscn_count;
10798                                 break;
10799 
10800                         default:
10801                                 break;
10802                         }
10803                 }
10804         } else if ((r_ctl == R_CTL_ELS_REQ) &&
10805             (buf->ub_buffer[0] == LA_ELS_RSCN)) {
10806                 if (++port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
10807                         ++port->fp_rscn_count;
10808                 }
10809                 rscn_count = port->fp_rscn_count;
10810         }
10811 
10812         mutex_exit(&port->fp_mutex);
10813 
10814         switch (r_ctl & R_CTL_ROUTING) {
10815         case R_CTL_DEVICE_DATA:
10816                 /*
10817                  * If the unsolicited buffer is a CT IU,
10818                  * have the job_handler thread work on it.
10819                  */
10820                 if (buf->ub_frame.type == FC_TYPE_FC_SERVICES) {
10821                         break;
10822                 }
10823                 /* FALLTHROUGH */
10824 
10825         case R_CTL_FC4_SVC: {
10826                 int sendup = 0;
10827 
10828                 /*
10829                  * If a LOGIN isn't performed before this request
10830                  * shut the door on this port with a reply that a
10831                  * LOGIN is required. We make an exception however
10832                  * for IP broadcast packets and pass them through
10833                  * to the IP ULP(s) to handle broadcast requests.
10834                  * This is not a problem for private loop devices
10835                  * but for fabric topologies we don't log into the
10836                  * remote ports during port initialization and
10837                  * the ULPs need to log into requesting ports on
10838                  * demand.
10839                  */
10840                 pd = fctl_get_remote_port_by_did(port, s_id);
10841                 if (pd) {
10842                         mutex_enter(&pd->pd_mutex);
10843                         if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
10844                                 sendup++;
10845                         }
10846                         mutex_exit(&pd->pd_mutex);
10847                 } else if ((pd == NULL) &&
10848                     (buf->ub_frame.type == FC_TYPE_IS8802_SNAP) &&
10849                     (buf->ub_frame.d_id == 0xffffff ||
10850                     buf->ub_frame.d_id == 0x00)) {
10851                         /* brodacst IP frame - so sendup via job thread */
10852                         break;
10853                 }
10854 
10855                 /*
10856                  * Send all FC4 services via job thread too
10857                  */
10858                 if ((r_ctl & R_CTL_ROUTING) == R_CTL_FC4_SVC) {
10859                         break;
10860                 }
10861 
10862                 if (sendup || !FC_IS_REAL_DEVICE(s_id)) {
10863                         fctl_ulp_unsol_cb(port, buf, buf->ub_frame.type);
10864                         return;
10865                 }
10866 
10867                 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
10868                         cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t),
10869                             0, KM_NOSLEEP, pd);
10870                         if (cmd != NULL) {
10871                                 fp_els_rjt_init(port, cmd, buf,
10872                                     FC_ACTION_NON_RETRYABLE,
10873                                     FC_REASON_LOGIN_REQUIRED, NULL);
10874 
10875                                 if (fp_sendcmd(port, cmd,
10876                                     port->fp_fca_handle) != FC_SUCCESS) {
10877                                         fp_free_pkt(cmd);
10878                                 }
10879                         }
10880                 }
10881 
10882                 mutex_enter(&port->fp_mutex);
10883                 ASSERT(port->fp_active_ubs > 0);
10884                 if (--(port->fp_active_ubs) == 0) {
10885                         port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB;
10886                 }
10887                 mutex_exit(&port->fp_mutex);
10888                 port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
10889                     1, &buf->ub_token);
10890 
10891                 return;
10892         }
10893 
10894         default:
10895                 break;
10896         }
10897 
10898         /*
10899          * Submit a Request to the job_handler thread to work
10900          * on the unsolicited request. The potential side effect
10901          * of this is that the unsolicited buffer takes a little
10902          * longer to get released but we save interrupt time in
10903          * the bargain.
10904          */
10905         cb_arg = (rscn_count == FC_INVALID_RSCN_COUNT) ? NULL : rscn_count;
10906 
10907         /*
10908          * One way that the rscn_count will get used is described below :
10909          *
10910          * 1. fp_unsol_cb() gets an RSCN and updates fp_rscn_count.
10911          * 2. Before mutex is released, a copy of it is stored in rscn_count.
10912          * 3. The count is passed to job thread as JOB_UNSOL_REQUEST (below)
10913          *    by overloading the job_cb_arg to pass the rscn_count
10914          * 4. When one of the routines processing the RSCN picks it up (ex:
10915          *    fp_validate_rscn_page()), it passes this count in the map
10916          *    structure (as part of the map_rscn_info structure member) to the
10917          *    ULPs.
10918          * 5. When ULPs make calls back to the transport (example interfaces for
10919          *    this are fc_ulp_transport(), fc_ulp_login(), fc_issue_els()), they
10920          *    can now pass back this count as part of the fc_packet's
10921          *    pkt_ulp_rscn_count member. fcp does this currently.
10922          * 6. When transport gets a call to transport a command on the wire, it
10923          *    will check to see if there is a valid pkt_ulp_rsvd1 field in the
10924          *    fc_packet. If there is, it will match that info with the current
10925          *    rscn_count on that instance of the port. If they don't match up
10926          *    then there was a newer RSCN. The ULP gets back an error code which
10927          *    informs it about it - FC_DEVICE_BUSY_NEW_RSCN.
10928          * 7. At this point the ULP is free to make up its own mind as to how to
10929          *    handle this. Currently, fcp will reset its retry counters and keep
10930          *    retrying the operation it was doing in anticipation of getting a
10931          *    new state change call back for the new RSCN.
10932          */
10933         job = fctl_alloc_job(JOB_UNSOL_REQUEST, 0, NULL,
10934             (opaque_t)(uintptr_t)cb_arg, KM_NOSLEEP);
10935         if (job == NULL) {
10936                 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, "fp_unsol_cb() "
10937                     "couldn't submit a job to the thread, failing..");
10938 
10939                 mutex_enter(&port->fp_mutex);
10940 
10941                 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
10942                         --port->fp_rscn_count;
10943                 }
10944 
10945                 ASSERT(port->fp_active_ubs > 0);
10946                 if (--(port->fp_active_ubs) == 0) {
10947                         port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB;
10948                 }
10949 
10950                 mutex_exit(&port->fp_mutex);
10951                 port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
10952                     1, &buf->ub_token);
10953 
10954                 return;
10955         }
10956         job->job_private = (void *)buf;
10957         fctl_enque_job(port, job);
10958 }
10959 
10960 
10961 /*
10962  * Handle unsolicited requests
10963  */
10964 static void
10965 fp_handle_unsol_buf(fc_local_port_t *port, fc_unsol_buf_t *buf,
10966     job_request_t *job)
10967 {
10968         uchar_t                 r_ctl;
10969         uchar_t                 ls_code;
10970         uint32_t                s_id;
10971         fp_cmd_t                *cmd;
10972         fc_remote_port_t        *pd;
10973         fp_unsol_spec_t         *ub_spec;
10974 
10975         r_ctl = buf->ub_frame.r_ctl;
10976         s_id = buf->ub_frame.s_id;
10977 
10978         switch (r_ctl & R_CTL_ROUTING) {
10979         case R_CTL_EXTENDED_SVC:
10980                 if (r_ctl != R_CTL_ELS_REQ) {
10981                         break;
10982                 }
10983 
10984                 ls_code = buf->ub_buffer[0];
10985                 switch (ls_code) {
10986                 case LA_ELS_LOGO:
10987                 case LA_ELS_ADISC:
10988                 case LA_ELS_PRLO:
10989                         pd = fctl_get_remote_port_by_did(port, s_id);
10990                         if (pd == NULL) {
10991                                 if (!FC_IS_REAL_DEVICE(s_id)) {
10992                                         break;
10993                                 }
10994                                 if (!FP_IS_CLASS_1_OR_2(buf->ub_class)) {
10995                                         break;
10996                                 }
10997                                 if ((cmd = fp_alloc_pkt(port,
10998                                     sizeof (la_els_rjt_t), 0, KM_SLEEP,
10999                                     NULL)) == NULL) {
11000                                         /*
11001                                          * Can this actually fail when
11002                                          * given KM_SLEEP?  (Could be used
11003                                          * this way in a number of places.)
11004                                          */
11005                                         break;
11006                                 }
11007 
11008                                 fp_els_rjt_init(port, cmd, buf,
11009                                     FC_ACTION_NON_RETRYABLE,
11010                                     FC_REASON_INVALID_LINK_CTRL, job);
11011 
11012                                 if (fp_sendcmd(port, cmd,
11013                                     port->fp_fca_handle) != FC_SUCCESS) {
11014                                         fp_free_pkt(cmd);
11015                                 }
11016 
11017                                 break;
11018                         }
11019                         if (ls_code == LA_ELS_LOGO) {
11020                                 fp_handle_unsol_logo(port, buf, pd, job);
11021                         } else if (ls_code == LA_ELS_ADISC) {
11022                                 fp_handle_unsol_adisc(port, buf, pd, job);
11023                         } else {
11024                                 fp_handle_unsol_prlo(port, buf, pd, job);
11025                         }
11026                         break;
11027 
11028                 case LA_ELS_PLOGI:
11029                         fp_handle_unsol_plogi(port, buf, job, KM_SLEEP);
11030                         break;
11031 
11032                 case LA_ELS_FLOGI:
11033                         fp_handle_unsol_flogi(port, buf, job, KM_SLEEP);
11034                         break;
11035 
11036                 case LA_ELS_RSCN:
11037                         fp_handle_unsol_rscn(port, buf, job, KM_SLEEP);
11038                         break;
11039 
11040                 default:
11041                         ub_spec = kmem_zalloc(sizeof (*ub_spec), KM_SLEEP);
11042                         ub_spec->port = port;
11043                         ub_spec->buf = buf;
11044 
11045                         (void) taskq_dispatch(port->fp_taskq,
11046                             fp_ulp_unsol_cb, ub_spec, KM_SLEEP);
11047                         return;
11048                 }
11049                 break;
11050 
11051         case R_CTL_BASIC_SVC:
11052                 /*
11053                  * The unsolicited basic link services could be ABTS
11054                  * and RMC (Or even a NOP). Just BA_RJT them until
11055                  * such time there arises a need to handle them more
11056                  * carefully.
11057                  */
11058                 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11059                         cmd = fp_alloc_pkt(port, sizeof (la_ba_rjt_t),
11060                             0, KM_SLEEP, NULL);
11061                         if (cmd != NULL) {
11062                                 fp_ba_rjt_init(port, cmd, buf, job);
11063                                 if (fp_sendcmd(port, cmd,
11064                                     port->fp_fca_handle) != FC_SUCCESS) {
11065                                         fp_free_pkt(cmd);
11066                                 }
11067                         }
11068                 }
11069                 break;
11070 
11071         case R_CTL_DEVICE_DATA:
11072                 if (buf->ub_frame.type == FC_TYPE_FC_SERVICES) {
11073                         /*
11074                          * Mostly this is of type FC_TYPE_FC_SERVICES.
11075                          * As we don't like any Unsolicited FC services
11076                          * requests, we would do well to RJT them as
11077                          * well.
11078                          */
11079                         if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11080                                 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t),
11081                                     0, KM_SLEEP, NULL);
11082                                 if (cmd != NULL) {
11083                                         fp_els_rjt_init(port, cmd, buf,
11084                                             FC_ACTION_NON_RETRYABLE,
11085                                             FC_REASON_INVALID_LINK_CTRL, job);
11086 
11087                                         if (fp_sendcmd(port, cmd,
11088                                             port->fp_fca_handle) !=
11089                                             FC_SUCCESS) {
11090                                                 fp_free_pkt(cmd);
11091                                         }
11092                                 }
11093                         }
11094                         break;
11095                 }
11096                 /* FALLTHROUGH */
11097 
11098         case R_CTL_FC4_SVC:
11099                 ub_spec = kmem_zalloc(sizeof (*ub_spec), KM_SLEEP);
11100                 ub_spec->port = port;
11101                 ub_spec->buf = buf;
11102 
11103                 (void) taskq_dispatch(port->fp_taskq,
11104                     fp_ulp_unsol_cb, ub_spec, KM_SLEEP);
11105                 return;
11106 
11107         case R_CTL_LINK_CTL:
11108                 /*
11109                  * Turn deaf ear on unsolicited link control frames.
11110                  * Typical unsolicited link control Frame is an LCR
11111                  * (to reset End to End credit to the default login
11112                  * value and abort current sequences for all classes)
11113                  * An intelligent microcode/firmware should handle
11114                  * this transparently at its level and not pass all
11115                  * the way up here.
11116                  *
11117                  * Possible responses to LCR are R_RDY, F_RJT, P_RJT
11118                  * or F_BSY. P_RJT is chosen to be the most appropriate
11119                  * at this time.
11120                  */
11121                 /* FALLTHROUGH */
11122 
11123         default:
11124                 /*
11125                  * Just reject everything else as an invalid request.
11126                  */
11127                 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11128                         cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t),
11129                             0, KM_SLEEP, NULL);
11130                         if (cmd != NULL) {
11131                                 fp_els_rjt_init(port, cmd, buf,
11132                                     FC_ACTION_NON_RETRYABLE,
11133                                     FC_REASON_INVALID_LINK_CTRL, job);
11134 
11135                                 if (fp_sendcmd(port, cmd,
11136                                     port->fp_fca_handle) != FC_SUCCESS) {
11137                                         fp_free_pkt(cmd);
11138                                 }
11139                         }
11140                 }
11141                 break;
11142         }
11143 
11144         mutex_enter(&port->fp_mutex);
11145         ASSERT(port->fp_active_ubs > 0);
11146         if (--(port->fp_active_ubs) == 0) {
11147                 port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB;
11148         }
11149         mutex_exit(&port->fp_mutex);
11150         port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
11151             1, &buf->ub_token);
11152 }
11153 
11154 
11155 /*
11156  * Prepare a BA_RJT and send it over.
11157  */
11158 static void
11159 fp_ba_rjt_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf,
11160     job_request_t *job)
11161 {
11162         fc_packet_t     *pkt;
11163         la_ba_rjt_t     payload;
11164 
11165         ASSERT(!MUTEX_HELD(&port->fp_mutex));
11166 
11167         cmd->cmd_pkt.pkt_tran_flags = buf->ub_class;
11168         cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND;
11169         cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
11170         cmd->cmd_retry_count = 1;
11171         cmd->cmd_ulp_pkt = NULL;
11172 
11173         cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
11174         cmd->cmd_job = job;
11175 
11176         pkt = &cmd->cmd_pkt;
11177 
11178         fp_unsol_resp_init(pkt, buf, R_CTL_LS_BA_RJT, FC_TYPE_BASIC_LS);
11179 
11180         payload.reserved = 0;
11181         payload.reason_code = FC_REASON_CMD_UNSUPPORTED;
11182         payload.explanation = FC_EXPLN_NONE;
11183         payload.vendor = 0;
11184 
11185         FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
11186             (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
11187 }
11188 
11189 
11190 /*
11191  * Prepare an LS_RJT and send it over
11192  */
11193 static void
11194 fp_els_rjt_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf,
11195     uchar_t action, uchar_t reason, job_request_t *job)
11196 {
11197         fc_packet_t     *pkt;
11198         la_els_rjt_t    payload;
11199 
11200         ASSERT(!MUTEX_HELD(&port->fp_mutex));
11201 
11202         cmd->cmd_pkt.pkt_tran_flags = buf->ub_class;
11203         cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND;
11204         cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
11205         cmd->cmd_retry_count = 1;
11206         cmd->cmd_ulp_pkt = NULL;
11207 
11208         cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
11209         cmd->cmd_job = job;
11210 
11211         pkt = &cmd->cmd_pkt;
11212 
11213         fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP, FC_TYPE_EXTENDED_LS);
11214 
11215         payload.ls_code.ls_code = LA_ELS_RJT;
11216         payload.ls_code.mbz = 0;
11217         payload.action = action;
11218         payload.reason = reason;
11219         payload.reserved = 0;
11220         payload.vu = 0;
11221 
11222         FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
11223             (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
11224 }
11225 
11226 /*
11227  *     Function: fp_prlo_acc_init
11228  *
11229  *  Description: Initializes an Link Service Accept for a PRLO.
11230  *
11231  *    Arguments: *port          Local port through which the PRLO was
11232  *                              received.
11233  *               cmd            Command that will carry the accept.
11234  *               *buf           Unsolicited buffer containing the PRLO
11235  *                              request.
11236  *               job            Job request.
11237  *               sleep          Allocation mode.
11238  *
11239  * Return Value: *cmd           Command containing the response.
11240  *
11241  *      Context: Depends on the parameter sleep.
11242  */
11243 fp_cmd_t *
11244 fp_prlo_acc_init(fc_local_port_t *port, fc_remote_port_t *pd,
11245     fc_unsol_buf_t *buf, job_request_t *job, int sleep)
11246 {
11247         fp_cmd_t        *cmd;
11248         fc_packet_t     *pkt;
11249         la_els_prlo_t   *req;
11250         size_t          len;
11251         uint16_t        flags;
11252 
11253         req = (la_els_prlo_t *)buf->ub_buffer;
11254         len = (size_t)ntohs(req->payload_length);
11255 
11256         /*
11257          * The payload of the accept to a PRLO has to be the exact match of
11258          * the payload of the request (at the exception of the code).
11259          */
11260         cmd = fp_alloc_pkt(port, (int)len, 0, sleep, pd);
11261 
11262         if (cmd) {
11263                 /*
11264                  * The fp command was successfully allocated.
11265                  */
11266                 cmd->cmd_pkt.pkt_tran_flags = buf->ub_class;
11267                 cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND;
11268                 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
11269                 cmd->cmd_retry_count = 1;
11270                 cmd->cmd_ulp_pkt = NULL;
11271 
11272                 cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
11273                 cmd->cmd_job = job;
11274 
11275                 pkt = &cmd->cmd_pkt;
11276 
11277                 fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP,
11278                     FC_TYPE_EXTENDED_LS);
11279 
11280                 /* The code is overwritten for the copy. */
11281                 req->ls_code = LA_ELS_ACC;
11282                 /* Response code is set. */
11283                 flags = ntohs(req->flags);
11284                 flags &= ~SP_RESP_CODE_MASK;
11285                 flags |= SP_RESP_CODE_REQ_EXECUTED;
11286                 req->flags = htons(flags);
11287 
11288                 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)req,
11289                     (uint8_t *)pkt->pkt_cmd, len, DDI_DEV_AUTOINCR);
11290         }
11291         return (cmd);
11292 }
11293 
11294 /*
11295  * Prepare an ACC response to an ELS request
11296  */
11297 static void
11298 fp_els_acc_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf,
11299     job_request_t *job)
11300 {
11301         fc_packet_t     *pkt;
11302         ls_code_t       payload;
11303 
11304         cmd->cmd_pkt.pkt_tran_flags = buf->ub_class;
11305         cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND;
11306         cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
11307         cmd->cmd_retry_count = 1;
11308         cmd->cmd_ulp_pkt = NULL;
11309 
11310         cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
11311         cmd->cmd_job = job;
11312 
11313         pkt = &cmd->cmd_pkt;
11314 
11315         fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP, FC_TYPE_EXTENDED_LS);
11316 
11317         payload.ls_code = LA_ELS_ACC;
11318         payload.mbz = 0;
11319 
11320         FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
11321             (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
11322 }
11323 
11324 /*
11325  * Unsolicited PRLO handler
11326  *
11327  * A Process Logout should be handled by the ULP that established it.  However,
11328  * some devices send a PRLO to trigger a PLOGI followed by a PRLI.  This happens
11329  * when a device implicitly logs out an initiator (for whatever reason) and
11330  * tries to get that initiator to restablish the connection (PLOGI and PRLI).
11331  * The logical thing to do for the device would be to send a LOGO in response
11332  * to any FC4 frame sent by the initiator. Some devices choose, however, to send
11333  * a PRLO instead.
11334  *
11335  * From a Fibre Channel standpoint a PRLO calls for a PRLI. There's no reason to
11336  * think that the Port Login has been lost.  If we follow the Fibre Channel
11337  * protocol to the letter a PRLI should be sent after accepting the PRLO.  If
11338  * the Port Login has also been lost, the remote port will reject the PRLI
11339  * indicating that we must PLOGI first.  The initiator will then turn around and
11340  * send a PLOGI.  The way Leadville is layered and the way the ULP interface
11341  * is defined doesn't allow this scenario to be followed easily.  If FCP were to
11342  * handle the PRLO and attempt the PRLI, the reject indicating that a PLOGI is
11343  * needed would be received by FCP. FCP would have, then, to tell the transport
11344  * (fp) to PLOGI.  The problem is, the transport would still think the Port
11345  * Login is valid and there is no way for FCP to tell the transport: "PLOGI even
11346  * if you think it's not necessary".  To work around that difficulty, the PRLO
11347  * is treated by the transport as a LOGO.  The downside to it is a Port Login
11348  * may be disrupted (if a PLOGI wasn't actually needed) and another ULP (that
11349  * has nothing to do with the PRLO) may be impacted.  However, this is a
11350  * scenario very unlikely to happen.  As of today the only ULP in Leadville
11351  * using PRLI/PRLOs is FCP.  For a PRLO to disrupt another ULP (that would be
11352  * FCIP), a SCSI target would have to be running FCP and FCIP (which is very
11353  * unlikely).
11354  */
11355 static void
11356 fp_handle_unsol_prlo(fc_local_port_t *port, fc_unsol_buf_t *buf,
11357     fc_remote_port_t *pd, job_request_t *job)
11358 {
11359         int             busy;
11360         int             rval;
11361         int             retain;
11362         fp_cmd_t        *cmd;
11363         fc_portmap_t    *listptr;
11364         boolean_t       tolerance;
11365         la_els_prlo_t   *req;
11366 
11367         req = (la_els_prlo_t *)buf->ub_buffer;
11368 
11369         if ((ntohs(req->payload_length) !=
11370             (sizeof (service_parameter_page_t) + sizeof (ls_code_t))) ||
11371             (req->page_length != sizeof (service_parameter_page_t))) {
11372                 /*
11373                  * We are being very restrictive.  Only on page per
11374                  * payload.  If it is not the case we reject the ELS although
11375                  * we should reply indicating we handle only single page
11376                  * per PRLO.
11377                  */
11378                 goto fp_reject_prlo;
11379         }
11380 
11381         if (ntohs(req->payload_length) > buf->ub_bufsize) {
11382                 /*
11383                  * This is in case the payload advertizes a size bigger than
11384                  * what it really is.
11385                  */
11386                 goto fp_reject_prlo;
11387         }
11388 
11389         mutex_enter(&port->fp_mutex);
11390         busy = port->fp_statec_busy;
11391         mutex_exit(&port->fp_mutex);
11392 
11393         mutex_enter(&pd->pd_mutex);
11394         tolerance = fctl_tc_increment(&pd->pd_logo_tc);
11395         if (!busy) {
11396                 if (pd->pd_state != PORT_DEVICE_LOGGED_IN ||
11397                     pd->pd_state == PORT_DEVICE_INVALID ||
11398                     pd->pd_flags == PD_ELS_IN_PROGRESS ||
11399                     pd->pd_type == PORT_DEVICE_OLD) {
11400                         busy++;
11401                 }
11402         }
11403 
11404         if (busy) {
11405                 mutex_exit(&pd->pd_mutex);
11406 
11407                 FP_TRACE(FP_NHEAD1(5, 0), "Logout; D_ID=%x,"
11408                     "pd=%p - busy",
11409                     pd->pd_port_id.port_id, pd);
11410 
11411                 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11412                         goto fp_reject_prlo;
11413                 }
11414         } else {
11415                 retain = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0;
11416 
11417                 if (tolerance) {
11418                         fctl_tc_reset(&pd->pd_logo_tc);
11419                         retain = 0;
11420                         pd->pd_state = PORT_DEVICE_INVALID;
11421                 }
11422 
11423                 FP_TRACE(FP_NHEAD1(5, 0), "Accepting LOGO; d_id=%x, pd=%p,"
11424                     " tolerance=%d retain=%d", pd->pd_port_id.port_id, pd,
11425                     tolerance, retain);
11426 
11427                 pd->pd_aux_flags |= PD_LOGGED_OUT;
11428                 mutex_exit(&pd->pd_mutex);
11429 
11430                 cmd = fp_prlo_acc_init(port, pd, buf, job, KM_SLEEP);
11431                 if (cmd == NULL) {
11432                         return;
11433                 }
11434 
11435                 rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
11436                 if (rval != FC_SUCCESS) {
11437                         fp_free_pkt(cmd);
11438                         return;
11439                 }
11440 
11441                 listptr = kmem_zalloc(sizeof (fc_portmap_t), KM_SLEEP);
11442 
11443                 if (retain) {
11444                         fp_unregister_login(pd);
11445                         fctl_copy_portmap(listptr, pd);
11446                 } else {
11447                         uint32_t        d_id;
11448                         char            ww_name[17];
11449 
11450                         mutex_enter(&pd->pd_mutex);
11451                         d_id = pd->pd_port_id.port_id;
11452                         fc_wwn_to_str(&pd->pd_port_name, ww_name);
11453                         mutex_exit(&pd->pd_mutex);
11454 
11455                         FP_TRACE(FP_NHEAD2(9, 0),
11456                             "N_x Port with D_ID=%x, PWWN=%s logged out"
11457                             " %d times in %d us; Giving up", d_id, ww_name,
11458                             FC_LOGO_TOLERANCE_LIMIT,
11459                             FC_LOGO_TOLERANCE_TIME_LIMIT);
11460 
11461                         fp_fillout_old_map(listptr, pd, 0);
11462                         listptr->map_type = PORT_DEVICE_OLD;
11463                 }
11464 
11465                 (void) fp_ulp_devc_cb(port, listptr, 1, 1, KM_SLEEP, 0);
11466                 return;
11467         }
11468 
11469 fp_reject_prlo:
11470 
11471         cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t), 0, KM_SLEEP, pd);
11472         if (cmd != NULL) {
11473                 fp_els_rjt_init(port, cmd, buf, FC_ACTION_NON_RETRYABLE,
11474                     FC_REASON_INVALID_LINK_CTRL, job);
11475 
11476                 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
11477                         fp_free_pkt(cmd);
11478                 }
11479         }
11480 }
11481 
11482 /*
11483  * Unsolicited LOGO handler
11484  */
11485 static void
11486 fp_handle_unsol_logo(fc_local_port_t *port, fc_unsol_buf_t *buf,
11487     fc_remote_port_t *pd, job_request_t *job)
11488 {
11489         int             busy;
11490         int             rval;
11491         int             retain;
11492         fp_cmd_t        *cmd;
11493         fc_portmap_t    *listptr;
11494         boolean_t       tolerance;
11495 
11496         mutex_enter(&port->fp_mutex);
11497         busy = port->fp_statec_busy;
11498         mutex_exit(&port->fp_mutex);
11499 
11500         mutex_enter(&pd->pd_mutex);
11501         tolerance = fctl_tc_increment(&pd->pd_logo_tc);
11502         if (!busy) {
11503                 if (pd->pd_state != PORT_DEVICE_LOGGED_IN ||
11504                     pd->pd_state == PORT_DEVICE_INVALID ||
11505                     pd->pd_flags == PD_ELS_IN_PROGRESS ||
11506                     pd->pd_type == PORT_DEVICE_OLD) {
11507                         busy++;
11508                 }
11509         }
11510 
11511         if (busy) {
11512                 mutex_exit(&pd->pd_mutex);
11513 
11514                 FP_TRACE(FP_NHEAD1(5, 0), "Logout; D_ID=%x,"
11515                     "pd=%p - busy",
11516                     pd->pd_port_id.port_id, pd);
11517 
11518                 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11519                         cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t),
11520                             0, KM_SLEEP, pd);
11521                         if (cmd != NULL) {
11522                                 fp_els_rjt_init(port, cmd, buf,
11523                                     FC_ACTION_NON_RETRYABLE,
11524                                     FC_REASON_INVALID_LINK_CTRL, job);
11525 
11526                                 if (fp_sendcmd(port, cmd,
11527                                     port->fp_fca_handle) != FC_SUCCESS) {
11528                                         fp_free_pkt(cmd);
11529                                 }
11530                         }
11531                 }
11532         } else {
11533                 retain = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0;
11534 
11535                 if (tolerance) {
11536                         fctl_tc_reset(&pd->pd_logo_tc);
11537                         retain = 0;
11538                         pd->pd_state = PORT_DEVICE_INVALID;
11539                 }
11540 
11541                 FP_TRACE(FP_NHEAD1(5, 0), "Accepting LOGO; d_id=%x, pd=%p,"
11542                     " tolerance=%d retain=%d", pd->pd_port_id.port_id, pd,
11543                     tolerance, retain);
11544 
11545                 pd->pd_aux_flags |= PD_LOGGED_OUT;
11546                 mutex_exit(&pd->pd_mutex);
11547 
11548                 cmd = fp_alloc_pkt(port, FP_PORT_IDENTIFIER_LEN, 0,
11549                     KM_SLEEP, pd);
11550                 if (cmd == NULL) {
11551                         return;
11552                 }
11553 
11554                 fp_els_acc_init(port, cmd, buf, job);
11555 
11556                 rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
11557                 if (rval != FC_SUCCESS) {
11558                         fp_free_pkt(cmd);
11559                         return;
11560                 }
11561 
11562                 listptr = kmem_zalloc(sizeof (fc_portmap_t), KM_SLEEP);
11563 
11564                 if (retain) {
11565                         job_request_t   *job;
11566                         fctl_ns_req_t   *ns_cmd;
11567 
11568                         /*
11569                          * when get LOGO, first try to get PID from nameserver
11570                          * if failed, then we do not need
11571                          * send PLOGI to that remote port
11572                          */
11573                         job = fctl_alloc_job(
11574                             JOB_NS_CMD, 0, NULL, (opaque_t)port, KM_SLEEP);
11575 
11576                         if (job != NULL) {
11577                                 ns_cmd = fctl_alloc_ns_cmd(
11578                                     sizeof (ns_req_gid_pn_t),
11579                                     sizeof (ns_resp_gid_pn_t),
11580                                     sizeof (ns_resp_gid_pn_t),
11581                                     0, KM_SLEEP);
11582                                 if (ns_cmd != NULL) {
11583                                         int ret;
11584                                         job->job_result = FC_SUCCESS;
11585                                         ns_cmd->ns_cmd_code = NS_GID_PN;
11586                                         ((ns_req_gid_pn_t *)
11587                                             (ns_cmd->ns_cmd_buf))->pwwn =
11588                                             pd->pd_port_name;
11589                                         ret = fp_ns_query(
11590                                             port, ns_cmd, job, 1, KM_SLEEP);
11591                                         if ((ret != FC_SUCCESS) ||
11592                                             (job->job_result != FC_SUCCESS)) {
11593                                                 fctl_free_ns_cmd(ns_cmd);
11594                                                 fctl_dealloc_job(job);
11595                                                 FP_TRACE(FP_NHEAD2(9, 0),
11596                                                     "NS query failed,",
11597                                                     " delete pd");
11598                                                 goto delete_pd;
11599                                         }
11600                                         fctl_free_ns_cmd(ns_cmd);
11601                                 }
11602                                 fctl_dealloc_job(job);
11603                         }
11604                         fp_unregister_login(pd);
11605                         fctl_copy_portmap(listptr, pd);
11606                 } else {
11607                         uint32_t        d_id;
11608                         char            ww_name[17];
11609 
11610                 delete_pd:
11611                         mutex_enter(&pd->pd_mutex);
11612                         d_id = pd->pd_port_id.port_id;
11613                         fc_wwn_to_str(&pd->pd_port_name, ww_name);
11614                         mutex_exit(&pd->pd_mutex);
11615 
11616                         FP_TRACE(FP_NHEAD2(9, 0),
11617                             "N_x Port with D_ID=%x, PWWN=%s logged out"
11618                             " %d times in %d us; Giving up", d_id, ww_name,
11619                             FC_LOGO_TOLERANCE_LIMIT,
11620                             FC_LOGO_TOLERANCE_TIME_LIMIT);
11621 
11622                         fp_fillout_old_map(listptr, pd, 0);
11623                         listptr->map_type = PORT_DEVICE_OLD;
11624                 }
11625 
11626                 (void) fp_ulp_devc_cb(port, listptr, 1, 1, KM_SLEEP, 0);
11627         }
11628 }
11629 
11630 
11631 /*
11632  * Perform general purpose preparation of a response to an unsolicited request
11633  */
11634 static void
11635 fp_unsol_resp_init(fc_packet_t *pkt, fc_unsol_buf_t *buf,
11636     uchar_t r_ctl, uchar_t type)
11637 {
11638         pkt->pkt_cmd_fhdr.r_ctl = r_ctl;
11639         pkt->pkt_cmd_fhdr.d_id = buf->ub_frame.s_id;
11640         pkt->pkt_cmd_fhdr.s_id = buf->ub_frame.d_id;
11641         pkt->pkt_cmd_fhdr.type = type;
11642         pkt->pkt_cmd_fhdr.f_ctl = F_CTL_LAST_SEQ | F_CTL_XCHG_CONTEXT;
11643         pkt->pkt_cmd_fhdr.seq_id = buf->ub_frame.seq_id;
11644         pkt->pkt_cmd_fhdr.df_ctl  = buf->ub_frame.df_ctl;
11645         pkt->pkt_cmd_fhdr.seq_cnt = buf->ub_frame.seq_cnt;
11646         pkt->pkt_cmd_fhdr.ox_id = buf->ub_frame.ox_id;
11647         pkt->pkt_cmd_fhdr.rx_id = buf->ub_frame.rx_id;
11648         pkt->pkt_cmd_fhdr.ro = 0;
11649         pkt->pkt_cmd_fhdr.rsvd = 0;
11650         pkt->pkt_comp = fp_unsol_intr;
11651         pkt->pkt_timeout = FP_ELS_TIMEOUT;
11652         pkt->pkt_ub_resp_token = (opaque_t)buf;
11653 }
11654 
11655 /*
11656  * Immediate handling of unsolicited FLOGI and PLOGI requests. In the
11657  * early development days of public loop soc+ firmware, numerous problems
11658  * were encountered (the details are undocumented and history now) which
11659  * led to the birth of this function.
11660  *
11661  * If a pre-allocated unsolicited response packet is free, send out an
11662  * immediate response, otherwise submit the request to the port thread
11663  * to do the deferred processing.
11664  */
11665 static void
11666 fp_i_handle_unsol_els(fc_local_port_t *port, fc_unsol_buf_t *buf)
11667 {
11668         int                     sent;
11669         int                     f_port;
11670         int                     do_acc;
11671         fp_cmd_t                *cmd;
11672         la_els_logi_t           *payload;
11673         fc_remote_port_t        *pd;
11674         char                    dww_name[17];
11675 
11676         ASSERT(!MUTEX_HELD(&port->fp_mutex));
11677 
11678         cmd = port->fp_els_resp_pkt;
11679 
11680         mutex_enter(&port->fp_mutex);
11681         do_acc = (port->fp_statec_busy == 0) ? 1 : 0;
11682         mutex_exit(&port->fp_mutex);
11683 
11684         switch (buf->ub_buffer[0]) {
11685         case LA_ELS_PLOGI: {
11686                 int small;
11687 
11688                 payload = (la_els_logi_t *)buf->ub_buffer;
11689 
11690                 f_port = FP_IS_F_PORT(payload->
11691                     common_service.cmn_features) ? 1 : 0;
11692 
11693                 small = fctl_wwn_cmp(&port->fp_service_params.nport_ww_name,
11694                     &payload->nport_ww_name);
11695                 pd = fctl_get_remote_port_by_pwwn(port,
11696                     &payload->nport_ww_name);
11697                 if (pd) {
11698                         mutex_enter(&pd->pd_mutex);
11699                         sent = (pd->pd_flags == PD_ELS_IN_PROGRESS) ? 1 : 0;
11700                         /*
11701                          * Most likely this means a cross login is in
11702                          * progress or a device about to be yanked out.
11703                          * Only accept the plogi if my wwn is smaller.
11704                          */
11705                         if (pd->pd_type == PORT_DEVICE_OLD) {
11706                                 sent = 1;
11707                         }
11708                         /*
11709                          * Stop plogi request (if any)
11710                          * attempt from local side to speedup
11711                          * the discovery progress.
11712                          * Mark the pd as PD_PLOGI_RECEPIENT.
11713                          */
11714                         if (f_port == 0 && small < 0) {
11715                                 pd->pd_recepient = PD_PLOGI_RECEPIENT;
11716                         }
11717                         fc_wwn_to_str(&pd->pd_port_name, dww_name);
11718 
11719                         mutex_exit(&pd->pd_mutex);
11720 
11721                         FP_TRACE(FP_NHEAD1(3, 0), "fp_i_handle_unsol_els: "
11722                             "Unsol PLOGI received. PD still exists in the "
11723                             "PWWN list. pd=%p PWWN=%s, sent=%x",
11724                             pd, dww_name, sent);
11725 
11726                         if (f_port == 0 && small < 0) {
11727                                 FP_TRACE(FP_NHEAD1(3, 0),
11728                                     "fp_i_handle_unsol_els: Mark the pd"
11729                                     " as plogi recipient, pd=%p, PWWN=%s"
11730                                     ", sent=%x",
11731                                     pd, dww_name, sent);
11732                         }
11733                 } else {
11734                         sent = 0;
11735                 }
11736 
11737                 /*
11738                  * To avoid Login collisions, accept only if my WWN
11739                  * is smaller than the requester (A curious side note
11740                  * would be that this rule may not satisfy the PLOGIs
11741                  * initiated by the switch from not-so-well known
11742                  * ports such as 0xFFFC41)
11743                  */
11744                 if ((f_port == 0 && small < 0) ||
11745                     (((small > 0 && do_acc) ||
11746                     FC_MUST_ACCEPT_D_ID(buf->ub_frame.s_id)) && sent == 0)) {
11747                         if (fp_is_class_supported(port->fp_cos,
11748                             buf->ub_class) == FC_FAILURE) {
11749                                 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11750                                         cmd->cmd_pkt.pkt_cmdlen =
11751                                             sizeof (la_els_rjt_t);
11752                                         cmd->cmd_pkt.pkt_rsplen = 0;
11753                                         fp_els_rjt_init(port, cmd, buf,
11754                                             FC_ACTION_NON_RETRYABLE,
11755                                             FC_REASON_CLASS_NOT_SUPP, NULL);
11756                                         FP_TRACE(FP_NHEAD1(3, 0),
11757                                             "fp_i_handle_unsol_els: "
11758                                             "Unsupported class. "
11759                                             "Rejecting PLOGI");
11760 
11761                                 } else {
11762                                         mutex_enter(&port->fp_mutex);
11763                                         port->fp_els_resp_pkt_busy = 0;
11764                                         mutex_exit(&port->fp_mutex);
11765                                         return;
11766                                 }
11767                         } else {
11768                                 cmd->cmd_pkt.pkt_cmdlen =
11769                                     sizeof (la_els_logi_t);
11770                                 cmd->cmd_pkt.pkt_rsplen = 0;
11771 
11772                                 /*
11773                                  * If fp_port_id is zero and topology is
11774                                  * Point-to-Point, get the local port id from
11775                                  * the d_id in the PLOGI request.
11776                                  * If the outgoing FLOGI hasn't been accepted,
11777                                  * the topology will be unknown here. But it's
11778                                  * still safe to save the d_id to fp_port_id,
11779                                  * just because it will be overwritten later
11780                                  * if the topology is not Point-to-Point.
11781                                  */
11782                                 mutex_enter(&port->fp_mutex);
11783                                 if ((port->fp_port_id.port_id == 0) &&
11784                                     (port->fp_topology == FC_TOP_PT_PT ||
11785                                     port->fp_topology == FC_TOP_UNKNOWN)) {
11786                                         port->fp_port_id.port_id =
11787                                             buf->ub_frame.d_id;
11788                                 }
11789                                 mutex_exit(&port->fp_mutex);
11790 
11791                                 /*
11792                                  * Sometime later, we should validate
11793                                  * the service parameters instead of
11794                                  * just accepting it.
11795                                  */
11796                                 fp_login_acc_init(port, cmd, buf, NULL,
11797                                     KM_NOSLEEP);
11798                                 FP_TRACE(FP_NHEAD1(3, 0),
11799                                     "fp_i_handle_unsol_els: Accepting PLOGI,"
11800                                     " f_port=%d, small=%d, do_acc=%d,"
11801                                     " sent=%d.", f_port, small, do_acc,
11802                                     sent);
11803                         }
11804                 } else {
11805                         if (FP_IS_CLASS_1_OR_2(buf->ub_class) ||
11806                             port->fp_options & FP_SEND_RJT) {
11807                                 cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_rjt_t);
11808                                 cmd->cmd_pkt.pkt_rsplen = 0;
11809                                 fp_els_rjt_init(port, cmd, buf,
11810                                     FC_ACTION_NON_RETRYABLE,
11811                                     FC_REASON_LOGICAL_BSY, NULL);
11812                                 FP_TRACE(FP_NHEAD1(3, 0),
11813                                     "fp_i_handle_unsol_els: "
11814                                     "Rejecting PLOGI with Logical Busy."
11815                                     "Possible Login collision.");
11816                         } else {
11817                                 mutex_enter(&port->fp_mutex);
11818                                 port->fp_els_resp_pkt_busy = 0;
11819                                 mutex_exit(&port->fp_mutex);
11820                                 return;
11821                         }
11822                 }
11823                 break;
11824         }
11825 
11826         case LA_ELS_FLOGI:
11827                 if (fp_is_class_supported(port->fp_cos,
11828                     buf->ub_class) == FC_FAILURE) {
11829                         if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11830                                 cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_rjt_t);
11831                                 cmd->cmd_pkt.pkt_rsplen = 0;
11832                                 fp_els_rjt_init(port, cmd, buf,
11833                                     FC_ACTION_NON_RETRYABLE,
11834                                     FC_REASON_CLASS_NOT_SUPP, NULL);
11835                                 FP_TRACE(FP_NHEAD1(3, 0),
11836                                     "fp_i_handle_unsol_els: "
11837                                     "Unsupported Class. Rejecting FLOGI.");
11838                         } else {
11839                                 mutex_enter(&port->fp_mutex);
11840                                 port->fp_els_resp_pkt_busy = 0;
11841                                 mutex_exit(&port->fp_mutex);
11842                                 return;
11843                         }
11844                 } else {
11845                         mutex_enter(&port->fp_mutex);
11846                         if (FC_PORT_STATE_MASK(port->fp_state) !=
11847                             FC_STATE_ONLINE || (port->fp_port_id.port_id &&
11848                             buf->ub_frame.s_id == port->fp_port_id.port_id)) {
11849                                 mutex_exit(&port->fp_mutex);
11850                                 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
11851                                         cmd->cmd_pkt.pkt_cmdlen =
11852                                             sizeof (la_els_rjt_t);
11853                                         cmd->cmd_pkt.pkt_rsplen = 0;
11854                                         fp_els_rjt_init(port, cmd, buf,
11855                                             FC_ACTION_NON_RETRYABLE,
11856                                             FC_REASON_INVALID_LINK_CTRL,
11857                                             NULL);
11858                                         FP_TRACE(FP_NHEAD1(3, 0),
11859                                             "fp_i_handle_unsol_els: "
11860                                             "Invalid Link Ctrl. "
11861                                             "Rejecting FLOGI.");
11862                                 } else {
11863                                         mutex_enter(&port->fp_mutex);
11864                                         port->fp_els_resp_pkt_busy = 0;
11865                                         mutex_exit(&port->fp_mutex);
11866                                         return;
11867                                 }
11868                         } else {
11869                                 mutex_exit(&port->fp_mutex);
11870                                 cmd->cmd_pkt.pkt_cmdlen =
11871                                     sizeof (la_els_logi_t);
11872                                 cmd->cmd_pkt.pkt_rsplen = 0;
11873                                 /*
11874                                  * Let's not aggressively validate the N_Port's
11875                                  * service parameters until PLOGI. Suffice it
11876                                  * to give a hint that we are an N_Port and we
11877                                  * are game to some serious stuff here.
11878                                  */
11879                                 fp_login_acc_init(port, cmd, buf,
11880                                     NULL, KM_NOSLEEP);
11881                                 FP_TRACE(FP_NHEAD1(3, 0),
11882                                     "fp_i_handle_unsol_els: "
11883                                     "Accepting FLOGI.");
11884                         }
11885                 }
11886                 break;
11887 
11888         default:
11889                 return;
11890         }
11891 
11892         if ((fp_sendcmd(port, cmd, port->fp_fca_handle)) != FC_SUCCESS) {
11893                 mutex_enter(&port->fp_mutex);
11894                 port->fp_els_resp_pkt_busy = 0;
11895                 mutex_exit(&port->fp_mutex);
11896         }
11897 }
11898 
11899 
11900 /*
11901  * Handle unsolicited PLOGI request
11902  */
11903 static void
11904 fp_handle_unsol_plogi(fc_local_port_t *port, fc_unsol_buf_t *buf,
11905     job_request_t *job, int sleep)
11906 {
11907         int                     sent;
11908         int                     small;
11909         int                     f_port;
11910         int                     do_acc;
11911         fp_cmd_t                *cmd;
11912         la_wwn_t                *swwn;
11913         la_wwn_t                *dwwn;
11914         la_els_logi_t           *payload;
11915         fc_remote_port_t        *pd;
11916         char                    dww_name[17];
11917 
11918         payload = (la_els_logi_t *)buf->ub_buffer;
11919         f_port = FP_IS_F_PORT(payload->common_service.cmn_features) ? 1 : 0;
11920 
11921         mutex_enter(&port->fp_mutex);
11922         do_acc = (port->fp_statec_busy == 0) ? 1 : 0;
11923         mutex_exit(&port->fp_mutex);
11924 
11925         FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_plogi: s_id=%x, d_id=%x,"
11926             "type=%x, f_ctl=%x"
11927             " seq_id=%x, ox_id=%x, rx_id=%x"
11928             " ro=%x", buf->ub_frame.s_id, buf->ub_frame.d_id,
11929             buf->ub_frame.type, buf->ub_frame.f_ctl, buf->ub_frame.seq_id,
11930             buf->ub_frame.ox_id, buf->ub_frame.rx_id, buf->ub_frame.ro);
11931 
11932         swwn = &port->fp_service_params.nport_ww_name;
11933         dwwn = &payload->nport_ww_name;
11934         small = fctl_wwn_cmp(swwn, dwwn);
11935         pd = fctl_get_remote_port_by_pwwn(port, dwwn);
11936         if (pd) {
11937                 mutex_enter(&pd->pd_mutex);
11938                 sent = (pd->pd_flags == PD_ELS_IN_PROGRESS) ? 1 : 0;
11939                 /*
11940                  * Most likely this means a cross login is in
11941                  * progress or a device about to be yanked out.
11942                  * Only accept the plogi if my wwn is smaller.
11943                  */
11944 
11945                 if (pd->pd_type == PORT_DEVICE_OLD) {
11946                         sent = 1;
11947                 }
11948                 /*
11949                  * Stop plogi request (if any)
11950                  * attempt from local side to speedup
11951                  * the discovery progress.
11952                  * Mark the pd as PD_PLOGI_RECEPIENT.
11953                  */
11954                 if (f_port == 0 && small < 0) {
11955                         pd->pd_recepient = PD_PLOGI_RECEPIENT;
11956                 }
11957                 fc_wwn_to_str(&pd->pd_port_name, dww_name);
11958 
11959                 mutex_exit(&pd->pd_mutex);
11960 
11961                 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_plogi: Unsol PLOGI"
11962                     " received. PD still exists in the PWWN list. pd=%p "
11963                     "PWWN=%s, sent=%x", pd, dww_name, sent);
11964 
11965                 if (f_port == 0 && small < 0) {
11966                         FP_TRACE(FP_NHEAD1(3, 0),
11967                             "fp_handle_unsol_plogi: Mark the pd"
11968                             " as plogi recipient, pd=%p, PWWN=%s"
11969                             ", sent=%x",
11970                             pd, dww_name, sent);
11971                 }
11972         } else {
11973                 sent = 0;
11974         }
11975 
11976         /*
11977          * Avoid Login collisions by accepting only if my WWN is smaller.
11978          *
11979          * A side note: There is no need to start a PLOGI from this end in
11980          *      this context if login isn't going to be accepted for the
11981          *      above reason as either a LIP (in private loop), RSCN (in
11982          *      fabric topology), or an FLOGI (in point to point - Huh ?
11983          *      check FC-PH) would normally drive the PLOGI from this end.
11984          *      At this point of time there is no need for an inbound PLOGI
11985          *      to kick an outbound PLOGI when it is going to be rejected
11986          *      for the reason of WWN being smaller. However it isn't hard
11987          *      to do that either (when such a need arises, start a timer
11988          *      for a duration that extends beyond a normal device discovery
11989          *      time and check if an outbound PLOGI did go before that, if
11990          *      none fire one)
11991          *
11992          *      Unfortunately, as it turned out, during booting, it is possible
11993          *      to miss another initiator in the same loop as port driver
11994          *      instances are serially attached. While preserving the above
11995          *      comments for belly laughs, please kick an outbound PLOGI in
11996          *      a non-switch environment (which is a pt pt between N_Ports or
11997          *      a private loop)
11998          *
11999          *      While preserving the above comments for amusement, send an
12000          *      ACC if the PLOGI is going to be rejected for WWN being smaller
12001          *      when no discovery is in progress at this end. Turn around
12002          *      and make the port device as the PLOGI initiator, so that
12003          *      during subsequent link/loop initialization, this end drives
12004          *      the PLOGI (In fact both ends do in this particular case, but
12005          *      only one wins)
12006          *
12007          * Make sure the PLOGIs initiated by the switch from not-so-well-known
12008          * ports (such as 0xFFFC41) are accepted too.
12009          */
12010         if ((f_port == 0 && small < 0) || (((small > 0 && do_acc) ||
12011             FC_MUST_ACCEPT_D_ID(buf->ub_frame.s_id)) && sent == 0)) {
12012                 if (fp_is_class_supported(port->fp_cos,
12013                     buf->ub_class) == FC_FAILURE) {
12014                         if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
12015                                 cmd = fp_alloc_pkt(port,
12016                                     sizeof (la_els_logi_t), 0, sleep, pd);
12017                                 if (cmd == NULL) {
12018                                         return;
12019                                 }
12020                                 cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_rjt_t);
12021                                 cmd->cmd_pkt.pkt_rsplen = 0;
12022                                 fp_els_rjt_init(port, cmd, buf,
12023                                     FC_ACTION_NON_RETRYABLE,
12024                                     FC_REASON_CLASS_NOT_SUPP, job);
12025                                 FP_TRACE(FP_NHEAD1(3, 0),
12026                                     "fp_handle_unsol_plogi: "
12027                                     "Unsupported class. rejecting PLOGI");
12028                         }
12029                 } else {
12030                         cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t),
12031                             0, sleep, pd);
12032                         if (cmd == NULL) {
12033                                 return;
12034                         }
12035                         cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_logi_t);
12036                         cmd->cmd_pkt.pkt_rsplen = 0;
12037 
12038                         /*
12039                          * Sometime later, we should validate the service
12040                          * parameters instead of just accepting it.
12041                          */
12042                         fp_login_acc_init(port, cmd, buf, job, KM_SLEEP);
12043                         FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_plogi: "
12044                             "Accepting PLOGI, f_port=%d, small=%d, "
12045                             "do_acc=%d, sent=%d.", f_port, small, do_acc,
12046                             sent);
12047 
12048                         /*
12049                          * If fp_port_id is zero and topology is
12050                          * Point-to-Point, get the local port id from
12051                          * the d_id in the PLOGI request.
12052                          * If the outgoing FLOGI hasn't been accepted,
12053                          * the topology will be unknown here. But it's
12054                          * still safe to save the d_id to fp_port_id,
12055                          * just because it will be overwritten later
12056                          * if the topology is not Point-to-Point.
12057                          */
12058                         mutex_enter(&port->fp_mutex);
12059                         if ((port->fp_port_id.port_id == 0) &&
12060                             (port->fp_topology == FC_TOP_PT_PT ||
12061                             port->fp_topology == FC_TOP_UNKNOWN)) {
12062                                 port->fp_port_id.port_id =
12063                                     buf->ub_frame.d_id;
12064                         }
12065                         mutex_exit(&port->fp_mutex);
12066                 }
12067         } else {
12068                 if (FP_IS_CLASS_1_OR_2(buf->ub_class) ||
12069                     port->fp_options & FP_SEND_RJT) {
12070                         cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t),
12071                             0, sleep, pd);
12072                         if (cmd == NULL) {
12073                                 return;
12074                         }
12075                         cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_rjt_t);
12076                         cmd->cmd_pkt.pkt_rsplen = 0;
12077                         /*
12078                          * Send out Logical busy to indicate
12079                          * the detection of PLOGI collision
12080                          */
12081                         fp_els_rjt_init(port, cmd, buf,
12082                             FC_ACTION_NON_RETRYABLE,
12083                             FC_REASON_LOGICAL_BSY, job);
12084 
12085                         fc_wwn_to_str(dwwn, dww_name);
12086                         FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_plogi: "
12087                             "Rejecting Unsol PLOGI with Logical Busy."
12088                             "possible PLOGI collision. PWWN=%s, sent=%x",
12089                             dww_name, sent);
12090                 } else {
12091                         return;
12092                 }
12093         }
12094 
12095         if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
12096                 fp_free_pkt(cmd);
12097         }
12098 }
12099 
12100 
12101 /*
12102  * Handle mischievous turning over of our own FLOGI requests back to
12103  * us by the SOC+ microcode. In other words, look at the class of such
12104  * bone headed requests, if 1 or 2, bluntly P_RJT them, if 3 drop them
12105  * on the floor
12106  */
12107 static void
12108 fp_handle_unsol_flogi(fc_local_port_t *port, fc_unsol_buf_t *buf,
12109     job_request_t *job, int sleep)
12110 {
12111         uint32_t        state;
12112         uint32_t        s_id;
12113         fp_cmd_t        *cmd;
12114 
12115         if (fp_is_class_supported(port->fp_cos, buf->ub_class) == FC_FAILURE) {
12116                 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
12117                         cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t),
12118                             0, sleep, NULL);
12119                         if (cmd == NULL) {
12120                                 return;
12121                         }
12122                         fp_els_rjt_init(port, cmd, buf,
12123                             FC_ACTION_NON_RETRYABLE,
12124                             FC_REASON_CLASS_NOT_SUPP, job);
12125                 } else {
12126                         return;
12127                 }
12128         } else {
12129 
12130                 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_flogi:"
12131                     " s_id=%x, d_id=%x, type=%x, f_ctl=%x"
12132                     " seq_id=%x, ox_id=%x, rx_id=%x, ro=%x",
12133                     buf->ub_frame.s_id, buf->ub_frame.d_id,
12134                     buf->ub_frame.type, buf->ub_frame.f_ctl,
12135                     buf->ub_frame.seq_id, buf->ub_frame.ox_id,
12136                     buf->ub_frame.rx_id, buf->ub_frame.ro);
12137 
12138                 mutex_enter(&port->fp_mutex);
12139                 state = FC_PORT_STATE_MASK(port->fp_state);
12140                 s_id = port->fp_port_id.port_id;
12141                 mutex_exit(&port->fp_mutex);
12142 
12143                 if (state != FC_STATE_ONLINE ||
12144                     (s_id && buf->ub_frame.s_id == s_id)) {
12145                         if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
12146                                 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t),
12147                                     0, sleep, NULL);
12148                                 if (cmd == NULL) {
12149                                         return;
12150                                 }
12151                                 fp_els_rjt_init(port, cmd, buf,
12152                                     FC_ACTION_NON_RETRYABLE,
12153                                     FC_REASON_INVALID_LINK_CTRL, job);
12154                                 FP_TRACE(FP_NHEAD1(3, 0),
12155                                     "fp_handle_unsol_flogi: "
12156                                     "Rejecting PLOGI. Invalid Link CTRL");
12157                         } else {
12158                                 return;
12159                         }
12160                 } else {
12161                         cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t),
12162                             0, sleep, NULL);
12163                         if (cmd == NULL) {
12164                                 return;
12165                         }
12166                         /*
12167                          * Let's not aggressively validate the N_Port's
12168                          * service parameters until PLOGI. Suffice it
12169                          * to give a hint that we are an N_Port and we
12170                          * are game to some serious stuff here.
12171                          */
12172                         fp_login_acc_init(port, cmd, buf, job, KM_SLEEP);
12173                         FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_flogi: "
12174                             "Accepting PLOGI");
12175                 }
12176         }
12177 
12178         if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
12179                 fp_free_pkt(cmd);
12180         }
12181 }
12182 
12183 
12184 /*
12185  * Perform PLOGI accept
12186  */
12187 static void
12188 fp_login_acc_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf,
12189     job_request_t *job, int sleep)
12190 {
12191         fc_packet_t     *pkt;
12192         fc_portmap_t    *listptr;
12193         la_els_logi_t   payload;
12194 
12195         ASSERT(buf != NULL);
12196 
12197         /*
12198          * If we are sending ACC to PLOGI and we haven't already
12199          * create port and node device handles, let's create them
12200          * here.
12201          */
12202         if (buf->ub_buffer[0] == LA_ELS_PLOGI &&
12203             FC_IS_REAL_DEVICE(buf->ub_frame.s_id)) {
12204                 int                     small;
12205                 int                     do_acc;
12206                 fc_remote_port_t        *pd;
12207                 la_els_logi_t           *req;
12208 
12209                 req = (la_els_logi_t *)buf->ub_buffer;
12210                 small = fctl_wwn_cmp(&port->fp_service_params.nport_ww_name,
12211                     &req->nport_ww_name);
12212 
12213                 mutex_enter(&port->fp_mutex);
12214                 do_acc = (port->fp_statec_busy == 0) ? 1 : 0;
12215                 mutex_exit(&port->fp_mutex);
12216 
12217                 FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_acc_init fp %x, pd %x",
12218                     port->fp_port_id.port_id, buf->ub_frame.s_id);
12219                 pd = fctl_create_remote_port(port, &req->node_ww_name,
12220                     &req->nport_ww_name, buf->ub_frame.s_id,
12221                     PD_PLOGI_RECEPIENT, sleep);
12222                 if (pd == NULL) {
12223                         FP_TRACE(FP_NHEAD1(3, 0), "login_acc_init: "
12224                             "Couldn't create port device for d_id:0x%x",
12225                             buf->ub_frame.s_id);
12226 
12227                         fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
12228                             "couldn't create port device d_id=%x",
12229                             buf->ub_frame.s_id);
12230                 } else {
12231                         /*
12232                          * usoc currently returns PLOGIs inline and
12233                          * the maximum buffer size is 60 bytes or so.
12234                          * So attempt not to look beyond what is in
12235                          * the unsolicited buffer
12236                          *
12237                          * JNI also traverses this path sometimes
12238                          */
12239                         if (buf->ub_bufsize >= sizeof (la_els_logi_t)) {
12240                                 fp_register_login(NULL, pd, req, buf->ub_class);
12241                         } else {
12242                                 mutex_enter(&pd->pd_mutex);
12243                                 if (pd->pd_login_count == 0) {
12244                                         pd->pd_login_count++;
12245                                 }
12246                                 pd->pd_state = PORT_DEVICE_LOGGED_IN;
12247                                 pd->pd_login_class = buf->ub_class;
12248                                 mutex_exit(&pd->pd_mutex);
12249                         }
12250 
12251                         listptr = kmem_zalloc(sizeof (fc_portmap_t), sleep);
12252                         if (listptr != NULL) {
12253                                 fctl_copy_portmap(listptr, pd);
12254                                 (void) fp_ulp_devc_cb(port, listptr,
12255                                     1, 1, sleep, 0);
12256                         }
12257 
12258                         if (small > 0 && do_acc) {
12259                                 mutex_enter(&pd->pd_mutex);
12260                                 pd->pd_recepient = PD_PLOGI_INITIATOR;
12261                                 mutex_exit(&pd->pd_mutex);
12262                         }
12263                 }
12264         }
12265 
12266         cmd->cmd_pkt.pkt_tran_flags = buf->ub_class;
12267         cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND;
12268         cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
12269         cmd->cmd_retry_count = 1;
12270         cmd->cmd_ulp_pkt = NULL;
12271 
12272         cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
12273         cmd->cmd_job = job;
12274 
12275         pkt = &cmd->cmd_pkt;
12276 
12277         fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP, FC_TYPE_EXTENDED_LS);
12278 
12279         payload = port->fp_service_params;
12280         payload.ls_code.ls_code = LA_ELS_ACC;
12281 
12282         FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
12283             (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
12284 
12285         FP_TRACE(FP_NHEAD1(3, 0), "login_acc_init: ELS:0x%x d_id:0x%x "
12286             "bufsize:0x%x sizeof (la_els_logi):0x%x "
12287             "port's wwn:0x%01x%03x%04x%08x requestor's wwn:0x%01x%03x%04x%08x "
12288             "statec_busy:0x%x", buf->ub_buffer[0], buf->ub_frame.s_id,
12289             buf->ub_bufsize, sizeof (la_els_logi_t),
12290             port->fp_service_params.nport_ww_name.w.naa_id,
12291             port->fp_service_params.nport_ww_name.w.nport_id,
12292             port->fp_service_params.nport_ww_name.w.wwn_hi,
12293             port->fp_service_params.nport_ww_name.w.wwn_lo,
12294             ((la_els_logi_t *)buf->ub_buffer)->nport_ww_name.w.naa_id,
12295             ((la_els_logi_t *)buf->ub_buffer)->nport_ww_name.w.nport_id,
12296             ((la_els_logi_t *)buf->ub_buffer)->nport_ww_name.w.wwn_hi,
12297             ((la_els_logi_t *)buf->ub_buffer)->nport_ww_name.w.wwn_lo,
12298             port->fp_statec_busy);
12299 }
12300 
12301 
12302 #define RSCN_EVENT_NAME_LEN     256
12303 
12304 /*
12305  * Handle RSCNs
12306  */
12307 static void
12308 fp_handle_unsol_rscn(fc_local_port_t *port, fc_unsol_buf_t *buf,
12309     job_request_t *job, int sleep)
12310 {
12311         uint32_t                mask;
12312         fp_cmd_t                *cmd;
12313         uint32_t                count;
12314         int                     listindex;
12315         int16_t                 len;
12316         fc_rscn_t               *payload;
12317         fc_portmap_t            *listptr;
12318         fctl_ns_req_t           *ns_cmd;
12319         fc_affected_id_t        *page;
12320         caddr_t                 nvname;
12321         nvlist_t                *attr_list = NULL;
12322 
12323         mutex_enter(&port->fp_mutex);
12324         if (!FC_IS_TOP_SWITCH(port->fp_topology)) {
12325                 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
12326                         --port->fp_rscn_count;
12327                 }
12328                 mutex_exit(&port->fp_mutex);
12329                 return;
12330         }
12331         mutex_exit(&port->fp_mutex);
12332 
12333         cmd = fp_alloc_pkt(port, FP_PORT_IDENTIFIER_LEN, 0, sleep, NULL);
12334         if (cmd != NULL) {
12335                 fp_els_acc_init(port, cmd, buf, job);
12336                 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
12337                         fp_free_pkt(cmd);
12338                 }
12339         }
12340 
12341         payload = (fc_rscn_t *)buf->ub_buffer;
12342         ASSERT(payload->rscn_code == LA_ELS_RSCN);
12343         ASSERT(payload->rscn_len == FP_PORT_IDENTIFIER_LEN);
12344 
12345         len = payload->rscn_payload_len - FP_PORT_IDENTIFIER_LEN;
12346 
12347         if (len <= 0) {
12348                 mutex_enter(&port->fp_mutex);
12349                 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
12350                         --port->fp_rscn_count;
12351                 }
12352                 mutex_exit(&port->fp_mutex);
12353 
12354                 return;
12355         }
12356 
12357         ASSERT((len & 0x3) == 0);   /* Must be power of 4 */
12358         count = (len >> 2) << 1;    /* number of pages multiplied by 2 */
12359 
12360         listptr = kmem_zalloc(sizeof (fc_portmap_t) * count, sleep);
12361         page = (fc_affected_id_t *)(buf->ub_buffer + sizeof (fc_rscn_t));
12362 
12363         ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
12364 
12365         ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gpn_id_t),
12366             sizeof (ns_resp_gpn_id_t), sizeof (ns_resp_gpn_id_t),
12367             0, sleep);
12368         if (ns_cmd == NULL) {
12369                 kmem_free(listptr, sizeof (fc_portmap_t) * count);
12370 
12371                 mutex_enter(&port->fp_mutex);
12372                 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
12373                         --port->fp_rscn_count;
12374                 }
12375                 mutex_exit(&port->fp_mutex);
12376 
12377                 return;
12378         }
12379 
12380         ns_cmd->ns_cmd_code = NS_GPN_ID;
12381 
12382         FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_rscn: s_id=%x, d_id=%x,"
12383             "type=%x, f_ctl=%x seq_id=%x, ox_id=%x, rx_id=%x"
12384             " ro=%x", buf->ub_frame.s_id, buf->ub_frame.d_id,
12385             buf->ub_frame.type, buf->ub_frame.f_ctl, buf->ub_frame.seq_id,
12386             buf->ub_frame.ox_id, buf->ub_frame.rx_id, buf->ub_frame.ro);
12387 
12388         /* Only proceed if we can allocate nvname and the nvlist */
12389         if ((nvname = kmem_zalloc(RSCN_EVENT_NAME_LEN, KM_NOSLEEP)) != NULL &&
12390             nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE,
12391             KM_NOSLEEP) == DDI_SUCCESS) {
12392                 if (!(attr_list && nvlist_add_uint32(attr_list, "instance",
12393                     port->fp_instance) == DDI_SUCCESS &&
12394                     nvlist_add_byte_array(attr_list, "port-wwn",
12395                     port->fp_service_params.nport_ww_name.raw_wwn,
12396                     sizeof (la_wwn_t)) == DDI_SUCCESS)) {
12397                         nvlist_free(attr_list);
12398                         attr_list = NULL;
12399                 }
12400         }
12401 
12402         for (listindex = 0; len; len -= FP_PORT_IDENTIFIER_LEN, page++) {
12403                 /* Add affected page to the event payload */
12404                 if (attr_list != NULL) {
12405                         (void) snprintf(nvname, RSCN_EVENT_NAME_LEN,
12406                             "affected_page_%d", listindex);
12407                         if (attr_list && nvlist_add_uint32(attr_list, nvname,
12408                             ntohl(*(uint32_t *)page)) != DDI_SUCCESS) {
12409                                 /* We don't send a partial event, so dump it */
12410                                 nvlist_free(attr_list);
12411                                 attr_list = NULL;
12412                         }
12413                 }
12414                 /*
12415                  * Query the NS to get the Port WWN for this
12416                  * affected D_ID.
12417                  */
12418                 mask = 0;
12419                 switch (page->aff_format & FC_RSCN_ADDRESS_MASK) {
12420                 case FC_RSCN_PORT_ADDRESS:
12421                         fp_validate_rscn_page(port, page, job, ns_cmd,
12422                             listptr, &listindex, sleep);
12423 
12424                         if (listindex == 0) {
12425                                 /*
12426                                  * We essentially did not process this RSCN. So,
12427                                  * ULPs are not going to be called and so we
12428                                  * decrement the rscn_count
12429                                  */
12430                                 mutex_enter(&port->fp_mutex);
12431                                 if (--port->fp_rscn_count ==
12432                                     FC_INVALID_RSCN_COUNT) {
12433                                         --port->fp_rscn_count;
12434                                 }
12435                                 mutex_exit(&port->fp_mutex);
12436                         }
12437                         break;
12438 
12439                 case FC_RSCN_AREA_ADDRESS:
12440                         mask = 0xFFFF00;
12441                         /* FALLTHROUGH */
12442 
12443                 case FC_RSCN_DOMAIN_ADDRESS:
12444                         if (!mask) {
12445                                 mask = 0xFF0000;
12446                         }
12447                         fp_validate_area_domain(port, page->aff_d_id, mask,
12448                             job, sleep);
12449                         break;
12450 
12451                 case FC_RSCN_FABRIC_ADDRESS:
12452                         /*
12453                          * We need to discover all the devices on this
12454                          * port.
12455                          */
12456                         fp_validate_area_domain(port, 0, 0, job, sleep);
12457                         break;
12458 
12459                 default:
12460                         break;
12461                 }
12462         }
12463         if (attr_list != NULL) {
12464                 (void) ddi_log_sysevent(port->fp_port_dip, DDI_VENDOR_SUNW,
12465                     EC_SUNFC, ESC_SUNFC_PORT_RSCN, attr_list,
12466                     NULL, DDI_SLEEP);
12467                 nvlist_free(attr_list);
12468         } else {
12469                 FP_TRACE(FP_NHEAD1(9, 0),
12470                     "RSCN handled, but event not sent to userland");
12471         }
12472         if (nvname != NULL) {
12473                 kmem_free(nvname, RSCN_EVENT_NAME_LEN);
12474         }
12475 
12476         if (ns_cmd) {
12477                 fctl_free_ns_cmd(ns_cmd);
12478         }
12479 
12480         if (listindex) {
12481 #ifdef  DEBUG
12482                 page = (fc_affected_id_t *)(buf->ub_buffer +
12483                     sizeof (fc_rscn_t));
12484 
12485                 if (listptr->map_did.port_id != page->aff_d_id) {
12486                         FP_TRACE(FP_NHEAD1(9, 0),
12487                             "PORT RSCN: processed=%x, reporting=%x",
12488                             listptr->map_did.port_id, page->aff_d_id);
12489                 }
12490 #endif
12491 
12492                 (void) fp_ulp_devc_cb(port, listptr, listindex, count,
12493                     sleep, 0);
12494         } else {
12495                 kmem_free(listptr, sizeof (fc_portmap_t) * count);
12496         }
12497 }
12498 
12499 
12500 /*
12501  * Fill out old map for ULPs with fp_mutex, fd_mutex and pd_mutex held
12502  */
12503 static void
12504 fp_fillout_old_map_held(fc_portmap_t *map, fc_remote_port_t *pd, uchar_t flag)
12505 {
12506         int             is_switch;
12507         int             initiator;
12508         fc_local_port_t *port;
12509 
12510         port = pd->pd_port;
12511 
12512         /* This function has the following bunch of assumptions */
12513         ASSERT(port != NULL);
12514         ASSERT(MUTEX_HELD(&port->fp_mutex));
12515         ASSERT(MUTEX_HELD(&pd->pd_remote_nodep->fd_mutex));
12516         ASSERT(MUTEX_HELD(&pd->pd_mutex));
12517 
12518         pd->pd_state = PORT_DEVICE_INVALID;
12519         pd->pd_type = PORT_DEVICE_OLD;
12520         initiator = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0;
12521         is_switch = FC_IS_TOP_SWITCH(port->fp_topology);
12522 
12523         fctl_delist_did_table(port, pd);
12524         fctl_delist_pwwn_table(port, pd);
12525 
12526         FP_TRACE(FP_NHEAD1(6, 0), "fp_fillout_old_map_held: port=%p, d_id=%x"
12527             " removed the PD=%p from DID and PWWN tables",
12528             port, pd->pd_port_id.port_id, pd);
12529 
12530         if ((!flag) && port && initiator && is_switch) {
12531                 (void) fctl_add_orphan_held(port, pd);
12532         }
12533         fctl_copy_portmap_held(map, pd);
12534         map->map_pd = pd;
12535 }
12536 
12537 /*
12538  * Fill out old map for ULPs
12539  */
12540 static void
12541 fp_fillout_old_map(fc_portmap_t *map, fc_remote_port_t *pd, uchar_t flag)
12542 {
12543         int             is_switch;
12544         int             initiator;
12545         fc_local_port_t *port;
12546 
12547         mutex_enter(&pd->pd_mutex);
12548         port = pd->pd_port;
12549         mutex_exit(&pd->pd_mutex);
12550 
12551         mutex_enter(&port->fp_mutex);
12552         mutex_enter(&pd->pd_mutex);
12553 
12554         pd->pd_state = PORT_DEVICE_INVALID;
12555         pd->pd_type = PORT_DEVICE_OLD;
12556         initiator = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0;
12557         is_switch = FC_IS_TOP_SWITCH(port->fp_topology);
12558 
12559         fctl_delist_did_table(port, pd);
12560         fctl_delist_pwwn_table(port, pd);
12561 
12562         FP_TRACE(FP_NHEAD1(6, 0), "fp_fillout_old_map: port=%p, d_id=%x"
12563             " removed the PD=%p from DID and PWWN tables",
12564             port, pd->pd_port_id.port_id, pd);
12565 
12566         mutex_exit(&pd->pd_mutex);
12567         mutex_exit(&port->fp_mutex);
12568 
12569         ASSERT(port != NULL);
12570         if ((!flag) && port && initiator && is_switch) {
12571                 (void) fctl_add_orphan(port, pd, KM_NOSLEEP);
12572         }
12573         fctl_copy_portmap(map, pd);
12574         map->map_pd = pd;
12575 }
12576 
12577 
12578 /*
12579  * Fillout Changed Map for ULPs
12580  */
12581 static void
12582 fp_fillout_changed_map(fc_portmap_t *map, fc_remote_port_t *pd,
12583     uint32_t *new_did, la_wwn_t *new_pwwn)
12584 {
12585         ASSERT(MUTEX_HELD(&pd->pd_mutex));
12586 
12587         pd->pd_type = PORT_DEVICE_CHANGED;
12588         if (new_did) {
12589                 pd->pd_port_id.port_id = *new_did;
12590         }
12591         if (new_pwwn) {
12592                 pd->pd_port_name = *new_pwwn;
12593         }
12594         mutex_exit(&pd->pd_mutex);
12595 
12596         fctl_copy_portmap(map, pd);
12597 
12598         mutex_enter(&pd->pd_mutex);
12599         pd->pd_type = PORT_DEVICE_NOCHANGE;
12600 }
12601 
12602 
12603 /*
12604  * Fillout New Name Server map
12605  */
12606 static void
12607 fp_fillout_new_nsmap(fc_local_port_t *port, ddi_acc_handle_t *handle,
12608     fc_portmap_t *port_map, ns_resp_gan_t *gan_resp, uint32_t d_id)
12609 {
12610         ASSERT(!MUTEX_HELD(&port->fp_mutex));
12611 
12612         if (handle) {
12613                 FC_GET_RSP(port, *handle, (uint8_t *)&port_map->map_pwwn,
12614                     (uint8_t *)&gan_resp->gan_pwwn, sizeof (gan_resp->gan_pwwn),
12615                     DDI_DEV_AUTOINCR);
12616                 FC_GET_RSP(port, *handle, (uint8_t *)&port_map->map_nwwn,
12617                     (uint8_t *)&gan_resp->gan_nwwn, sizeof (gan_resp->gan_nwwn),
12618                     DDI_DEV_AUTOINCR);
12619                 FC_GET_RSP(port, *handle, (uint8_t *)port_map->map_fc4_types,
12620                     (uint8_t *)gan_resp->gan_fc4types,
12621                     sizeof (gan_resp->gan_fc4types), DDI_DEV_AUTOINCR);
12622         } else {
12623                 bcopy(&gan_resp->gan_pwwn, &port_map->map_pwwn,
12624                     sizeof (gan_resp->gan_pwwn));
12625                 bcopy(&gan_resp->gan_nwwn, &port_map->map_nwwn,
12626                     sizeof (gan_resp->gan_nwwn));
12627                 bcopy(gan_resp->gan_fc4types, port_map->map_fc4_types,
12628                     sizeof (gan_resp->gan_fc4types));
12629         }
12630         port_map->map_did.port_id = d_id;
12631         port_map->map_did.priv_lilp_posit = 0;
12632         port_map->map_hard_addr.hard_addr = 0;
12633         port_map->map_hard_addr.rsvd = 0;
12634         port_map->map_state = PORT_DEVICE_INVALID;
12635         port_map->map_type = PORT_DEVICE_NEW;
12636         port_map->map_flags = 0;
12637         port_map->map_pd = NULL;
12638 
12639         (void) fctl_remove_if_orphan(port, &port_map->map_pwwn);
12640 
12641         ASSERT(port != NULL);
12642 }
12643 
12644 
12645 /*
12646  * Perform LINIT ELS
12647  */
12648 static int
12649 fp_remote_lip(fc_local_port_t *port, la_wwn_t *pwwn, int sleep,
12650     job_request_t *job)
12651 {
12652         int                     rval;
12653         uint32_t                d_id;
12654         uint32_t                s_id;
12655         uint32_t                lfa;
12656         uchar_t                 class;
12657         uint32_t                ret;
12658         fp_cmd_t                *cmd;
12659         fc_porttype_t           ptype;
12660         fc_packet_t             *pkt;
12661         fc_linit_req_t          payload;
12662         fc_remote_port_t        *pd;
12663 
12664         rval = 0;
12665 
12666         ASSERT(job != NULL);
12667         ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
12668 
12669         pd = fctl_get_remote_port_by_pwwn(port, pwwn);
12670         if (pd == NULL) {
12671                 fctl_ns_req_t *ns_cmd;
12672 
12673                 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t),
12674                     sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t),
12675                     0, sleep);
12676 
12677                 if (ns_cmd == NULL) {
12678                         return (FC_NOMEM);
12679                 }
12680                 job->job_result = FC_SUCCESS;
12681                 ns_cmd->ns_cmd_code = NS_GID_PN;
12682                 ((ns_req_gid_pn_t *)(ns_cmd->ns_cmd_buf))->pwwn = *pwwn;
12683 
12684                 ret = fp_ns_query(port, ns_cmd, job, 1, sleep);
12685                 if (ret != FC_SUCCESS || job->job_result != FC_SUCCESS) {
12686                         fctl_free_ns_cmd(ns_cmd);
12687                         return (FC_FAILURE);
12688                 }
12689                 bcopy(ns_cmd->ns_data_buf, (caddr_t)&d_id, sizeof (d_id));
12690                 d_id = BE_32(*((uint32_t *)ns_cmd->ns_data_buf));
12691 
12692                 fctl_free_ns_cmd(ns_cmd);
12693                 lfa = d_id & 0xFFFF00;
12694 
12695                 /*
12696                  * Given this D_ID, get the port type to see if
12697                  * we can do LINIT on the LFA
12698                  */
12699                 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gpt_id_t),
12700                     sizeof (ns_resp_gpt_id_t), sizeof (ns_resp_gpt_id_t),
12701                     0, sleep);
12702 
12703                 if (ns_cmd == NULL) {
12704                         return (FC_NOMEM);
12705                 }
12706 
12707                 job->job_result = FC_SUCCESS;
12708                 ns_cmd->ns_cmd_code = NS_GPT_ID;
12709 
12710                 ((ns_req_gpt_id_t *)(ns_cmd->ns_cmd_buf))->pid.port_id = d_id;
12711                 ((ns_req_gpt_id_t *)
12712                     (ns_cmd->ns_cmd_buf))->pid.priv_lilp_posit = 0;
12713 
12714                 ret = fp_ns_query(port, ns_cmd, job, 1, sleep);
12715                 if (ret != FC_SUCCESS || job->job_result != FC_SUCCESS) {
12716                         fctl_free_ns_cmd(ns_cmd);
12717                         return (FC_FAILURE);
12718                 }
12719                 bcopy(ns_cmd->ns_data_buf, (caddr_t)&ptype, sizeof (ptype));
12720 
12721                 fctl_free_ns_cmd(ns_cmd);
12722 
12723                 switch (ptype.port_type) {
12724                 case FC_NS_PORT_NL:
12725                 case FC_NS_PORT_F_NL:
12726                 case FC_NS_PORT_FL:
12727                         break;
12728 
12729                 default:
12730                         return (FC_FAILURE);
12731                 }
12732         } else {
12733                 mutex_enter(&pd->pd_mutex);
12734                 ptype = pd->pd_porttype;
12735 
12736                 switch (pd->pd_porttype.port_type) {
12737                 case FC_NS_PORT_NL:
12738                 case FC_NS_PORT_F_NL:
12739                 case FC_NS_PORT_FL:
12740                         lfa = pd->pd_port_id.port_id & 0xFFFF00;
12741                         break;
12742 
12743                 default:
12744                         mutex_exit(&pd->pd_mutex);
12745                         return (FC_FAILURE);
12746                 }
12747                 mutex_exit(&pd->pd_mutex);
12748         }
12749 
12750         mutex_enter(&port->fp_mutex);
12751         s_id = port->fp_port_id.port_id;
12752         class = port->fp_ns_login_class;
12753         mutex_exit(&port->fp_mutex);
12754 
12755         cmd = fp_alloc_pkt(port, sizeof (fc_linit_req_t),
12756             sizeof (fc_linit_resp_t), sleep, pd);
12757         if (cmd == NULL) {
12758                 return (FC_NOMEM);
12759         }
12760 
12761         cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class;
12762         cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
12763         cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
12764         cmd->cmd_retry_count = fp_retry_count;
12765         cmd->cmd_ulp_pkt = NULL;
12766 
12767         pkt = &cmd->cmd_pkt;
12768         cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
12769 
12770         fp_els_init(cmd, s_id, lfa, fp_linit_intr, job);
12771 
12772         /*
12773          * How does LIP work by the way ?
12774          *      If the L_Port receives three consecutive identical ordered
12775          *      sets whose first two characters (fully decoded) are equal to
12776          *      the values shown in Table 3 of FC-AL-2 then the L_Port shall
12777          *      recognize a Loop Initialization Primitive sequence. The
12778          *      character 3 determines the type of lip:
12779          *              LIP(F7)         Normal LIP
12780          *              LIP(F8)         Loop Failure LIP
12781          *
12782          * The possible combination for the 3rd and 4th bytes are:
12783          *      F7,     F7      Normal Lip      - No valid AL_PA
12784          *      F8,     F8      Loop Failure    - No valid AL_PA
12785          *      F7,     AL_PS   Normal Lip      - Valid source AL_PA
12786          *      F8,     AL_PS   Loop Failure    - Valid source AL_PA
12787          *      AL_PD   AL_PS   Loop reset of AL_PD originated by AL_PS
12788          *                      And Normal Lip for all other loop members
12789          *      0xFF    AL_PS   Vendor specific reset of all loop members
12790          *
12791          * Now, it may not always be that we, at the source, may have an
12792          * AL_PS (AL_PA of source) for 4th character slot, so we decide
12793          * to do (Normal Lip, No Valid AL_PA), that means, in the LINIT
12794          * payload we are going to set:
12795          *      lip_b3 = 0xF7;          Normal LIP
12796          *      lip_b4 = 0xF7;          No valid source AL_PA
12797          */
12798         payload.ls_code.ls_code = LA_ELS_LINIT;
12799         payload.ls_code.mbz = 0;
12800         payload.rsvd = 0;
12801         payload.func = 0;               /* Let Fabric determine the best way */
12802         payload.lip_b3 = 0xF7;          /* Normal LIP */
12803         payload.lip_b4 = 0xF7;          /* No valid source AL_PA */
12804 
12805         FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
12806             (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
12807 
12808         job->job_counter = 1;
12809 
12810         ret = fp_sendcmd(port, cmd, port->fp_fca_handle);
12811         if (ret == FC_SUCCESS) {
12812                 fp_jobwait(job);
12813                 rval = job->job_result;
12814         } else {
12815                 rval = FC_FAILURE;
12816                 fp_free_pkt(cmd);
12817         }
12818 
12819         return (rval);
12820 }
12821 
12822 
12823 /*
12824  * Fill out the device handles with GAN response
12825  */
12826 static void
12827 fp_stuff_device_with_gan(ddi_acc_handle_t *handle, fc_remote_port_t *pd,
12828     ns_resp_gan_t *gan_resp)
12829 {
12830         fc_remote_node_t        *node;
12831         fc_porttype_t           type;
12832         fc_local_port_t         *port;
12833 
12834         ASSERT(pd != NULL);
12835         ASSERT(handle != NULL);
12836 
12837         port = pd->pd_port;
12838 
12839         FP_TRACE(FP_NHEAD1(1, 0), "GAN PD stuffing; pd=%p,"
12840             " port_id=%x, sym_len=%d fc4-type=%x",
12841             pd, gan_resp->gan_type_id.rsvd,
12842             gan_resp->gan_spnlen, gan_resp->gan_fc4types[0]);
12843 
12844         mutex_enter(&pd->pd_mutex);
12845 
12846         FC_GET_RSP(port, *handle, (uint8_t *)&type,
12847             (uint8_t *)&gan_resp->gan_type_id, sizeof (type), DDI_DEV_AUTOINCR);
12848 
12849         pd->pd_porttype.port_type = type.port_type;
12850         pd->pd_porttype.rsvd = 0;
12851 
12852         pd->pd_spn_len = gan_resp->gan_spnlen;
12853         if (pd->pd_spn_len) {
12854                 FC_GET_RSP(port, *handle, (uint8_t *)pd->pd_spn,
12855                     (uint8_t *)gan_resp->gan_spname, pd->pd_spn_len,
12856                     DDI_DEV_AUTOINCR);
12857         }
12858 
12859         FC_GET_RSP(port, *handle, (uint8_t *)pd->pd_ip_addr,
12860             (uint8_t *)gan_resp->gan_ip, sizeof (pd->pd_ip_addr),
12861             DDI_DEV_AUTOINCR);
12862         FC_GET_RSP(port, *handle, (uint8_t *)&pd->pd_cos,
12863             (uint8_t *)&gan_resp->gan_cos, sizeof (pd->pd_cos),
12864             DDI_DEV_AUTOINCR);
12865         FC_GET_RSP(port, *handle, (uint8_t *)pd->pd_fc4types,
12866             (uint8_t *)gan_resp->gan_fc4types, sizeof (pd->pd_fc4types),
12867             DDI_DEV_AUTOINCR);
12868 
12869         node = pd->pd_remote_nodep;
12870         mutex_exit(&pd->pd_mutex);
12871 
12872         mutex_enter(&node->fd_mutex);
12873 
12874         FC_GET_RSP(port, *handle, (uint8_t *)node->fd_ipa,
12875             (uint8_t *)gan_resp->gan_ipa, sizeof (node->fd_ipa),
12876             DDI_DEV_AUTOINCR);
12877 
12878         node->fd_snn_len = gan_resp->gan_snnlen;
12879         if (node->fd_snn_len) {
12880                 FC_GET_RSP(port, *handle, (uint8_t *)node->fd_snn,
12881                     (uint8_t *)gan_resp->gan_snname, node->fd_snn_len,
12882                     DDI_DEV_AUTOINCR);
12883         }
12884 
12885         mutex_exit(&node->fd_mutex);
12886 }
12887 
12888 
12889 /*
12890  * Handles all NS Queries (also means that this function
12891  * doesn't handle NS object registration)
12892  */
12893 static int
12894 fp_ns_query(fc_local_port_t *port, fctl_ns_req_t *ns_cmd, job_request_t *job,
12895     int polled, int sleep)
12896 {
12897         int             rval;
12898         fp_cmd_t        *cmd;
12899 
12900         ASSERT(!MUTEX_HELD(&port->fp_mutex));
12901 
12902         if (ns_cmd->ns_cmd_code == NS_GA_NXT) {
12903                 FP_TRACE(FP_NHEAD1(1, 0), "fp_ns_query GA_NXT fp %x pd %x",
12904                     port->fp_port_id.port_id, ns_cmd->ns_gan_sid);
12905         }
12906 
12907         if (ns_cmd->ns_cmd_size == 0) {
12908                 return (FC_FAILURE);
12909         }
12910 
12911         cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) +
12912             ns_cmd->ns_cmd_size, sizeof (fc_ct_header_t) +
12913             ns_cmd->ns_resp_size, sleep, NULL);
12914         if (cmd == NULL) {
12915                 return (FC_NOMEM);
12916         }
12917 
12918         fp_ct_init(port, cmd, ns_cmd, ns_cmd->ns_cmd_code, ns_cmd->ns_cmd_buf,
12919             ns_cmd->ns_cmd_size, ns_cmd->ns_resp_size, job);
12920 
12921         if (polled) {
12922                 job->job_counter = 1;
12923                 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
12924         }
12925         rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
12926         if (rval != FC_SUCCESS) {
12927                 job->job_result = rval;
12928                 fp_iodone(cmd);
12929                 if (polled == 0) {
12930                         /*
12931                          * Return FC_SUCCESS to indicate that
12932                          * fp_iodone is performed already.
12933                          */
12934                         rval = FC_SUCCESS;
12935                 }
12936         }
12937 
12938         if (polled) {
12939                 fp_jobwait(job);
12940                 rval = job->job_result;
12941         }
12942 
12943         return (rval);
12944 }
12945 
12946 
12947 /*
12948  * Initialize Common Transport request
12949  */
12950 static void
12951 fp_ct_init(fc_local_port_t *port, fp_cmd_t *cmd, fctl_ns_req_t *ns_cmd,
12952     uint16_t cmd_code, caddr_t cmd_buf, uint16_t cmd_len,
12953     uint16_t resp_len, job_request_t *job)
12954 {
12955         uint32_t        s_id;
12956         uchar_t         class;
12957         fc_packet_t     *pkt;
12958         fc_ct_header_t  ct;
12959 
12960         ASSERT(!MUTEX_HELD(&port->fp_mutex));
12961 
12962         mutex_enter(&port->fp_mutex);
12963         s_id = port->fp_port_id.port_id;
12964         class = port->fp_ns_login_class;
12965         mutex_exit(&port->fp_mutex);
12966 
12967         cmd->cmd_job = job;
12968         cmd->cmd_private = ns_cmd;
12969         pkt = &cmd->cmd_pkt;
12970 
12971         ct.ct_rev = CT_REV;
12972         ct.ct_inid = 0;
12973         ct.ct_fcstype = FCSTYPE_DIRECTORY;
12974         ct.ct_fcssubtype = FCSSUB_DS_NAME_SERVER;
12975         ct.ct_options = 0;
12976         ct.ct_reserved1 = 0;
12977         ct.ct_cmdrsp = cmd_code;
12978         ct.ct_aiusize = resp_len >> 2;
12979         ct.ct_reserved2 = 0;
12980         ct.ct_reason = 0;
12981         ct.ct_expln = 0;
12982         ct.ct_vendor = 0;
12983 
12984         FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&ct,
12985             (uint8_t *)pkt->pkt_cmd, sizeof (ct), DDI_DEV_AUTOINCR);
12986 
12987         pkt->pkt_cmd_fhdr.r_ctl = R_CTL_UNSOL_CONTROL;
12988         pkt->pkt_cmd_fhdr.d_id = 0xFFFFFC;
12989         pkt->pkt_cmd_fhdr.s_id = s_id;
12990         pkt->pkt_cmd_fhdr.type = FC_TYPE_FC_SERVICES;
12991         pkt->pkt_cmd_fhdr.f_ctl = F_CTL_SEQ_INITIATIVE |
12992             F_CTL_FIRST_SEQ | F_CTL_END_SEQ;
12993         pkt->pkt_cmd_fhdr.seq_id = 0;
12994         pkt->pkt_cmd_fhdr.df_ctl  = 0;
12995         pkt->pkt_cmd_fhdr.seq_cnt = 0;
12996         pkt->pkt_cmd_fhdr.ox_id = 0xffff;
12997         pkt->pkt_cmd_fhdr.rx_id = 0xffff;
12998         pkt->pkt_cmd_fhdr.ro = 0;
12999         pkt->pkt_cmd_fhdr.rsvd = 0;
13000 
13001         pkt->pkt_comp = fp_ns_intr;
13002         pkt->pkt_ulp_private = (opaque_t)cmd;
13003         pkt->pkt_timeout = FP_NS_TIMEOUT;
13004 
13005         if (cmd_buf) {
13006                 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)cmd_buf,
13007                     (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
13008                     cmd_len, DDI_DEV_AUTOINCR);
13009         }
13010 
13011         cmd->cmd_transport = port->fp_fca_tran->fca_transport;
13012 
13013         cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class;
13014         cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
13015         cmd->cmd_flags = FP_CMD_PLOGI_DONT_CARE;
13016         cmd->cmd_retry_count = fp_retry_count;
13017         cmd->cmd_ulp_pkt = NULL;
13018 }
13019 
13020 
13021 /*
13022  * Name Server request interrupt routine
13023  */
13024 static void
13025 fp_ns_intr(fc_packet_t *pkt)
13026 {
13027         fp_cmd_t        *cmd;
13028         fc_local_port_t *port;
13029         fc_ct_header_t  resp_hdr;
13030         fc_ct_header_t  cmd_hdr;
13031         fctl_ns_req_t   *ns_cmd;
13032 
13033         cmd = pkt->pkt_ulp_private;
13034         port = cmd->cmd_port;
13035 
13036         mutex_enter(&port->fp_mutex);
13037         port->fp_out_fpcmds--;
13038         mutex_exit(&port->fp_mutex);
13039 
13040         FC_GET_RSP(port, pkt->pkt_cmd_acc, (uint8_t *)&cmd_hdr,
13041             (uint8_t *)pkt->pkt_cmd, sizeof (cmd_hdr), DDI_DEV_AUTOINCR);
13042         ns_cmd = (fctl_ns_req_t *)
13043             (((fp_cmd_t *)(pkt->pkt_ulp_private))->cmd_private);
13044         if (!FP_IS_PKT_ERROR(pkt)) {
13045                 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp_hdr,
13046                     (uint8_t *)pkt->pkt_resp, sizeof (resp_hdr),
13047                     DDI_DEV_AUTOINCR);
13048 
13049                 /*
13050                  * On x86 architectures, make sure the resp_hdr is big endian.
13051                  * This macro is a NOP on sparc architectures mainly because
13052                  * we don't want to end up wasting time since the end result
13053                  * is going to be the same.
13054                  */
13055                 MAKE_BE_32(&resp_hdr);
13056 
13057                 if (ns_cmd) {
13058                         /*
13059                          * Always copy out the response CT_HDR
13060                          */
13061                         bcopy(&resp_hdr, &ns_cmd->ns_resp_hdr,
13062                             sizeof (resp_hdr));
13063                 }
13064 
13065                 if (resp_hdr.ct_cmdrsp == FS_RJT_IU) {
13066                         pkt->pkt_state = FC_PKT_FS_RJT;
13067                         pkt->pkt_reason = resp_hdr.ct_reason;
13068                         pkt->pkt_expln = resp_hdr.ct_expln;
13069                 }
13070         }
13071 
13072         if (FP_IS_PKT_ERROR(pkt)) {
13073                 if (ns_cmd) {
13074                         if (ns_cmd->ns_flags & FCTL_NS_VALIDATE_PD) {
13075                                 ASSERT(ns_cmd->ns_pd != NULL);
13076 
13077                                 /* Mark it OLD if not already done */
13078                                 mutex_enter(&ns_cmd->ns_pd->pd_mutex);
13079                                 ns_cmd->ns_pd->pd_type = PORT_DEVICE_OLD;
13080                                 mutex_exit(&ns_cmd->ns_pd->pd_mutex);
13081                         }
13082 
13083                         if (ns_cmd->ns_flags & FCTL_NS_ASYNC_REQUEST) {
13084                                 fctl_free_ns_cmd(ns_cmd);
13085                                 ((fp_cmd_t *)
13086                                     (pkt->pkt_ulp_private))->cmd_private = NULL;
13087                         }
13088 
13089                 }
13090 
13091                 FP_TRACE(FP_NHEAD2(1, 0), "%x NS failure pkt state=%x "
13092                     "reason=%x, expln=%x, NSCMD=%04X, NSRSP=%04X",
13093                     port->fp_port_id.port_id, pkt->pkt_state,
13094                     pkt->pkt_reason, pkt->pkt_expln,
13095                     cmd_hdr.ct_cmdrsp,  resp_hdr.ct_cmdrsp);
13096 
13097                 (void) fp_common_intr(pkt, 1);
13098 
13099                 return;
13100         }
13101 
13102         if (resp_hdr.ct_cmdrsp != FS_ACC_IU) {
13103                 uint32_t        d_id;
13104                 fc_local_port_t *port;
13105                 fp_cmd_t        *cmd;
13106 
13107                 d_id = pkt->pkt_cmd_fhdr.d_id;
13108                 cmd = pkt->pkt_ulp_private;
13109                 port = cmd->cmd_port;
13110                 FP_TRACE(FP_NHEAD2(9, 0),
13111                     "Bogus NS response received for D_ID=%x", d_id);
13112         }
13113 
13114         if (cmd_hdr.ct_cmdrsp == NS_GA_NXT) {
13115                 fp_gan_handler(pkt, ns_cmd);
13116                 return;
13117         }
13118 
13119         if (cmd_hdr.ct_cmdrsp >= NS_GPN_ID &&
13120             cmd_hdr.ct_cmdrsp <= NS_GID_PT) {
13121                 if (ns_cmd) {
13122                         if ((ns_cmd->ns_flags & FCTL_NS_NO_DATA_BUF) == 0) {
13123                                 fp_ns_query_handler(pkt, ns_cmd);
13124                                 return;
13125                         }
13126                 }
13127         }
13128 
13129         fp_iodone(pkt->pkt_ulp_private);
13130 }
13131 
13132 
13133 /*
13134  * Process NS_GAN response
13135  */
13136 static void
13137 fp_gan_handler(fc_packet_t *pkt, fctl_ns_req_t *ns_cmd)
13138 {
13139         int                     my_did;
13140         fc_portid_t             d_id;
13141         fp_cmd_t                *cmd;
13142         fc_local_port_t         *port;
13143         fc_remote_port_t        *pd;
13144         ns_req_gan_t            gan_req;
13145         ns_resp_gan_t           *gan_resp;
13146 
13147         ASSERT(ns_cmd != NULL);
13148 
13149         cmd = pkt->pkt_ulp_private;
13150         port = cmd->cmd_port;
13151 
13152         gan_resp = (ns_resp_gan_t *)(pkt->pkt_resp + sizeof (fc_ct_header_t));
13153 
13154         FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&d_id,
13155             (uint8_t *)&gan_resp->gan_type_id, sizeof (d_id), DDI_DEV_AUTOINCR);
13156 
13157         *(uint32_t *)&d_id = BE_32(*(uint32_t *)&d_id);
13158 
13159         /*
13160          * In this case the priv_lilp_posit field  in reality
13161          * is actually represents the relative position on a private loop.
13162          * So zero it while dealing with Port Identifiers.
13163          */
13164         d_id.priv_lilp_posit = 0;
13165         pd = fctl_get_remote_port_by_did(port, d_id.port_id);
13166         if (ns_cmd->ns_gan_sid == d_id.port_id) {
13167                 /*
13168                  * We've come a full circle; time to get out.
13169                  */
13170                 fp_iodone(cmd);
13171                 return;
13172         }
13173 
13174         if (ns_cmd->ns_gan_sid == FCTL_GAN_START_ID) {
13175                 ns_cmd->ns_gan_sid = d_id.port_id;
13176         }
13177 
13178         mutex_enter(&port->fp_mutex);
13179         my_did = (d_id.port_id == port->fp_port_id.port_id) ? 1 : 0;
13180         mutex_exit(&port->fp_mutex);
13181 
13182         FP_TRACE(FP_NHEAD1(1, 0), "GAN response; port=%p, fp %x pd %x", port,
13183             port->fp_port_id.port_id, d_id.port_id);
13184         if (my_did == 0) {
13185                 la_wwn_t pwwn;
13186                 la_wwn_t nwwn;
13187 
13188                 FP_TRACE(FP_NHEAD1(1, 0), "GAN response details; "
13189                     "port=%p, d_id=%x, type_id=%x, "
13190                     "pwwn=%x %x %x %x %x %x %x %x, "
13191                     "nwwn=%x %x %x %x %x %x %x %x",
13192                     port, d_id.port_id, gan_resp->gan_type_id,
13193 
13194                     gan_resp->gan_pwwn.raw_wwn[0],
13195                     gan_resp->gan_pwwn.raw_wwn[1],
13196                     gan_resp->gan_pwwn.raw_wwn[2],
13197                     gan_resp->gan_pwwn.raw_wwn[3],
13198                     gan_resp->gan_pwwn.raw_wwn[4],
13199                     gan_resp->gan_pwwn.raw_wwn[5],
13200                     gan_resp->gan_pwwn.raw_wwn[6],
13201                     gan_resp->gan_pwwn.raw_wwn[7],
13202 
13203                     gan_resp->gan_nwwn.raw_wwn[0],
13204                     gan_resp->gan_nwwn.raw_wwn[1],
13205                     gan_resp->gan_nwwn.raw_wwn[2],
13206                     gan_resp->gan_nwwn.raw_wwn[3],
13207                     gan_resp->gan_nwwn.raw_wwn[4],
13208                     gan_resp->gan_nwwn.raw_wwn[5],
13209                     gan_resp->gan_nwwn.raw_wwn[6],
13210                     gan_resp->gan_nwwn.raw_wwn[7]);
13211 
13212                 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&nwwn,
13213                     (uint8_t *)&gan_resp->gan_nwwn, sizeof (nwwn),
13214                     DDI_DEV_AUTOINCR);
13215 
13216                 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&pwwn,
13217                     (uint8_t *)&gan_resp->gan_pwwn, sizeof (pwwn),
13218                     DDI_DEV_AUTOINCR);
13219 
13220                 if (ns_cmd->ns_flags & FCTL_NS_CREATE_DEVICE && pd == NULL) {
13221                         FP_TRACE(FP_NHEAD1(1, 0), "fp %x gan_hander create"
13222                             "pd %x", port->fp_port_id.port_id, d_id.port_id);
13223                         pd = fctl_create_remote_port(port, &nwwn, &pwwn,
13224                             d_id.port_id, PD_PLOGI_INITIATOR, KM_NOSLEEP);
13225                 }
13226                 if (pd != NULL) {
13227                         fp_stuff_device_with_gan(&pkt->pkt_resp_acc,
13228                             pd, gan_resp);
13229                 }
13230 
13231                 if (ns_cmd->ns_flags & FCTL_NS_GET_DEV_COUNT) {
13232                         *((int *)ns_cmd->ns_data_buf) += 1;
13233                 }
13234 
13235                 if (ns_cmd->ns_flags & FCTL_NS_FILL_NS_MAP) {
13236                         ASSERT((ns_cmd->ns_flags & FCTL_NS_NO_DATA_BUF) == 0);
13237 
13238                         if (ns_cmd->ns_flags & FCTL_NS_BUF_IS_USERLAND) {
13239                                 fc_port_dev_t *userbuf;
13240 
13241                                 userbuf = ((fc_port_dev_t *)
13242                                     ns_cmd->ns_data_buf) +
13243                                     ns_cmd->ns_gan_index++;
13244 
13245                                 userbuf->dev_did = d_id;
13246 
13247                                 FC_GET_RSP(port, pkt->pkt_resp_acc,
13248                                     (uint8_t *)userbuf->dev_type,
13249                                     (uint8_t *)gan_resp->gan_fc4types,
13250                                     sizeof (userbuf->dev_type),
13251                                     DDI_DEV_AUTOINCR);
13252 
13253                                 userbuf->dev_nwwn = nwwn;
13254                                 userbuf->dev_pwwn = pwwn;
13255 
13256                                 if (pd != NULL) {
13257                                         mutex_enter(&pd->pd_mutex);
13258                                         userbuf->dev_state = pd->pd_state;
13259                                         userbuf->dev_hard_addr =
13260                                             pd->pd_hard_addr;
13261                                         mutex_exit(&pd->pd_mutex);
13262                                 } else {
13263                                         userbuf->dev_state =
13264                                             PORT_DEVICE_INVALID;
13265                                 }
13266                         } else if (ns_cmd->ns_flags &
13267                             FCTL_NS_BUF_IS_FC_PORTMAP) {
13268                                 fc_portmap_t *map;
13269 
13270                                 map = ((fc_portmap_t *)
13271                                     ns_cmd->ns_data_buf) +
13272                                     ns_cmd->ns_gan_index++;
13273 
13274                                 /*
13275                                  * First fill it like any new map
13276                                  * and update the port device info
13277                                  * below.
13278                                  */
13279                                 fp_fillout_new_nsmap(port, &pkt->pkt_resp_acc,
13280                                     map, gan_resp, d_id.port_id);
13281                                 if (pd != NULL) {
13282                                         fctl_copy_portmap(map, pd);
13283                                 } else {
13284                                         map->map_state = PORT_DEVICE_INVALID;
13285                                         map->map_type = PORT_DEVICE_NOCHANGE;
13286                                 }
13287                         } else {
13288                                 caddr_t dst_ptr;
13289 
13290                                 dst_ptr = ns_cmd->ns_data_buf +
13291                                     (NS_GAN_RESP_LEN) * ns_cmd->ns_gan_index++;
13292 
13293                                 FC_GET_RSP(port, pkt->pkt_resp_acc,
13294                                     (uint8_t *)dst_ptr, (uint8_t *)gan_resp,
13295                                     NS_GAN_RESP_LEN, DDI_DEV_AUTOINCR);
13296                         }
13297                 } else {
13298                         ns_cmd->ns_gan_index++;
13299                 }
13300                 if (ns_cmd->ns_gan_index >= ns_cmd->ns_gan_max) {
13301                         fp_iodone(cmd);
13302                         return;
13303                 }
13304         }
13305 
13306         gan_req.pid = d_id;
13307 
13308         FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&gan_req,
13309             (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
13310             sizeof (gan_req), DDI_DEV_AUTOINCR);
13311 
13312         if (cmd->cmd_transport(port->fp_fca_handle, pkt) != FC_SUCCESS) {
13313                 pkt->pkt_state = FC_PKT_TRAN_ERROR;
13314                 fp_iodone(cmd);
13315         } else {
13316                 mutex_enter(&port->fp_mutex);
13317                 port->fp_out_fpcmds++;
13318                 mutex_exit(&port->fp_mutex);
13319         }
13320 }
13321 
13322 
13323 /*
13324  * Handle NS Query interrupt
13325  */
13326 static void
13327 fp_ns_query_handler(fc_packet_t *pkt, fctl_ns_req_t *ns_cmd)
13328 {
13329         fp_cmd_t        *cmd;
13330         fc_local_port_t *port;
13331         caddr_t         src_ptr;
13332         uint32_t        xfer_len;
13333 
13334         cmd = pkt->pkt_ulp_private;
13335         port = cmd->cmd_port;
13336 
13337         xfer_len = ns_cmd->ns_resp_size;
13338 
13339         FP_TRACE(FP_NHEAD1(1, 0), "NS Query response, cmd_code=%x, xfer_len=%x",
13340             ns_cmd->ns_cmd_code, xfer_len);
13341 
13342         if (ns_cmd->ns_cmd_code == NS_GPN_ID) {
13343                 src_ptr = (caddr_t)pkt->pkt_resp + sizeof (fc_ct_header_t);
13344 
13345                 FP_TRACE(FP_NHEAD1(6, 0), "GPN_ID results; %x %x %x %x %x",
13346                     src_ptr[0], src_ptr[1], src_ptr[2], src_ptr[3], src_ptr[4]);
13347         }
13348 
13349         if (xfer_len <= ns_cmd->ns_data_len) {
13350                 src_ptr = (caddr_t)pkt->pkt_resp + sizeof (fc_ct_header_t);
13351                 FC_GET_RSP(port, pkt->pkt_resp_acc,
13352                     (uint8_t *)ns_cmd->ns_data_buf,
13353                     (uint8_t *)src_ptr, xfer_len, DDI_DEV_AUTOINCR);
13354         }
13355 
13356         if (ns_cmd->ns_flags & FCTL_NS_VALIDATE_PD) {
13357                 ASSERT(ns_cmd->ns_pd != NULL);
13358 
13359                 mutex_enter(&ns_cmd->ns_pd->pd_mutex);
13360                 if (ns_cmd->ns_pd->pd_type == PORT_DEVICE_OLD) {
13361                         ns_cmd->ns_pd->pd_type = PORT_DEVICE_NOCHANGE;
13362                 }
13363                 mutex_exit(&ns_cmd->ns_pd->pd_mutex);
13364         }
13365 
13366         if (ns_cmd->ns_flags & FCTL_NS_ASYNC_REQUEST) {
13367                 fctl_free_ns_cmd(ns_cmd);
13368                 ((fp_cmd_t *)(pkt->pkt_ulp_private))->cmd_private = NULL;
13369         }
13370         fp_iodone(cmd);
13371 }
13372 
13373 
13374 /*
13375  * Handle unsolicited ADISC ELS request
13376  */
13377 static void
13378 fp_handle_unsol_adisc(fc_local_port_t *port, fc_unsol_buf_t *buf,
13379     fc_remote_port_t *pd, job_request_t *job)
13380 {
13381         int             rval;
13382         fp_cmd_t        *cmd;
13383 
13384         FP_TRACE(FP_NHEAD1(5, 0), "ADISC; port=%p, D_ID=%x state=%x, pd=%p",
13385             port, pd->pd_port_id.port_id, pd->pd_state, pd);
13386         mutex_enter(&pd->pd_mutex);
13387         if (pd->pd_state != PORT_DEVICE_LOGGED_IN) {
13388                 mutex_exit(&pd->pd_mutex);
13389                 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) {
13390                         cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t),
13391                             0, KM_SLEEP, pd);
13392                         if (cmd != NULL) {
13393                                 fp_els_rjt_init(port, cmd, buf,
13394                                     FC_ACTION_NON_RETRYABLE,
13395                                     FC_REASON_INVALID_LINK_CTRL, job);
13396 
13397                                 if (fp_sendcmd(port, cmd,
13398                                     port->fp_fca_handle) != FC_SUCCESS) {
13399                                         fp_free_pkt(cmd);
13400                                 }
13401                         }
13402                 }
13403         } else {
13404                 mutex_exit(&pd->pd_mutex);
13405                 /*
13406                  * Yes, yes, we don't have a hard address. But we
13407                  * we should still respond. Huh ? Visit 21.19.2
13408                  * of FC-PH-2 which essentially says that if an
13409                  * NL_Port doesn't have a hard address, or if a port
13410                  * does not have FC-AL capability, it shall report
13411                  * zeroes in this field.
13412                  */
13413                 cmd = fp_alloc_pkt(port, sizeof (la_els_adisc_t),
13414                     0, KM_SLEEP, pd);
13415                 if (cmd == NULL) {
13416                         return;
13417                 }
13418                 fp_adisc_acc_init(port, cmd, buf, job);
13419                 rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
13420                 if (rval != FC_SUCCESS) {
13421                         fp_free_pkt(cmd);
13422                 }
13423         }
13424 }
13425 
13426 
13427 /*
13428  * Initialize ADISC response.
13429  */
13430 static void
13431 fp_adisc_acc_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf,
13432     job_request_t *job)
13433 {
13434         fc_packet_t     *pkt;
13435         la_els_adisc_t  payload;
13436 
13437         cmd->cmd_pkt.pkt_tran_flags = buf->ub_class;
13438         cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND;
13439         cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED;
13440         cmd->cmd_retry_count = 1;
13441         cmd->cmd_ulp_pkt = NULL;
13442 
13443         cmd->cmd_transport = port->fp_fca_tran->fca_els_send;
13444         cmd->cmd_job = job;
13445 
13446         pkt = &cmd->cmd_pkt;
13447 
13448         fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP, FC_TYPE_EXTENDED_LS);
13449 
13450         payload.ls_code.ls_code = LA_ELS_ACC;
13451         payload.ls_code.mbz = 0;
13452 
13453         mutex_enter(&port->fp_mutex);
13454         payload.nport_id = port->fp_port_id;
13455         payload.hard_addr = port->fp_hard_addr;
13456         mutex_exit(&port->fp_mutex);
13457 
13458         payload.port_wwn = port->fp_service_params.nport_ww_name;
13459         payload.node_wwn = port->fp_service_params.node_ww_name;
13460 
13461         FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
13462             (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
13463 }
13464 
13465 
13466 /*
13467  * Hold and Install the requested ULP drivers
13468  */
13469 static void
13470 fp_load_ulp_modules(dev_info_t *dip, fc_local_port_t *port)
13471 {
13472         int             len;
13473         int             count;
13474         int             data_len;
13475         major_t         ulp_major;
13476         caddr_t         ulp_name;
13477         caddr_t         data_ptr;
13478         caddr_t         data_buf;
13479 
13480         ASSERT(!MUTEX_HELD(&port->fp_mutex));
13481 
13482         data_buf = NULL;
13483         if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
13484             DDI_PROP_DONTPASS, "load-ulp-list",
13485             (caddr_t)&data_buf, &data_len) != DDI_PROP_SUCCESS) {
13486                 return;
13487         }
13488 
13489         len = strlen(data_buf);
13490         port->fp_ulp_nload = fctl_atoi(data_buf, 10);
13491 
13492         data_ptr = data_buf + len + 1;
13493         for (count = 0; count < port->fp_ulp_nload; count++) {
13494                 len = strlen(data_ptr) + 1;
13495                 ulp_name = kmem_zalloc(len, KM_SLEEP);
13496                 bcopy(data_ptr, ulp_name, len);
13497 
13498                 ulp_major = ddi_name_to_major(ulp_name);
13499 
13500                 if (ulp_major != (major_t)-1) {
13501                         if (modload("drv", ulp_name) < 0) {
13502                                 fp_printf(port, CE_NOTE, FP_LOG_ONLY,
13503                                     0, NULL, "failed to load %s",
13504                                     ulp_name);
13505                         }
13506                 } else {
13507                         fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
13508                             "%s isn't a valid driver", ulp_name);
13509                 }
13510 
13511                 kmem_free(ulp_name, len);
13512                 data_ptr += len;        /* Skip to next field */
13513         }
13514 
13515         /*
13516          * Free the memory allocated by DDI
13517          */
13518         if (data_buf != NULL) {
13519                 kmem_free(data_buf, data_len);
13520         }
13521 }
13522 
13523 
13524 /*
13525  * Perform LOGO operation
13526  */
13527 static int
13528 fp_logout(fc_local_port_t *port, fc_remote_port_t *pd, job_request_t *job)
13529 {
13530         int             rval;
13531         fp_cmd_t        *cmd;
13532 
13533         ASSERT(!MUTEX_HELD(&port->fp_mutex));
13534         ASSERT(!MUTEX_HELD(&pd->pd_mutex));
13535 
13536         cmd = fp_alloc_pkt(port, sizeof (la_els_logo_t),
13537             FP_PORT_IDENTIFIER_LEN, KM_SLEEP, pd);
13538 
13539         mutex_enter(&port->fp_mutex);
13540         mutex_enter(&pd->pd_mutex);
13541 
13542         ASSERT(pd->pd_state == PORT_DEVICE_LOGGED_IN);
13543         ASSERT(pd->pd_login_count == 1);
13544 
13545         cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
13546         cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
13547         cmd->cmd_flags = 0;
13548         cmd->cmd_retry_count = 1;
13549         cmd->cmd_ulp_pkt = NULL;
13550 
13551         fp_logo_init(pd, cmd, job);
13552 
13553         mutex_exit(&pd->pd_mutex);
13554         mutex_exit(&port->fp_mutex);
13555 
13556         rval = fp_sendcmd(port, cmd, port->fp_fca_handle);
13557         if (rval != FC_SUCCESS) {
13558                 fp_iodone(cmd);
13559         }
13560 
13561         return (rval);
13562 }
13563 
13564 
13565 /*
13566  * Perform Port attach callbacks to registered ULPs
13567  */
13568 static void
13569 fp_attach_ulps(fc_local_port_t *port, fc_attach_cmd_t cmd)
13570 {
13571         fp_soft_attach_t *att;
13572 
13573         att = kmem_zalloc(sizeof (*att), KM_SLEEP);
13574         att->att_cmd = cmd;
13575         att->att_port = port;
13576 
13577         /*
13578          * We need to remember whether or not fctl_busy_port
13579          * succeeded so we know whether or not to call
13580          * fctl_idle_port when the task is complete.
13581          */
13582 
13583         if (fctl_busy_port(port) == 0) {
13584                 att->att_need_pm_idle = B_TRUE;
13585         } else {
13586                 att->att_need_pm_idle = B_FALSE;
13587         }
13588 
13589         (void) taskq_dispatch(port->fp_taskq, fp_ulp_port_attach,
13590             att, KM_SLEEP);
13591 }
13592 
13593 
13594 /*
13595  * Forward state change notifications on to interested ULPs.
13596  * Spawns a call to fctl_ulp_statec_cb() in a taskq thread to do all the
13597  * real work.
13598  */
13599 static int
13600 fp_ulp_notify(fc_local_port_t *port, uint32_t statec, int sleep)
13601 {
13602         fc_port_clist_t *clist;
13603 
13604         clist = kmem_zalloc(sizeof (*clist), sleep);
13605         if (clist == NULL) {
13606                 return (FC_NOMEM);
13607         }
13608 
13609         clist->clist_state = statec;
13610 
13611         mutex_enter(&port->fp_mutex);
13612         clist->clist_flags = port->fp_topology;
13613         mutex_exit(&port->fp_mutex);
13614 
13615         clist->clist_port = (opaque_t)port;
13616         clist->clist_len = 0;
13617         clist->clist_size = 0;
13618         clist->clist_map = NULL;
13619 
13620         (void) taskq_dispatch(port->fp_taskq, fctl_ulp_statec_cb,
13621             clist, KM_SLEEP);
13622 
13623         return (FC_SUCCESS);
13624 }
13625 
13626 
13627 /*
13628  * Get name server map
13629  */
13630 static int
13631 fp_ns_getmap(fc_local_port_t *port, job_request_t *job, fc_portmap_t **map,
13632     uint32_t *len, uint32_t sid)
13633 {
13634         int ret;
13635         fctl_ns_req_t *ns_cmd;
13636 
13637         /*
13638          * Don't let the allocator do anything for response;
13639          * we have have buffer ready to fillout.
13640          */
13641         ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t),
13642             sizeof (ns_resp_gan_t), 0, (FCTL_NS_FILL_NS_MAP |
13643             FCTL_NS_BUF_IS_FC_PORTMAP), KM_SLEEP);
13644 
13645         ns_cmd->ns_data_len = sizeof (**map) * (*len);
13646         ns_cmd->ns_data_buf = (caddr_t)*map;
13647 
13648         ASSERT(ns_cmd != NULL);
13649 
13650         ns_cmd->ns_gan_index = 0;
13651         ns_cmd->ns_gan_sid = sid;
13652         ns_cmd->ns_cmd_code = NS_GA_NXT;
13653         ns_cmd->ns_gan_max = *len;
13654 
13655         ret = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP);
13656 
13657         if (ns_cmd->ns_gan_index != *len) {
13658                 *len = ns_cmd->ns_gan_index;
13659         }
13660         ns_cmd->ns_data_len = 0;
13661         ns_cmd->ns_data_buf = NULL;
13662         fctl_free_ns_cmd(ns_cmd);
13663 
13664         return (ret);
13665 }
13666 
13667 
13668 /*
13669  * Create a remote port in Fabric topology by using NS services
13670  */
13671 static fc_remote_port_t *
13672 fp_create_remote_port_by_ns(fc_local_port_t *port, uint32_t d_id, int sleep)
13673 {
13674         int                     rval;
13675         job_request_t           *job;
13676         fctl_ns_req_t           *ns_cmd;
13677         fc_remote_port_t        *pd;
13678 
13679         ASSERT(!MUTEX_HELD(&port->fp_mutex));
13680 
13681         FP_TRACE(FP_NHEAD1(1, 0), "PD creation begin; port=%p, d_id=%x",
13682             port, d_id);
13683 
13684 #ifdef  DEBUG
13685         mutex_enter(&port->fp_mutex);
13686         ASSERT(FC_IS_TOP_SWITCH(port->fp_topology));
13687         mutex_exit(&port->fp_mutex);
13688 #endif
13689 
13690         job = fctl_alloc_job(JOB_NS_CMD, 0, NULL, (opaque_t)port, sleep);
13691         if (job == NULL) {
13692                 return (NULL);
13693         }
13694 
13695         ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t),
13696             sizeof (ns_resp_gan_t), 0, (FCTL_NS_CREATE_DEVICE |
13697             FCTL_NS_NO_DATA_BUF), sleep);
13698         if (ns_cmd == NULL) {
13699                 return (NULL);
13700         }
13701 
13702         job->job_result = FC_SUCCESS;
13703         ns_cmd->ns_gan_max = 1;
13704         ns_cmd->ns_cmd_code = NS_GA_NXT;
13705         ns_cmd->ns_gan_sid = FCTL_GAN_START_ID;
13706         ((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.port_id = d_id - 1;
13707         ((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.priv_lilp_posit = 0;
13708 
13709         ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
13710         rval = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP);
13711         fctl_free_ns_cmd(ns_cmd);
13712 
13713         if (rval != FC_SUCCESS || job->job_result != FC_SUCCESS) {
13714                 fctl_dealloc_job(job);
13715                 return (NULL);
13716         }
13717         fctl_dealloc_job(job);
13718 
13719         pd = fctl_get_remote_port_by_did(port, d_id);
13720 
13721         FP_TRACE(FP_NHEAD1(1, 0), "PD creation end; port=%p, d_id=%x, pd=%p",
13722             port, d_id, pd);
13723 
13724         return (pd);
13725 }
13726 
13727 
13728 /*
13729  * Check for the permissions on an ioctl command. If it is required to have an
13730  * EXCLUSIVE open performed, return a FAILURE to just shut the door on it. If
13731  * the ioctl command isn't in one of the list built, shut the door on that too.
13732  *
13733  *      Certain ioctls perform hardware accesses in FCA drivers, and it needs
13734  *      to be made sure that users open the port for an exclusive access while
13735  *      performing those operations.
13736  *
13737  *      This can prevent a casual user from inflicting damage on the port by
13738  *      sending these ioctls from multiple processes/threads (there is no good
13739  *      reason why one would need to do that) without actually realizing how
13740  *      expensive such commands could turn out to be.
13741  *
13742  *      It is also important to note that, even with an exclusive access,
13743  *      multiple threads can share the same file descriptor and fire down
13744  *      commands in parallel. To prevent that the driver needs to make sure
13745  *      that such commands aren't in progress already. This is taken care of
13746  *      in the FP_EXCL_BUSY bit of fp_flag.
13747  */
13748 static int
13749 fp_check_perms(uchar_t open_flag, uint16_t ioctl_cmd)
13750 {
13751         int ret = FC_FAILURE;
13752         int count;
13753 
13754         for (count = 0;
13755             count < sizeof (fp_perm_list) / sizeof (fp_perm_list[0]);
13756             count++) {
13757                 if (fp_perm_list[count].fp_ioctl_cmd == ioctl_cmd) {
13758                         if (fp_perm_list[count].fp_open_flag & open_flag) {
13759                                 ret = FC_SUCCESS;
13760                         }
13761                         break;
13762                 }
13763         }
13764 
13765         return (ret);
13766 }
13767 
13768 
13769 /*
13770  * Bind Port driver's unsolicited, state change callbacks
13771  */
13772 static int
13773 fp_bind_callbacks(fc_local_port_t *port)
13774 {
13775         fc_fca_bind_info_t      bind_info = {0};
13776         fc_fca_port_info_t      *port_info;
13777         int             rval =  DDI_SUCCESS;
13778         uint16_t        class;
13779         int             node_namelen, port_namelen;
13780         char            *nname = NULL, *pname = NULL;
13781 
13782         ASSERT(!MUTEX_HELD(&port->fp_mutex));
13783 
13784         if (ddi_prop_lookup_string(DDI_DEV_T_ANY, port->fp_port_dip,
13785             DDI_PROP_NOTPROM | DDI_PROP_DONTPASS,
13786             "node-name", &nname) != DDI_PROP_SUCCESS) {
13787                 FP_TRACE(FP_NHEAD1(1, 0),
13788                     "fp_bind_callback fail to get node-name");
13789         }
13790         if (nname) {
13791                 fc_str_to_wwn(nname, &(bind_info.port_nwwn));
13792         }
13793 
13794         if (ddi_prop_lookup_string(DDI_DEV_T_ANY, port->fp_port_dip,
13795             DDI_PROP_NOTPROM | DDI_PROP_DONTPASS,
13796             "port-name", &pname) != DDI_PROP_SUCCESS) {
13797                 FP_TRACE(FP_NHEAD1(1, 0),
13798                     "fp_bind_callback fail to get port-name");
13799         }
13800         if (pname) {
13801                 fc_str_to_wwn(pname, &(bind_info.port_pwwn));
13802         }
13803 
13804         if (port->fp_npiv_type == FC_NPIV_PORT) {
13805                 bind_info.port_npiv = 1;
13806         }
13807 
13808         /*
13809          * fca_bind_port returns the FCA driver's handle for the local
13810          * port instance. If the port number isn't supported it returns NULL.
13811          * It also sets up callback in the FCA for various
13812          * things like state change, ELS etc..
13813          */
13814         bind_info.port_statec_cb = fp_statec_cb;
13815         bind_info.port_unsol_cb = fp_unsol_cb;
13816         bind_info.port_num = port->fp_port_num;
13817         bind_info.port_handle = (opaque_t)port;
13818 
13819         port_info = kmem_zalloc(sizeof (*port_info), KM_SLEEP);
13820 
13821         /*
13822          * Hold the port driver mutex as the callbacks are bound until the
13823          * service parameters are properly filled in (in order to be able to
13824          * properly respond to unsolicited ELS requests)
13825          */
13826         mutex_enter(&port->fp_mutex);
13827 
13828         port->fp_fca_handle = port->fp_fca_tran->fca_bind_port(
13829             port->fp_fca_dip, port_info, &bind_info);
13830 
13831         if (port->fp_fca_handle == NULL) {
13832                 rval = DDI_FAILURE;
13833                 goto exit;
13834         }
13835 
13836         /*
13837          * Only fcoei will set this bit
13838          */
13839         if (port_info->pi_port_state & FC_STATE_FCA_IS_NODMA) {
13840                 port->fp_soft_state |= FP_SOFT_FCA_IS_NODMA;
13841                 port_info->pi_port_state &= ~(FC_STATE_FCA_IS_NODMA);
13842         }
13843 
13844         port->fp_bind_state = port->fp_state = port_info->pi_port_state;
13845         port->fp_service_params = port_info->pi_login_params;
13846         port->fp_hard_addr = port_info->pi_hard_addr;
13847 
13848         /* Copy from the FCA structure to the FP structure */
13849         port->fp_hba_port_attrs = port_info->pi_attrs;
13850 
13851         if (port_info->pi_rnid_params.status == FC_SUCCESS) {
13852                 port->fp_rnid_init = 1;
13853                 bcopy(&port_info->pi_rnid_params.params,
13854                     &port->fp_rnid_params,
13855                     sizeof (port->fp_rnid_params));
13856         } else {
13857                 port->fp_rnid_init = 0;
13858         }
13859 
13860         node_namelen = strlen((char *)&port_info->pi_attrs.sym_node_name);
13861         if (node_namelen) {
13862                 bcopy(&port_info->pi_attrs.sym_node_name,
13863                     &port->fp_sym_node_name,
13864                     node_namelen);
13865                 port->fp_sym_node_namelen = node_namelen;
13866         }
13867         port_namelen = strlen((char *)&port_info->pi_attrs.sym_port_name);
13868         if (port_namelen) {
13869                 bcopy(&port_info->pi_attrs.sym_port_name,
13870                     &port->fp_sym_port_name,
13871                     port_namelen);
13872                 port->fp_sym_port_namelen = port_namelen;
13873         }
13874 
13875         /* zero out the normally unused fields right away */
13876         port->fp_service_params.ls_code.mbz = 0;
13877         port->fp_service_params.ls_code.ls_code = 0;
13878         bzero(&port->fp_service_params.reserved,
13879             sizeof (port->fp_service_params.reserved));
13880 
13881         class = port_info->pi_login_params.class_1.class_opt;
13882         port->fp_cos |= (class & 0x8000) ? FC_NS_CLASS1 : 0;
13883 
13884         class = port_info->pi_login_params.class_2.class_opt;
13885         port->fp_cos |= (class & 0x8000) ? FC_NS_CLASS2 : 0;
13886 
13887         class = port_info->pi_login_params.class_3.class_opt;
13888         port->fp_cos |= (class & 0x8000) ? FC_NS_CLASS3 : 0;
13889 
13890 exit:
13891         if (nname) {
13892                 ddi_prop_free(nname);
13893         }
13894         if (pname) {
13895                 ddi_prop_free(pname);
13896         }
13897         mutex_exit(&port->fp_mutex);
13898         kmem_free(port_info, sizeof (*port_info));
13899 
13900         return (rval);
13901 }
13902 
13903 
13904 /*
13905  * Retrieve FCA capabilities
13906  */
13907 static void
13908 fp_retrieve_caps(fc_local_port_t *port)
13909 {
13910         int                     rval;
13911         int                     ub_count;
13912         fc_fcp_dma_t            fcp_dma;
13913         fc_reset_action_t       action;
13914         fc_dma_behavior_t       dma_behavior;
13915 
13916         ASSERT(!MUTEX_HELD(&port->fp_mutex));
13917 
13918         rval = port->fp_fca_tran->fca_get_cap(port->fp_fca_handle,
13919             FC_CAP_UNSOL_BUF, &ub_count);
13920 
13921         switch (rval) {
13922         case FC_CAP_FOUND:
13923         case FC_CAP_SETTABLE:
13924                 switch (ub_count) {
13925                 case 0:
13926                         break;
13927 
13928                 case -1:
13929                         ub_count = fp_unsol_buf_count;
13930                         break;
13931 
13932                 default:
13933                         /* 1/4th of total buffers is my share */
13934                         ub_count =
13935                             (ub_count / port->fp_fca_tran->fca_numports) >> 2;
13936                         break;
13937                 }
13938                 break;
13939 
13940         default:
13941                 ub_count = 0;
13942                 break;
13943         }
13944 
13945         mutex_enter(&port->fp_mutex);
13946         port->fp_ub_count = ub_count;
13947         mutex_exit(&port->fp_mutex);
13948 
13949         rval = port->fp_fca_tran->fca_get_cap(port->fp_fca_handle,
13950             FC_CAP_POST_RESET_BEHAVIOR, &action);
13951 
13952         switch (rval) {
13953         case FC_CAP_FOUND:
13954         case FC_CAP_SETTABLE:
13955                 switch (action) {
13956                 case FC_RESET_RETURN_NONE:
13957                 case FC_RESET_RETURN_ALL:
13958                 case FC_RESET_RETURN_OUTSTANDING:
13959                         break;
13960 
13961                 default:
13962                         action = FC_RESET_RETURN_NONE;
13963                         break;
13964                 }
13965                 break;
13966 
13967         default:
13968                 action = FC_RESET_RETURN_NONE;
13969                 break;
13970         }
13971         mutex_enter(&port->fp_mutex);
13972         port->fp_reset_action = action;
13973         mutex_exit(&port->fp_mutex);
13974 
13975         rval = port->fp_fca_tran->fca_get_cap(port->fp_fca_handle,
13976             FC_CAP_NOSTREAM_ON_UNALIGN_BUF, &dma_behavior);
13977 
13978         switch (rval) {
13979         case FC_CAP_FOUND:
13980                 switch (dma_behavior) {
13981                 case FC_ALLOW_STREAMING:
13982                         /* FALLTHROUGH */
13983                 case FC_NO_STREAMING:
13984                         break;
13985 
13986                 default:
13987                         /*
13988                          * If capability was found and the value
13989                          * was incorrect assume the worst
13990                          */
13991                         dma_behavior = FC_NO_STREAMING;
13992                         break;
13993                 }
13994                 break;
13995 
13996         default:
13997                 /*
13998                  * If capability was not defined - allow streaming; existing
13999                  * FCAs should not be affected.
14000                  */
14001                 dma_behavior = FC_ALLOW_STREAMING;
14002                 break;
14003         }
14004         mutex_enter(&port->fp_mutex);
14005         port->fp_dma_behavior = dma_behavior;
14006         mutex_exit(&port->fp_mutex);
14007 
14008         rval = port->fp_fca_tran->fca_get_cap(port->fp_fca_handle,
14009             FC_CAP_FCP_DMA, &fcp_dma);
14010 
14011         if (rval != FC_CAP_FOUND || (fcp_dma != FC_NO_DVMA_SPACE &&
14012             fcp_dma != FC_DVMA_SPACE)) {
14013                 fcp_dma = FC_DVMA_SPACE;
14014         }
14015 
14016         mutex_enter(&port->fp_mutex);
14017         port->fp_fcp_dma = fcp_dma;
14018         mutex_exit(&port->fp_mutex);
14019 }
14020 
14021 
14022 /*
14023  * Handle Domain, Area changes in the Fabric.
14024  */
14025 static void
14026 fp_validate_area_domain(fc_local_port_t *port, uint32_t id, uint32_t mask,
14027     job_request_t *job, int sleep)
14028 {
14029 #ifdef  DEBUG
14030         uint32_t                dcnt;
14031 #endif
14032         int                     rval;
14033         int                     send;
14034         int                     index;
14035         int                     listindex;
14036         int                     login;
14037         int                     job_flags;
14038         char                    ww_name[17];
14039         uint32_t                d_id;
14040         uint32_t                count;
14041         fctl_ns_req_t           *ns_cmd;
14042         fc_portmap_t            *list;
14043         fc_orphan_t             *orp;
14044         fc_orphan_t             *norp;
14045         fc_orphan_t             *prev;
14046         fc_remote_port_t        *pd;
14047         fc_remote_port_t        *npd;
14048         struct pwwn_hash        *head;
14049 
14050         ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t),
14051             sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t),
14052             0, sleep);
14053         if (ns_cmd == NULL) {
14054                 mutex_enter(&port->fp_mutex);
14055                 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
14056                         --port->fp_rscn_count;
14057                 }
14058                 mutex_exit(&port->fp_mutex);
14059 
14060                 return;
14061         }
14062         ns_cmd->ns_cmd_code = NS_GID_PN;
14063 
14064         /*
14065          * We need to get a new count of devices from the
14066          * name server, which will also create any new devices
14067          * as needed.
14068          */
14069 
14070         (void) fp_ns_get_devcount(port, job, 1, sleep);
14071 
14072         FP_TRACE(FP_NHEAD1(3, 0),
14073             "fp_validate_area_domain: get_devcount found %d devices",
14074             port->fp_total_devices);
14075 
14076         mutex_enter(&port->fp_mutex);
14077 
14078         for (count = index = 0; index < pwwn_table_size; index++) {
14079                 head = &port->fp_pwwn_table[index];
14080                 pd = head->pwwn_head;
14081                 while (pd != NULL) {
14082                         mutex_enter(&pd->pd_mutex);
14083                         if (pd->pd_flags != PD_ELS_IN_PROGRESS) {
14084                                 if ((pd->pd_port_id.port_id & mask) == id &&
14085                                     pd->pd_recepient == PD_PLOGI_INITIATOR) {
14086                                         count++;
14087                                         pd->pd_type = PORT_DEVICE_OLD;
14088                                         pd->pd_flags = PD_ELS_MARK;
14089                                 }
14090                         }
14091                         mutex_exit(&pd->pd_mutex);
14092                         pd = pd->pd_wwn_hnext;
14093                 }
14094         }
14095 
14096 #ifdef  DEBUG
14097         dcnt = count;
14098 #endif /* DEBUG */
14099 
14100         /*
14101          * Since port->fp_orphan_count is declared an 'int' it is
14102          * theoretically possible that the count could go negative.
14103          *
14104          * This would be bad and if that happens we really do want
14105          * to know.
14106          */
14107 
14108         ASSERT(port->fp_orphan_count >= 0);
14109 
14110         count += port->fp_orphan_count;
14111 
14112         /*
14113          * We add the port->fp_total_devices value to the count
14114          * in the case where our port is newly attached. This is
14115          * because we haven't done any discovery and we don't have
14116          * any orphans in the port's orphan list. If we do not do
14117          * this addition to count then we won't alloc enough kmem
14118          * to do discovery with.
14119          */
14120 
14121         if (count == 0) {
14122                 count += port->fp_total_devices;
14123                 FP_TRACE(FP_NHEAD1(3, 0), "fp_validate_area_domain: "
14124                     "0x%x orphans found, using 0x%x",
14125                     port->fp_orphan_count, count);
14126         }
14127 
14128         mutex_exit(&port->fp_mutex);
14129 
14130         /*
14131          * Allocate the change list
14132          */
14133 
14134         list = kmem_zalloc(sizeof (fc_portmap_t) * count, sleep);
14135         if (list == NULL) {
14136                 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL,
14137                     " Not enough memory to service RSCNs"
14138                     " for %d ports, continuing...", count);
14139 
14140                 fctl_free_ns_cmd(ns_cmd);
14141 
14142                 mutex_enter(&port->fp_mutex);
14143                 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
14144                         --port->fp_rscn_count;
14145                 }
14146                 mutex_exit(&port->fp_mutex);
14147 
14148                 return;
14149         }
14150 
14151         /*
14152          * Attempt to validate or invalidate the devices that were
14153          * already in the pwwn hash table.
14154          */
14155 
14156         mutex_enter(&port->fp_mutex);
14157         for (listindex = 0, index = 0; index < pwwn_table_size; index++) {
14158                 head = &port->fp_pwwn_table[index];
14159                 npd = head->pwwn_head;
14160 
14161                 while ((pd = npd) != NULL) {
14162                         npd = pd->pd_wwn_hnext;
14163 
14164                         mutex_enter(&pd->pd_mutex);
14165                         if ((pd->pd_port_id.port_id & mask) == id &&
14166                             pd->pd_flags == PD_ELS_MARK) {
14167                                 la_wwn_t *pwwn;
14168 
14169                                 job->job_result = FC_SUCCESS;
14170 
14171                                 ((ns_req_gid_pn_t *)
14172                                     (ns_cmd->ns_cmd_buf))->pwwn =
14173                                     pd->pd_port_name;
14174 
14175                                 pwwn = &pd->pd_port_name;
14176                                 d_id = pd->pd_port_id.port_id;
14177 
14178                                 mutex_exit(&pd->pd_mutex);
14179                                 mutex_exit(&port->fp_mutex);
14180 
14181                                 rval = fp_ns_query(port, ns_cmd, job, 1,
14182                                     sleep);
14183                                 if (rval != FC_SUCCESS) {
14184                                         fc_wwn_to_str(pwwn, ww_name);
14185 
14186                                         FP_TRACE(FP_NHEAD1(3, 0),
14187                                             "AREA RSCN: PD disappeared; "
14188                                             "d_id=%x, PWWN=%s", d_id, ww_name);
14189 
14190                                         FP_TRACE(FP_NHEAD2(9, 0),
14191                                             "N_x Port with D_ID=%x,"
14192                                             " PWWN=%s disappeared from fabric",
14193                                             d_id, ww_name);
14194 
14195                                         fp_fillout_old_map(list + listindex++,
14196                                             pd, 1);
14197                                 } else {
14198                                         fctl_copy_portmap(list + listindex++,
14199                                             pd);
14200 
14201                                         mutex_enter(&pd->pd_mutex);
14202                                         pd->pd_flags = PD_ELS_IN_PROGRESS;
14203                                         mutex_exit(&pd->pd_mutex);
14204                                 }
14205 
14206                                 mutex_enter(&port->fp_mutex);
14207                         } else {
14208                                 mutex_exit(&pd->pd_mutex);
14209                         }
14210                 }
14211         }
14212 
14213         mutex_exit(&port->fp_mutex);
14214 
14215         ASSERT(listindex == dcnt);
14216 
14217         job->job_counter = listindex;
14218         job_flags = job->job_flags;
14219         job->job_flags |= JOB_TYPE_FP_ASYNC;
14220 
14221         /*
14222          * Login (if we were the initiator) or validate devices in the
14223          * port map.
14224          */
14225 
14226         for (index = 0; index < listindex; index++) {
14227                 pd = list[index].map_pd;
14228 
14229                 mutex_enter(&pd->pd_mutex);
14230                 ASSERT((pd->pd_port_id.port_id & mask) == id);
14231 
14232                 if (pd->pd_flags != PD_ELS_IN_PROGRESS) {
14233                         ASSERT(pd->pd_type == PORT_DEVICE_OLD);
14234                         mutex_exit(&pd->pd_mutex);
14235                         fp_jobdone(job);
14236                         continue;
14237                 }
14238 
14239                 login = (pd->pd_state == PORT_DEVICE_LOGGED_IN) ? 1 : 0;
14240                 send = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0;
14241                 d_id = pd->pd_port_id.port_id;
14242                 mutex_exit(&pd->pd_mutex);
14243 
14244                 if ((d_id & mask) == id && send) {
14245                         if (login) {
14246                                 FP_TRACE(FP_NHEAD1(6, 0),
14247                                     "RSCN and PLOGI request;"
14248                                     " pd=%p, job=%p d_id=%x, index=%d", pd,
14249                                     job, d_id, index);
14250 
14251                                 rval = fp_port_login(port, d_id, job,
14252                                     FP_CMD_PLOGI_RETAIN, sleep, pd, NULL);
14253                                 if (rval != FC_SUCCESS) {
14254                                         mutex_enter(&pd->pd_mutex);
14255                                         pd->pd_flags = PD_IDLE;
14256                                         mutex_exit(&pd->pd_mutex);
14257 
14258                                         job->job_result = rval;
14259                                         fp_jobdone(job);
14260                                 }
14261                                 FP_TRACE(FP_NHEAD1(1, 0),
14262                                     "PLOGI succeeded:no skip(1) for "
14263                                     "D_ID %x", d_id);
14264                                 list[index].map_flags |=
14265                                     PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY;
14266                         } else {
14267                                 FP_TRACE(FP_NHEAD1(6, 0), "RSCN and NS request;"
14268                                     " pd=%p, job=%p d_id=%x, index=%d", pd,
14269                                     job, d_id, index);
14270 
14271                                 rval = fp_ns_validate_device(port, pd, job,
14272                                     0, sleep);
14273                                 if (rval != FC_SUCCESS) {
14274                                         fp_jobdone(job);
14275                                 }
14276                                 mutex_enter(&pd->pd_mutex);
14277                                 pd->pd_flags = PD_IDLE;
14278                                 mutex_exit(&pd->pd_mutex);
14279                         }
14280                 } else {
14281                         FP_TRACE(FP_NHEAD1(6, 0),
14282                             "RSCN and NO request sent; pd=%p,"
14283                             " d_id=%x, index=%d", pd, d_id, index);
14284 
14285                         mutex_enter(&pd->pd_mutex);
14286                         pd->pd_flags = PD_IDLE;
14287                         mutex_exit(&pd->pd_mutex);
14288 
14289                         fp_jobdone(job);
14290                 }
14291         }
14292 
14293         if (listindex) {
14294                 fctl_jobwait(job);
14295         }
14296         job->job_flags = job_flags;
14297 
14298         /*
14299          * Orphan list validation.
14300          */
14301         mutex_enter(&port->fp_mutex);
14302         for (prev = NULL, orp = port->fp_orphan_list; port->fp_orphan_count &&
14303             orp != NULL; orp = norp) {
14304                 norp = orp->orp_next;
14305                 mutex_exit(&port->fp_mutex);
14306 
14307                 job->job_counter = 1;
14308                 job->job_result = FC_SUCCESS;
14309                 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0);
14310 
14311                 ((ns_req_gid_pn_t *)ns_cmd->ns_cmd_buf)->pwwn = orp->orp_pwwn;
14312 
14313                 ((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->pid.port_id = 0;
14314                 ((ns_resp_gid_pn_t *)
14315                     ns_cmd->ns_data_buf)->pid.priv_lilp_posit = 0;
14316 
14317                 rval = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP);
14318                 if (rval == FC_SUCCESS) {
14319                         d_id = BE_32(*((uint32_t *)ns_cmd->ns_data_buf));
14320                         pd = fp_create_remote_port_by_ns(port, d_id, KM_SLEEP);
14321                         if (pd != NULL) {
14322                                 fc_wwn_to_str(&orp->orp_pwwn, ww_name);
14323 
14324                                 FP_TRACE(FP_NHEAD1(6, 0),
14325                                     "RSCN and ORPHAN list "
14326                                     "success; d_id=%x, PWWN=%s", d_id, ww_name);
14327 
14328                                 FP_TRACE(FP_NHEAD2(6, 0),
14329                                     "N_x Port with D_ID=%x, PWWN=%s reappeared"
14330                                     " in fabric", d_id, ww_name);
14331 
14332                                 mutex_enter(&port->fp_mutex);
14333                                 if (prev) {
14334                                         prev->orp_next = orp->orp_next;
14335                                 } else {
14336                                         ASSERT(orp == port->fp_orphan_list);
14337                                         port->fp_orphan_list = orp->orp_next;
14338                                 }
14339                                 port->fp_orphan_count--;
14340                                 mutex_exit(&port->fp_mutex);
14341 
14342                                 kmem_free(orp, sizeof (*orp));
14343                                 fctl_copy_portmap(list + listindex++, pd);
14344                         } else {
14345                                 prev = orp;
14346                         }
14347                 } else {
14348                         prev = orp;
14349                 }
14350                 mutex_enter(&port->fp_mutex);
14351         }
14352         mutex_exit(&port->fp_mutex);
14353 
14354         /*
14355          * One more pass through the list to delist old devices from
14356          * the d_id and pwwn tables and possibly add to the orphan list.
14357          */
14358 
14359         for (index = 0; index < listindex; index++) {
14360                 pd = list[index].map_pd;
14361                 ASSERT(pd != NULL);
14362 
14363                 /*
14364                  * Update PLOGI results; For NS validation
14365                  * of orphan list, it is redundant
14366                  *
14367                  * Take care to preserve PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY if
14368                  * appropriate as fctl_copy_portmap() will clear map_flags.
14369                  */
14370                 if (list[index].map_flags &
14371                     PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY) {
14372                         fctl_copy_portmap(list + index, pd);
14373                         list[index].map_flags |=
14374                             PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY;
14375                 } else {
14376                         fctl_copy_portmap(list + index, pd);
14377                 }
14378 
14379                 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with Area DOMAIN "
14380                     "results; pd=%p, d_id=%x pwwn=%x %x %x %x %x %x %x %x",
14381                     pd, pd->pd_port_id.port_id,
14382                     pd->pd_port_name.raw_wwn[0],
14383                     pd->pd_port_name.raw_wwn[1],
14384                     pd->pd_port_name.raw_wwn[2],
14385                     pd->pd_port_name.raw_wwn[3],
14386                     pd->pd_port_name.raw_wwn[4],
14387                     pd->pd_port_name.raw_wwn[5],
14388                     pd->pd_port_name.raw_wwn[6],
14389                     pd->pd_port_name.raw_wwn[7]);
14390 
14391                 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with Area DOMAIN "
14392                     "results continued, pd=%p type=%x, flags=%x, state=%x",
14393                     pd, pd->pd_type, pd->pd_flags, pd->pd_state);
14394 
14395                 mutex_enter(&pd->pd_mutex);
14396                 if (pd->pd_type == PORT_DEVICE_OLD) {
14397                         int initiator;
14398 
14399                         pd->pd_flags = PD_IDLE;
14400                         initiator = (pd->pd_recepient ==
14401                             PD_PLOGI_INITIATOR) ? 1 : 0;
14402 
14403                         mutex_exit(&pd->pd_mutex);
14404 
14405                         mutex_enter(&port->fp_mutex);
14406                         mutex_enter(&pd->pd_mutex);
14407 
14408                         pd->pd_state = PORT_DEVICE_INVALID;
14409                         fctl_delist_did_table(port, pd);
14410                         fctl_delist_pwwn_table(port, pd);
14411 
14412                         mutex_exit(&pd->pd_mutex);
14413                         mutex_exit(&port->fp_mutex);
14414 
14415                         if (initiator) {
14416                                 (void) fctl_add_orphan(port, pd, sleep);
14417                         }
14418                         list[index].map_pd = pd;
14419                 } else {
14420                         ASSERT(pd->pd_flags == PD_IDLE);
14421                         if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
14422                                 /*
14423                                  * Reset LOGO tolerance to zero
14424                                  */
14425                                 fctl_tc_reset(&pd->pd_logo_tc);
14426                         }
14427                         mutex_exit(&pd->pd_mutex);
14428                 }
14429         }
14430 
14431         if (ns_cmd) {
14432                 fctl_free_ns_cmd(ns_cmd);
14433         }
14434         if (listindex) {
14435                 (void) fp_ulp_devc_cb(port, list, listindex, count,
14436                     sleep, 0);
14437         } else {
14438                 kmem_free(list, sizeof (*list) * count);
14439 
14440                 mutex_enter(&port->fp_mutex);
14441                 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) {
14442                         --port->fp_rscn_count;
14443                 }
14444                 mutex_exit(&port->fp_mutex);
14445         }
14446 }
14447 
14448 
14449 /*
14450  * Work hard to make sense out of an RSCN page.
14451  */
14452 static void
14453 fp_validate_rscn_page(fc_local_port_t *port, fc_affected_id_t *page,
14454     job_request_t *job, fctl_ns_req_t *ns_cmd, fc_portmap_t *listptr,
14455     int *listindex, int sleep)
14456 {
14457         int                     rval;
14458         char                    ww_name[17];
14459         la_wwn_t                *pwwn;
14460         fc_remote_port_t        *pwwn_pd;
14461         fc_remote_port_t        *did_pd;
14462 
14463         did_pd = fctl_get_remote_port_by_did(port, page->aff_d_id);
14464 
14465         FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page; "
14466             "port=%p, d_id=%x, pd=%p, rscn_count:0x%x", port, page->aff_d_id,
14467             did_pd, (uint32_t)(uintptr_t)job->job_cb_arg);
14468 
14469         if (did_pd != NULL) {
14470                 mutex_enter(&did_pd->pd_mutex);
14471                 if (did_pd->pd_flags != PD_IDLE) {
14472                         mutex_exit(&did_pd->pd_mutex);
14473                         FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page: "
14474                             "PD is BUSY; port=%p, d_id=%x, pd=%p",
14475                             port, page->aff_d_id, did_pd);
14476                         return;
14477                 }
14478                 did_pd->pd_flags = PD_ELS_IN_PROGRESS;
14479                 mutex_exit(&did_pd->pd_mutex);
14480         }
14481 
14482         job->job_counter = 1;
14483 
14484         pwwn = &((ns_resp_gpn_id_t *)ns_cmd->ns_data_buf)->pwwn;
14485 
14486         ((ns_req_gpn_id_t *)ns_cmd->ns_cmd_buf)->pid.port_id = page->aff_d_id;
14487         ((ns_req_gpn_id_t *)ns_cmd->ns_cmd_buf)->pid.priv_lilp_posit = 0;
14488 
14489         bzero(ns_cmd->ns_data_buf, sizeof (la_wwn_t));
14490         rval = fp_ns_query(port, ns_cmd, job, 1, sleep);
14491 
14492         FP_TRACE(FP_NHEAD1(1, 0), "NS Query Response for D_ID page; rev=%x,"
14493             " in_id=%x, cmdrsp=%x, reason=%x, expln=%x",
14494             ns_cmd->ns_resp_hdr.ct_rev, ns_cmd->ns_resp_hdr.ct_inid,
14495             ns_cmd->ns_resp_hdr.ct_cmdrsp, ns_cmd->ns_resp_hdr.ct_reason,
14496             ns_cmd->ns_resp_hdr.ct_expln);
14497 
14498         job->job_counter = 1;
14499 
14500         if (rval != FC_SUCCESS || fctl_is_wwn_zero(pwwn) == FC_SUCCESS) {
14501                 /*
14502                  * What this means is that the D_ID
14503                  * disappeared from the Fabric.
14504                  */
14505                 if (did_pd == NULL) {
14506                         FP_TRACE(FP_NHEAD1(1, 0), "RSCN with D_ID page;"
14507                             " NULL PD disappeared, rval=%x", rval);
14508                         return;
14509                 }
14510 
14511                 fc_wwn_to_str(&did_pd->pd_port_name, ww_name);
14512 
14513                 (listptr + *listindex)->map_rscn_info.ulp_rscn_count =
14514                     (uint32_t)(uintptr_t)job->job_cb_arg;
14515 
14516                 fp_fillout_old_map(listptr + (*listindex)++, did_pd, 0);
14517 
14518                 FP_TRACE(FP_NHEAD1(3, 0), "RSCN: PD disappeared; "
14519                     "d_id=%x, PWWN=%s", page->aff_d_id, ww_name);
14520 
14521                 FP_TRACE(FP_NHEAD2(9, 0),
14522                     "GPN_ID for D_ID=%x failed", page->aff_d_id);
14523 
14524                 FP_TRACE(FP_NHEAD2(9, 0),
14525                     "N_x Port with D_ID=%x, PWWN=%s disappeared from"
14526                     " fabric", page->aff_d_id, ww_name);
14527 
14528                 mutex_enter(&did_pd->pd_mutex);
14529                 did_pd->pd_flags = PD_IDLE;
14530                 mutex_exit(&did_pd->pd_mutex);
14531 
14532                 FP_TRACE(FP_NHEAD1(3, 0), "RSCN with D_ID (%x) page; "
14533                     "PD disappeared, pd=%p", page->aff_d_id, did_pd);
14534 
14535                 return;
14536         }
14537 
14538         pwwn_pd = fctl_get_remote_port_by_pwwn(port, pwwn);
14539 
14540         if (did_pd != NULL && pwwn_pd != NULL && did_pd == pwwn_pd) {
14541                 /*
14542                  * There is no change. Do PLOGI again and add it to
14543                  * ULP portmap baggage and return. Note: When RSCNs
14544                  * arrive with per page states, the need for PLOGI
14545                  * can be determined correctly.
14546                  */
14547                 mutex_enter(&pwwn_pd->pd_mutex);
14548                 pwwn_pd->pd_type = PORT_DEVICE_NOCHANGE;
14549                 mutex_exit(&pwwn_pd->pd_mutex);
14550 
14551                 (listptr + *listindex)->map_rscn_info.ulp_rscn_count =
14552                     (uint32_t)(uintptr_t)job->job_cb_arg;
14553 
14554                 fctl_copy_portmap(listptr + (*listindex)++, pwwn_pd);
14555 
14556                 mutex_enter(&pwwn_pd->pd_mutex);
14557                 if ((pwwn_pd->pd_state == PORT_DEVICE_LOGGED_IN) ||
14558                     (pwwn_pd->pd_aux_flags & PD_LOGGED_OUT)) {
14559                         fc_wwn_to_str(&pwwn_pd->pd_port_name, ww_name);
14560                         mutex_exit(&pwwn_pd->pd_mutex);
14561 
14562                         rval = fp_port_login(port, page->aff_d_id, job,
14563                             FP_CMD_PLOGI_RETAIN, sleep, pwwn_pd, NULL);
14564                         if (rval == FC_SUCCESS) {
14565                                 fp_jobwait(job);
14566                                 rval = job->job_result;
14567 
14568                                 /*
14569                                  * Reset LOGO tolerance to zero
14570                                  * Also we are the PLOGI initiator now.
14571                                  */
14572                                 mutex_enter(&pwwn_pd->pd_mutex);
14573                                 fctl_tc_reset(&pwwn_pd->pd_logo_tc);
14574                                 pwwn_pd->pd_recepient = PD_PLOGI_INITIATOR;
14575                                 mutex_exit(&pwwn_pd->pd_mutex);
14576                         }
14577 
14578                         if (rval == FC_SUCCESS) {
14579                                 struct fc_portmap *map =
14580                                     listptr + *listindex - 1;
14581 
14582                                 FP_TRACE(FP_NHEAD1(1, 0),
14583                                     "PLOGI succeeded: no skip(2)"
14584                                     " for D_ID %x", page->aff_d_id);
14585                                 map->map_flags |=
14586                                     PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY;
14587                         } else {
14588                                 FP_TRACE(FP_NHEAD2(9, rval),
14589                                     "PLOGI to D_ID=%x failed", page->aff_d_id);
14590 
14591                                 FP_TRACE(FP_NHEAD2(9, 0),
14592                                     "N_x Port with D_ID=%x, PWWN=%s"
14593                                     " disappeared from fabric",
14594                                     page->aff_d_id, ww_name);
14595 
14596                                 fp_fillout_old_map(listptr +
14597                                     *listindex - 1, pwwn_pd, 0);
14598                         }
14599                 } else {
14600                         mutex_exit(&pwwn_pd->pd_mutex);
14601                 }
14602 
14603                 mutex_enter(&did_pd->pd_mutex);
14604                 did_pd->pd_flags = PD_IDLE;
14605                 mutex_exit(&did_pd->pd_mutex);
14606 
14607                 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID (0x%x) page; "
14608                     "Case ONE, rval=%x, result=%x pd=%p", page->aff_d_id, rval,
14609                     job->job_result, pwwn_pd);
14610 
14611                 return;
14612         }
14613 
14614         if (did_pd == NULL && pwwn_pd == NULL) {
14615 
14616                 fc_orphan_t     *orp  = NULL;
14617                 fc_orphan_t     *norp = NULL;
14618                 fc_orphan_t     *prev = NULL;
14619 
14620                 /*
14621                  * Hunt down the orphan list before giving up.
14622                  */
14623 
14624                 mutex_enter(&port->fp_mutex);
14625                 if (port->fp_orphan_count) {
14626 
14627                         for (orp = port->fp_orphan_list; orp; orp = norp) {
14628                                 norp = orp->orp_next;
14629 
14630                                 if (fctl_wwn_cmp(&orp->orp_pwwn, pwwn) != 0) {
14631                                         prev = orp;
14632                                         continue;
14633                                 }
14634 
14635                                 if (prev) {
14636                                         prev->orp_next = orp->orp_next;
14637                                 } else {
14638                                         ASSERT(orp ==
14639                                             port->fp_orphan_list);
14640                                         port->fp_orphan_list =
14641                                             orp->orp_next;
14642                                 }
14643                                 port->fp_orphan_count--;
14644                                 break;
14645                         }
14646                 }
14647 
14648                 mutex_exit(&port->fp_mutex);
14649                 pwwn_pd = fp_create_remote_port_by_ns(port,
14650                     page->aff_d_id, sleep);
14651 
14652                 if (pwwn_pd != NULL) {
14653 
14654                         if (orp) {
14655                                 fc_wwn_to_str(&orp->orp_pwwn,
14656                                     ww_name);
14657 
14658                                 FP_TRACE(FP_NHEAD2(9, 0),
14659                                     "N_x Port with D_ID=%x,"
14660                                     " PWWN=%s reappeared in fabric",
14661                                     page->aff_d_id, ww_name);
14662 
14663                                 kmem_free(orp, sizeof (*orp));
14664                         }
14665 
14666                         (listptr + *listindex)->
14667                             map_rscn_info.ulp_rscn_count =
14668                             (uint32_t)(uintptr_t)job->job_cb_arg;
14669 
14670                         fctl_copy_portmap(listptr +
14671                             (*listindex)++, pwwn_pd);
14672                 }
14673 
14674                 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID (0x%x) page; "
14675                     "Case TWO", page->aff_d_id);
14676 
14677                 return;
14678         }
14679 
14680         if (pwwn_pd != NULL && did_pd == NULL) {
14681                 uint32_t old_d_id;
14682                 uint32_t d_id = page->aff_d_id;
14683 
14684                 /*
14685                  * What this means is there is a new D_ID for this
14686                  * Port WWN. Take out the port device off D_ID
14687                  * list and put it back with a new D_ID. Perform
14688                  * PLOGI if already logged in.
14689                  */
14690                 mutex_enter(&port->fp_mutex);
14691                 mutex_enter(&pwwn_pd->pd_mutex);
14692 
14693                 old_d_id = pwwn_pd->pd_port_id.port_id;
14694 
14695                 fctl_delist_did_table(port, pwwn_pd);
14696 
14697                 (listptr + *listindex)->map_rscn_info.ulp_rscn_count =
14698                     (uint32_t)(uintptr_t)job->job_cb_arg;
14699 
14700                 fp_fillout_changed_map(listptr + (*listindex)++, pwwn_pd,
14701                     &d_id, NULL);
14702                 fctl_enlist_did_table(port, pwwn_pd);
14703 
14704                 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page;"
14705                     " Case THREE, pd=%p,"
14706                     " state=%x", pwwn_pd, pwwn_pd->pd_state);
14707 
14708                 if ((pwwn_pd->pd_state == PORT_DEVICE_LOGGED_IN) ||
14709                     (pwwn_pd->pd_aux_flags & PD_LOGGED_OUT)) {
14710                         fc_wwn_to_str(&pwwn_pd->pd_port_name, ww_name);
14711 
14712                         mutex_exit(&pwwn_pd->pd_mutex);
14713                         mutex_exit(&port->fp_mutex);
14714 
14715                         FP_TRACE(FP_NHEAD2(9, 0),
14716                             "N_x Port with D_ID=%x, PWWN=%s has a new"
14717                             " D_ID=%x now", old_d_id, ww_name, d_id);
14718 
14719                         rval = fp_port_login(port, page->aff_d_id, job,
14720                             FP_CMD_PLOGI_RETAIN, sleep, pwwn_pd, NULL);
14721                         if (rval == FC_SUCCESS) {
14722                                 fp_jobwait(job);
14723                                 rval = job->job_result;
14724                         }
14725 
14726                         if (rval != FC_SUCCESS) {
14727                                 fp_fillout_old_map(listptr +
14728                                     *listindex - 1, pwwn_pd, 0);
14729                         }
14730                 } else {
14731                         mutex_exit(&pwwn_pd->pd_mutex);
14732                         mutex_exit(&port->fp_mutex);
14733                 }
14734 
14735                 return;
14736         }
14737 
14738         if (pwwn_pd == NULL && did_pd != NULL) {
14739                 fc_portmap_t    *ptr;
14740                 uint32_t        len = 1;
14741                 char            old_ww_name[17];
14742 
14743                 mutex_enter(&did_pd->pd_mutex);
14744                 fc_wwn_to_str(&did_pd->pd_port_name, old_ww_name);
14745                 mutex_exit(&did_pd->pd_mutex);
14746 
14747                 fc_wwn_to_str(pwwn, ww_name);
14748 
14749                 (listptr + *listindex)->map_rscn_info.ulp_rscn_count =
14750                     (uint32_t)(uintptr_t)job->job_cb_arg;
14751 
14752                 /*
14753                  * What this means is that there is a new Port WWN for
14754                  * this D_ID; Mark the Port device as old and provide
14755                  * the new PWWN and D_ID combination as new.
14756                  */
14757                 fp_fillout_old_map(listptr + (*listindex)++, did_pd, 0);
14758 
14759                 FP_TRACE(FP_NHEAD2(9, 0),
14760                     "N_x Port with D_ID=%x, PWWN=%s has a new PWWN=%s now",
14761                     page->aff_d_id, old_ww_name, ww_name);
14762 
14763                 (listptr + *listindex)->map_rscn_info.ulp_rscn_count =
14764                     (uint32_t)(uintptr_t)job->job_cb_arg;
14765 
14766                 ptr = listptr + (*listindex)++;
14767 
14768                 job->job_counter = 1;
14769 
14770                 if (fp_ns_getmap(port, job, &ptr, &len,
14771                     page->aff_d_id - 1) != FC_SUCCESS) {
14772                         (*listindex)--;
14773                 }
14774 
14775                 mutex_enter(&did_pd->pd_mutex);
14776                 did_pd->pd_flags = PD_IDLE;
14777                 mutex_exit(&did_pd->pd_mutex);
14778 
14779                 return;
14780         }
14781 
14782         /*
14783          * A weird case of Port WWN and D_ID existence but not matching up
14784          * between them. Trust your instincts - Take the port device handle
14785          * off Port WWN list, fix it with new Port WWN and put it back, In
14786          * the mean time mark the port device corresponding to the old port
14787          * WWN as OLD.
14788          */
14789         FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page; Case WEIRD, pwwn_pd=%p,"
14790             " did_pd=%p", pwwn_pd, did_pd);
14791 
14792         mutex_enter(&port->fp_mutex);
14793         mutex_enter(&pwwn_pd->pd_mutex);
14794 
14795         pwwn_pd->pd_type = PORT_DEVICE_OLD;
14796         pwwn_pd->pd_state = PORT_DEVICE_INVALID;
14797         fctl_delist_did_table(port, pwwn_pd);
14798         fctl_delist_pwwn_table(port, pwwn_pd);
14799 
14800         FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page; case WEIRD continued,"
14801             " pwwn-d_id=%x pwwn-wwn=%x %x %x %x %x %x %x %x",
14802             pwwn_pd->pd_port_id.port_id,
14803 
14804             pwwn_pd->pd_port_name.raw_wwn[0],
14805             pwwn_pd->pd_port_name.raw_wwn[1],
14806             pwwn_pd->pd_port_name.raw_wwn[2],
14807             pwwn_pd->pd_port_name.raw_wwn[3],
14808             pwwn_pd->pd_port_name.raw_wwn[4],
14809             pwwn_pd->pd_port_name.raw_wwn[5],
14810             pwwn_pd->pd_port_name.raw_wwn[6],
14811             pwwn_pd->pd_port_name.raw_wwn[7]);
14812 
14813         mutex_exit(&pwwn_pd->pd_mutex);
14814         mutex_exit(&port->fp_mutex);
14815 
14816         (listptr + *listindex)->map_rscn_info.ulp_rscn_count =
14817             (uint32_t)(uintptr_t)job->job_cb_arg;
14818 
14819         fctl_copy_portmap(listptr + (*listindex)++, pwwn_pd);
14820 
14821         mutex_enter(&port->fp_mutex);
14822         mutex_enter(&did_pd->pd_mutex);
14823 
14824         fctl_delist_pwwn_table(port, did_pd);
14825 
14826         (listptr + *listindex)->map_rscn_info.ulp_rscn_count =
14827             (uint32_t)(uintptr_t)job->job_cb_arg;
14828 
14829         fp_fillout_changed_map(listptr + (*listindex)++, did_pd, NULL, pwwn);
14830         fctl_enlist_pwwn_table(port, did_pd);
14831 
14832         FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page; case WEIRD continued,"
14833             " d_id=%x, state=%x, did-wwn=%x %x %x %x %x %x %x %x",
14834             did_pd->pd_port_id.port_id, did_pd->pd_state,
14835 
14836             did_pd->pd_port_name.raw_wwn[0],
14837             did_pd->pd_port_name.raw_wwn[1],
14838             did_pd->pd_port_name.raw_wwn[2],
14839             did_pd->pd_port_name.raw_wwn[3],
14840             did_pd->pd_port_name.raw_wwn[4],
14841             did_pd->pd_port_name.raw_wwn[5],
14842             did_pd->pd_port_name.raw_wwn[6],
14843             did_pd->pd_port_name.raw_wwn[7]);
14844 
14845         if ((did_pd->pd_state == PORT_DEVICE_LOGGED_IN) ||
14846             (did_pd->pd_aux_flags & PD_LOGGED_OUT)) {
14847                 mutex_exit(&did_pd->pd_mutex);
14848                 mutex_exit(&port->fp_mutex);
14849 
14850                 rval = fp_port_login(port, page->aff_d_id, job,
14851                     FP_CMD_PLOGI_RETAIN, sleep, did_pd, NULL);
14852                 if (rval == FC_SUCCESS) {
14853                         fp_jobwait(job);
14854                         if (job->job_result != FC_SUCCESS) {
14855                                 fp_fillout_old_map(listptr +
14856                                     *listindex - 1, did_pd, 0);
14857                         }
14858                 } else {
14859                         fp_fillout_old_map(listptr + *listindex - 1, did_pd, 0);
14860                 }
14861         } else {
14862                 mutex_exit(&did_pd->pd_mutex);
14863                 mutex_exit(&port->fp_mutex);
14864         }
14865 
14866         mutex_enter(&did_pd->pd_mutex);
14867         did_pd->pd_flags = PD_IDLE;
14868         mutex_exit(&did_pd->pd_mutex);
14869 }
14870 
14871 
14872 /*
14873  * Check with NS for the presence of this port WWN
14874  */
14875 static int
14876 fp_ns_validate_device(fc_local_port_t *port, fc_remote_port_t *pd,
14877     job_request_t *job, int polled, int sleep)
14878 {
14879         la_wwn_t        pwwn;
14880         uint32_t        flags;
14881         fctl_ns_req_t   *ns_cmd;
14882 
14883         flags = FCTL_NS_VALIDATE_PD | ((polled) ? 0: FCTL_NS_ASYNC_REQUEST);
14884         ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t),
14885             sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t),
14886             flags, sleep);
14887         if (ns_cmd == NULL) {
14888                 return (FC_NOMEM);
14889         }
14890 
14891         mutex_enter(&pd->pd_mutex);
14892         pwwn = pd->pd_port_name;
14893         mutex_exit(&pd->pd_mutex);
14894 
14895         ns_cmd->ns_cmd_code = NS_GID_PN;
14896         ns_cmd->ns_pd = pd;
14897         ((ns_req_gid_pn_t *)ns_cmd->ns_cmd_buf)->pwwn = pwwn;
14898         ((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->pid.port_id = 0;
14899         ((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->pid.priv_lilp_posit = 0;
14900 
14901         return (fp_ns_query(port, ns_cmd, job, polled, sleep));
14902 }
14903 
14904 
14905 /*
14906  * Sanity check the LILP map returned by FCA
14907  */
14908 static int
14909 fp_validate_lilp_map(fc_lilpmap_t *lilp_map)
14910 {
14911         int     count;
14912 
14913         if (lilp_map->lilp_length == 0) {
14914                 return (FC_FAILURE);
14915         }
14916 
14917         for (count = 0; count < lilp_map->lilp_length; count++) {
14918                 if (fp_is_valid_alpa(lilp_map->lilp_alpalist[count]) !=
14919                     FC_SUCCESS) {
14920                         return (FC_FAILURE);
14921                 }
14922         }
14923 
14924         return (FC_SUCCESS);
14925 }
14926 
14927 
14928 /*
14929  * Sanity check if the AL_PA is a valid address
14930  */
14931 static int
14932 fp_is_valid_alpa(uchar_t al_pa)
14933 {
14934         int     count;
14935 
14936         for (count = 0; count < sizeof (fp_valid_alpas); count++) {
14937                 if (al_pa == fp_valid_alpas[count] || al_pa == 0) {
14938                         return (FC_SUCCESS);
14939                 }
14940         }
14941 
14942         return (FC_FAILURE);
14943 }
14944 
14945 
14946 /*
14947  * Post unsolicited callbacks to ULPs
14948  */
14949 static void
14950 fp_ulp_unsol_cb(void *arg)
14951 {
14952         fp_unsol_spec_t *ub_spec = (fp_unsol_spec_t *)arg;
14953 
14954         fctl_ulp_unsol_cb(ub_spec->port, ub_spec->buf,
14955             ub_spec->buf->ub_frame.type);
14956         kmem_free(ub_spec, sizeof (*ub_spec));
14957 }
14958 
14959 
14960 /*
14961  * Perform message reporting in a consistent manner. Unless there is
14962  * a strong reason NOT to use this function (which is very very rare)
14963  * all message reporting should go through this.
14964  */
14965 static void
14966 fp_printf(fc_local_port_t *port, int level, fp_mesg_dest_t dest, int fc_errno,
14967     fc_packet_t *pkt, const char *fmt, ...)
14968 {
14969         caddr_t         buf;
14970         va_list         ap;
14971 
14972         switch (level) {
14973         case CE_NOTE:
14974                 if ((port->fp_verbose & FP_WARNING_MESSAGES) == 0) {
14975                         return;
14976                 }
14977                 break;
14978 
14979         case CE_WARN:
14980                 if ((port->fp_verbose & FP_FATAL_MESSAGES) == 0) {
14981                         return;
14982                 }
14983                 break;
14984         }
14985 
14986         buf = kmem_zalloc(256, KM_NOSLEEP);
14987         if (buf == NULL) {
14988                 return;
14989         }
14990 
14991         (void) sprintf(buf, "fp(%d): ", port->fp_instance);
14992 
14993         va_start(ap, fmt);
14994         (void) vsprintf(buf + strlen(buf), fmt, ap);
14995         va_end(ap);
14996 
14997         if (fc_errno) {
14998                 char *errmsg;
14999 
15000                 (void) fc_ulp_error(fc_errno, &errmsg);
15001                 (void) sprintf(buf + strlen(buf), " FC Error=%s", errmsg);
15002         } else {
15003                 if (pkt) {
15004                         caddr_t state, reason, action, expln;
15005 
15006                         (void) fc_ulp_pkt_error(pkt, &state, &reason,
15007                             &action, &expln);
15008 
15009                         (void) sprintf(buf + strlen(buf),
15010                             " state=%s, reason=%s", state, reason);
15011 
15012                         if (pkt->pkt_resp_resid) {
15013                                 (void) sprintf(buf + strlen(buf),
15014                                     " resp resid=%x\n", pkt->pkt_resp_resid);
15015                         }
15016                 }
15017         }
15018 
15019         switch (dest) {
15020         case FP_CONSOLE_ONLY:
15021                 cmn_err(level, "^%s", buf);
15022                 break;
15023 
15024         case FP_LOG_ONLY:
15025                 cmn_err(level, "!%s", buf);
15026                 break;
15027 
15028         default:
15029                 cmn_err(level, "%s", buf);
15030                 break;
15031         }
15032 
15033         kmem_free(buf, 256);
15034 }
15035 
15036 static int
15037 fp_fcio_login(fc_local_port_t *port, fcio_t *fcio, job_request_t *job)
15038 {
15039         int                     ret;
15040         uint32_t                d_id;
15041         la_wwn_t                pwwn;
15042         fc_remote_port_t        *pd = NULL;
15043         fc_remote_port_t        *held_pd = NULL;
15044         fctl_ns_req_t           *ns_cmd;
15045         fc_portmap_t            *changelist;
15046 
15047         bcopy(fcio->fcio_ibuf, &pwwn, sizeof (pwwn));
15048 
15049         mutex_enter(&port->fp_mutex);
15050         if (FC_IS_TOP_SWITCH(port->fp_topology)) {
15051                 mutex_exit(&port->fp_mutex);
15052                 job->job_counter = 1;
15053 
15054                 job->job_result = FC_SUCCESS;
15055 
15056                 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t),
15057                     sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t),
15058                     FCTL_NS_BUF_IS_USERLAND, KM_SLEEP);
15059 
15060                 ASSERT(ns_cmd != NULL);
15061 
15062                 ns_cmd->ns_cmd_code = NS_GID_PN;
15063                 ((ns_req_gid_pn_t *)(ns_cmd->ns_cmd_buf))->pwwn = pwwn;
15064 
15065                 ret = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP);
15066 
15067                 if (ret != FC_SUCCESS || job->job_result != FC_SUCCESS) {
15068                         if (ret != FC_SUCCESS) {
15069                                 fcio->fcio_errno = ret;
15070                         } else {
15071                                 fcio->fcio_errno = job->job_result;
15072                         }
15073                         fctl_free_ns_cmd(ns_cmd);
15074                         return (EIO);
15075                 }
15076                 d_id = BE_32(*((uint32_t *)ns_cmd->ns_data_buf));
15077                 fctl_free_ns_cmd(ns_cmd);
15078         } else {
15079                 mutex_exit(&port->fp_mutex);
15080 
15081                 held_pd = fctl_hold_remote_port_by_pwwn(port, &pwwn);
15082                 if (held_pd == NULL) {
15083                         fcio->fcio_errno = FC_BADWWN;
15084                         return (EIO);
15085                 }
15086                 pd = held_pd;
15087 
15088                 mutex_enter(&pd->pd_mutex);
15089                 d_id = pd->pd_port_id.port_id;
15090                 mutex_exit(&pd->pd_mutex);
15091         }
15092 
15093         job->job_counter = 1;
15094 
15095         pd = fctl_get_remote_port_by_did(port, d_id);
15096 
15097         if (pd) {
15098                 mutex_enter(&pd->pd_mutex);
15099                 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) {
15100                         pd->pd_login_count++;
15101                         mutex_exit(&pd->pd_mutex);
15102 
15103                         fcio->fcio_errno = FC_SUCCESS;
15104                         if (held_pd) {
15105                                 fctl_release_remote_port(held_pd);
15106                         }
15107 
15108                         return (0);
15109                 }
15110                 mutex_exit(&pd->pd_mutex);
15111         } else {
15112                 mutex_enter(&port->fp_mutex);
15113                 if (FC_IS_TOP_SWITCH(port->fp_topology)) {
15114                         mutex_exit(&port->fp_mutex);
15115                         pd = fp_create_remote_port_by_ns(port, d_id, KM_SLEEP);
15116                         if (pd == NULL) {
15117                                 fcio->fcio_errno = FC_FAILURE;
15118                                 if (held_pd) {
15119                                         fctl_release_remote_port(held_pd);
15120                                 }
15121                                 return (EIO);
15122                         }
15123                 } else {
15124                         mutex_exit(&port->fp_mutex);
15125                 }
15126         }
15127 
15128         job->job_flags &= ~JOB_TYPE_FP_ASYNC;
15129         job->job_counter = 1;
15130 
15131         ret = fp_port_login(port, d_id, job, FP_CMD_PLOGI_RETAIN,
15132             KM_SLEEP, pd, NULL);
15133 
15134         if (ret != FC_SUCCESS) {
15135                 fcio->fcio_errno = ret;
15136                 if (held_pd) {
15137                         fctl_release_remote_port(held_pd);
15138                 }
15139                 return (EIO);
15140         }
15141         fp_jobwait(job);
15142 
15143         fcio->fcio_errno = job->job_result;
15144 
15145         if (held_pd) {
15146                 fctl_release_remote_port(held_pd);
15147         }
15148 
15149         if (job->job_result != FC_SUCCESS) {
15150                 return (EIO);
15151         }
15152 
15153         pd = fctl_hold_remote_port_by_pwwn(port, &pwwn);
15154         if (pd == NULL) {
15155                 fcio->fcio_errno = FC_BADDEV;
15156                 return (ENODEV);
15157         }
15158 
15159         changelist = kmem_zalloc(sizeof (*changelist), KM_SLEEP);
15160 
15161         fctl_copy_portmap(changelist, pd);
15162         changelist->map_type = PORT_DEVICE_USER_LOGIN;
15163 
15164         (void) fp_ulp_devc_cb(port, changelist, 1, 1, KM_SLEEP, 1);
15165 
15166         mutex_enter(&pd->pd_mutex);
15167         pd->pd_type = PORT_DEVICE_NOCHANGE;
15168         mutex_exit(&pd->pd_mutex);
15169 
15170         fctl_release_remote_port(pd);
15171 
15172         return (0);
15173 }
15174 
15175 
15176 static int
15177 fp_fcio_logout(fc_local_port_t *port, fcio_t *fcio, job_request_t *job)
15178 {
15179         la_wwn_t                pwwn;
15180         fp_cmd_t                *cmd;
15181         fc_portmap_t            *changelist;
15182         fc_remote_port_t        *pd;
15183 
15184         bcopy(fcio->fcio_ibuf, &pwwn, sizeof (pwwn));
15185 
15186         pd = fctl_hold_remote_port_by_pwwn(port, &pwwn);
15187         if (pd == NULL) {
15188                 fcio->fcio_errno = FC_BADWWN;
15189                 return (ENXIO);
15190         }
15191 
15192         mutex_enter(&pd->pd_mutex);
15193         if (pd->pd_state != PORT_DEVICE_LOGGED_IN) {
15194                 fcio->fcio_errno = FC_LOGINREQ;
15195                 mutex_exit(&pd->pd_mutex);
15196 
15197                 fctl_release_remote_port(pd);
15198 
15199                 return (EINVAL);
15200         }
15201 
15202         ASSERT(pd->pd_login_count >= 1);
15203 
15204         if (pd->pd_flags == PD_ELS_IN_PROGRESS) {
15205                 fcio->fcio_errno = FC_FAILURE;
15206                 mutex_exit(&pd->pd_mutex);
15207 
15208                 fctl_release_remote_port(pd);
15209 
15210                 return (EBUSY);
15211         }
15212 
15213         if (pd->pd_login_count > 1) {
15214                 pd->pd_login_count--;
15215                 fcio->fcio_errno = FC_SUCCESS;
15216                 mutex_exit(&pd->pd_mutex);
15217 
15218                 changelist = kmem_zalloc(sizeof (*changelist), KM_SLEEP);
15219 
15220                 fctl_copy_portmap(changelist, pd);
15221                 changelist->map_type = PORT_DEVICE_USER_LOGOUT;
15222 
15223                 fctl_release_remote_port(pd);
15224 
15225                 (void) fp_ulp_devc_cb(port, changelist, 1, 1, KM_SLEEP, 1);
15226 
15227                 return (0);
15228         }
15229 
15230         pd->pd_flags = PD_ELS_IN_PROGRESS;
15231         mutex_exit(&pd->pd_mutex);
15232 
15233         job->job_counter = 1;
15234 
15235         cmd = fp_alloc_pkt(port, sizeof (la_els_logo_t),
15236             FP_PORT_IDENTIFIER_LEN, KM_SLEEP, pd);
15237         if (cmd == NULL) {
15238                 fcio->fcio_errno = FC_NOMEM;
15239                 fctl_release_remote_port(pd);
15240 
15241                 mutex_enter(&pd->pd_mutex);
15242                 pd->pd_flags = PD_IDLE;
15243                 mutex_exit(&pd->pd_mutex);
15244 
15245                 return (ENOMEM);
15246         }
15247 
15248         mutex_enter(&port->fp_mutex);
15249         mutex_enter(&pd->pd_mutex);
15250 
15251         cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class;
15252         cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE;
15253         cmd->cmd_flags = FP_CMD_PLOGI_DONT_CARE;
15254         cmd->cmd_retry_count = 1;
15255         cmd->cmd_ulp_pkt = NULL;
15256 
15257         fp_logo_init(pd, cmd, job);
15258 
15259         mutex_exit(&pd->pd_mutex);
15260         mutex_exit(&port->fp_mutex);
15261 
15262         if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
15263                 mutex_enter(&pd->pd_mutex);
15264                 pd->pd_flags = PD_IDLE;
15265                 mutex_exit(&pd->pd_mutex);
15266 
15267                 fp_free_pkt(cmd);
15268                 fctl_release_remote_port(pd);
15269 
15270                 return (EIO);
15271         }
15272 
15273         fp_jobwait(job);
15274 
15275         fcio->fcio_errno = job->job_result;
15276         if (job->job_result != FC_SUCCESS) {
15277                 mutex_enter(&pd->pd_mutex);
15278                 pd->pd_flags = PD_IDLE;
15279                 mutex_exit(&pd->pd_mutex);
15280 
15281                 fctl_release_remote_port(pd);
15282 
15283                 return (EIO);
15284         }
15285 
15286         ASSERT(pd != NULL);
15287 
15288         changelist = kmem_zalloc(sizeof (*changelist), KM_SLEEP);
15289 
15290         fctl_copy_portmap(changelist, pd);
15291         changelist->map_type = PORT_DEVICE_USER_LOGOUT;
15292         changelist->map_state = PORT_DEVICE_INVALID;
15293 
15294         mutex_enter(&port->fp_mutex);
15295         mutex_enter(&pd->pd_mutex);
15296 
15297         fctl_delist_did_table(port, pd);
15298         fctl_delist_pwwn_table(port, pd);
15299         pd->pd_flags = PD_IDLE;
15300 
15301         mutex_exit(&pd->pd_mutex);
15302         mutex_exit(&port->fp_mutex);
15303 
15304         (void) fp_ulp_devc_cb(port, changelist, 1, 1, KM_SLEEP, 1);
15305 
15306         fctl_release_remote_port(pd);
15307 
15308         return (0);
15309 }
15310 
15311 
15312 
15313 /*
15314  * Send a syslog event for adapter port level events.
15315  */
15316 static void
15317 fp_log_port_event(fc_local_port_t *port, char *subclass)
15318 {
15319         nvlist_t *attr_list;
15320 
15321         if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE,
15322             KM_SLEEP) != DDI_SUCCESS) {
15323                 goto alloc_failed;
15324         }
15325 
15326         if (nvlist_add_uint32(attr_list, "instance",
15327             port->fp_instance) != DDI_SUCCESS) {
15328                 goto error;
15329         }
15330 
15331         if (nvlist_add_byte_array(attr_list, "port-wwn",
15332             port->fp_service_params.nport_ww_name.raw_wwn,
15333             sizeof (la_wwn_t)) != DDI_SUCCESS) {
15334                 goto error;
15335         }
15336 
15337         (void) ddi_log_sysevent(port->fp_port_dip, DDI_VENDOR_SUNW, EC_SUNFC,
15338             subclass, attr_list, NULL, DDI_SLEEP);
15339 
15340         nvlist_free(attr_list);
15341         return;
15342 
15343 error:
15344         nvlist_free(attr_list);
15345 alloc_failed:
15346         FP_TRACE(FP_NHEAD1(9, 0), "Unable to send %s event", subclass);
15347 }
15348 
15349 
15350 static void
15351 fp_log_target_event(fc_local_port_t *port, char *subclass, la_wwn_t tgt_pwwn,
15352     uint32_t port_id)
15353 {
15354         nvlist_t *attr_list;
15355 
15356         if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE,
15357             KM_SLEEP) != DDI_SUCCESS) {
15358                 goto alloc_failed;
15359         }
15360 
15361         if (nvlist_add_uint32(attr_list, "instance",
15362             port->fp_instance) != DDI_SUCCESS) {
15363                 goto error;
15364         }
15365 
15366         if (nvlist_add_byte_array(attr_list, "port-wwn",
15367             port->fp_service_params.nport_ww_name.raw_wwn,
15368             sizeof (la_wwn_t)) != DDI_SUCCESS) {
15369                 goto error;
15370         }
15371 
15372         if (nvlist_add_byte_array(attr_list, "target-port-wwn",
15373             tgt_pwwn.raw_wwn, sizeof (la_wwn_t)) != DDI_SUCCESS) {
15374                 goto error;
15375         }
15376 
15377         if (nvlist_add_uint32(attr_list, "target-port-id",
15378             port_id) != DDI_SUCCESS) {
15379                 goto error;
15380         }
15381 
15382         (void) ddi_log_sysevent(port->fp_port_dip, DDI_VENDOR_SUNW, EC_SUNFC,
15383             subclass, attr_list, NULL, DDI_SLEEP);
15384 
15385         nvlist_free(attr_list);
15386         return;
15387 
15388 error:
15389         nvlist_free(attr_list);
15390 alloc_failed:
15391         FP_TRACE(FP_NHEAD1(9, 0), "Unable to send %s event", subclass);
15392 }
15393 
15394 static uint32_t
15395 fp_map_remote_port_state(uint32_t rm_state)
15396 {
15397         switch (rm_state) {
15398         case PORT_DEVICE_LOGGED_IN:
15399                 return (FC_HBA_PORTSTATE_ONLINE);
15400         case PORT_DEVICE_VALID:
15401         case PORT_DEVICE_INVALID:
15402         default:
15403                 return (FC_HBA_PORTSTATE_UNKNOWN);
15404         }
15405 }