1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25 #include <sys/conf.h>
26 #include <sys/file.h>
27 #include <sys/ddi.h>
28 #include <sys/sunddi.h>
29 #include <sys/modctl.h>
30 #include <sys/scsi/scsi.h>
31 #include <sys/scsi/impl/scsi_reset_notify.h>
32 #include <sys/disp.h>
33 #include <sys/byteorder.h>
34 #include <sys/atomic.h>
35
36 #include <sys/stmf.h>
37 #include <sys/lpif.h>
38 #include <sys/portif.h>
39 #include <sys/stmf_ioctl.h>
40
41 #include "stmf_impl.h"
42 #include "lun_map.h"
43 #include "stmf_state.h"
44
45 void stmf_update_sessions_per_ve(stmf_view_entry_t *ve,
46 stmf_lu_t *lu, int action);
47 void stmf_add_lus_to_session_per_vemap(stmf_i_local_port_t *ilport,
48 stmf_i_scsi_session_t *iss, stmf_lun_map_t *vemap);
49 stmf_id_data_t *stmf_lookup_group_for_host(uint8_t *ident, uint16_t ident_size);
50 static stmf_status_t stmf_add_ent_to_map(stmf_lun_map_t *sm, void *ent,
51 uint8_t *lun);
52 static stmf_status_t stmf_remove_ent_from_map(stmf_lun_map_t *sm, uint8_t *lun);
53 uint16_t stmf_get_next_free_lun(stmf_lun_map_t *sm, uint8_t *lun);
54 stmf_status_t stmf_add_tg(uint8_t *tg_name, uint16_t tg_name_size,
55 int allow_special, uint32_t *err_detail);
56 stmf_status_t stmf_add_hg(uint8_t *hg_name, uint16_t hg_name_size,
57 int allow_special, uint32_t *err_detail);
58 stmf_i_local_port_t *stmf_targetident_to_ilport(uint8_t *target_ident,
59 uint16_t ident_size);
60 stmf_i_scsi_session_t *stmf_lookup_session_for_hostident(
61 stmf_i_local_port_t *ilport, uint8_t *host_ident,
62 uint16_t ident_size);
63 stmf_i_lu_t *stmf_luident_to_ilu(uint8_t *lu_ident);
64 stmf_lun_map_t *stmf_get_ve_map_per_ids(stmf_id_data_t *tgid,
65 stmf_id_data_t *hgid);
66 stmf_lun_map_t *stmf_duplicate_ve_map(stmf_lun_map_t *src);
67 int stmf_merge_ve_map(stmf_lun_map_t *src, stmf_lun_map_t *dst,
68 stmf_lun_map_t **pp_ret_map, stmf_merge_flags_t mf);
69 void stmf_destroy_ve_map(stmf_lun_map_t *dst);
70 void stmf_free_id(stmf_id_data_t *id);
71
72
73 /*
74 * Init the view
75 */
76 void
77 stmf_view_init()
78 {
79 uint8_t grpname_forall = '*';
80 (void) stmf_add_hg(&grpname_forall, 1, 1, NULL);
81 (void) stmf_add_tg(&grpname_forall, 1, 1, NULL);
82 }
83
84 /*
85 * Clear config database here
86 */
87 void
88 stmf_view_clear_config()
89 {
90 stmf_id_data_t *idgrp, *idgrp_next, *idmemb, *idmemb_next;
91 stmf_ver_tg_t *vtg, *vtg_next;
92 stmf_ver_hg_t *vhg, *vhg_next;
93 stmf_view_entry_t *ve, *ve_next;
94 stmf_i_lu_t *ilu;
95 stmf_id_list_t *idlist;
96 stmf_i_local_port_t *ilport;
97
98 for (vtg = stmf_state.stmf_ver_tg_head; vtg; vtg = vtg_next) {
99 for (vhg = vtg->vert_verh_list; vhg; vhg = vhg_next) {
100 if (vhg->verh_ve_map.lm_nentries) {
101 kmem_free(vhg->verh_ve_map.lm_plus,
102 vhg->verh_ve_map.lm_nentries *
103 sizeof (void *));
104 }
105 vhg_next = vhg->verh_next;
106 kmem_free(vhg, sizeof (stmf_ver_hg_t));
107 }
108 vtg_next = vtg->vert_next;
109 kmem_free(vtg, sizeof (stmf_ver_tg_t));
110 }
111 stmf_state.stmf_ver_tg_head = NULL;
112
113 if (stmf_state.stmf_luid_list.id_count) {
114 /* clear the views for lus */
115 for (idmemb = stmf_state.stmf_luid_list.idl_head;
116 idmemb; idmemb = idmemb_next) {
117 for (ve = (stmf_view_entry_t *)idmemb->id_impl_specific;
118 ve; ve = ve_next) {
119 ve_next = ve->ve_next;
120 ve->ve_hg->id_refcnt--;
121 ve->ve_tg->id_refcnt--;
122 kmem_free(ve, sizeof (stmf_view_entry_t));
123 }
124 if (idmemb->id_pt_to_object) {
125 ilu = (stmf_i_lu_t *)(idmemb->id_pt_to_object);
126 ilu->ilu_luid = NULL;
127 }
128 idmemb_next = idmemb->id_next;
129 stmf_free_id(idmemb);
130 }
131 stmf_state.stmf_luid_list.id_count = 0;
132 stmf_state.stmf_luid_list.idl_head =
133 stmf_state.stmf_luid_list.idl_tail = NULL;
134 }
135
136 if (stmf_state.stmf_hg_list.id_count) {
137 /* free all the host group */
138 for (idgrp = stmf_state.stmf_hg_list.idl_head;
139 idgrp; idgrp = idgrp_next) {
140 idlist = (stmf_id_list_t *)(idgrp->id_impl_specific);
141 if (idlist->id_count) {
142 for (idmemb = idlist->idl_head; idmemb;
143 idmemb = idmemb_next) {
144 idmemb_next = idmemb->id_next;
145 stmf_free_id(idmemb);
146 }
147 }
148 idgrp_next = idgrp->id_next;
149 stmf_free_id(idgrp);
150 }
151 stmf_state.stmf_hg_list.id_count = 0;
152 stmf_state.stmf_hg_list.idl_head =
153 stmf_state.stmf_hg_list.idl_tail = NULL;
154 }
155 if (stmf_state.stmf_tg_list.id_count) {
156 /* free all the target group */
157 for (idgrp = stmf_state.stmf_tg_list.idl_head;
158 idgrp; idgrp = idgrp_next) {
159 idlist = (stmf_id_list_t *)(idgrp->id_impl_specific);
160 if (idlist->id_count) {
161 for (idmemb = idlist->idl_head; idmemb;
162 idmemb = idmemb_next) {
163 idmemb_next = idmemb->id_next;
164 stmf_free_id(idmemb);
165 }
166 }
167 idgrp_next = idgrp->id_next;
168 stmf_free_id(idgrp);
169 }
170 stmf_state.stmf_tg_list.id_count = 0;
171 stmf_state.stmf_tg_list.idl_head =
172 stmf_state.stmf_tg_list.idl_tail = NULL;
173 }
174
175 for (ilport = stmf_state.stmf_ilportlist; ilport;
176 ilport = ilport->ilport_next) {
177 ilport->ilport_tg = NULL;
178 }
179 }
180
181 /*
182 * Create luns map for session based on the view
183 * iss_lockp is held
184 */
185 stmf_status_t
186 stmf_session_create_lun_map(stmf_i_local_port_t *ilport,
187 stmf_i_scsi_session_t *iss)
188 {
189 stmf_id_data_t *tg;
190 stmf_id_data_t *hg;
191 stmf_ver_tg_t *vertg;
192 char *phg_data, *ptg_data;
193 stmf_ver_hg_t *verhg;
194 stmf_lun_map_t *ve_map;
195
196 ASSERT(mutex_owned(&stmf_state.stmf_lock));
197
198 tg = ilport->ilport_tg;
199 hg = stmf_lookup_group_for_host(iss->iss_ss->ss_rport_id->ident,
200 iss->iss_ss->ss_rport_id->ident_length);
201 iss->iss_hg = hg;
202
203 /*
204 * get the view entry map,
205 * take all host/target group into consideration
206 */
207 ve_map = stmf_duplicate_ve_map(0);
208 for (vertg = stmf_state.stmf_ver_tg_head; vertg != NULL;
209 vertg = vertg->vert_next) {
210 ptg_data = (char *)vertg->vert_tg_ref->id_data;
211 if ((ptg_data[0] != '*') && (!tg ||
212 ((tg->id_data[0] != '*') &&
213 (vertg->vert_tg_ref != tg)))) {
214 continue;
215 }
216 for (verhg = vertg->vert_verh_list; verhg != NULL;
217 verhg = verhg->verh_next) {
218 phg_data = (char *)verhg->verh_hg_ref->id_data;
219 if ((phg_data[0] != '*') && (!hg ||
220 ((hg->id_data[0] != '*') &&
221 (verhg->verh_hg_ref != hg)))) {
222 continue;
223 }
224 (void) stmf_merge_ve_map(&verhg->verh_ve_map, ve_map,
225 &ve_map, 0);
226 }
227 }
228
229
230 if (ve_map->lm_nluns) {
231 stmf_add_lus_to_session_per_vemap(ilport, iss, ve_map);
232 }
233 /* not configured, cannot access any luns for now */
234
235 stmf_destroy_ve_map(ve_map);
236
237 return (STMF_SUCCESS);
238 }
239
240 /*
241 * Expects the session lock to be held.
242 * iss_lockp is held
243 */
244 stmf_xfer_data_t *
245 stmf_session_prepare_report_lun_data(stmf_lun_map_t *sm)
246 {
247 stmf_xfer_data_t *xd;
248 uint16_t nluns, ent;
249 uint32_t alloc_size, data_size;
250 int i;
251
252 nluns = sm->lm_nluns;
253
254 data_size = 8 + (((uint32_t)nluns) << 3);
255 if (nluns == 0) {
256 data_size += 8;
257 }
258 alloc_size = data_size + sizeof (stmf_xfer_data_t) - 4;
259
260 xd = (stmf_xfer_data_t *)kmem_zalloc(alloc_size, KM_NOSLEEP);
261
262 if (xd == NULL)
263 return (NULL);
264
265 xd->alloc_size = alloc_size;
266 xd->size_left = data_size;
267
268 *((uint32_t *)xd->buf) = BE_32(data_size - 8);
269 if (nluns == 0) {
270 return (xd);
271 }
272
273 ent = 0;
274
275 for (i = 0; ((i < sm->lm_nentries) && (ent < nluns)); i++) {
276 if (sm->lm_plus[i] == NULL)
277 continue;
278 /* Fill in the entry */
279 xd->buf[8 + (ent << 3) + 1] = (uchar_t)i;
280 xd->buf[8 + (ent << 3) + 0] = ((uchar_t)(i >> 8));
281 ent++;
282 }
283
284 ASSERT(ent == nluns);
285
286 return (xd);
287 }
288
289 /*
290 * Add a lu to active sessions based on LUN inventory.
291 * Only invoked when the lu is onlined
292 */
293 void
294 stmf_add_lu_to_active_sessions(stmf_lu_t *lu)
295 {
296 stmf_id_data_t *luid;
297 stmf_view_entry_t *ve;
298 stmf_i_lu_t *ilu;
299
300 ASSERT(mutex_owned(&stmf_state.stmf_lock));
301 ilu = (stmf_i_lu_t *)lu->lu_stmf_private;
302 ASSERT(ilu->ilu_state == STMF_STATE_ONLINE);
303
304 luid = ((stmf_i_lu_t *)lu->lu_stmf_private)->ilu_luid;
305
306 if (!luid) {
307 /* we did not configure view for this lun, so just return */
308 return;
309 }
310
311 for (ve = (stmf_view_entry_t *)luid->id_impl_specific;
312 ve; ve = ve->ve_next) {
313 stmf_update_sessions_per_ve(ve, lu, 1);
314 }
315 }
316 /*
317 * Unmap a lun from all sessions
318 */
319 void
320 stmf_session_lu_unmapall(stmf_lu_t *lu)
321 {
322 stmf_i_lu_t *ilu;
323 stmf_id_data_t *luid;
324 stmf_view_entry_t *ve;
325
326 ASSERT(mutex_owned(&stmf_state.stmf_lock));
327
328 ilu = (stmf_i_lu_t *)lu->lu_stmf_private;
329
330 if (ilu->ilu_ref_cnt == 0)
331 return;
332
333 luid = ((stmf_i_lu_t *)lu->lu_stmf_private)->ilu_luid;
334 if (!luid) {
335 /*
336 * we did not configure view for this lun, this should be
337 * an error
338 */
339 return;
340 }
341
342 for (ve = (stmf_view_entry_t *)luid->id_impl_specific;
343 ve; ve = ve->ve_next) {
344 stmf_update_sessions_per_ve(ve, lu, 0);
345 if (ilu->ilu_ref_cnt == 0)
346 break;
347 }
348 }
349 /*
350 * add lu to a session, stmf_lock is already held
351 * iss_lockp/ilport_lock already held
352 */
353 static stmf_status_t
354 stmf_add_lu_to_session(stmf_i_local_port_t *ilport,
355 stmf_i_scsi_session_t *iss,
356 stmf_lu_t *lu,
357 uint8_t *lu_nbr)
358 {
359 stmf_lun_map_t *sm = iss->iss_sm;
360 stmf_status_t ret;
361 stmf_i_lu_t *ilu = (stmf_i_lu_t *)lu->lu_stmf_private;
362 stmf_lun_map_ent_t *lun_map_ent;
363 uint32_t new_flags = 0;
364 uint16_t luNbr =
365 ((uint16_t)lu_nbr[1] | (((uint16_t)(lu_nbr[0] & 0x3F)) << 8));
366
367 ASSERT(mutex_owned(&stmf_state.stmf_lock));
368 ASSERT(!stmf_get_ent_from_map(sm, luNbr));
369
370 if ((sm->lm_nluns == 0) &&
371 ((iss->iss_flags & ISS_BEING_CREATED) == 0)) {
372 new_flags = ISS_GOT_INITIAL_LUNS;
373 atomic_or_32(&ilport->ilport_flags, ILPORT_SS_GOT_INITIAL_LUNS);
374 stmf_state.stmf_process_initial_luns = 1;
375 }
376
377 lun_map_ent = (stmf_lun_map_ent_t *)
378 kmem_zalloc(sizeof (stmf_lun_map_ent_t), KM_SLEEP);
379 lun_map_ent->ent_lu = lu;
380 ret = stmf_add_ent_to_map(sm, (void *)lun_map_ent, lu_nbr);
381 ASSERT(ret == STMF_SUCCESS);
382 atomic_inc_32(&ilu->ilu_ref_cnt);
383 /*
384 * do not set lun inventory flag for standby port
385 * as this would be handled from peer
386 */
387 if (ilport->ilport_standby == 0) {
388 new_flags |= ISS_LUN_INVENTORY_CHANGED;
389 }
390 atomic_or_32(&iss->iss_flags, new_flags);
391 return (STMF_SUCCESS);
392 }
393
394 /*
395 * remvoe lu from a session, stmf_lock is already held
396 * iss_lockp held
397 */
398 static void
399 stmf_remove_lu_from_session(stmf_i_scsi_session_t *iss,
400 stmf_lu_t *lu, uint8_t *lu_nbr)
401 {
402 stmf_status_t ret;
403 stmf_i_lu_t *ilu;
404 stmf_lun_map_t *sm = iss->iss_sm;
405 stmf_lun_map_ent_t *lun_map_ent;
406 uint16_t luNbr =
407 ((uint16_t)lu_nbr[1] | (((uint16_t)(lu_nbr[0] & 0x3F)) << 8));
408
409 ASSERT(mutex_owned(&stmf_state.stmf_lock));
410 lun_map_ent = stmf_get_ent_from_map(sm, luNbr);
411 ASSERT(lun_map_ent->ent_lu == lu);
412 if (lun_map_ent == NULL) {
413 return;
414 }
415
416 ilu = (stmf_i_lu_t *)lu->lu_stmf_private;
417
418 ret = stmf_remove_ent_from_map(sm, lu_nbr);
419 ASSERT(ret == STMF_SUCCESS);
420 atomic_dec_32(&ilu->ilu_ref_cnt);
421 iss->iss_flags |= ISS_LUN_INVENTORY_CHANGED;
422 if (lun_map_ent->ent_itl_datap) {
423 stmf_do_itl_dereg(lu, lun_map_ent->ent_itl_datap,
424 STMF_ITL_REASON_USER_REQUEST);
425 }
426 kmem_free((void *)lun_map_ent, sizeof (stmf_lun_map_ent_t));
427 }
428
429 /*
430 * add or remove lu from all related sessions based on view entry,
431 * action is 0 for delete, 1 for add
432 */
433 void
434 stmf_update_sessions_per_ve(stmf_view_entry_t *ve,
435 stmf_lu_t *lu, int action)
436 {
437 stmf_i_lu_t *ilu_tmp;
438 stmf_lu_t *lu_to_add;
439 stmf_i_local_port_t *ilport;
440 stmf_i_scsi_session_t *iss;
441 stmf_id_list_t *hostlist;
442 stmf_id_list_t *targetlist;
443 int all_hg = 0, all_tg = 0;
444
445 ASSERT(mutex_owned(&stmf_state.stmf_lock));
446
447 if (!lu) {
448 ilu_tmp = (stmf_i_lu_t *)ve->ve_luid->id_pt_to_object;
449 if (!ilu_tmp)
450 return;
451 lu_to_add = ilu_tmp->ilu_lu;
452 } else {
453 lu_to_add = lu;
454 ilu_tmp = (stmf_i_lu_t *)lu->lu_stmf_private;
455 }
456
457 if (ve->ve_hg->id_data[0] == '*')
458 all_hg = 1;
459 if (ve->ve_tg->id_data[0] == '*')
460 all_tg = 1;
461 hostlist = (stmf_id_list_t *)ve->ve_hg->id_impl_specific;
462 targetlist = (stmf_id_list_t *)ve->ve_tg->id_impl_specific;
463
464 if ((!all_hg && !hostlist->idl_head) ||
465 (!all_tg && !targetlist->idl_head))
466 /* No sessions to be updated */
467 return;
468
469 for (ilport = stmf_state.stmf_ilportlist; ilport != NULL;
470 ilport = ilport->ilport_next) {
471 if (!all_tg && ilport->ilport_tg != ve->ve_tg)
472 continue;
473 /* This ilport belongs to the target group */
474 rw_enter(&ilport->ilport_lock, RW_WRITER);
475 for (iss = ilport->ilport_ss_list; iss != NULL;
476 iss = iss->iss_next) {
477 if (!all_hg && iss->iss_hg != ve->ve_hg)
478 continue;
479 /* This host belongs to the host group */
480 if (action == 0) { /* to remove */
481 stmf_remove_lu_from_session(iss, lu_to_add,
482 ve->ve_lun);
483 if (ilu_tmp->ilu_ref_cnt == 0) {
484 rw_exit(&ilport->ilport_lock);
485 return;
486 }
487 } else {
488 (void) stmf_add_lu_to_session(ilport, iss,
489 lu_to_add, ve->ve_lun);
490 }
491 }
492 rw_exit(&ilport->ilport_lock);
493 }
494 }
495
496 /*
497 * add luns in view entry map to a session,
498 * and stmf_lock is already held
499 */
500 void
501 stmf_add_lus_to_session_per_vemap(stmf_i_local_port_t *ilport,
502 stmf_i_scsi_session_t *iss,
503 stmf_lun_map_t *vemap)
504 {
505 stmf_lu_t *lu;
506 stmf_i_lu_t *ilu;
507 stmf_view_entry_t *ve;
508 uint32_t i;
509
510 ASSERT(mutex_owned(&stmf_state.stmf_lock));
511 for (i = 0; i < vemap->lm_nentries; i++) {
512 ve = (stmf_view_entry_t *)vemap->lm_plus[i];
513 if (!ve)
514 continue;
515 ilu = (stmf_i_lu_t *)ve->ve_luid->id_pt_to_object;
516 if (ilu && ilu->ilu_state == STMF_STATE_ONLINE) {
517 lu = ilu->ilu_lu;
518 (void) stmf_add_lu_to_session(ilport, iss, lu,
519 ve->ve_lun);
520 }
521 }
522 }
523 /*
524 * remove luns in view entry map from a session
525 * iss_lockp held
526 */
527 void
528 stmf_remove_lus_from_session_per_vemap(stmf_i_scsi_session_t *iss,
529 stmf_lun_map_t *vemap)
530 {
531 stmf_lu_t *lu;
532 stmf_i_lu_t *ilu;
533 stmf_view_entry_t *ve;
534 uint32_t i;
535
536 ASSERT(mutex_owned(&stmf_state.stmf_lock));
537
538 for (i = 0; i < vemap->lm_nentries; i++) {
539 ve = (stmf_view_entry_t *)vemap->lm_plus[i];
540 if (!ve)
541 continue;
542 ilu = (stmf_i_lu_t *)ve->ve_luid->id_pt_to_object;
543 if (ilu && ilu->ilu_state == STMF_STATE_ONLINE) {
544 lu = ilu->ilu_lu;
545 stmf_remove_lu_from_session(iss, lu, ve->ve_lun);
546 }
547 }
548 }
549
550 stmf_id_data_t *
551 stmf_alloc_id(uint16_t id_size, uint16_t type, uint8_t *id_data,
552 uint32_t additional_size)
553 {
554 stmf_id_data_t *id;
555 int struct_size, total_size, real_id_size;
556
557 real_id_size = ((uint32_t)id_size + 7) & (~7);
558 struct_size = (sizeof (*id) + 7) & (~7);
559 total_size = ((additional_size + 7) & (~7)) + struct_size +
560 real_id_size;
561 id = (stmf_id_data_t *)kmem_zalloc(total_size, KM_SLEEP);
562 id->id_type = type;
563 id->id_data_size = id_size;
564 id->id_data = ((uint8_t *)id) + struct_size;
565 id->id_total_alloc_size = total_size;
566 if (additional_size) {
567 id->id_impl_specific = ((uint8_t *)id) + struct_size +
568 real_id_size;
569 }
570 bcopy(id_data, id->id_data, id_size);
571
572 return (id);
573 }
574
575 void
576 stmf_free_id(stmf_id_data_t *id)
577 {
578 kmem_free(id, id->id_total_alloc_size);
579 }
580
581
582 stmf_id_data_t *
583 stmf_lookup_id(stmf_id_list_t *idlist, uint16_t id_size, uint8_t *data)
584 {
585 stmf_id_data_t *id;
586
587 for (id = idlist->idl_head; id != NULL; id = id->id_next) {
588 if ((id->id_data_size == id_size) &&
589 (bcmp(id->id_data, data, id_size) == 0)) {
590 return (id);
591 }
592 }
593
594 return (NULL);
595 }
596 /* Return the target group which a target belong to */
597 stmf_id_data_t *
598 stmf_lookup_group_for_target(uint8_t *ident, uint16_t ident_size)
599 {
600 stmf_id_data_t *tgid;
601 stmf_id_data_t *target;
602
603 ASSERT(mutex_owned(&stmf_state.stmf_lock));
604
605 for (tgid = stmf_state.stmf_tg_list.idl_head; tgid;
606 tgid = tgid->id_next) {
607 target = stmf_lookup_id(
608 (stmf_id_list_t *)tgid->id_impl_specific,
609 ident_size, ident);
610 if (target)
611 return (tgid);
612 }
613 return (NULL);
614 }
615 /* Return the host group which a host belong to */
616 stmf_id_data_t *
617 stmf_lookup_group_for_host(uint8_t *ident, uint16_t ident_size)
618 {
619 stmf_id_data_t *hgid;
620 stmf_id_data_t *host;
621
622 ASSERT(mutex_owned(&stmf_state.stmf_lock));
623
624 for (hgid = stmf_state.stmf_hg_list.idl_head; hgid;
625 hgid = hgid->id_next) {
626 host = stmf_lookup_id(
627 (stmf_id_list_t *)hgid->id_impl_specific,
628 ident_size, ident);
629 if (host)
630 return (hgid);
631 }
632 return (NULL);
633 }
634
635 void
636 stmf_append_id(stmf_id_list_t *idlist, stmf_id_data_t *id)
637 {
638 id->id_next = NULL;
639
640 if ((id->id_prev = idlist->idl_tail) == NULL) {
641 idlist->idl_head = idlist->idl_tail = id;
642 } else {
643 idlist->idl_tail->id_next = id;
644 idlist->idl_tail = id;
645 }
646 atomic_inc_32(&idlist->id_count);
647 }
648
649 void
650 stmf_remove_id(stmf_id_list_t *idlist, stmf_id_data_t *id)
651 {
652 if (id->id_next) {
653 id->id_next->id_prev = id->id_prev;
654 } else {
655 idlist->idl_tail = id->id_prev;
656 }
657
658 if (id->id_prev) {
659 id->id_prev->id_next = id->id_next;
660 } else {
661 idlist->idl_head = id->id_next;
662 }
663 atomic_dec_32(&idlist->id_count);
664 }
665
666
667 /*
668 * The refcnts of objects in a view entry are updated when then entry
669 * is successfully added. ve_map is just another representation of the
670 * view enrtries in a LU. Duplicating or merging a ve map does not
671 * affect any refcnts.
672 * stmf_state.stmf_lock held
673 */
674 stmf_lun_map_t *
675 stmf_duplicate_ve_map(stmf_lun_map_t *src)
676 {
677 stmf_lun_map_t *dst;
678 int i;
679
680 dst = (stmf_lun_map_t *)kmem_zalloc(sizeof (*dst), KM_SLEEP);
681
682 if (src == NULL)
683 return (dst);
684
685 if (src->lm_nentries) {
686 dst->lm_plus = kmem_zalloc(dst->lm_nentries *
687 sizeof (void *), KM_SLEEP);
688 for (i = 0; i < dst->lm_nentries; i++) {
689 dst->lm_plus[i] = src->lm_plus[i];
690 }
691 }
692
693 return (dst);
694 }
695
696 void
697 stmf_destroy_ve_map(stmf_lun_map_t *dst)
698 {
699 if (dst->lm_nentries) {
700 kmem_free(dst->lm_plus, dst->lm_nentries * sizeof (void *));
701 }
702 kmem_free(dst, sizeof (*dst));
703 }
704
705 /*
706 * stmf_state.stmf_lock held. Operations are stmf global in nature and
707 * not session level.
708 */
709 int
710 stmf_merge_ve_map(stmf_lun_map_t *src, stmf_lun_map_t *dst,
711 stmf_lun_map_t **pp_ret_map, stmf_merge_flags_t mf)
712 {
713 int i;
714 int nentries;
715 int to_create_space = 0;
716
717 if (dst == NULL) {
718 *pp_ret_map = stmf_duplicate_ve_map(src);
719 return (1);
720 }
721
722 if (src == NULL || src->lm_nluns == 0) {
723 if (mf & MERGE_FLAG_RETURN_NEW_MAP)
724 *pp_ret_map = stmf_duplicate_ve_map(dst);
725 else
726 *pp_ret_map = dst;
727 return (1);
728 }
729
730 if (mf & MERGE_FLAG_RETURN_NEW_MAP) {
731 *pp_ret_map = stmf_duplicate_ve_map(NULL);
732 nentries = max(dst->lm_nentries, src->lm_nentries);
733 to_create_space = 1;
734 } else {
735 *pp_ret_map = dst;
736 /* If there is not enough space in dst map */
737 if (dst->lm_nentries < src->lm_nentries) {
738 nentries = src->lm_nentries;
739 to_create_space = 1;
740 }
741 }
742 if (to_create_space) {
743 void **p;
744 p = (void **)kmem_zalloc(nentries * sizeof (void *), KM_SLEEP);
745 if (dst->lm_nentries) {
746 bcopy(dst->lm_plus, p,
747 dst->lm_nentries * sizeof (void *));
748 }
749 if (mf & (MERGE_FLAG_RETURN_NEW_MAP == 0))
750 kmem_free(dst->lm_plus,
751 dst->lm_nentries * sizeof (void *));
752 (*pp_ret_map)->lm_plus = p;
753 (*pp_ret_map)->lm_nentries = nentries;
754 }
755
756 for (i = 0; i < src->lm_nentries; i++) {
757 if (src->lm_plus[i] == NULL)
758 continue;
759 if (dst->lm_plus[i] != NULL) {
760 if (mf & MERGE_FLAG_NO_DUPLICATE) {
761 if (mf & MERGE_FLAG_RETURN_NEW_MAP) {
762 stmf_destroy_ve_map(*pp_ret_map);
763 *pp_ret_map = NULL;
764 }
765 return (0);
766 }
767 } else {
768 dst->lm_plus[i] = src->lm_plus[i];
769 dst->lm_nluns++;
770 }
771 }
772
773 return (1);
774 }
775
776 /*
777 * add host group, id_impl_specific point to a list of hosts,
778 * on return, if error happened, err_detail may be assigned if
779 * the pointer is not NULL
780 */
781 stmf_status_t
782 stmf_add_hg(uint8_t *hg_name, uint16_t hg_name_size,
783 int allow_special, uint32_t *err_detail)
784 {
785 stmf_id_data_t *id;
786
787 if (!allow_special) {
788 if (hg_name[0] == '*')
789 return (STMF_INVALID_ARG);
790 }
791
792 if (stmf_lookup_id(&stmf_state.stmf_hg_list,
793 hg_name_size, (uint8_t *)hg_name)) {
794 if (err_detail)
795 *err_detail = STMF_IOCERR_HG_EXISTS;
796 return (STMF_ALREADY);
797 }
798 id = stmf_alloc_id(hg_name_size, STMF_ID_TYPE_HOST_GROUP,
799 (uint8_t *)hg_name, sizeof (stmf_id_list_t));
800 stmf_append_id(&stmf_state.stmf_hg_list, id);
801
802 return (STMF_SUCCESS);
803 }
804
805 /* add target group */
806 stmf_status_t
807 stmf_add_tg(uint8_t *tg_name, uint16_t tg_name_size,
808 int allow_special, uint32_t *err_detail)
809 {
810 stmf_id_data_t *id;
811
812 if (!allow_special) {
813 if (tg_name[0] == '*')
814 return (STMF_INVALID_ARG);
815 }
816
817
818 if (stmf_lookup_id(&stmf_state.stmf_tg_list, tg_name_size,
819 (uint8_t *)tg_name)) {
820 if (err_detail)
821 *err_detail = STMF_IOCERR_TG_EXISTS;
822 return (STMF_ALREADY);
823 }
824 id = stmf_alloc_id(tg_name_size, STMF_ID_TYPE_TARGET_GROUP,
825 (uint8_t *)tg_name, sizeof (stmf_id_list_t));
826 stmf_append_id(&stmf_state.stmf_tg_list, id);
827
828 return (STMF_SUCCESS);
829 }
830
831 /*
832 * insert view entry into list for a luid, if ve->ve_id is 0xffffffff,
833 * pick up a smallest available veid for it, and return the veid in ve->ve_id.
834 * The view entries list is sorted based on veid.
835 */
836 stmf_status_t
837 stmf_add_ve_to_luid(stmf_id_data_t *luid, stmf_view_entry_t *ve)
838 {
839 stmf_view_entry_t *ve_tmp = NULL;
840 stmf_view_entry_t *ve_prev = NULL;
841
842 ASSERT(mutex_owned(&stmf_state.stmf_lock));
843
844 ve_tmp = (stmf_view_entry_t *)luid->id_impl_specific;
845
846 if (ve->ve_id != 0xffffffff) {
847 for (; ve_tmp; ve_tmp = ve_tmp->ve_next) {
848 if (ve_tmp->ve_id > ve->ve_id) {
849 break;
850 } else if (ve_tmp->ve_id == ve->ve_id) {
851 return (STMF_ALREADY);
852 }
853 ve_prev = ve_tmp;
854 }
855 } else {
856 uint32_t veid = 0;
857 /* search the smallest available veid */
858 for (; ve_tmp; ve_tmp = ve_tmp->ve_next) {
859 ASSERT(ve_tmp->ve_id >= veid);
860 if (ve_tmp->ve_id != veid)
861 break;
862 veid++;
863 if (veid == 0xffffffff)
864 return (STMF_NOT_SUPPORTED);
865 ve_prev = ve_tmp;
866 }
867 ve->ve_id = veid;
868 }
869
870 /* insert before ve_tmp if it exist */
871 ve->ve_next = ve_tmp;
872 ve->ve_prev = ve_prev;
873 if (ve_tmp) {
874 ve_tmp->ve_prev = ve;
875 }
876 if (ve_prev) {
877 ve_prev->ve_next = ve;
878 } else {
879 luid->id_impl_specific = (void *)ve;
880 }
881 return (STMF_SUCCESS);
882 }
883
884 /* stmf_lock is already held, err_detail may be assigned if error happens */
885 stmf_status_t
886 stmf_add_view_entry(stmf_id_data_t *hg, stmf_id_data_t *tg,
887 uint8_t *lu_guid, uint32_t *ve_id, uint8_t *lun,
888 stmf_view_entry_t **conflicting, uint32_t *err_detail)
889 {
890 stmf_id_data_t *luid;
891 stmf_view_entry_t *ve;
892 char *phg, *ptg;
893 stmf_lun_map_t *ve_map = NULL;
894 stmf_ver_hg_t *verhg = NULL, *verhg_ex = NULL;
895 stmf_ver_tg_t *vertg = NULL, *vertg_ex = NULL;
896 char luid_new;
897 uint16_t lun_num;
898 stmf_i_lu_t *ilu;
899 stmf_status_t ret;
900
901 ASSERT(mutex_owned(&stmf_state.stmf_lock));
902
903 lun_num = ((uint16_t)lun[1] | (((uint16_t)(lun[0] & 0x3F)) << 8));
904
905 luid = stmf_lookup_id(&stmf_state.stmf_luid_list, 16, lu_guid);
906 if (luid == NULL) {
907 luid = stmf_alloc_id(16, STMF_ID_TYPE_LU_GUID, lu_guid, 0);
908 ilu = stmf_luident_to_ilu(lu_guid);
909 if (ilu) {
910 ilu->ilu_luid = luid;
911 luid->id_pt_to_object = (void *)ilu;
912 }
913 luid_new = 1;
914 } else {
915 luid_new = 0;
916 ilu = (stmf_i_lu_t *)luid->id_pt_to_object;
917 }
918
919 /* The view entry won't be added if there is any confilict */
920 phg = (char *)hg->id_data; ptg = (char *)tg->id_data;
921 for (ve = (stmf_view_entry_t *)luid->id_impl_specific; ve != NULL;
922 ve = ve->ve_next) {
923 if (((phg[0] == '*') || (ve->ve_hg->id_data[0] == '*') ||
924 (hg == ve->ve_hg)) && ((ptg[0] == '*') ||
925 (ve->ve_tg->id_data[0] == '*') || (tg == ve->ve_tg))) {
926 *conflicting = ve;
927 *err_detail = STMF_IOCERR_VIEW_ENTRY_CONFLICT;
928 ret = STMF_ALREADY;
929 goto add_ve_err_ret;
930 }
931 }
932
933 ve_map = stmf_duplicate_ve_map(0);
934 for (vertg = stmf_state.stmf_ver_tg_head; vertg != NULL;
935 vertg = vertg->vert_next) {
936 ptg = (char *)vertg->vert_tg_ref->id_data;
937 if ((ptg[0] != '*') && (tg->id_data[0] != '*') &&
938 (vertg->vert_tg_ref != tg)) {
939 continue;
940 }
941 if (vertg->vert_tg_ref == tg)
942 vertg_ex = vertg;
943 for (verhg = vertg->vert_verh_list; verhg != NULL;
944 verhg = verhg->verh_next) {
945 phg = (char *)verhg->verh_hg_ref->id_data;
946 if ((phg[0] != '*') && (hg->id_data[0] != '*') &&
947 (verhg->verh_hg_ref != hg)) {
948 continue;
949 }
950 if ((vertg_ex == vertg) && (verhg->verh_hg_ref == hg))
951 verhg_ex = verhg;
952 (void) stmf_merge_ve_map(&verhg->verh_ve_map, ve_map,
953 &ve_map, 0);
954 }
955 }
956
957 if (lun[2] == 0xFF) {
958 /* Pick a LUN number */
959 lun_num = stmf_get_next_free_lun(ve_map, lun);
960 if (lun_num > 0x3FFF) {
961 stmf_destroy_ve_map(ve_map);
962 ret = STMF_NOT_SUPPORTED;
963 goto add_ve_err_ret;
964 }
965 } else {
966 if ((*conflicting = stmf_get_ent_from_map(ve_map, lun_num))
967 != NULL) {
968 stmf_destroy_ve_map(ve_map);
969 *err_detail = STMF_IOCERR_LU_NUMBER_IN_USE;
970 ret = STMF_LUN_TAKEN;
971 goto add_ve_err_ret;
972 }
973 }
974 stmf_destroy_ve_map(ve_map);
975
976 /* All is well, do the actual addition now */
977 ve = (stmf_view_entry_t *)kmem_zalloc(sizeof (*ve), KM_SLEEP);
978 ve->ve_id = *ve_id;
979 ve->ve_lun[0] = lun[0];
980 ve->ve_lun[1] = lun[1];
981
982 if ((ret = stmf_add_ve_to_luid(luid, ve)) != STMF_SUCCESS) {
983 kmem_free(ve, sizeof (stmf_view_entry_t));
984 goto add_ve_err_ret;
985 }
986 ve->ve_hg = hg; hg->id_refcnt++;
987 ve->ve_tg = tg; tg->id_refcnt++;
988 ve->ve_luid = luid; luid->id_refcnt++;
989
990 *ve_id = ve->ve_id;
991
992 if (luid_new) {
993 stmf_append_id(&stmf_state.stmf_luid_list, luid);
994 }
995
996 if (vertg_ex == NULL) {
997 vertg_ex = (stmf_ver_tg_t *)kmem_zalloc(sizeof (stmf_ver_tg_t),
998 KM_SLEEP);
999 vertg_ex->vert_next = stmf_state.stmf_ver_tg_head;
1000 stmf_state.stmf_ver_tg_head = vertg_ex;
1001 vertg_ex->vert_tg_ref = tg;
1002 verhg_ex = vertg_ex->vert_verh_list =
1003 (stmf_ver_hg_t *)kmem_zalloc(sizeof (stmf_ver_hg_t),
1004 KM_SLEEP);
1005 verhg_ex->verh_hg_ref = hg;
1006 }
1007 if (verhg_ex == NULL) {
1008 verhg_ex = (stmf_ver_hg_t *)kmem_zalloc(sizeof (stmf_ver_hg_t),
1009 KM_SLEEP);
1010 verhg_ex->verh_next = vertg_ex->vert_verh_list;
1011 vertg_ex->vert_verh_list = verhg_ex;
1012 verhg_ex->verh_hg_ref = hg;
1013 }
1014 ret = stmf_add_ent_to_map(&verhg_ex->verh_ve_map, ve, ve->ve_lun);
1015 ASSERT(ret == STMF_SUCCESS);
1016
1017 /* we need to update the affected session */
1018 if (stmf_state.stmf_service_running) {
1019 if (ilu && ilu->ilu_state == STMF_STATE_ONLINE)
1020 stmf_update_sessions_per_ve(ve, ilu->ilu_lu, 1);
1021 }
1022
1023 return (STMF_SUCCESS);
1024 add_ve_err_ret:
1025 if (luid_new) {
1026 if (ilu)
1027 ilu->ilu_luid = NULL;
1028 stmf_free_id(luid);
1029 }
1030 return (ret);
1031 }
1032
1033 /*
1034 * protected by stmf_state.stmf_lock when working on global lun map.
1035 * iss_lockp when working at the session level.
1036 */
1037 static stmf_status_t
1038 stmf_add_ent_to_map(stmf_lun_map_t *lm, void *ent, uint8_t *lun)
1039 {
1040 uint16_t n;
1041 if (((lun[0] & 0xc0) >> 6) != 0)
1042 return (STMF_FAILURE);
1043
1044 n = (uint16_t)lun[1] | (((uint16_t)(lun[0] & 0x3F)) << 8);
1045 try_again_to_add:
1046 if (lm->lm_nentries && (n < lm->lm_nentries)) {
1047 if (lm->lm_plus[n] == NULL) {
1048 lm->lm_plus[n] = ent;
1049 lm->lm_nluns++;
1050 return (STMF_SUCCESS);
1051 } else {
1052 return (STMF_LUN_TAKEN);
1053 }
1054 } else {
1055 void **pplu;
1056 uint16_t m = n + 1;
1057 m = ((m + 7) & ~7) & 0x7FFF;
1058 pplu = (void **)kmem_zalloc(m * sizeof (void *), KM_SLEEP);
1059 bcopy(lm->lm_plus, pplu,
1060 lm->lm_nentries * sizeof (void *));
1061 kmem_free(lm->lm_plus, lm->lm_nentries * sizeof (void *));
1062 lm->lm_plus = pplu;
1063 lm->lm_nentries = m;
1064 goto try_again_to_add;
1065 }
1066 }
1067
1068
1069 /*
1070 * iss_lockp held when working on a session.
1071 * stmf_state.stmf_lock is held when working on the global views.
1072 */
1073 static stmf_status_t
1074 stmf_remove_ent_from_map(stmf_lun_map_t *lm, uint8_t *lun)
1075 {
1076 uint16_t n, i;
1077 uint8_t lutype = (lun[0] & 0xc0) >> 6;
1078 if (lutype != 0)
1079 return (STMF_FAILURE);
1080
1081 n = (uint16_t)lun[1] | (((uint16_t)(lun[0] & 0x3F)) << 8);
1082
1083 if (n >= lm->lm_nentries)
1084 return (STMF_NOT_FOUND);
1085 if (lm->lm_plus[n] == NULL)
1086 return (STMF_NOT_FOUND);
1087
1088 lm->lm_plus[n] = NULL;
1089 lm->lm_nluns--;
1090
1091 for (i = 0; i < lm->lm_nentries; i++) {
1092 if (lm->lm_plus[lm->lm_nentries - 1 - i] != NULL)
1093 break;
1094 }
1095 i &= ~15;
1096 if (i >= 16) {
1097 void **pplu;
1098 uint16_t m;
1099 m = lm->lm_nentries - i;
1100 pplu = (void **)kmem_zalloc(m * sizeof (void *), KM_SLEEP);
1101 bcopy(lm->lm_plus, pplu, m * sizeof (void *));
1102 kmem_free(lm->lm_plus, lm->lm_nentries * sizeof (void *));
1103 lm->lm_plus = pplu;
1104 lm->lm_nentries = m;
1105 }
1106
1107 return (STMF_SUCCESS);
1108 }
1109
1110 /*
1111 * stmf_state.stmf_lock held
1112 */
1113 uint16_t
1114 stmf_get_next_free_lun(stmf_lun_map_t *sm, uint8_t *lun)
1115 {
1116 uint16_t luNbr;
1117
1118
1119 if (sm->lm_nluns < 0x4000) {
1120 for (luNbr = 0; luNbr < sm->lm_nentries; luNbr++) {
1121 if (sm->lm_plus[luNbr] == NULL)
1122 break;
1123 }
1124 } else {
1125 return (0xFFFF);
1126 }
1127 if (lun) {
1128 bzero(lun, 8);
1129 lun[1] = luNbr & 0xff;
1130 lun[0] = (luNbr >> 8) & 0xff;
1131 }
1132
1133 return (luNbr);
1134 }
1135
1136 /*
1137 * stmf_state.stmf_lock is held when working on global view map
1138 * iss_lockp (RW_WRITER) is held when working on session map.
1139 */
1140 void *
1141 stmf_get_ent_from_map(stmf_lun_map_t *sm, uint16_t lun_num)
1142 {
1143 if ((lun_num & 0xC000) == 0) {
1144 if (sm->lm_nentries > lun_num)
1145 return (sm->lm_plus[lun_num & 0x3FFF]);
1146 else
1147 return (NULL);
1148 }
1149
1150 return (NULL);
1151 }
1152
1153 int
1154 stmf_add_ve(uint8_t *hgname, uint16_t hgname_size,
1155 uint8_t *tgname, uint16_t tgname_size,
1156 uint8_t *lu_guid, uint32_t *ve_id,
1157 uint8_t *luNbr, uint32_t *err_detail)
1158 {
1159 stmf_id_data_t *hg;
1160 stmf_id_data_t *tg;
1161 stmf_view_entry_t *conflictve;
1162 stmf_status_t ret;
1163
1164 ASSERT(mutex_owned(&stmf_state.stmf_lock));
1165
1166 hg = stmf_lookup_id(&stmf_state.stmf_hg_list, hgname_size,
1167 (uint8_t *)hgname);
1168 if (!hg) {
1169 *err_detail = STMF_IOCERR_INVALID_HG;
1170 return (ENOENT); /* could not find group */
1171 }
1172 tg = stmf_lookup_id(&stmf_state.stmf_tg_list, tgname_size,
1173 (uint8_t *)tgname);
1174 if (!tg) {
1175 *err_detail = STMF_IOCERR_INVALID_TG;
1176 return (ENOENT); /* could not find group */
1177 }
1178 ret = stmf_add_view_entry(hg, tg, lu_guid, ve_id, luNbr,
1179 &conflictve, err_detail);
1180
1181 if (ret == STMF_ALREADY) {
1182 return (EALREADY);
1183 } else if (ret == STMF_LUN_TAKEN) {
1184 return (EEXIST);
1185 } else if (ret == STMF_NOT_SUPPORTED) {
1186 return (E2BIG);
1187 } else if (ret != STMF_SUCCESS) {
1188 return (EINVAL);
1189 }
1190 return (0);
1191 }
1192
1193 int
1194 stmf_remove_ve_by_id(uint8_t *guid, uint32_t veid, uint32_t *err_detail)
1195 {
1196 stmf_id_data_t *luid;
1197 stmf_view_entry_t *ve;
1198 stmf_ver_tg_t *vtg;
1199 stmf_ver_hg_t *vhg;
1200 stmf_ver_tg_t *prev_vtg = NULL;
1201 stmf_ver_hg_t *prev_vhg = NULL;
1202 int found = 0;
1203 stmf_i_lu_t *ilu;
1204
1205 ASSERT(mutex_owned(&stmf_state.stmf_lock));
1206 luid = stmf_lookup_id(&stmf_state.stmf_luid_list, 16, guid);
1207 if (luid == NULL) {
1208 *err_detail = STMF_IOCERR_INVALID_LU_ID;
1209 return (ENODEV);
1210 }
1211 ilu = (stmf_i_lu_t *)luid->id_pt_to_object;
1212
1213 for (ve = (stmf_view_entry_t *)luid->id_impl_specific;
1214 ve; ve = ve->ve_next) {
1215 if (ve->ve_id == veid) {
1216 break;
1217 }
1218 }
1219 if (!ve) {
1220 *err_detail = STMF_IOCERR_INVALID_VE_ID;
1221 return (ENODEV);
1222 }
1223 /* remove the ve */
1224 if (ve->ve_next)
1225 ve->ve_next->ve_prev = ve->ve_prev;
1226 if (ve->ve_prev)
1227 ve->ve_prev->ve_next = ve->ve_next;
1228 else {
1229 luid->id_impl_specific = (void *)ve->ve_next;
1230 if (!luid->id_impl_specific) {
1231 /* don't have any view entries related to this lu */
1232 stmf_remove_id(&stmf_state.stmf_luid_list, luid);
1233 if (ilu)
1234 ilu->ilu_luid = NULL;
1235 stmf_free_id(luid);
1236 }
1237 }
1238
1239 /* we need to update ver_hg->verh_ve_map */
1240 for (vtg = stmf_state.stmf_ver_tg_head; vtg; vtg = vtg->vert_next) {
1241 if (vtg->vert_tg_ref == ve->ve_tg) {
1242 found = 1;
1243 break;
1244 }
1245 prev_vtg = vtg;
1246 }
1247 ASSERT(found);
1248 found = 0;
1249 for (vhg = vtg->vert_verh_list; vhg; vhg = vhg->verh_next) {
1250 if (vhg->verh_hg_ref == ve->ve_hg) {
1251 found = 1;
1252 break;
1253 }
1254 prev_vhg = vhg;
1255 }
1256 ASSERT(found);
1257
1258 (void) stmf_remove_ent_from_map(&vhg->verh_ve_map, ve->ve_lun);
1259
1260 /* free verhg if it don't have any ve entries related */
1261 if (!vhg->verh_ve_map.lm_nluns) {
1262 /* we don't have any view entry related */
1263 if (prev_vhg)
1264 prev_vhg->verh_next = vhg->verh_next;
1265 else
1266 vtg->vert_verh_list = vhg->verh_next;
1267
1268 /* Free entries in case the map still has memory */
1269 if (vhg->verh_ve_map.lm_nentries) {
1270 kmem_free(vhg->verh_ve_map.lm_plus,
1271 vhg->verh_ve_map.lm_nentries *
1272 sizeof (void *));
1273 }
1274 kmem_free(vhg, sizeof (stmf_ver_hg_t));
1275 if (!vtg->vert_verh_list) {
1276 /* we don't have any ve related */
1277 if (prev_vtg)
1278 prev_vtg->vert_next = vtg->vert_next;
1279 else
1280 stmf_state.stmf_ver_tg_head = vtg->vert_next;
1281 kmem_free(vtg, sizeof (stmf_ver_tg_t));
1282 }
1283 }
1284
1285 if (stmf_state.stmf_service_running && ilu &&
1286 ilu->ilu_state == STMF_STATE_ONLINE) {
1287 stmf_update_sessions_per_ve(ve, ilu->ilu_lu, 0);
1288 }
1289
1290 ve->ve_hg->id_refcnt--;
1291 ve->ve_tg->id_refcnt--;
1292
1293 kmem_free(ve, sizeof (stmf_view_entry_t));
1294 return (0);
1295 }
1296
1297 int
1298 stmf_add_group(uint8_t *grpname, uint16_t grpname_size,
1299 stmf_id_type_t group_type, uint32_t *err_detail)
1300 {
1301 stmf_status_t status;
1302
1303 ASSERT(mutex_owned(&stmf_state.stmf_lock));
1304
1305 if (group_type == STMF_ID_TYPE_HOST_GROUP)
1306 status = stmf_add_hg(grpname, grpname_size, 0, err_detail);
1307 else if (group_type == STMF_ID_TYPE_TARGET_GROUP)
1308 status = stmf_add_tg(grpname, grpname_size, 0, err_detail);
1309 else {
1310 return (EINVAL);
1311 }
1312 switch (status) {
1313 case STMF_SUCCESS:
1314 return (0);
1315 case STMF_INVALID_ARG:
1316 return (EINVAL);
1317 case STMF_ALREADY:
1318 return (EEXIST);
1319 default:
1320 return (EIO);
1321 }
1322 }
1323
1324 /*
1325 * Group can only be removed only when it does not have
1326 * any view entry related
1327 */
1328 int
1329 stmf_remove_group(uint8_t *grpname, uint16_t grpname_size,
1330 stmf_id_type_t group_type, uint32_t *err_detail)
1331 {
1332 stmf_id_data_t *id;
1333 stmf_id_data_t *idmemb;
1334 stmf_id_list_t *grp_memblist;
1335 stmf_i_scsi_session_t *iss;
1336 stmf_i_local_port_t *ilport;
1337
1338 if (grpname[0] == '*')
1339 return (EINVAL);
1340
1341 ASSERT(mutex_owned(&stmf_state.stmf_lock));
1342
1343 if (group_type == STMF_ID_TYPE_HOST_GROUP)
1344 id = stmf_lookup_id(&stmf_state.stmf_hg_list,
1345 grpname_size, grpname);
1346 else if (group_type == STMF_ID_TYPE_TARGET_GROUP)
1347 id = stmf_lookup_id(&stmf_state.stmf_tg_list,
1348 grpname_size, grpname);
1349 if (!id) {
1350 *err_detail = (group_type == STMF_ID_TYPE_HOST_GROUP)?
1351 STMF_IOCERR_INVALID_HG:STMF_IOCERR_INVALID_TG;
1352 return (ENODEV); /* no such grp */
1353 }
1354 if (id->id_refcnt) {
1355 /* fail, still have viewentry related to it */
1356 *err_detail = (group_type == STMF_ID_TYPE_HOST_GROUP)?
1357 STMF_IOCERR_HG_IN_USE:STMF_IOCERR_TG_IN_USE;
1358 return (EBUSY);
1359 }
1360 grp_memblist = (stmf_id_list_t *)id->id_impl_specific;
1361 while ((idmemb = grp_memblist->idl_head) != NULL) {
1362 stmf_remove_id(grp_memblist, idmemb);
1363 stmf_free_id(idmemb);
1364 }
1365
1366 ASSERT(!grp_memblist->id_count);
1367 if (id->id_type == STMF_ID_TYPE_TARGET_GROUP) {
1368 for (ilport = stmf_state.stmf_ilportlist; ilport;
1369 ilport = ilport->ilport_next) {
1370 if (ilport->ilport_tg == (void *)id) {
1371 ilport->ilport_tg = NULL;
1372 }
1373 }
1374 stmf_remove_id(&stmf_state.stmf_tg_list, id);
1375 } else {
1376 for (ilport = stmf_state.stmf_ilportlist; ilport;
1377 ilport = ilport->ilport_next) {
1378 for (iss = ilport->ilport_ss_list; iss;
1379 iss = iss->iss_next) {
1380 if (iss->iss_hg == (void *)id)
1381 iss->iss_hg = NULL;
1382 }
1383 }
1384 stmf_remove_id(&stmf_state.stmf_hg_list, id);
1385 }
1386 stmf_free_id(id);
1387 return (0);
1388
1389 }
1390
1391 int
1392 stmf_add_group_member(uint8_t *grpname, uint16_t grpname_size,
1393 uint8_t *entry_ident, uint16_t entry_size,
1394 stmf_id_type_t entry_type, uint32_t *err_detail)
1395 {
1396 stmf_id_data_t *id_grp, *id_alltgt;
1397 stmf_id_data_t *id_member;
1398 stmf_id_data_t *id_grp_tmp;
1399 stmf_i_scsi_session_t *iss;
1400 stmf_i_local_port_t *ilport;
1401 stmf_lun_map_t *vemap, *vemap_alltgt;
1402 uint8_t grpname_forall = '*';
1403
1404 ASSERT(mutex_owned(&stmf_state.stmf_lock));
1405 ASSERT(grpname[0] != '*');
1406
1407 if (entry_type == STMF_ID_TYPE_HOST) {
1408 id_grp = stmf_lookup_id(&stmf_state.stmf_hg_list,
1409 grpname_size, grpname);
1410 id_grp_tmp = stmf_lookup_group_for_host(entry_ident,
1411 entry_size);
1412 } else {
1413 id_grp = stmf_lookup_id(&stmf_state.stmf_tg_list,
1414 grpname_size, grpname);
1415 id_grp_tmp = stmf_lookup_group_for_target(entry_ident,
1416 entry_size);
1417 }
1418 if (id_grp == NULL) {
1419 *err_detail = (entry_type == STMF_ID_TYPE_HOST)?
1420 STMF_IOCERR_INVALID_HG:STMF_IOCERR_INVALID_TG;
1421 return (ENODEV); /* not found */
1422 }
1423
1424 /* Check whether this member already bound to a group */
1425 if (id_grp_tmp) {
1426 if (id_grp_tmp != id_grp) {
1427 *err_detail = (entry_type == STMF_ID_TYPE_HOST)?
1428 STMF_IOCERR_HG_ENTRY_EXISTS:
1429 STMF_IOCERR_TG_ENTRY_EXISTS;
1430 return (EEXIST); /* already added into another grp */
1431 }
1432 else
1433 return (0);
1434 }
1435
1436 /* verify target is offline */
1437 if (entry_type == STMF_ID_TYPE_TARGET) {
1438 ilport = stmf_targetident_to_ilport(entry_ident, entry_size);
1439 if (ilport && ilport->ilport_state != STMF_STATE_OFFLINE) {
1440 *err_detail = STMF_IOCERR_TG_NEED_TG_OFFLINE;
1441 return (EBUSY);
1442 }
1443 }
1444
1445 id_member = stmf_alloc_id(entry_size, entry_type,
1446 entry_ident, 0);
1447 stmf_append_id((stmf_id_list_t *)id_grp->id_impl_specific, id_member);
1448
1449 if (entry_type == STMF_ID_TYPE_TARGET) {
1450 ilport = stmf_targetident_to_ilport(entry_ident, entry_size);
1451 if (ilport)
1452 ilport->ilport_tg = (void *)id_grp;
1453 return (0);
1454 }
1455 /* For host group member, update the session if needed */
1456 if (!stmf_state.stmf_service_running)
1457 return (0);
1458 /* Need to consider all target group + this host group */
1459 id_alltgt = stmf_lookup_id(&stmf_state.stmf_tg_list,
1460 1, &grpname_forall);
1461 vemap_alltgt = stmf_get_ve_map_per_ids(id_alltgt, id_grp);
1462
1463 /* check whether there are sessions may be affected */
1464 for (ilport = stmf_state.stmf_ilportlist; ilport;
1465 ilport = ilport->ilport_next) {
1466 if (ilport->ilport_state != STMF_STATE_ONLINE)
1467 continue;
1468 iss = stmf_lookup_session_for_hostident(ilport,
1469 entry_ident, entry_size);
1470 if (iss) {
1471 stmf_id_data_t *tgid;
1472 iss->iss_hg = (void *)id_grp;
1473 tgid = ilport->ilport_tg;
1474 rw_enter(iss->iss_lockp, RW_WRITER);
1475 if (tgid) {
1476 vemap = stmf_get_ve_map_per_ids(tgid, id_grp);
1477 if (vemap)
1478 stmf_add_lus_to_session_per_vemap(
1479 ilport, iss, vemap);
1480 }
1481 if (vemap_alltgt)
1482 stmf_add_lus_to_session_per_vemap(ilport,
1483 iss, vemap_alltgt);
1484 rw_exit(iss->iss_lockp);
1485 }
1486 }
1487
1488 return (0);
1489 }
1490
1491 int
1492 stmf_remove_group_member(uint8_t *grpname, uint16_t grpname_size,
1493 uint8_t *entry_ident, uint16_t entry_size,
1494 stmf_id_type_t entry_type, uint32_t *err_detail)
1495 {
1496 stmf_id_data_t *id_grp, *id_alltgt;
1497 stmf_id_data_t *id_member;
1498 stmf_lun_map_t *vemap, *vemap_alltgt;
1499 uint8_t grpname_forall = '*';
1500 stmf_i_local_port_t *ilport;
1501 stmf_i_scsi_session_t *iss;
1502
1503 ASSERT(mutex_owned(&stmf_state.stmf_lock));
1504 ASSERT(grpname[0] != '*');
1505
1506 if (entry_type == STMF_ID_TYPE_HOST) {
1507 id_grp = stmf_lookup_id(&stmf_state.stmf_hg_list,
1508 grpname_size, grpname);
1509 } else {
1510 id_grp = stmf_lookup_id(&stmf_state.stmf_tg_list,
1511 grpname_size, grpname);
1512 }
1513 if (id_grp == NULL) {
1514 *err_detail = (entry_type == STMF_ID_TYPE_HOST)?
1515 STMF_IOCERR_INVALID_HG:STMF_IOCERR_INVALID_TG;
1516 return (ENODEV); /* no such group */
1517 }
1518 id_member = stmf_lookup_id((stmf_id_list_t *)id_grp->id_impl_specific,
1519 entry_size, entry_ident);
1520 if (!id_member) {
1521 *err_detail = (entry_type == STMF_ID_TYPE_HOST)?
1522 STMF_IOCERR_INVALID_HG_ENTRY:STMF_IOCERR_INVALID_TG_ENTRY;
1523 return (ENODEV); /* no such member */
1524 }
1525 /* verify target is offline */
1526 if (entry_type == STMF_ID_TYPE_TARGET) {
1527 ilport = stmf_targetident_to_ilport(entry_ident, entry_size);
1528 if (ilport && ilport->ilport_state != STMF_STATE_OFFLINE) {
1529 *err_detail = STMF_IOCERR_TG_NEED_TG_OFFLINE;
1530 return (EBUSY);
1531 }
1532 }
1533
1534 stmf_remove_id((stmf_id_list_t *)id_grp->id_impl_specific, id_member);
1535 stmf_free_id(id_member);
1536
1537 if (entry_type == STMF_ID_TYPE_TARGET) {
1538 ilport = stmf_targetident_to_ilport(entry_ident, entry_size);
1539 if (ilport)
1540 ilport->ilport_tg = NULL;
1541 return (0);
1542 }
1543 /* For host group member, update the session */
1544 if (!stmf_state.stmf_service_running)
1545 return (0);
1546
1547 /* Need to consider all target group + this host group */
1548 id_alltgt = stmf_lookup_id(&stmf_state.stmf_tg_list,
1549 1, &grpname_forall);
1550 vemap_alltgt = stmf_get_ve_map_per_ids(id_alltgt, id_grp);
1551
1552 /* check if there are session related, if so, update it */
1553 for (ilport = stmf_state.stmf_ilportlist; ilport;
1554 ilport = ilport->ilport_next) {
1555 if (ilport->ilport_state != STMF_STATE_ONLINE)
1556 continue;
1557 iss = stmf_lookup_session_for_hostident(ilport,
1558 entry_ident, entry_size);
1559 if (iss) {
1560 stmf_id_data_t *tgid;
1561 rw_enter(iss->iss_lockp, RW_WRITER);
1562 iss->iss_hg = NULL;
1563 tgid = ilport->ilport_tg;
1564 if (tgid) {
1565 vemap = stmf_get_ve_map_per_ids(tgid, id_grp);
1566 if (vemap)
1567 stmf_remove_lus_from_session_per_vemap(
1568 iss, vemap);
1569 }
1570 if (vemap_alltgt)
1571 stmf_remove_lus_from_session_per_vemap(iss,
1572 vemap_alltgt);
1573 rw_exit(iss->iss_lockp);
1574 }
1575 }
1576
1577 return (0);
1578 }
1579
1580 /* Assert stmf_lock is already held */
1581 stmf_i_local_port_t *
1582 stmf_targetident_to_ilport(uint8_t *target_ident, uint16_t ident_size)
1583 {
1584 stmf_i_local_port_t *ilport;
1585 uint8_t *id;
1586
1587 ASSERT(mutex_owned(&stmf_state.stmf_lock));
1588
1589 for (ilport = stmf_state.stmf_ilportlist; ilport;
1590 ilport = ilport->ilport_next) {
1591 id = (uint8_t *)ilport->ilport_lport->lport_id;
1592 if ((id[3] == ident_size) &&
1593 bcmp(id + 4, target_ident, ident_size) == 0) {
1594 return (ilport);
1595 }
1596 }
1597 return (NULL);
1598 }
1599
1600 stmf_i_scsi_session_t *
1601 stmf_lookup_session_for_hostident(stmf_i_local_port_t *ilport,
1602 uint8_t *host_ident, uint16_t ident_size)
1603 {
1604 stmf_i_scsi_session_t *iss;
1605 uint8_t *id;
1606
1607 ASSERT(mutex_owned(&stmf_state.stmf_lock));
1608
1609 for (iss = ilport->ilport_ss_list; iss; iss = iss->iss_next) {
1610 id = (uint8_t *)iss->iss_ss->ss_rport_id;
1611 if ((id[3] == ident_size) &&
1612 bcmp(id + 4, host_ident, ident_size) == 0) {
1613 return (iss);
1614 }
1615 }
1616 return (NULL);
1617 }
1618
1619 stmf_i_lu_t *
1620 stmf_luident_to_ilu(uint8_t *lu_ident)
1621 {
1622 stmf_i_lu_t *ilu;
1623
1624 ASSERT(mutex_owned(&stmf_state.stmf_lock));
1625
1626 for (ilu = stmf_state.stmf_ilulist; ilu; ilu = ilu->ilu_next) {
1627 if (bcmp(&ilu->ilu_lu->lu_id->ident[0], lu_ident, 16) == 0)
1628 return (ilu);
1629 }
1630
1631 return (NULL);
1632 }
1633
1634 /*
1635 * Assert stmf_lock is already held,
1636 * Just get the view map for the specific target group and host group
1637 * tgid and hgid can not be NULL
1638 */
1639 stmf_lun_map_t *
1640 stmf_get_ve_map_per_ids(stmf_id_data_t *tgid, stmf_id_data_t *hgid)
1641 {
1642 int found = 0;
1643 stmf_ver_tg_t *vertg;
1644 stmf_ver_hg_t *verhg;
1645
1646 ASSERT(mutex_owned(&stmf_state.stmf_lock));
1647
1648 for (vertg = stmf_state.stmf_ver_tg_head;
1649 vertg; vertg = vertg->vert_next) {
1650 if (vertg->vert_tg_ref == tgid) {
1651 found = 1;
1652 break;
1653 }
1654 }
1655 if (!found)
1656 return (NULL);
1657
1658 for (verhg = vertg->vert_verh_list; verhg; verhg = verhg->verh_next) {
1659 if (verhg->verh_hg_ref == hgid) {
1660 return (&verhg->verh_ve_map);
1661 }
1662 }
1663 return (NULL);
1664 }
1665
1666 stmf_status_t
1667 stmf_validate_lun_view_entry(stmf_id_data_t *hg, stmf_id_data_t *tg,
1668 uint8_t *lun, uint32_t *err_detail)
1669 {
1670 char *phg, *ptg;
1671 stmf_lun_map_t *ve_map = NULL;
1672 stmf_ver_hg_t *verhg = NULL;
1673 stmf_ver_tg_t *vertg = NULL;
1674 uint16_t lun_num;
1675 stmf_status_t ret = STMF_SUCCESS;
1676
1677 ASSERT(mutex_owned(&stmf_state.stmf_lock));
1678
1679 ve_map = stmf_duplicate_ve_map(0);
1680 for (vertg = stmf_state.stmf_ver_tg_head; vertg != NULL;
1681 vertg = vertg->vert_next) {
1682 ptg = (char *)vertg->vert_tg_ref->id_data;
1683 if ((ptg[0] != '*') && (tg->id_data[0] != '*') &&
1684 (vertg->vert_tg_ref != tg)) {
1685 continue;
1686 }
1687 for (verhg = vertg->vert_verh_list; verhg != NULL;
1688 verhg = verhg->verh_next) {
1689 phg = (char *)verhg->verh_hg_ref->id_data;
1690 if ((phg[0] != '*') && (hg->id_data[0] != '*') &&
1691 (verhg->verh_hg_ref != hg)) {
1692 continue;
1693 }
1694 (void) stmf_merge_ve_map(&verhg->verh_ve_map, ve_map,
1695 &ve_map, 0);
1696 }
1697 }
1698
1699 ret = STMF_SUCCESS;
1700 /* Return an available lun number */
1701 if (lun[2] == 0xFF) {
1702 /* Pick a LUN number */
1703 lun_num = stmf_get_next_free_lun(ve_map, lun);
1704 if (lun_num > 0x3FFF)
1705 ret = STMF_NOT_SUPPORTED;
1706 } else {
1707 lun_num = (uint16_t)lun[1] | (((uint16_t)(lun[0] & 0x3F)) << 8);
1708 if (stmf_get_ent_from_map(ve_map, lun_num) != NULL) {
1709 *err_detail = STMF_IOCERR_LU_NUMBER_IN_USE;
1710 ret = STMF_LUN_TAKEN;
1711 }
1712 }
1713 stmf_destroy_ve_map(ve_map);
1714
1715 return (ret);
1716 }
1717
1718 int
1719 stmf_validate_lun_ve(uint8_t *hgname, uint16_t hgname_size,
1720 uint8_t *tgname, uint16_t tgname_size,
1721 uint8_t *luNbr, uint32_t *err_detail)
1722 {
1723 stmf_id_data_t *hg;
1724 stmf_id_data_t *tg;
1725 stmf_status_t ret;
1726
1727 ASSERT(mutex_owned(&stmf_state.stmf_lock));
1728
1729 hg = stmf_lookup_id(&stmf_state.stmf_hg_list, hgname_size,
1730 (uint8_t *)hgname);
1731 if (!hg) {
1732 *err_detail = STMF_IOCERR_INVALID_HG;
1733 return (ENOENT); /* could not find group */
1734 }
1735 tg = stmf_lookup_id(&stmf_state.stmf_tg_list, tgname_size,
1736 (uint8_t *)tgname);
1737 if (!tg) {
1738 *err_detail = STMF_IOCERR_INVALID_TG;
1739 return (ENOENT); /* could not find group */
1740 }
1741 ret = stmf_validate_lun_view_entry(hg, tg, luNbr, err_detail);
1742
1743 if (ret == STMF_LUN_TAKEN) {
1744 return (EEXIST);
1745 } else if (ret == STMF_NOT_SUPPORTED) {
1746 return (E2BIG);
1747 } else if (ret != STMF_SUCCESS) {
1748 return (EINVAL);
1749 }
1750 return (0);
1751 }