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 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 *
25 * iSCSI logical unit interfaces
26 */
27
28 #include "iscsi.h"
29 #include <sys/fs/dv_node.h> /* devfs_clean */
30 #include <sys/bootprops.h>
31 #include <sys/sysevent/eventdefs.h>
32 #include <sys/sysevent/dev.h>
33
34 /* tpgt bytes in string form */
35 #define TPGT_EXT_SIZE 5
36
37 /* logical unit number bytes in string form */
38 #define LUN_EXT_SIZE 10
39
40 /*
41 * Addition addr size of size of ',' + max str form of tpgt (2 bytes) +
42 * ',' + max str form of logical unit number (4 bytes).
43 */
44 #define ADDR_EXT_SIZE (1 + TPGT_EXT_SIZE + 1 + LUN_EXT_SIZE)
45
46 /* internal interfaces */
47 static iscsi_status_t iscsi_lun_virt_create(iscsi_sess_t *isp,
48 uint16_t lun_num, iscsi_lun_t *ilp, struct scsi_inquiry *inq);
49 static iscsi_status_t iscsi_lun_phys_create(iscsi_sess_t *isp,
106 (void) snprintf(addr,
107 (strlen((char *)isp->sess_name) +
108 ADDR_EXT_SIZE + 1),
109 "%02X%02X%s%04X,%d", isp->sess_isid[4],
110 isp->sess_isid[5], isp->sess_name,
111 isp->sess_tpgt_nego & 0xFFFF, lun_num);
112
113 /* allocate space for lun struct */
114 ilp = kmem_zalloc(sizeof (iscsi_lun_t), KM_SLEEP);
115 ilp->lun_sig = ISCSI_SIG_LUN;
116 ilp->lun_state &= ISCSI_LUN_STATE_CLEAR;
117 ilp->lun_state |= ISCSI_LUN_STATE_OFFLINE;
118
119 /* initialize common LU information */
120 ilp->lun_num = lun_num;
121 ilp->lun_addr_type = lun_addr_type;
122 ilp->lun_sess = isp;
123 ilp->lun_addr = addr;
124 ilp->lun_type = inq->inq_dtype & DTYPE_MASK;
125 ilp->lun_oid = oid_tmp;
126
127 bcopy(inq->inq_vid, ilp->lun_vid, sizeof (inq->inq_vid));
128 bcopy(inq->inq_pid, ilp->lun_pid, sizeof (inq->inq_pid));
129
130 /* store GUID if valid one exists */
131 if (guid != NULL) {
132 ilp->lun_guid_size = strlen(guid) + 1;
133 ilp->lun_guid = kmem_zalloc(ilp->lun_guid_size, KM_SLEEP);
134 (void) strcpy(ilp->lun_guid, guid);
135 } else {
136 ilp->lun_guid_size = 0;
137 ilp->lun_guid = NULL;
138 }
139
140 /*
141 * We need to add the lun to our lists now because during the
142 * lun creation we will get called back into multiple times
143 * depending on the createion type. These callbacks will
144 * occur via our tran_init_lun, tran_get_name, tran_get_bus_addr,
145 * tran_init_pkt, tran_start.
172 } else {
173 /* if not head, set prev lun's next to our next */
174 for (ilp_tmp = isp->sess_lun_list; ilp_tmp;
175 ilp_tmp = ilp_tmp->lun_next) {
176 if (ilp_tmp->lun_next == ilp) {
177 ilp_tmp->lun_next = ilp->lun_next;
178 break;
179 }
180 }
181 }
182
183 kmem_free(ilp->lun_addr,
184 (strlen((char *)isp->sess_name) +
185 ADDR_EXT_SIZE + 1));
186 ilp->lun_addr = NULL;
187
188 if (ilp->lun_guid != NULL) {
189 kmem_free(ilp->lun_guid, ilp->lun_guid_size);
190 ilp->lun_guid = NULL;
191 }
192 kmem_free(ilp, sizeof (iscsi_lun_t));
193 } else {
194 ilp->lun_state &= ISCSI_LUN_STATE_CLEAR;
195 ilp->lun_state |= ISCSI_LUN_STATE_ONLINE;
196 ilp->lun_time_online = ddi_get_time();
197
198 /* Check whether this is the required LUN for iscsi boot */
199 if (iscsiboot_prop != NULL && isp->sess_boot == B_TRUE &&
200 iscsiboot_prop->boot_tgt.lun_online == 0) {
201 lun_num_ptr =
202 (uint64_t *)iscsiboot_prop->boot_tgt.tgt_boot_lun;
203 boot_lun_num = (uint16_t)(*lun_num_ptr);
204 if (boot_lun_num == ilp->lun_num) {
205 /*
206 * During iscsi boot, the boot lun has been
207 * online, we should set the "online flag".
208 */
209 iscsiboot_prop->boot_tgt.lun_online = 1;
210 }
211 }
212 }
213 rw_exit(&isp->sess_lun_list_rwlock);
214
215 return (rtn);
216 }
217
218 /*
219 * iscsi_lun_destroy - offline and remove lun
220 *
221 * This interface is called when a name service change has
222 * occured and the storage is no longer available to this
223 * initiator. This function will offline and free the
224 * solaris node resources. Then it will free all iscsi lun
225 * resources.
226 *
227 * This function can fail with ISCSI_STATUS_BUSY if the
228 * logical unit is in use. The user should unmount or
229 * close the device and perform the nameservice operation
230 * again if this occurs.
231 */
232 iscsi_status_t
233 iscsi_lun_destroy(iscsi_hba_t *ihp, iscsi_lun_t *ilp)
234 {
235 iscsi_status_t status = ISCSI_STATUS_SUCCESS;
236 iscsi_sess_t *isp = NULL;
237 iscsi_lun_t *t_ilp = NULL;
238
239 ASSERT(ilp != NULL);
240 isp = ilp->lun_sess;
241 ASSERT(isp != NULL);
242
243 /* attempt to offline and free solaris node */
244 status = iscsi_lun_offline(ihp, ilp, B_TRUE);
245
246 /* If we successfully unplumbed the lun remove it from our lists */
247 if (ISCSI_SUCCESS(status)) {
248 if (isp->sess_lun_list == ilp) {
249 /* target first item in list */
250 isp->sess_lun_list = ilp->lun_next;
251 } else {
252 /*
253 * search session list for ilp pointing
254 * to lun being removed. Then
255 * update that luns next pointer.
256 */
257 t_ilp = isp->sess_lun_list;
258 while (t_ilp->lun_next != NULL) {
259 if (t_ilp->lun_next == ilp) {
260 break;
261 }
262 t_ilp = t_ilp->lun_next;
263 }
264 if (t_ilp->lun_next == ilp) {
265 t_ilp->lun_next = ilp->lun_next;
266 } else {
267 /* couldn't find session */
268 ASSERT(FALSE);
269 }
270 }
271
272 /* release its memory */
273 kmem_free(ilp->lun_addr, (strlen((char *)isp->sess_name) +
274 ADDR_EXT_SIZE + 1));
275 ilp->lun_addr = NULL;
276 if (ilp->lun_guid != NULL) {
277 kmem_free(ilp->lun_guid, ilp->lun_guid_size);
278 ilp->lun_guid = NULL;
279 }
280 kmem_free(ilp, sizeof (iscsi_lun_t));
281 ilp = NULL;
282 }
283
284 return (status);
285 }
286
287 /*
288 * +--------------------------------------------------------------------+
289 * | External Logical Unit Interfaces |
290 * +--------------------------------------------------------------------+
291 */
292
293 /*
294 * iscsi_lun_virt_create - Creates solaris logical unit via MDI
295 */
296 static iscsi_status_t
297 iscsi_lun_virt_create(iscsi_sess_t *isp, uint16_t lun_num, iscsi_lun_t *ilp,
298 struct scsi_inquiry *inq)
299 {
300 iscsi_status_t rtn = ISCSI_STATUS_INTERNAL_ERROR;
301 int mdi_rtn = MDI_FAILURE;
302 iscsi_hba_t *ihp = NULL;
624 * be called to both offline and free the logical unit.
625 * (This operates soley on the solaris node states.
626 * iscsi_lun_destroy() should be called when attempting
627 * to free all iscsi lun resources.)
628 *
629 * This function can fail with ISCSI_STATUS_BUSY if the
630 * logical unit is in use. The user should unmount or
631 * close the device and perform the nameservice operation
632 * again if this occurs.
633 *
634 * If we fail to offline a LUN that we don't want to destroy,
635 * we will mark it with invalid state. If this LUN still
636 * exists on the target, we can have another chance to online
637 * it again when we do the LUN enumeration.
638 */
639 iscsi_status_t
640 iscsi_lun_offline(iscsi_hba_t *ihp, iscsi_lun_t *ilp, boolean_t lun_free)
641 {
642 iscsi_status_t status = ISCSI_STATUS_SUCCESS;
643 int circ = 0;
644 dev_info_t *cdip, *pdip;
645 char *devname = NULL;
646 char *pathname = NULL;
647 int rval;
648 boolean_t offline = B_FALSE;
649 nvlist_t *attr_list = NULL;
650
651 ASSERT(ilp != NULL);
652 ASSERT((ilp->lun_pip != NULL) || (ilp->lun_dip != NULL));
653
654 /*
655 * Since we carry the logical units parent
656 * lock across the offline call it will not
657 * issue devfs_clean() and may fail with a
658 * devi_ref count > 0.
659 */
660 if (ilp->lun_pip == NULL) {
661 cdip = ilp->lun_dip;
662 } else {
663 cdip = mdi_pi_get_client(ilp->lun_pip);
664 }
665
666 if ((cdip != NULL) &&
667 (lun_free == B_TRUE) &&
668 (ilp->lun_state & ISCSI_LUN_STATE_ONLINE)) {
669 /*
670 * Make sure node is attached otherwise
671 * it won't have related cache nodes to
672 * clean up. i_ddi_devi_attached is
673 * similiar to i_ddi_node_state(cdip) >=
674 * DS_ATTACHED. We should clean up only
675 * when lun_free is set.
676 */
677 if (i_ddi_devi_attached(cdip)) {
678
679 /* Get parent dip */
680 pdip = ddi_get_parent(cdip);
681
682 /* Get full devname */
683 devname = kmem_alloc(MAXNAMELEN + 1, KM_SLEEP);
684 ndi_devi_enter(pdip, &circ);
685 (void) ddi_deviname(cdip, devname);
686 /* Release lock before devfs_clean() */
687 ndi_devi_exit(pdip, circ);
688
689 /* Clean cache */
690 (void) devfs_clean(pdip, devname + 1, DV_CLEAN_FORCE);
691 kmem_free(devname, MAXNAMELEN + 1);
692 }
693 }
694
695 if (cdip != NULL && ilp->lun_type == DTYPE_DIRECT) {
696 pathname = kmem_zalloc(MAXNAMELEN + 1, KM_SLEEP);
697 (void) ddi_pathname(cdip, pathname);
698 }
699
700 /* Attempt to offline the logical units */
701 if (ilp->lun_pip != NULL) {
702
703 /* virt/mdi */
704 ndi_devi_enter(scsi_vhci_dip, &circ);
705 if ((lun_free == B_TRUE) &&
706 (ilp->lun_state & ISCSI_LUN_STATE_ONLINE)) {
707 rval = mdi_pi_offline(ilp->lun_pip,
708 NDI_DEVI_REMOVE);
709 } else {
710 rval = mdi_pi_offline(ilp->lun_pip, 0);
711 }
712
713 if (rval == MDI_SUCCESS) {
714 ilp->lun_state &= ISCSI_LUN_STATE_CLEAR;
715 ilp->lun_state |= ISCSI_LUN_STATE_OFFLINE;
716 if (lun_free == B_TRUE) {
717 (void) mdi_prop_remove(ilp->lun_pip, NULL);
718 (void) mdi_pi_free(ilp->lun_pip, 0);
719 }
720 offline = B_TRUE;
721 } else {
722 status = ISCSI_STATUS_BUSY;
723 if (lun_free == B_FALSE) {
724 ilp->lun_state |= ISCSI_LUN_STATE_INVALID;
725 offline = B_TRUE;
726 }
727 }
728 ndi_devi_exit(scsi_vhci_dip, circ);
729
730 } else {
731
732 /* phys/ndi */
733 ndi_devi_enter(ihp->hba_dip, &circ);
734 if ((lun_free == B_TRUE) &&
735 (ilp->lun_state & ISCSI_LUN_STATE_ONLINE)) {
736 rval = ndi_devi_offline(
737 ilp->lun_dip, NDI_DEVI_REMOVE);
738 } else {
739 rval = ndi_devi_offline(
740 ilp->lun_dip, 0);
741 }
742 if (rval != NDI_SUCCESS) {
743 status = ISCSI_STATUS_BUSY;
744 if (lun_free == B_FALSE) {
745 ilp->lun_state |= ISCSI_LUN_STATE_INVALID;
746 offline = B_TRUE;
747 }
748 } else {
749 ilp->lun_state &= ISCSI_LUN_STATE_CLEAR;
750 ilp->lun_state |= ISCSI_LUN_STATE_OFFLINE;
751 offline = B_TRUE;
752 }
753 ndi_devi_exit(ihp->hba_dip, circ);
754 }
755
756 if (offline == B_TRUE && pathname != NULL &&
757 ilp->lun_type == DTYPE_DIRECT) {
758 if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, KM_SLEEP) !=
759 DDI_SUCCESS) {
760 kmem_free(pathname, MAXNAMELEN + 1);
761 return (status);
762 }
|
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 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * Copyright 2019 Nexenta Systems, Inc.
29 */
30
31 /*
32 * iSCSI logical unit interfaces
33 */
34
35 #include "iscsi.h"
36 #include <sys/bootprops.h>
37 #include <sys/sysevent/eventdefs.h>
38 #include <sys/sysevent/dev.h>
39
40 /* tpgt bytes in string form */
41 #define TPGT_EXT_SIZE 5
42
43 /* logical unit number bytes in string form */
44 #define LUN_EXT_SIZE 10
45
46 /*
47 * Addition addr size of size of ',' + max str form of tpgt (2 bytes) +
48 * ',' + max str form of logical unit number (4 bytes).
49 */
50 #define ADDR_EXT_SIZE (1 + TPGT_EXT_SIZE + 1 + LUN_EXT_SIZE)
51
52 /* internal interfaces */
53 static iscsi_status_t iscsi_lun_virt_create(iscsi_sess_t *isp,
54 uint16_t lun_num, iscsi_lun_t *ilp, struct scsi_inquiry *inq);
55 static iscsi_status_t iscsi_lun_phys_create(iscsi_sess_t *isp,
112 (void) snprintf(addr,
113 (strlen((char *)isp->sess_name) +
114 ADDR_EXT_SIZE + 1),
115 "%02X%02X%s%04X,%d", isp->sess_isid[4],
116 isp->sess_isid[5], isp->sess_name,
117 isp->sess_tpgt_nego & 0xFFFF, lun_num);
118
119 /* allocate space for lun struct */
120 ilp = kmem_zalloc(sizeof (iscsi_lun_t), KM_SLEEP);
121 ilp->lun_sig = ISCSI_SIG_LUN;
122 ilp->lun_state &= ISCSI_LUN_STATE_CLEAR;
123 ilp->lun_state |= ISCSI_LUN_STATE_OFFLINE;
124
125 /* initialize common LU information */
126 ilp->lun_num = lun_num;
127 ilp->lun_addr_type = lun_addr_type;
128 ilp->lun_sess = isp;
129 ilp->lun_addr = addr;
130 ilp->lun_type = inq->inq_dtype & DTYPE_MASK;
131 ilp->lun_oid = oid_tmp;
132 /*
133 * Setting refcnt to 1 is the first hold for the LUN structure.
134 */
135 ilp->lun_refcnt = 1;
136 mutex_init(&ilp->lun_mutex, NULL, MUTEX_DRIVER, NULL);
137
138 bcopy(inq->inq_vid, ilp->lun_vid, sizeof (inq->inq_vid));
139 bcopy(inq->inq_pid, ilp->lun_pid, sizeof (inq->inq_pid));
140
141 /* store GUID if valid one exists */
142 if (guid != NULL) {
143 ilp->lun_guid_size = strlen(guid) + 1;
144 ilp->lun_guid = kmem_zalloc(ilp->lun_guid_size, KM_SLEEP);
145 (void) strcpy(ilp->lun_guid, guid);
146 } else {
147 ilp->lun_guid_size = 0;
148 ilp->lun_guid = NULL;
149 }
150
151 /*
152 * We need to add the lun to our lists now because during the
153 * lun creation we will get called back into multiple times
154 * depending on the createion type. These callbacks will
155 * occur via our tran_init_lun, tran_get_name, tran_get_bus_addr,
156 * tran_init_pkt, tran_start.
183 } else {
184 /* if not head, set prev lun's next to our next */
185 for (ilp_tmp = isp->sess_lun_list; ilp_tmp;
186 ilp_tmp = ilp_tmp->lun_next) {
187 if (ilp_tmp->lun_next == ilp) {
188 ilp_tmp->lun_next = ilp->lun_next;
189 break;
190 }
191 }
192 }
193
194 kmem_free(ilp->lun_addr,
195 (strlen((char *)isp->sess_name) +
196 ADDR_EXT_SIZE + 1));
197 ilp->lun_addr = NULL;
198
199 if (ilp->lun_guid != NULL) {
200 kmem_free(ilp->lun_guid, ilp->lun_guid_size);
201 ilp->lun_guid = NULL;
202 }
203 mutex_destroy(&ilp->lun_mutex);
204 kmem_free(ilp, sizeof (iscsi_lun_t));
205 } else {
206 ilp->lun_state &= ISCSI_LUN_STATE_CLEAR;
207 ilp->lun_state |= ISCSI_LUN_STATE_ONLINE;
208 ilp->lun_time_online = ddi_get_time();
209
210 /* Check whether this is the required LUN for iscsi boot */
211 if (iscsiboot_prop != NULL && isp->sess_boot == B_TRUE &&
212 iscsiboot_prop->boot_tgt.lun_online == 0) {
213 lun_num_ptr =
214 (uint64_t *)iscsiboot_prop->boot_tgt.tgt_boot_lun;
215 boot_lun_num = (uint16_t)(*lun_num_ptr);
216 if (boot_lun_num == ilp->lun_num) {
217 /*
218 * During iscsi boot, the boot lun has been
219 * online, we should set the "online flag".
220 */
221 iscsiboot_prop->boot_tgt.lun_online = 1;
222 }
223 }
224 }
225 rw_exit(&isp->sess_lun_list_rwlock);
226
227 return (rtn);
228 }
229
230 void
231 iscsi_lun_hold(iscsi_lun_t *ilp)
232 {
233 mutex_enter(&ilp->lun_mutex);
234 /*
235 * By design lun_refcnt should never be zero when this routine
236 * is called. When the LUN is created the refcnt is set to 1.
237 * If iscsi_lun_rele is called and the refcnt goes to zero the
238 * structure will be freed so this method shouldn't be called
239 * afterwards.
240 */
241 ASSERT(ilp->lun_refcnt > 0);
242 ilp->lun_refcnt++;
243 mutex_exit(&ilp->lun_mutex);
244 }
245
246 void
247 iscsi_lun_rele(iscsi_lun_t *ilp)
248 {
249 ASSERT(ilp != NULL);
250
251 mutex_enter(&ilp->lun_mutex);
252 ASSERT(ilp->lun_refcnt > 0);
253 if (--ilp->lun_refcnt == 0) {
254 iscsi_sess_t *isp;
255
256 isp = ilp->lun_sess;
257 ASSERT(isp != NULL);
258
259 /* ---- release its memory ---- */
260 kmem_free(ilp->lun_addr, (strlen((char *)isp->sess_name) +
261 ADDR_EXT_SIZE + 1));
262
263 if (ilp->lun_guid != NULL) {
264 kmem_free(ilp->lun_guid, ilp->lun_guid_size);
265 }
266 mutex_destroy(&ilp->lun_mutex);
267 kmem_free(ilp, sizeof (iscsi_lun_t));
268 } else {
269 mutex_exit(&ilp->lun_mutex);
270 }
271 }
272
273 /*
274 * iscsi_lun_cmd_cancel -- as the name implies, cancel all commands for the lun
275 *
276 * This code is similar to the timeout function with a lot less checking of
277 * state before sending the ABORT event for commands on the pending queue.
278 *
279 * This function is only used by iscsi_lun_destroy().
280 */
281 static void
282 iscsi_lun_cmd_cancel(iscsi_lun_t *ilp)
283 {
284 iscsi_sess_t *isp;
285 iscsi_cmd_t *icmdp, *nicmdp;
286
287 isp = ilp->lun_sess;
288 rw_enter(&isp->sess_state_rwlock, RW_READER);
289 mutex_enter(&isp->sess_queue_pending.mutex);
290 for (icmdp = isp->sess_queue_pending.head;
291 icmdp; icmdp = nicmdp) {
292 nicmdp = icmdp->cmd_next;
293
294 /*
295 * For commands on the pending queue we can go straight
296 * to and abort request which will free the command
297 * and call back to the complete function.
298 */
299 iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E4, isp);
300 }
301 mutex_exit(&isp->sess_queue_pending.mutex);
302 rw_exit(&isp->sess_state_rwlock);
303 }
304
305 /*
306 * iscsi_lun_destroy - offline and remove lun
307 *
308 * This interface is called when a name service change has
309 * occured and the storage is no longer available to this
310 * initiator. This function will offline and free the
311 * solaris node resources. Then it will free all iscsi lun
312 * resources.
313 *
314 * This function can fail with ISCSI_STATUS_BUSY if the
315 * logical unit is in use. The user should unmount or
316 * close the device and perform the nameservice operation
317 * again if this occurs.
318 */
319 iscsi_status_t
320 iscsi_lun_destroy(iscsi_hba_t *ihp, iscsi_lun_t *ilp)
321 {
322 iscsi_status_t status = ISCSI_STATUS_SUCCESS;
323 iscsi_sess_t *isp = NULL;
324 iscsi_lun_t *t_ilp = NULL;
325
326 ASSERT(ilp != NULL);
327 isp = ilp->lun_sess;
328 ASSERT(isp != NULL);
329
330 /* flush all outstanding commands first */
331 iscsi_lun_cmd_cancel(ilp);
332
333 /* attempt to offline and free solaris node */
334 status = iscsi_lun_offline(ihp, ilp, B_TRUE);
335
336 /* If we successfully unplumbed the lun remove it from our lists */
337 if (ISCSI_SUCCESS(status)) {
338 if (isp->sess_lun_list == ilp) {
339 /* target first item in list */
340 isp->sess_lun_list = ilp->lun_next;
341 } else {
342 /*
343 * search session list for ilp pointing
344 * to lun being removed. Then
345 * update that luns next pointer.
346 */
347 t_ilp = isp->sess_lun_list;
348 while (t_ilp->lun_next != NULL) {
349 if (t_ilp->lun_next == ilp) {
350 break;
351 }
352 t_ilp = t_ilp->lun_next;
353 }
354 if (t_ilp->lun_next == ilp) {
355 t_ilp->lun_next = ilp->lun_next;
356 } else {
357 /* couldn't find session */
358 ASSERT(FALSE);
359 }
360 }
361
362 iscsi_lun_rele(ilp);
363 }
364
365 return (status);
366 }
367
368 /*
369 * +--------------------------------------------------------------------+
370 * | External Logical Unit Interfaces |
371 * +--------------------------------------------------------------------+
372 */
373
374 /*
375 * iscsi_lun_virt_create - Creates solaris logical unit via MDI
376 */
377 static iscsi_status_t
378 iscsi_lun_virt_create(iscsi_sess_t *isp, uint16_t lun_num, iscsi_lun_t *ilp,
379 struct scsi_inquiry *inq)
380 {
381 iscsi_status_t rtn = ISCSI_STATUS_INTERNAL_ERROR;
382 int mdi_rtn = MDI_FAILURE;
383 iscsi_hba_t *ihp = NULL;
705 * be called to both offline and free the logical unit.
706 * (This operates soley on the solaris node states.
707 * iscsi_lun_destroy() should be called when attempting
708 * to free all iscsi lun resources.)
709 *
710 * This function can fail with ISCSI_STATUS_BUSY if the
711 * logical unit is in use. The user should unmount or
712 * close the device and perform the nameservice operation
713 * again if this occurs.
714 *
715 * If we fail to offline a LUN that we don't want to destroy,
716 * we will mark it with invalid state. If this LUN still
717 * exists on the target, we can have another chance to online
718 * it again when we do the LUN enumeration.
719 */
720 iscsi_status_t
721 iscsi_lun_offline(iscsi_hba_t *ihp, iscsi_lun_t *ilp, boolean_t lun_free)
722 {
723 iscsi_status_t status = ISCSI_STATUS_SUCCESS;
724 int circ = 0;
725 dev_info_t *cdip;
726 char *pathname = NULL;
727 boolean_t offline = B_FALSE;
728 nvlist_t *attr_list = NULL;
729
730 ASSERT(ilp != NULL);
731 ASSERT((ilp->lun_pip != NULL) || (ilp->lun_dip != NULL));
732
733 if (ilp->lun_pip == NULL)
734 cdip = ilp->lun_dip;
735 else
736 cdip = mdi_pi_get_client(ilp->lun_pip);
737
738 if (cdip != NULL && ilp->lun_type == DTYPE_DIRECT) {
739 pathname = kmem_zalloc(MAXNAMELEN + 1, KM_SLEEP);
740 (void) ddi_pathname(cdip, pathname);
741 }
742
743 /* Attempt to offline the logical units */
744 if (ilp->lun_pip != NULL) {
745 /* virt/mdi */
746 ndi_devi_enter(scsi_vhci_dip, &circ);
747 if (mdi_pi_offline(ilp->lun_pip, 0) == MDI_SUCCESS) {
748 ilp->lun_state &= ISCSI_LUN_STATE_CLEAR;
749 ilp->lun_state |= ISCSI_LUN_STATE_OFFLINE;
750 if (lun_free == B_TRUE) {
751 (void) mdi_prop_remove(ilp->lun_pip, NULL);
752 (void) mdi_pi_free(ilp->lun_pip, 0);
753 }
754 offline = B_TRUE;
755 } else {
756 status = ISCSI_STATUS_BUSY;
757 if (lun_free == B_FALSE) {
758 ilp->lun_state |= ISCSI_LUN_STATE_INVALID;
759 offline = B_TRUE;
760 }
761 }
762 ndi_devi_exit(scsi_vhci_dip, circ);
763
764 } else {
765 /* phys/ndi */
766 int flags = NDI_DEVFS_CLEAN;
767
768 ndi_devi_enter(ihp->hba_dip, &circ);
769 if (lun_free == B_TRUE &&
770 (ilp->lun_state & ISCSI_LUN_STATE_ONLINE))
771 flags |= NDI_DEVI_REMOVE;
772 if (ndi_devi_offline(ilp->lun_dip, flags) != NDI_SUCCESS) {
773 status = ISCSI_STATUS_BUSY;
774 if (lun_free == B_FALSE) {
775 ilp->lun_state |= ISCSI_LUN_STATE_INVALID;
776 offline = B_TRUE;
777 }
778 } else {
779 ilp->lun_state &= ISCSI_LUN_STATE_CLEAR;
780 ilp->lun_state |= ISCSI_LUN_STATE_OFFLINE;
781 offline = B_TRUE;
782 }
783 ndi_devi_exit(ihp->hba_dip, circ);
784 }
785
786 if (offline == B_TRUE && pathname != NULL &&
787 ilp->lun_type == DTYPE_DIRECT) {
788 if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, KM_SLEEP) !=
789 DDI_SUCCESS) {
790 kmem_free(pathname, MAXNAMELEN + 1);
791 return (status);
792 }
|