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:
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) {
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
|
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:
8140 "Can not ONLINE LUN; D_ID=%x, LUN=%x\n",
8141 plun->lun_tgt->tgt_d_id, plun->lun_num);
8142 }
8143 }
8144 }
8145 }
8146
8147
8148 /*
8149 * function to online/offline devices
8150 */
8151 static int
8152 fcp_trigger_lun(struct fcp_lun *plun, child_info_t *cip, int old_mpxio,
8153 int online, int lcount, int tcount, int flags)
8154 {
8155 int rval = NDI_FAILURE;
8156 int circ;
8157 child_info_t *ccip;
8158 struct fcp_port *pptr = plun->lun_tgt->tgt_port;
8159 int is_mpxio = pptr->port_mpxio;
8160
8161 if ((old_mpxio != 0) && (plun->lun_mpxio != old_mpxio)) {
8162 /*
8163 * When this event gets serviced, lun_cip and lun_mpxio
8164 * has changed, so it should be invalidated now.
8165 */
8166 FCP_TRACE(fcp_logq, pptr->port_instbuf, fcp_trace,
8167 FCP_BUF_LEVEL_2, 0, "fcp_trigger_lun: lun_mpxio changed: "
8168 "plun: %p, cip: %p, what:%d", plun, cip, online);
8169 return (rval);
8170 }
8171
8172 FCP_TRACE(fcp_logq, pptr->port_instbuf,
8173 fcp_trace, FCP_BUF_LEVEL_2, 0,
8174 "fcp_trigger_lun: plun=%p target=%x lun=%d cip=%p what=%x "
8175 "flags=%x mpxio=%x\n",
8176 plun, LUN_TGT->tgt_d_id, plun->lun_num, cip, online, flags,
8177 plun->lun_mpxio);
8178
8179 /*
8180 * lun_mpxio needs checking here because we can end up in a race
8181 * condition where this task has been dispatched while lun_mpxio is
8182 * set, but an earlier FCP_ONLINE task for the same LUN tried to
8183 * enable MPXIO for the LUN, but was unable to, and hence cleared
8184 * the flag. We rely on the serialization of the tasks here. We return
8185 * NDI_SUCCESS so any callers continue without reporting spurious
8186 * errors, and the still think we're an MPXIO LUN.
8187 */
8188
8189 if (online == FCP_MPXIO_PATH_CLEAR_BUSY ||
8190 online == FCP_MPXIO_PATH_SET_BUSY) {
8191 if (plun->lun_mpxio) {
8192 rval = fcp_update_mpxio_path(plun, cip, online);
8193 } else {
8194 rval = NDI_SUCCESS;
8195 }
8196 return (rval);
8197 }
8198
8199 if (fc_ulp_busy_port(pptr->port_fp_handle) != 0) {
8200 return (NDI_FAILURE);
8201 }
8202
8203 if (is_mpxio) {
8204 mdi_devi_enter(pptr->port_dip, &circ);
8205 } else {
8206 ndi_devi_enter(pptr->port_dip, &circ);
8207 }
8208
8209 mutex_enter(&pptr->port_mutex);
8210 mutex_enter(&plun->lun_mutex);
8211
8212 if (online == FCP_ONLINE) {
8213 ccip = fcp_get_cip(plun, cip, lcount, tcount);
8214 if (ccip == NULL) {
8215 goto fail;
8216 }
8217 } else {
8218 if (fcp_is_child_present(plun, cip) != FC_SUCCESS) {
13260 if (plun->lun_cip == NULL) {
13261 FCP_TRACE(fcp_logq, pptr->port_instbuf,
13262 fcp_trace, FCP_BUF_LEVEL_3, 0,
13263 "fcp_offline_child: plun->lun_cip is NULL: "
13264 "plun: %p lun state: %x num: %d target state: %x",
13265 plun, plun->lun_state, plun->lun_num,
13266 plun->lun_tgt->tgt_port->port_state);
13267 return (NDI_FAILURE);
13268 }
13269
13270 /*
13271 * We will use this value twice. Make a copy to be sure we use
13272 * the same value in both places.
13273 */
13274 lun_mpxio = plun->lun_mpxio;
13275
13276 if (lun_mpxio == 0) {
13277 cdip = DIP(cip);
13278 mutex_exit(&plun->lun_mutex);
13279 mutex_exit(&pptr->port_mutex);
13280 rval = ndi_devi_offline(DIP(cip), NDI_DEVFS_CLEAN | flags);
13281 if (rval != NDI_SUCCESS) {
13282 FCP_TRACE(fcp_logq, pptr->port_instbuf,
13283 fcp_trace, FCP_BUF_LEVEL_3, 0,
13284 "fcp_offline_child: ndi_devi_offline failed "
13285 "rval=%x cip=%p", rval, cip);
13286 }
13287 } else {
13288 cdip = mdi_pi_get_client(PIP(cip));
13289 mutex_exit(&plun->lun_mutex);
13290 mutex_exit(&pptr->port_mutex);
13291
13292 /*
13293 * Exit phci to avoid deadlock with power management code
13294 * during mdi_pi_offline
13295 */
13296 mdi_hold_path(PIP(cip));
13297 mdi_devi_exit_phci(pptr->port_dip, *circ);
13298
13299 rval = mdi_pi_offline(PIP(cip), flags);
13300
|