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
|