Print this page
NEX-18203 fcp should call mdi_pi_offline() without NDI_DEVI_REMOVE
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Dan Fields <dan.fields@nexenta.com>
NEX-17944 HBA drivers don't need the redundant devfs_clean step
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
NEX-3153 fcp unable to offline paths to drives behind ATTO Fibrebridge 6500
Reviewed by: Steve Peng <steve.peng@nexenta.com>
Reviewed by: Dan Fields <dan.fields@nexenta.com>
   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) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
  23  *






  24  * Fibre Channel SCSI ULP Mapping driver
  25  */
  26 
  27 #include <sys/scsi/scsi.h>
  28 #include <sys/types.h>
  29 #include <sys/varargs.h>
  30 #include <sys/devctl.h>
  31 #include <sys/thread.h>
  32 #include <sys/thread.h>
  33 #include <sys/open.h>
  34 #include <sys/file.h>
  35 #include <sys/sunndi.h>
  36 #include <sys/console.h>
  37 #include <sys/proc.h>
  38 #include <sys/time.h>
  39 #include <sys/utsname.h>
  40 #include <sys/scsi/impl/scsi_reset_notify.h>
  41 #include <sys/ndi_impldefs.h>
  42 #include <sys/byteorder.h>
  43 #include <sys/fs/dv_node.h>
  44 #include <sys/ctype.h>
  45 #include <sys/sunmdi.h>
  46 
  47 #include <sys/fibre-channel/fc.h>
  48 #include <sys/fibre-channel/impl/fc_ulpif.h>
  49 #include <sys/fibre-channel/ulp/fcpvar.h>
  50 
  51 /*
  52  * Discovery Process
  53  * =================
  54  *
  55  *    The discovery process is a major function of FCP.  In order to help
  56  * understand that function a flow diagram is given here.  This diagram
  57  * doesn't claim to cover all the cases and the events that can occur during
  58  * the discovery process nor the subtleties of the code.  The code paths shown
  59  * are simplified.  Its purpose is to help the reader (and potentially bug
  60  * fixer) have an overall view of the logic of the code.  For that reason the
  61  * diagram covers the simple case of the line coming up cleanly or of a new
  62  * port attaching to FCP the link being up.  The reader must keep in mind
  63  * that:


3849                 mutex_enter(&pptr->port_mutex);
3850                 if (pip != NULL) {
3851                         cip = CIP(pip);
3852                 }
3853                 if ((plun = fcp_get_lun_from_cip(pptr, cip)) == NULL) {
3854                         mutex_exit(&pptr->port_mutex);
3855                         *rval = ENXIO;
3856                         break;
3857                 }
3858 
3859                 head = fcp_scan_commands(plun);
3860                 if (head != NULL) {
3861                         fcp_abort_commands(head, LUN_PORT);
3862                 }
3863                 lcount = pptr->port_link_cnt;
3864                 tcount = plun->lun_tgt->tgt_change_cnt;
3865                 mutex_exit(&pptr->port_mutex);
3866 
3867                 if (cmd == DEVCTL_DEVICE_REMOVE) {
3868                         flag = NDI_DEVI_REMOVE;


3869                 }
3870 
3871                 if (is_mpxio) {
3872                         mdi_devi_exit(pptr->port_dip, circ);
3873                 } else {
3874                         ndi_devi_exit(pptr->port_dip, circ);
3875                 }
3876                 devi_entered = 0;
3877 
3878                 *rval = fcp_pass_to_hp_and_wait(pptr, plun, cip,
3879                     FCP_OFFLINE, lcount, tcount, flag);
3880 
3881                 if (*rval != NDI_SUCCESS) {
3882                         *rval = (*rval == NDI_BUSY) ? EBUSY : EIO;
3883                         break;
3884                 }
3885 
3886                 fcp_update_offline_flags(plun);
3887 
3888                 ptgt = plun->lun_tgt;


8134                                     "Can not ONLINE LUN; D_ID=%x, LUN=%x\n",
8135                                     plun->lun_tgt->tgt_d_id, plun->lun_num);
8136                         }
8137                 }
8138         }
8139 }
8140 
8141 
8142 /*
8143  * function to online/offline devices
8144  */
8145 static int
8146 fcp_trigger_lun(struct fcp_lun *plun, child_info_t *cip, int old_mpxio,
8147     int online, int lcount, int tcount, int flags)
8148 {
8149         int                     rval = NDI_FAILURE;
8150         int                     circ;
8151         child_info_t            *ccip;
8152         struct fcp_port         *pptr = plun->lun_tgt->tgt_port;
8153         int                     is_mpxio = pptr->port_mpxio;
8154         dev_info_t              *cdip, *pdip;
8155         char                    *devname;
8156 
8157         if ((old_mpxio != 0) && (plun->lun_mpxio != old_mpxio)) {
8158                 /*
8159                  * When this event gets serviced, lun_cip and lun_mpxio
8160                  * has changed, so it should be invalidated now.
8161                  */
8162                 FCP_TRACE(fcp_logq, pptr->port_instbuf, fcp_trace,
8163                     FCP_BUF_LEVEL_2, 0, "fcp_trigger_lun: lun_mpxio changed: "
8164                     "plun: %p, cip: %p, what:%d", plun, cip, online);
8165                 return (rval);
8166         }
8167 
8168         FCP_TRACE(fcp_logq, pptr->port_instbuf,
8169             fcp_trace, FCP_BUF_LEVEL_2, 0,
8170             "fcp_trigger_lun: plun=%p target=%x lun=%d cip=%p what=%x "
8171             "flags=%x mpxio=%x\n",
8172             plun, LUN_TGT->tgt_d_id, plun->lun_num, cip, online, flags,
8173             plun->lun_mpxio);
8174 
8175         /*
8176          * lun_mpxio needs checking here because we can end up in a race
8177          * condition where this task has been dispatched while lun_mpxio is
8178          * set, but an earlier FCP_ONLINE task for the same LUN tried to
8179          * enable MPXIO for the LUN, but was unable to, and hence cleared
8180          * the flag. We rely on the serialization of the tasks here. We return
8181          * NDI_SUCCESS so any callers continue without reporting spurious
8182          * errors, and the still think we're an MPXIO LUN.
8183          */
8184 
8185         if (online == FCP_MPXIO_PATH_CLEAR_BUSY ||
8186             online == FCP_MPXIO_PATH_SET_BUSY) {
8187                 if (plun->lun_mpxio) {
8188                         rval = fcp_update_mpxio_path(plun, cip, online);
8189                 } else {
8190                         rval = NDI_SUCCESS;
8191                 }
8192                 return (rval);
8193         }
8194 
8195         /*
8196          * Explicit devfs_clean() due to ndi_devi_offline() not
8197          * executing devfs_clean() if parent lock is held.
8198          */
8199         ASSERT(!servicing_interrupt());
8200         if (online == FCP_OFFLINE) {
8201                 if (plun->lun_mpxio == 0) {
8202                         if (plun->lun_cip == cip) {
8203                                 cdip = DIP(plun->lun_cip);
8204                         } else {
8205                                 cdip = DIP(cip);
8206                         }
8207                 } else if ((plun->lun_cip == cip) && plun->lun_cip) {
8208                         cdip = mdi_pi_get_client(PIP(plun->lun_cip));
8209                 } else if ((plun->lun_cip != cip) && cip) {
8210                         /*
8211                          * This means a DTYPE/GUID change, we shall get the
8212                          * dip of the old cip instead of the current lun_cip.
8213                          */
8214                         cdip = mdi_pi_get_client(PIP(cip));
8215                 }
8216                 if (cdip) {
8217                         if (i_ddi_devi_attached(cdip)) {
8218                                 pdip = ddi_get_parent(cdip);
8219                                 devname = kmem_alloc(MAXNAMELEN + 1, KM_SLEEP);
8220                                 ndi_devi_enter(pdip, &circ);
8221                                 (void) ddi_deviname(cdip, devname);
8222                                 /*
8223                                  * Release parent lock before calling
8224                                  * devfs_clean().
8225                                  */
8226                                 ndi_devi_exit(pdip, circ);
8227                                 (void) devfs_clean(pdip, devname + 1,
8228                                     DV_CLEAN_FORCE);
8229                                 kmem_free(devname, MAXNAMELEN + 1);
8230                         }
8231                 }
8232         }
8233 
8234         if (fc_ulp_busy_port(pptr->port_fp_handle) != 0) {
8235                 return (NDI_FAILURE);
8236         }
8237 
8238         if (is_mpxio) {
8239                 mdi_devi_enter(pptr->port_dip, &circ);
8240         } else {
8241                 ndi_devi_enter(pptr->port_dip, &circ);
8242         }
8243 
8244         mutex_enter(&pptr->port_mutex);
8245         mutex_enter(&plun->lun_mutex);
8246 
8247         if (online == FCP_ONLINE) {
8248                 ccip = fcp_get_cip(plun, cip, lcount, tcount);
8249                 if (ccip == NULL) {
8250                         goto fail;
8251                 }
8252         } else {
8253                 if (fcp_is_child_present(plun, cip) != FC_SUCCESS) {


13053          *
13054          * The behavior is different on other devices. For instance, on a HDS,
13055          * there was no RSCN generated by the device but the next I/O generated
13056          * a check condition and rediscovery got triggered that way. So, in
13057          * such cases, this path will not be exercised
13058          */
13059         if (pip == NULL) {
13060                 FCP_TRACE(fcp_logq, LUN_PORT->port_instbuf,
13061                     fcp_trace, FCP_BUF_LEVEL_4, 0,
13062                     "fcp_is_pip_present: plun->lun_cip is NULL: "
13063                     "plun: %p lun state: %x num: %d target state: %x",
13064                     plun, plun->lun_state, plun->lun_num,
13065                     plun->lun_tgt->tgt_port->port_state);
13066                 return (rval);
13067         }
13068 
13069         fcp_wwn_to_ascii(plun->lun_tgt->tgt_port_wwn.raw_wwn, buf);
13070 
13071         (void) snprintf(uaddr, MAXNAMELEN, "w%s,%x", buf, plun->lun_num);
13072 
13073         if (plun->lun_old_guid) {
13074                 if (mdi_pi_find(pdip, plun->lun_old_guid, uaddr) == pip) {
13075                         rval = FC_SUCCESS;
13076                 }
13077         } else {
13078                 if (mdi_pi_find(pdip, plun->lun_guid, uaddr) == pip) {
13079                         rval = FC_SUCCESS;
13080                 }
13081         }
13082         return (rval);
13083 }
13084 
13085 static mdi_pathinfo_t *
13086 fcp_find_existing_pip(struct fcp_lun *plun, dev_info_t *pdip)
13087 {
13088         char                    buf[MAXNAMELEN];
13089         char                    uaddr[MAXNAMELEN];
13090         mdi_pathinfo_t          *pip;
13091         struct fcp_tgt  *ptgt = plun->lun_tgt;
13092         struct fcp_port *pptr = ptgt->tgt_port;
13093 
13094         ASSERT(MUTEX_HELD(&pptr->port_mutex));
13095 
13096         fcp_wwn_to_ascii(ptgt->tgt_port_wwn.raw_wwn, buf);
13097         (void) snprintf(uaddr, MAXNAMELEN, "w%s,%x", buf, plun->lun_num);
13098 
13099         pip = mdi_pi_find(pdip, plun->lun_guid, uaddr);
13100 
13101         return (pip);


13295         if (plun->lun_cip == NULL) {
13296                 FCP_TRACE(fcp_logq, pptr->port_instbuf,
13297                     fcp_trace, FCP_BUF_LEVEL_3, 0,
13298                     "fcp_offline_child: plun->lun_cip is NULL: "
13299                     "plun: %p lun state: %x num: %d target state: %x",
13300                     plun, plun->lun_state, plun->lun_num,
13301                     plun->lun_tgt->tgt_port->port_state);
13302                 return (NDI_FAILURE);
13303         }
13304 
13305         /*
13306          * We will use this value twice. Make a copy to be sure we use
13307          * the same value in both places.
13308          */
13309         lun_mpxio = plun->lun_mpxio;
13310 
13311         if (lun_mpxio == 0) {
13312                 cdip = DIP(cip);
13313                 mutex_exit(&plun->lun_mutex);
13314                 mutex_exit(&pptr->port_mutex);
13315                 rval = ndi_devi_offline(DIP(cip), flags);
13316                 if (rval != NDI_SUCCESS) {
13317                         FCP_TRACE(fcp_logq, pptr->port_instbuf,
13318                             fcp_trace, FCP_BUF_LEVEL_3, 0,
13319                             "fcp_offline_child: ndi_devi_offline failed "
13320                             "rval=%x cip=%p", rval, cip);
13321                 }
13322         } else {
13323                 cdip = mdi_pi_get_client(PIP(cip));
13324                 mutex_exit(&plun->lun_mutex);
13325                 mutex_exit(&pptr->port_mutex);
13326 
13327                 /*
13328                  * Exit phci to avoid deadlock with power management code
13329                  * during mdi_pi_offline
13330                  */
13331                 mdi_hold_path(PIP(cip));
13332                 mdi_devi_exit_phci(pptr->port_dip, *circ);
13333 
13334                 rval = mdi_pi_offline(PIP(cip), flags);
13335 
13336                 mdi_devi_enter_phci(pptr->port_dip, circ);
13337                 mdi_rele_path(PIP(cip));
13338 
13339                 rval = (rval == MDI_SUCCESS) ? NDI_SUCCESS : NDI_FAILURE;
13340         }
13341 
13342         mutex_enter(&ptgt->tgt_mutex);
13343         plun->lun_state &= ~FCP_LUN_INIT;
13344         mutex_exit(&ptgt->tgt_mutex);
13345 
13346         if (rval == NDI_SUCCESS) {
13347                 cdip = NULL;
13348                 if (flags & NDI_DEVI_REMOVE) {
13349                         mutex_enter(&plun->lun_mutex);
13350                         /*
13351                          * If the guid of the LUN changes, lun_cip will not
13352                          * equal to cip, and after offlining the LUN with the
13353                          * old guid, we should keep lun_cip since it's the cip
13354                          * of the LUN with the new guid.


13414         if (fcp_is_child_present(plun, plun->lun_cip) == FC_SUCCESS) {
13415                 if (plun->lun_mpxio == 0) {
13416                         (void) ndi_prop_remove_all(DIP(plun->lun_cip));
13417                         (void) ndi_devi_free(DIP(plun->lun_cip));
13418                         plun->lun_cip = NULL;
13419                 } else {
13420                         /*
13421                          * Clear reference to the child node in the lun.
13422                          * This must be done before freeing it with mdi_pi_free
13423                          * and with lun_mutex held so that other threads always
13424                          * see either valid lun_cip or NULL when holding
13425                          * lun_mutex. We keep a copy in cip.
13426                          */
13427                         cip = plun->lun_cip;
13428                         plun->lun_cip = NULL;
13429 
13430                         mutex_exit(&plun->lun_mutex);
13431                         mutex_exit(&plun->lun_tgt->tgt_mutex);
13432                         mutex_exit(&plun->lun_tgt->tgt_port->port_mutex);
13433 
13434                         mdi_devi_enter(
13435                             plun->lun_tgt->tgt_port->port_dip, &circ);
13436 
13437                         /*
13438                          * Exit phci to avoid deadlock with power management
13439                          * code during mdi_pi_offline
13440                          */
13441                         mdi_hold_path(PIP(cip));
13442                         mdi_devi_exit_phci(
13443                             plun->lun_tgt->tgt_port->port_dip, circ);
13444                         (void) mdi_pi_offline(PIP(cip),
13445                             NDI_DEVI_REMOVE);
13446                         mdi_devi_enter_phci(
13447                             plun->lun_tgt->tgt_port->port_dip, &circ);
13448                         mdi_rele_path(PIP(cip));
13449 
13450                         mdi_devi_exit(
13451                             plun->lun_tgt->tgt_port->port_dip, circ);
13452 
13453                         FCP_TRACE(fcp_logq,
13454                             plun->lun_tgt->tgt_port->port_instbuf,
13455                             fcp_trace, FCP_BUF_LEVEL_3, 0,
13456                             "lun=%p pip freed %p", plun, cip);
13457 
13458                         (void) mdi_prop_remove(PIP(cip), NULL);
13459                         (void) mdi_pi_free(PIP(cip), 0);
13460 
13461                         mutex_enter(&plun->lun_tgt->tgt_port->port_mutex);
13462                         mutex_enter(&plun->lun_tgt->tgt_mutex);
13463                         mutex_enter(&plun->lun_mutex);
13464                 }
13465         } else {
13466                 plun->lun_cip = NULL;
13467         }
13468 }
13469 
13470 /*
13471  * called when a timeout occurs


   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 /*
  23  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
  24  */
  25 
  26 /*
  27  * Copyright 2018 Nexenta Systems, Inc.
  28  */
  29 
  30 /*
  31  * Fibre Channel SCSI ULP Mapping driver
  32  */
  33 
  34 #include <sys/scsi/scsi.h>
  35 #include <sys/types.h>
  36 #include <sys/varargs.h>
  37 #include <sys/devctl.h>
  38 #include <sys/thread.h>
  39 #include <sys/thread.h>
  40 #include <sys/open.h>
  41 #include <sys/file.h>
  42 #include <sys/sunndi.h>
  43 #include <sys/console.h>
  44 #include <sys/proc.h>
  45 #include <sys/time.h>
  46 #include <sys/utsname.h>
  47 #include <sys/scsi/impl/scsi_reset_notify.h>
  48 #include <sys/ndi_impldefs.h>
  49 #include <sys/byteorder.h>

  50 #include <sys/ctype.h>
  51 #include <sys/sunmdi.h>
  52 
  53 #include <sys/fibre-channel/fc.h>
  54 #include <sys/fibre-channel/impl/fc_ulpif.h>
  55 #include <sys/fibre-channel/ulp/fcpvar.h>
  56 
  57 /*
  58  * Discovery Process
  59  * =================
  60  *
  61  *    The discovery process is a major function of FCP.  In order to help
  62  * understand that function a flow diagram is given here.  This diagram
  63  * doesn't claim to cover all the cases and the events that can occur during
  64  * the discovery process nor the subtleties of the code.  The code paths shown
  65  * are simplified.  Its purpose is to help the reader (and potentially bug
  66  * fixer) have an overall view of the logic of the code.  For that reason the
  67  * diagram covers the simple case of the line coming up cleanly or of a new
  68  * port attaching to FCP the link being up.  The reader must keep in mind
  69  * that:


3855                 mutex_enter(&pptr->port_mutex);
3856                 if (pip != NULL) {
3857                         cip = CIP(pip);
3858                 }
3859                 if ((plun = fcp_get_lun_from_cip(pptr, cip)) == NULL) {
3860                         mutex_exit(&pptr->port_mutex);
3861                         *rval = ENXIO;
3862                         break;
3863                 }
3864 
3865                 head = fcp_scan_commands(plun);
3866                 if (head != NULL) {
3867                         fcp_abort_commands(head, LUN_PORT);
3868                 }
3869                 lcount = pptr->port_link_cnt;
3870                 tcount = plun->lun_tgt->tgt_change_cnt;
3871                 mutex_exit(&pptr->port_mutex);
3872 
3873                 if (cmd == DEVCTL_DEVICE_REMOVE) {
3874                         flag = NDI_DEVI_REMOVE;
3875                         if (is_mpxio)
3876                                 flag |= NDI_USER_REQ;
3877                 }
3878 
3879                 if (is_mpxio) {
3880                         mdi_devi_exit(pptr->port_dip, circ);
3881                 } else {
3882                         ndi_devi_exit(pptr->port_dip, circ);
3883                 }
3884                 devi_entered = 0;
3885 
3886                 *rval = fcp_pass_to_hp_and_wait(pptr, plun, cip,
3887                     FCP_OFFLINE, lcount, tcount, flag);
3888 
3889                 if (*rval != NDI_SUCCESS) {
3890                         *rval = (*rval == NDI_BUSY) ? EBUSY : EIO;
3891                         break;
3892                 }
3893 
3894                 fcp_update_offline_flags(plun);
3895 
3896                 ptgt = plun->lun_tgt;


8142                                     "Can not ONLINE LUN; D_ID=%x, LUN=%x\n",
8143                                     plun->lun_tgt->tgt_d_id, plun->lun_num);
8144                         }
8145                 }
8146         }
8147 }
8148 
8149 
8150 /*
8151  * function to online/offline devices
8152  */
8153 static int
8154 fcp_trigger_lun(struct fcp_lun *plun, child_info_t *cip, int old_mpxio,
8155     int online, int lcount, int tcount, int flags)
8156 {
8157         int                     rval = NDI_FAILURE;
8158         int                     circ;
8159         child_info_t            *ccip;
8160         struct fcp_port         *pptr = plun->lun_tgt->tgt_port;
8161         int                     is_mpxio = pptr->port_mpxio;


8162 
8163         if ((old_mpxio != 0) && (plun->lun_mpxio != old_mpxio)) {
8164                 /*
8165                  * When this event gets serviced, lun_cip and lun_mpxio
8166                  * has changed, so it should be invalidated now.
8167                  */
8168                 FCP_TRACE(fcp_logq, pptr->port_instbuf, fcp_trace,
8169                     FCP_BUF_LEVEL_2, 0, "fcp_trigger_lun: lun_mpxio changed: "
8170                     "plun: %p, cip: %p, what:%d", plun, cip, online);
8171                 return (rval);
8172         }
8173 
8174         FCP_TRACE(fcp_logq, pptr->port_instbuf,
8175             fcp_trace, FCP_BUF_LEVEL_2, 0,
8176             "fcp_trigger_lun: plun=%p target=%x lun=%d cip=%p what=%x "
8177             "flags=%x mpxio=%x\n",
8178             plun, LUN_TGT->tgt_d_id, plun->lun_num, cip, online, flags,
8179             plun->lun_mpxio);
8180 
8181         /*
8182          * lun_mpxio needs checking here because we can end up in a race
8183          * condition where this task has been dispatched while lun_mpxio is
8184          * set, but an earlier FCP_ONLINE task for the same LUN tried to
8185          * enable MPXIO for the LUN, but was unable to, and hence cleared
8186          * the flag. We rely on the serialization of the tasks here. We return
8187          * NDI_SUCCESS so any callers continue without reporting spurious
8188          * errors, and the still think we're an MPXIO LUN.
8189          */
8190 
8191         if (online == FCP_MPXIO_PATH_CLEAR_BUSY ||
8192             online == FCP_MPXIO_PATH_SET_BUSY) {
8193                 if (plun->lun_mpxio) {
8194                         rval = fcp_update_mpxio_path(plun, cip, online);
8195                 } else {
8196                         rval = NDI_SUCCESS;
8197                 }
8198                 return (rval);
8199         }
8200 







































8201         if (fc_ulp_busy_port(pptr->port_fp_handle) != 0) {
8202                 return (NDI_FAILURE);
8203         }
8204 
8205         if (is_mpxio) {
8206                 mdi_devi_enter(pptr->port_dip, &circ);
8207         } else {
8208                 ndi_devi_enter(pptr->port_dip, &circ);
8209         }
8210 
8211         mutex_enter(&pptr->port_mutex);
8212         mutex_enter(&plun->lun_mutex);
8213 
8214         if (online == FCP_ONLINE) {
8215                 ccip = fcp_get_cip(plun, cip, lcount, tcount);
8216                 if (ccip == NULL) {
8217                         goto fail;
8218                 }
8219         } else {
8220                 if (fcp_is_child_present(plun, cip) != FC_SUCCESS) {


13020          *
13021          * The behavior is different on other devices. For instance, on a HDS,
13022          * there was no RSCN generated by the device but the next I/O generated
13023          * a check condition and rediscovery got triggered that way. So, in
13024          * such cases, this path will not be exercised
13025          */
13026         if (pip == NULL) {
13027                 FCP_TRACE(fcp_logq, LUN_PORT->port_instbuf,
13028                     fcp_trace, FCP_BUF_LEVEL_4, 0,
13029                     "fcp_is_pip_present: plun->lun_cip is NULL: "
13030                     "plun: %p lun state: %x num: %d target state: %x",
13031                     plun, plun->lun_state, plun->lun_num,
13032                     plun->lun_tgt->tgt_port->port_state);
13033                 return (rval);
13034         }
13035 
13036         fcp_wwn_to_ascii(plun->lun_tgt->tgt_port_wwn.raw_wwn, buf);
13037 
13038         (void) snprintf(uaddr, MAXNAMELEN, "w%s,%x", buf, plun->lun_num);
13039 
13040         if (mdi_pi_find(pdip, NULL, uaddr) == pip) {

13041                 rval = FC_SUCCESS;
13042         }
13043 




13044         return (rval);
13045 }
13046 
13047 static mdi_pathinfo_t *
13048 fcp_find_existing_pip(struct fcp_lun *plun, dev_info_t *pdip)
13049 {
13050         char                    buf[MAXNAMELEN];
13051         char                    uaddr[MAXNAMELEN];
13052         mdi_pathinfo_t          *pip;
13053         struct fcp_tgt  *ptgt = plun->lun_tgt;
13054         struct fcp_port *pptr = ptgt->tgt_port;
13055 
13056         ASSERT(MUTEX_HELD(&pptr->port_mutex));
13057 
13058         fcp_wwn_to_ascii(ptgt->tgt_port_wwn.raw_wwn, buf);
13059         (void) snprintf(uaddr, MAXNAMELEN, "w%s,%x", buf, plun->lun_num);
13060 
13061         pip = mdi_pi_find(pdip, plun->lun_guid, uaddr);
13062 
13063         return (pip);


13257         if (plun->lun_cip == NULL) {
13258                 FCP_TRACE(fcp_logq, pptr->port_instbuf,
13259                     fcp_trace, FCP_BUF_LEVEL_3, 0,
13260                     "fcp_offline_child: plun->lun_cip is NULL: "
13261                     "plun: %p lun state: %x num: %d target state: %x",
13262                     plun, plun->lun_state, plun->lun_num,
13263                     plun->lun_tgt->tgt_port->port_state);
13264                 return (NDI_FAILURE);
13265         }
13266 
13267         /*
13268          * We will use this value twice. Make a copy to be sure we use
13269          * the same value in both places.
13270          */
13271         lun_mpxio = plun->lun_mpxio;
13272 
13273         if (lun_mpxio == 0) {
13274                 cdip = DIP(cip);
13275                 mutex_exit(&plun->lun_mutex);
13276                 mutex_exit(&pptr->port_mutex);
13277                 rval = ndi_devi_offline(DIP(cip), NDI_DEVFS_CLEAN | flags);
13278                 if (rval != NDI_SUCCESS) {
13279                         FCP_TRACE(fcp_logq, pptr->port_instbuf,
13280                             fcp_trace, FCP_BUF_LEVEL_3, 0,
13281                             "fcp_offline_child: ndi_devi_offline failed "
13282                             "rval=%x cip=%p", rval, cip);
13283                 }
13284         } else {
13285                 cdip = mdi_pi_get_client(PIP(cip));
13286                 mutex_exit(&plun->lun_mutex);
13287                 mutex_exit(&pptr->port_mutex);
13288 
13289                 /*
13290                  * Exit phci to avoid deadlock with power management code
13291                  * during mdi_pi_offline
13292                  */
13293                 mdi_hold_path(PIP(cip));
13294                 mdi_devi_exit_phci(pptr->port_dip, *circ);
13295 
13296                 rval = mdi_pi_offline(PIP(cip), flags & ~NDI_DEVI_REMOVE);
13297 
13298                 mdi_devi_enter_phci(pptr->port_dip, circ);
13299                 mdi_rele_path(PIP(cip));
13300 
13301                 rval = (rval == MDI_SUCCESS) ? NDI_SUCCESS : NDI_FAILURE;
13302         }
13303 
13304         mutex_enter(&ptgt->tgt_mutex);
13305         plun->lun_state &= ~FCP_LUN_INIT;
13306         mutex_exit(&ptgt->tgt_mutex);
13307 
13308         if (rval == NDI_SUCCESS) {
13309                 cdip = NULL;
13310                 if (flags & NDI_DEVI_REMOVE) {
13311                         mutex_enter(&plun->lun_mutex);
13312                         /*
13313                          * If the guid of the LUN changes, lun_cip will not
13314                          * equal to cip, and after offlining the LUN with the
13315                          * old guid, we should keep lun_cip since it's the cip
13316                          * of the LUN with the new guid.


13376         if (fcp_is_child_present(plun, plun->lun_cip) == FC_SUCCESS) {
13377                 if (plun->lun_mpxio == 0) {
13378                         (void) ndi_prop_remove_all(DIP(plun->lun_cip));
13379                         (void) ndi_devi_free(DIP(plun->lun_cip));
13380                         plun->lun_cip = NULL;
13381                 } else {
13382                         /*
13383                          * Clear reference to the child node in the lun.
13384                          * This must be done before freeing it with mdi_pi_free
13385                          * and with lun_mutex held so that other threads always
13386                          * see either valid lun_cip or NULL when holding
13387                          * lun_mutex. We keep a copy in cip.
13388                          */
13389                         cip = plun->lun_cip;
13390                         plun->lun_cip = NULL;
13391 
13392                         mutex_exit(&plun->lun_mutex);
13393                         mutex_exit(&plun->lun_tgt->tgt_mutex);
13394                         mutex_exit(&plun->lun_tgt->tgt_port->port_mutex);
13395 
13396                         mdi_devi_enter(plun->lun_tgt->tgt_port->port_dip,
13397                             &circ);
13398 
13399                         /*
13400                          * Exit phci to avoid deadlock with power management
13401                          * code during mdi_pi_offline
13402                          */
13403                         mdi_hold_path(PIP(cip));
13404                         mdi_devi_exit_phci(plun->lun_tgt->tgt_port->port_dip,
13405                             circ);
13406                         (void) mdi_pi_offline(PIP(cip), 0);
13407                         mdi_devi_enter_phci(plun->lun_tgt->tgt_port->port_dip,
13408                             &circ);

13409                         mdi_rele_path(PIP(cip));
13410 
13411                         mdi_devi_exit(plun->lun_tgt->tgt_port->port_dip, circ);

13412 
13413                         FCP_TRACE(fcp_logq,
13414                             plun->lun_tgt->tgt_port->port_instbuf,
13415                             fcp_trace, FCP_BUF_LEVEL_3, 0,
13416                             "lun=%p pip freed %p", plun, cip);
13417 
13418                         (void) mdi_prop_remove(PIP(cip), NULL);
13419                         (void) mdi_pi_free(PIP(cip), 0);
13420 
13421                         mutex_enter(&plun->lun_tgt->tgt_port->port_mutex);
13422                         mutex_enter(&plun->lun_tgt->tgt_mutex);
13423                         mutex_enter(&plun->lun_mutex);
13424                 }
13425         } else {
13426                 plun->lun_cip = NULL;
13427         }
13428 }
13429 
13430 /*
13431  * called when a timeout occurs