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 * Copyright 2012, Nexenta Systems, Inc. All rights reserved.
26 */
27
28 #include <sys/conf.h>
29 #include <sys/file.h>
30 #include <sys/ddi.h>
31 #include <sys/sunddi.h>
32 #include <sys/modctl.h>
33 #include <sys/scsi/scsi.h>
34 #include <sys/scsi/generic/persist.h>
35 #include <sys/scsi/impl/scsi_reset_notify.h>
36 #include <sys/disp.h>
37 #include <sys/byteorder.h>
38 #include <sys/atomic.h>
39 #include <sys/ethernet.h>
40 #include <sys/sdt.h>
41 #include <sys/nvpair.h>
42 #include <sys/zone.h>
43 #include <sys/id_space.h>
44
45 #include <sys/stmf.h>
46 #include <sys/lpif.h>
47 #include <sys/portif.h>
48 #include <sys/stmf_ioctl.h>
49 #include <sys/pppt_ic_if.h>
50
51 #include "stmf_impl.h"
52 #include "lun_map.h"
53 #include "stmf_state.h"
54 #include "stmf_stats.h"
55
56 /*
57 * Lock order:
58 * stmf_state_lock --> ilport_lock/iss_lockp --> ilu_task_lock
59 */
60
61 static uint64_t stmf_session_counter = 0;
62 static uint16_t stmf_rtpid_counter = 0;
63 /* start messages at 1 */
64 static uint64_t stmf_proxy_msg_id = 1;
65 #define MSG_ID_TM_BIT 0x8000000000000000
66 #define ALIGNED_TO_8BYTE_BOUNDARY(i) (((i) + 7) & ~7)
67
68 struct stmf_svc_clocks;
69
70 static int stmf_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
71 static int stmf_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
72 static int stmf_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
73 void **result);
74 static int stmf_open(dev_t *devp, int flag, int otype, cred_t *credp);
75 static int stmf_close(dev_t dev, int flag, int otype, cred_t *credp);
76 static int stmf_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
77 cred_t *credp, int *rval);
78 static int stmf_get_stmf_state(stmf_state_desc_t *std);
79 static int stmf_set_stmf_state(stmf_state_desc_t *std);
80 static void stmf_abort_task_offline(scsi_task_t *task, int offline_lu,
81 char *info);
82 static int stmf_set_alua_state(stmf_alua_state_desc_t *alua_state);
83 static void stmf_get_alua_state(stmf_alua_state_desc_t *alua_state);
84
85 static void stmf_task_audit(stmf_i_scsi_task_t *itask,
86 task_audit_event_t te, uint32_t cmd_or_iof, stmf_data_buf_t *dbuf);
87
88 static boolean_t stmf_base16_str_to_binary(char *c, int dplen, uint8_t *dp);
89 static char stmf_ctoi(char c);
90 stmf_xfer_data_t *stmf_prepare_tpgs_data(uint8_t ilu_alua);
91 void stmf_svc_init();
92 stmf_status_t stmf_svc_fini();
93 void stmf_svc(void *arg);
94 void stmf_svc_queue(int cmd, void *obj, stmf_state_change_info_t *info);
95 static void stmf_svc_kill_obj_requests(void *obj);
96 static void stmf_svc_timeout(struct stmf_svc_clocks *);
97 void stmf_check_freetask();
98 void stmf_abort_target_reset(scsi_task_t *task);
99 stmf_status_t stmf_lun_reset_poll(stmf_lu_t *lu, struct scsi_task *task,
100 int target_reset);
101 void stmf_target_reset_poll(struct scsi_task *task);
102 void stmf_handle_lun_reset(scsi_task_t *task);
103 void stmf_handle_target_reset(scsi_task_t *task);
104 void stmf_xd_to_dbuf(stmf_data_buf_t *dbuf, int set_rel_off);
105 int stmf_load_ppd_ioctl(stmf_ppioctl_data_t *ppi, uint64_t *ppi_token,
106 uint32_t *err_ret);
107 int stmf_delete_ppd_ioctl(stmf_ppioctl_data_t *ppi);
108 int stmf_get_ppd_ioctl(stmf_ppioctl_data_t *ppi, stmf_ppioctl_data_t *ppi_out,
109 uint32_t *err_ret);
110 void stmf_delete_ppd(stmf_pp_data_t *ppd);
111 void stmf_delete_all_ppds();
112 void stmf_trace_clear();
113 void stmf_worker_init();
114 stmf_status_t stmf_worker_fini();
115 void stmf_worker_mgmt();
116 void stmf_worker_task(void *arg);
117 static void stmf_task_lu_free(scsi_task_t *task, stmf_i_scsi_session_t *iss);
118 static stmf_status_t stmf_ic_lu_reg(stmf_ic_reg_dereg_lun_msg_t *msg,
119 uint32_t type);
120 static stmf_status_t stmf_ic_lu_dereg(stmf_ic_reg_dereg_lun_msg_t *msg);
121 static stmf_status_t stmf_ic_rx_scsi_status(stmf_ic_scsi_status_msg_t *msg);
122 static stmf_status_t stmf_ic_rx_status(stmf_ic_status_msg_t *msg);
123 static stmf_status_t stmf_ic_rx_scsi_data(stmf_ic_scsi_data_msg_t *msg);
124 void stmf_task_lu_killall(stmf_lu_t *lu, scsi_task_t *tm_task, stmf_status_t s);
125
126 /* pppt modhandle */
127 ddi_modhandle_t pppt_mod;
128
129 /* pppt modload imported functions */
130 stmf_ic_reg_port_msg_alloc_func_t ic_reg_port_msg_alloc;
131 stmf_ic_dereg_port_msg_alloc_func_t ic_dereg_port_msg_alloc;
132 stmf_ic_reg_lun_msg_alloc_func_t ic_reg_lun_msg_alloc;
133 stmf_ic_dereg_lun_msg_alloc_func_t ic_dereg_lun_msg_alloc;
134 stmf_ic_lun_active_msg_alloc_func_t ic_lun_active_msg_alloc;
135 stmf_ic_scsi_cmd_msg_alloc_func_t ic_scsi_cmd_msg_alloc;
136 stmf_ic_scsi_data_xfer_done_msg_alloc_func_t ic_scsi_data_xfer_done_msg_alloc;
137 stmf_ic_session_create_msg_alloc_func_t ic_session_reg_msg_alloc;
138 stmf_ic_session_destroy_msg_alloc_func_t ic_session_dereg_msg_alloc;
139 stmf_ic_tx_msg_func_t ic_tx_msg;
140 stmf_ic_msg_free_func_t ic_msg_free;
141
142 static void stmf_itl_task_start(stmf_i_scsi_task_t *itask);
143 static void stmf_itl_lu_new_task(stmf_i_scsi_task_t *itask);
144 static void stmf_itl_task_done(stmf_i_scsi_task_t *itask);
145
146 static void stmf_lport_xfer_start(stmf_i_scsi_task_t *itask,
147 stmf_data_buf_t *dbuf);
148 static void stmf_lport_xfer_done(stmf_i_scsi_task_t *itask,
149 stmf_data_buf_t *dbuf);
150
151 static void stmf_update_kstat_lu_q(scsi_task_t *, void());
152 static void stmf_update_kstat_lport_q(scsi_task_t *, void());
153 static void stmf_update_kstat_lu_io(scsi_task_t *, stmf_data_buf_t *);
154 static void stmf_update_kstat_lport_io(scsi_task_t *, stmf_data_buf_t *);
155
156 static int stmf_irport_compare(const void *void_irport1,
157 const void *void_irport2);
158 static stmf_i_remote_port_t *stmf_irport_create(scsi_devid_desc_t *rport_devid);
159 static void stmf_irport_destroy(stmf_i_remote_port_t *irport);
160 static stmf_i_remote_port_t *stmf_irport_register(
161 scsi_devid_desc_t *rport_devid);
162 static stmf_i_remote_port_t *stmf_irport_lookup_locked(
163 scsi_devid_desc_t *rport_devid);
164 static void stmf_irport_deregister(stmf_i_remote_port_t *irport);
165
166 static void stmf_teardown_itl_kstats(stmf_i_itl_kstat_t *ks);
167 static void stmf_delete_itl_kstat_by_lport(char *);
168 static void stmf_delete_itl_kstat_by_guid(char *);
169 static int stmf_itl_kstat_compare(const void*, const void*);
170 static stmf_i_itl_kstat_t *stmf_itl_kstat_lookup(char *kstat_nm);
171 static stmf_i_itl_kstat_t *stmf_itl_kstat_create(stmf_itl_data_t *itl,
172 char *nm, scsi_devid_desc_t *lport, scsi_devid_desc_t *lun);
173
174 extern struct mod_ops mod_driverops;
175
176 /* =====[ Tunables ]===== */
177 /* Internal tracing */
178 volatile int stmf_trace_on = 1;
179 volatile int stmf_trace_buf_size = (1 * 1024 * 1024);
180 /*
181 * The reason default task timeout is 75 is because we want the
182 * host to timeout 1st and mostly host timeout is 60 seconds.
183 */
184 volatile int stmf_default_task_timeout = 75;
185 /*
186 * Setting this to one means, you are responsible for config load and keeping
187 * things in sync with persistent database.
188 */
189 volatile int stmf_allow_modunload = 0;
190
191 volatile int stmf_max_nworkers = 256;
192 volatile int stmf_min_nworkers = 4;
193 volatile int stmf_worker_scale_down_delay = 20;
194
195 /* === [ Debugging and fault injection ] === */
196 #ifdef DEBUG
197 volatile int stmf_drop_task_counter = 0;
198 volatile int stmf_drop_buf_counter = 0;
199
200 #endif
201
202 stmf_state_t stmf_state;
203 static stmf_lu_t *dlun0;
204
205 static uint8_t stmf_first_zero[] =
206 { 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 0xff };
207 static uint8_t stmf_first_one[] =
208 { 0xff, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 };
209
210 static kmutex_t trace_buf_lock;
211 static int trace_buf_size;
212 static int trace_buf_curndx;
213 caddr_t stmf_trace_buf;
214
215 static enum {
216 STMF_WORKERS_DISABLED = 0,
217 STMF_WORKERS_ENABLING,
218 STMF_WORKERS_ENABLED
219 } stmf_workers_state = STMF_WORKERS_DISABLED;
220 static int stmf_i_max_nworkers;
221 static int stmf_i_min_nworkers;
222 static int stmf_nworkers_cur; /* # of workers currently running */
223 static int stmf_nworkers_needed; /* # of workers need to be running */
224 static int stmf_worker_sel_counter = 0;
225 static uint32_t stmf_cur_ntasks = 0;
226 static clock_t stmf_wm_last = 0;
227 /*
228 * This is equal to stmf_nworkers_cur while we are increasing # workers and
229 * stmf_nworkers_needed while we are decreasing the worker count.
230 */
231 static int stmf_nworkers_accepting_cmds;
232 static stmf_worker_t *stmf_workers = NULL;
233 static clock_t stmf_worker_mgmt_delay = 2;
234 static clock_t stmf_worker_scale_down_timer = 0;
235 static int stmf_worker_scale_down_qd = 0;
236
237 static struct cb_ops stmf_cb_ops = {
238 stmf_open, /* open */
239 stmf_close, /* close */
240 nodev, /* strategy */
241 nodev, /* print */
242 nodev, /* dump */
243 nodev, /* read */
244 nodev, /* write */
245 stmf_ioctl, /* ioctl */
246 nodev, /* devmap */
247 nodev, /* mmap */
248 nodev, /* segmap */
249 nochpoll, /* chpoll */
250 ddi_prop_op, /* cb_prop_op */
251 0, /* streamtab */
252 D_NEW | D_MP, /* cb_flag */
253 CB_REV, /* rev */
254 nodev, /* aread */
255 nodev /* awrite */
256 };
257
258 static struct dev_ops stmf_ops = {
259 DEVO_REV,
260 0,
261 stmf_getinfo,
262 nulldev, /* identify */
263 nulldev, /* probe */
264 stmf_attach,
265 stmf_detach,
266 nodev, /* reset */
267 &stmf_cb_ops,
268 NULL, /* bus_ops */
269 NULL /* power */
270 };
271
272 #define STMF_NAME "COMSTAR STMF"
273 #define STMF_MODULE_NAME "stmf"
274
275 static struct modldrv modldrv = {
276 &mod_driverops,
277 STMF_NAME,
278 &stmf_ops
279 };
280
281 static struct modlinkage modlinkage = {
282 MODREV_1,
283 &modldrv,
284 NULL
285 };
286
287 int
288 _init(void)
289 {
290 int ret;
291
292 ret = mod_install(&modlinkage);
293 if (ret)
294 return (ret);
295 stmf_trace_buf = kmem_zalloc(stmf_trace_buf_size, KM_SLEEP);
296 trace_buf_size = stmf_trace_buf_size;
297 trace_buf_curndx = 0;
298 mutex_init(&trace_buf_lock, NULL, MUTEX_DRIVER, 0);
299 bzero(&stmf_state, sizeof (stmf_state_t));
300 /* STMF service is off by default */
301 stmf_state.stmf_service_running = 0;
302 /* default lu/lport states are online */
303 stmf_state.stmf_default_lu_state = STMF_STATE_ONLINE;
304 stmf_state.stmf_default_lport_state = STMF_STATE_ONLINE;
305 mutex_init(&stmf_state.stmf_lock, NULL, MUTEX_DRIVER, NULL);
306 cv_init(&stmf_state.stmf_cv, NULL, CV_DRIVER, NULL);
307 stmf_session_counter = (uint64_t)ddi_get_lbolt();
308 avl_create(&stmf_state.stmf_irportlist,
309 stmf_irport_compare, sizeof (stmf_i_remote_port_t),
310 offsetof(stmf_i_remote_port_t, irport_ln));
311 stmf_state.stmf_ilport_inst_space =
312 id_space_create("lport-instances", 0, MAX_ILPORT);
313 stmf_state.stmf_irport_inst_space =
314 id_space_create("rport-instances", 0, MAX_IRPORT);
315 avl_create(&stmf_state.stmf_itl_kstat_list,
316 stmf_itl_kstat_compare, sizeof (stmf_i_itl_kstat_t),
317 offsetof(stmf_i_itl_kstat_t, iitl_kstat_ln));
318 stmf_view_init();
319 stmf_svc_init();
320 stmf_dlun_init();
321 return (ret);
322 }
323
324 int
325 _fini(void)
326 {
327 int ret;
328 stmf_i_remote_port_t *irport;
329 stmf_i_itl_kstat_t *ks_itl;
330 void *avl_dest_cookie = NULL;
331
332 if (stmf_state.stmf_service_running)
333 return (EBUSY);
334 if ((!stmf_allow_modunload) &&
335 (stmf_state.stmf_config_state != STMF_CONFIG_NONE)) {
336 return (EBUSY);
337 }
338 if (stmf_state.stmf_nlps || stmf_state.stmf_npps) {
339 return (EBUSY);
340 }
341 if (stmf_dlun_fini() != STMF_SUCCESS)
342 return (EBUSY);
343 if (stmf_worker_fini() != STMF_SUCCESS) {
344 stmf_dlun_init();
345 return (EBUSY);
346 }
347 if (stmf_svc_fini() != STMF_SUCCESS) {
348 stmf_dlun_init();
349 stmf_worker_init();
350 return (EBUSY);
351 }
352
353 ret = mod_remove(&modlinkage);
354 if (ret) {
355 stmf_svc_init();
356 stmf_dlun_init();
357 stmf_worker_init();
358 return (ret);
359 }
360
361 stmf_view_clear_config();
362
363 while ((irport = avl_destroy_nodes(&stmf_state.stmf_irportlist,
364 &avl_dest_cookie)) != NULL)
365 stmf_irport_destroy(irport);
366 avl_destroy(&stmf_state.stmf_irportlist);
367 id_space_destroy(stmf_state.stmf_ilport_inst_space);
368 id_space_destroy(stmf_state.stmf_irport_inst_space);
369
370 avl_dest_cookie = NULL;
371 while ((ks_itl = avl_destroy_nodes(&stmf_state.stmf_itl_kstat_list,
372 &avl_dest_cookie)) != NULL) {
373 stmf_teardown_itl_kstats(ks_itl);
374 kmem_free(ks_itl, sizeof (ks_itl));
375 }
376 avl_destroy(&stmf_state.stmf_itl_kstat_list);
377
378 kmem_free(stmf_trace_buf, stmf_trace_buf_size);
379 mutex_destroy(&trace_buf_lock);
380 mutex_destroy(&stmf_state.stmf_lock);
381 cv_destroy(&stmf_state.stmf_cv);
382 return (ret);
383 }
384
385 int
386 _info(struct modinfo *modinfop)
387 {
388 return (mod_info(&modlinkage, modinfop));
389 }
390
391 /* ARGSUSED */
392 static int
393 stmf_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
394 {
395 switch (cmd) {
396 case DDI_INFO_DEVT2DEVINFO:
397 *result = stmf_state.stmf_dip;
398 break;
399 case DDI_INFO_DEVT2INSTANCE:
400 *result =
401 (void *)(uintptr_t)ddi_get_instance(stmf_state.stmf_dip);
402 break;
403 default:
404 return (DDI_FAILURE);
405 }
406
407 return (DDI_SUCCESS);
408 }
409
410 static int
411 stmf_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
412 {
413 switch (cmd) {
414 case DDI_ATTACH:
415 stmf_state.stmf_dip = dip;
416
417 if (ddi_create_minor_node(dip, "admin", S_IFCHR, 0,
418 DDI_NT_STMF, 0) != DDI_SUCCESS) {
419 break;
420 }
421 ddi_report_dev(dip);
422 return (DDI_SUCCESS);
423 }
424
425 return (DDI_FAILURE);
426 }
427
428 static int
429 stmf_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
430 {
431 switch (cmd) {
432 case DDI_DETACH:
433 ddi_remove_minor_node(dip, 0);
434 return (DDI_SUCCESS);
435 }
436
437 return (DDI_FAILURE);
438 }
439
440 /* ARGSUSED */
441 static int
442 stmf_open(dev_t *devp, int flag, int otype, cred_t *credp)
443 {
444 mutex_enter(&stmf_state.stmf_lock);
445 if (stmf_state.stmf_exclusive_open) {
446 mutex_exit(&stmf_state.stmf_lock);
447 return (EBUSY);
448 }
449 if (flag & FEXCL) {
450 if (stmf_state.stmf_opened) {
451 mutex_exit(&stmf_state.stmf_lock);
452 return (EBUSY);
453 }
454 stmf_state.stmf_exclusive_open = 1;
455 }
456 stmf_state.stmf_opened = 1;
457 mutex_exit(&stmf_state.stmf_lock);
458 return (0);
459 }
460
461 /* ARGSUSED */
462 static int
463 stmf_close(dev_t dev, int flag, int otype, cred_t *credp)
464 {
465 mutex_enter(&stmf_state.stmf_lock);
466 stmf_state.stmf_opened = 0;
467 if (stmf_state.stmf_exclusive_open &&
468 (stmf_state.stmf_config_state != STMF_CONFIG_INIT_DONE)) {
469 stmf_state.stmf_config_state = STMF_CONFIG_NONE;
470 stmf_delete_all_ppds();
471 stmf_view_clear_config();
472 stmf_view_init();
473 }
474 stmf_state.stmf_exclusive_open = 0;
475 mutex_exit(&stmf_state.stmf_lock);
476 return (0);
477 }
478
479 int
480 stmf_copyin_iocdata(intptr_t data, int mode, stmf_iocdata_t **iocd,
481 void **ibuf, void **obuf)
482 {
483 int ret;
484
485 *ibuf = NULL;
486 *obuf = NULL;
487 *iocd = kmem_zalloc(sizeof (stmf_iocdata_t), KM_SLEEP);
488
489 ret = ddi_copyin((void *)data, *iocd, sizeof (stmf_iocdata_t), mode);
490 if (ret)
491 return (EFAULT);
492 if ((*iocd)->stmf_version != STMF_VERSION_1) {
493 ret = EINVAL;
494 goto copyin_iocdata_done;
495 }
496 if ((*iocd)->stmf_ibuf_size) {
497 *ibuf = kmem_zalloc((*iocd)->stmf_ibuf_size, KM_SLEEP);
498 ret = ddi_copyin((void *)((unsigned long)(*iocd)->stmf_ibuf),
499 *ibuf, (*iocd)->stmf_ibuf_size, mode);
500 }
501 if ((*iocd)->stmf_obuf_size)
502 *obuf = kmem_zalloc((*iocd)->stmf_obuf_size, KM_SLEEP);
503
504 if (ret == 0)
505 return (0);
506 ret = EFAULT;
507 copyin_iocdata_done:;
508 if (*obuf) {
509 kmem_free(*obuf, (*iocd)->stmf_obuf_size);
510 *obuf = NULL;
511 }
512 if (*ibuf) {
513 kmem_free(*ibuf, (*iocd)->stmf_ibuf_size);
514 *ibuf = NULL;
515 }
516 kmem_free(*iocd, sizeof (stmf_iocdata_t));
517 return (ret);
518 }
519
520 int
521 stmf_copyout_iocdata(intptr_t data, int mode, stmf_iocdata_t *iocd, void *obuf)
522 {
523 int ret;
524
525 if (iocd->stmf_obuf_size) {
526 ret = ddi_copyout(obuf, (void *)(unsigned long)iocd->stmf_obuf,
527 iocd->stmf_obuf_size, mode);
528 if (ret)
529 return (EFAULT);
530 }
531 ret = ddi_copyout(iocd, (void *)data, sizeof (stmf_iocdata_t), mode);
532 if (ret)
533 return (EFAULT);
534 return (0);
535 }
536
537 /* ARGSUSED */
538 static int
539 stmf_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
540 cred_t *credp, int *rval)
541 {
542 stmf_iocdata_t *iocd;
543 void *ibuf = NULL, *obuf = NULL;
544 slist_lu_t *luid_list;
545 slist_target_port_t *lportid_list;
546 stmf_i_lu_t *ilu;
547 stmf_i_local_port_t *ilport;
548 stmf_i_scsi_session_t *iss;
549 slist_scsi_session_t *iss_list;
550 sioc_lu_props_t *lup;
551 sioc_target_port_props_t *lportp;
552 stmf_ppioctl_data_t *ppi, *ppi_out = NULL;
553 uint64_t *ppi_token = NULL;
554 uint8_t *p_id, *id;
555 stmf_state_desc_t *std;
556 stmf_status_t ctl_ret;
557 stmf_state_change_info_t ssi;
558 int ret = 0;
559 uint32_t n;
560 int i;
561 stmf_group_op_data_t *grp_entry;
562 stmf_group_name_t *grpname;
563 stmf_view_op_entry_t *ve;
564 stmf_id_type_t idtype;
565 stmf_id_data_t *id_entry;
566 stmf_id_list_t *id_list;
567 stmf_view_entry_t *view_entry;
568 stmf_set_props_t *stmf_set_props;
569 uint32_t veid;
570 if ((cmd & 0xff000000) != STMF_IOCTL) {
571 return (ENOTTY);
572 }
573
574 if (drv_priv(credp) != 0) {
575 return (EPERM);
576 }
577
578 ret = stmf_copyin_iocdata(data, mode, &iocd, &ibuf, &obuf);
579 if (ret)
580 return (ret);
581 iocd->stmf_error = 0;
582
583 switch (cmd) {
584 case STMF_IOCTL_LU_LIST:
585 /* retrieves both registered/unregistered */
586 mutex_enter(&stmf_state.stmf_lock);
587 id_list = &stmf_state.stmf_luid_list;
588 n = min(id_list->id_count,
589 (iocd->stmf_obuf_size)/sizeof (slist_lu_t));
590 iocd->stmf_obuf_max_nentries = id_list->id_count;
591 luid_list = (slist_lu_t *)obuf;
592 id_entry = id_list->idl_head;
593 for (i = 0; i < n; i++) {
594 bcopy(id_entry->id_data, luid_list[i].lu_guid, 16);
595 id_entry = id_entry->id_next;
596 }
597
598 n = iocd->stmf_obuf_size/sizeof (slist_lu_t);
599 for (ilu = stmf_state.stmf_ilulist; ilu; ilu = ilu->ilu_next) {
600 id = (uint8_t *)ilu->ilu_lu->lu_id;
601 if (stmf_lookup_id(id_list, 16, id + 4) == NULL) {
602 iocd->stmf_obuf_max_nentries++;
603 if (i < n) {
604 bcopy(id + 4, luid_list[i].lu_guid,
605 sizeof (slist_lu_t));
606 i++;
607 }
608 }
609 }
610 iocd->stmf_obuf_nentries = i;
611 mutex_exit(&stmf_state.stmf_lock);
612 break;
613
614 case STMF_IOCTL_REG_LU_LIST:
615 mutex_enter(&stmf_state.stmf_lock);
616 iocd->stmf_obuf_max_nentries = stmf_state.stmf_nlus;
617 n = min(stmf_state.stmf_nlus,
618 (iocd->stmf_obuf_size)/sizeof (slist_lu_t));
619 iocd->stmf_obuf_nentries = n;
620 ilu = stmf_state.stmf_ilulist;
621 luid_list = (slist_lu_t *)obuf;
622 for (i = 0; i < n; i++) {
623 uint8_t *id;
624 id = (uint8_t *)ilu->ilu_lu->lu_id;
625 bcopy(id + 4, luid_list[i].lu_guid, 16);
626 ilu = ilu->ilu_next;
627 }
628 mutex_exit(&stmf_state.stmf_lock);
629 break;
630
631 case STMF_IOCTL_VE_LU_LIST:
632 mutex_enter(&stmf_state.stmf_lock);
633 id_list = &stmf_state.stmf_luid_list;
634 n = min(id_list->id_count,
635 (iocd->stmf_obuf_size)/sizeof (slist_lu_t));
636 iocd->stmf_obuf_max_nentries = id_list->id_count;
637 iocd->stmf_obuf_nentries = n;
638 luid_list = (slist_lu_t *)obuf;
639 id_entry = id_list->idl_head;
640 for (i = 0; i < n; i++) {
641 bcopy(id_entry->id_data, luid_list[i].lu_guid, 16);
642 id_entry = id_entry->id_next;
643 }
644 mutex_exit(&stmf_state.stmf_lock);
645 break;
646
647 case STMF_IOCTL_TARGET_PORT_LIST:
648 mutex_enter(&stmf_state.stmf_lock);
649 iocd->stmf_obuf_max_nentries = stmf_state.stmf_nlports;
650 n = min(stmf_state.stmf_nlports,
651 (iocd->stmf_obuf_size)/sizeof (slist_target_port_t));
652 iocd->stmf_obuf_nentries = n;
653 ilport = stmf_state.stmf_ilportlist;
654 lportid_list = (slist_target_port_t *)obuf;
655 for (i = 0; i < n; i++) {
656 uint8_t *id;
657 id = (uint8_t *)ilport->ilport_lport->lport_id;
658 bcopy(id, lportid_list[i].target, id[3] + 4);
659 ilport = ilport->ilport_next;
660 }
661 mutex_exit(&stmf_state.stmf_lock);
662 break;
663
664 case STMF_IOCTL_SESSION_LIST:
665 p_id = (uint8_t *)ibuf;
666 if ((p_id == NULL) || (iocd->stmf_ibuf_size < 4) ||
667 (iocd->stmf_ibuf_size < (p_id[3] + 4))) {
668 ret = EINVAL;
669 break;
670 }
671 mutex_enter(&stmf_state.stmf_lock);
672 for (ilport = stmf_state.stmf_ilportlist; ilport; ilport =
673 ilport->ilport_next) {
674 uint8_t *id;
675 id = (uint8_t *)ilport->ilport_lport->lport_id;
676 if ((p_id[3] == id[3]) &&
677 (bcmp(p_id + 4, id + 4, id[3]) == 0)) {
678 break;
679 }
680 }
681 if (ilport == NULL) {
682 mutex_exit(&stmf_state.stmf_lock);
683 ret = ENOENT;
684 break;
685 }
686 iocd->stmf_obuf_max_nentries = ilport->ilport_nsessions;
687 n = min(ilport->ilport_nsessions,
688 (iocd->stmf_obuf_size)/sizeof (slist_scsi_session_t));
689 iocd->stmf_obuf_nentries = n;
690 iss = ilport->ilport_ss_list;
691 iss_list = (slist_scsi_session_t *)obuf;
692 for (i = 0; i < n; i++) {
693 uint8_t *id;
694 id = (uint8_t *)iss->iss_ss->ss_rport_id;
695 bcopy(id, iss_list[i].initiator, id[3] + 4);
696 iss_list[i].creation_time = (uint32_t)
697 iss->iss_creation_time;
698 if (iss->iss_ss->ss_rport_alias) {
699 (void) strncpy(iss_list[i].alias,
700 iss->iss_ss->ss_rport_alias, 255);
701 iss_list[i].alias[255] = 0;
702 } else {
703 iss_list[i].alias[0] = 0;
704 }
705 iss = iss->iss_next;
706 }
707 mutex_exit(&stmf_state.stmf_lock);
708 break;
709
710 case STMF_IOCTL_GET_LU_PROPERTIES:
711 p_id = (uint8_t *)ibuf;
712 if ((iocd->stmf_ibuf_size < 16) ||
713 (iocd->stmf_obuf_size < sizeof (sioc_lu_props_t)) ||
714 (p_id[0] == 0)) {
715 ret = EINVAL;
716 break;
717 }
718 mutex_enter(&stmf_state.stmf_lock);
719 for (ilu = stmf_state.stmf_ilulist; ilu; ilu = ilu->ilu_next) {
720 if (bcmp(p_id, ilu->ilu_lu->lu_id->ident, 16) == 0)
721 break;
722 }
723 if (ilu == NULL) {
724 mutex_exit(&stmf_state.stmf_lock);
725 ret = ENOENT;
726 break;
727 }
728 lup = (sioc_lu_props_t *)obuf;
729 bcopy(ilu->ilu_lu->lu_id->ident, lup->lu_guid, 16);
730 lup->lu_state = ilu->ilu_state & 0x0f;
731 lup->lu_present = 1; /* XXX */
732 (void) strncpy(lup->lu_provider_name,
733 ilu->ilu_lu->lu_lp->lp_name, 255);
734 lup->lu_provider_name[254] = 0;
735 if (ilu->ilu_lu->lu_alias) {
736 (void) strncpy(lup->lu_alias,
737 ilu->ilu_lu->lu_alias, 255);
738 lup->lu_alias[255] = 0;
739 } else {
740 lup->lu_alias[0] = 0;
741 }
742 mutex_exit(&stmf_state.stmf_lock);
743 break;
744
745 case STMF_IOCTL_GET_TARGET_PORT_PROPERTIES:
746 p_id = (uint8_t *)ibuf;
747 if ((p_id == NULL) ||
748 (iocd->stmf_ibuf_size < (p_id[3] + 4)) ||
749 (iocd->stmf_obuf_size <
750 sizeof (sioc_target_port_props_t))) {
751 ret = EINVAL;
752 break;
753 }
754 mutex_enter(&stmf_state.stmf_lock);
755 for (ilport = stmf_state.stmf_ilportlist; ilport;
756 ilport = ilport->ilport_next) {
757 uint8_t *id;
758 id = (uint8_t *)ilport->ilport_lport->lport_id;
759 if ((p_id[3] == id[3]) &&
760 (bcmp(p_id+4, id+4, id[3]) == 0))
761 break;
762 }
763 if (ilport == NULL) {
764 mutex_exit(&stmf_state.stmf_lock);
765 ret = ENOENT;
766 break;
767 }
768 lportp = (sioc_target_port_props_t *)obuf;
769 bcopy(ilport->ilport_lport->lport_id, lportp->tgt_id,
770 ilport->ilport_lport->lport_id->ident_length + 4);
771 lportp->tgt_state = ilport->ilport_state & 0x0f;
772 lportp->tgt_present = 1; /* XXX */
773 (void) strncpy(lportp->tgt_provider_name,
774 ilport->ilport_lport->lport_pp->pp_name, 255);
775 lportp->tgt_provider_name[254] = 0;
776 if (ilport->ilport_lport->lport_alias) {
777 (void) strncpy(lportp->tgt_alias,
778 ilport->ilport_lport->lport_alias, 255);
779 lportp->tgt_alias[255] = 0;
780 } else {
781 lportp->tgt_alias[0] = 0;
782 }
783 mutex_exit(&stmf_state.stmf_lock);
784 break;
785
786 case STMF_IOCTL_SET_STMF_STATE:
787 if ((ibuf == NULL) ||
788 (iocd->stmf_ibuf_size < sizeof (stmf_state_desc_t))) {
789 ret = EINVAL;
790 break;
791 }
792 ret = stmf_set_stmf_state((stmf_state_desc_t *)ibuf);
793 break;
794
795 case STMF_IOCTL_GET_STMF_STATE:
796 if ((obuf == NULL) ||
797 (iocd->stmf_obuf_size < sizeof (stmf_state_desc_t))) {
798 ret = EINVAL;
799 break;
800 }
801 ret = stmf_get_stmf_state((stmf_state_desc_t *)obuf);
802 break;
803
804 case STMF_IOCTL_SET_ALUA_STATE:
805 if ((ibuf == NULL) ||
806 (iocd->stmf_ibuf_size < sizeof (stmf_alua_state_desc_t))) {
807 ret = EINVAL;
808 break;
809 }
810 ret = stmf_set_alua_state((stmf_alua_state_desc_t *)ibuf);
811 break;
812
813 case STMF_IOCTL_GET_ALUA_STATE:
814 if ((obuf == NULL) ||
815 (iocd->stmf_obuf_size < sizeof (stmf_alua_state_desc_t))) {
816 ret = EINVAL;
817 break;
818 }
819 stmf_get_alua_state((stmf_alua_state_desc_t *)obuf);
820 break;
821
822 case STMF_IOCTL_SET_LU_STATE:
823 ssi.st_rflags = STMF_RFLAG_USER_REQUEST;
824 ssi.st_additional_info = NULL;
825 std = (stmf_state_desc_t *)ibuf;
826 if ((ibuf == NULL) ||
827 (iocd->stmf_ibuf_size < sizeof (stmf_state_desc_t))) {
828 ret = EINVAL;
829 break;
830 }
831 p_id = std->ident;
832 mutex_enter(&stmf_state.stmf_lock);
833 if (stmf_state.stmf_inventory_locked) {
834 mutex_exit(&stmf_state.stmf_lock);
835 ret = EBUSY;
836 break;
837 }
838 for (ilu = stmf_state.stmf_ilulist; ilu; ilu = ilu->ilu_next) {
839 if (bcmp(p_id, ilu->ilu_lu->lu_id->ident, 16) == 0)
840 break;
841 }
842 if (ilu == NULL) {
843 mutex_exit(&stmf_state.stmf_lock);
844 ret = ENOENT;
845 break;
846 }
847 stmf_state.stmf_inventory_locked = 1;
848 mutex_exit(&stmf_state.stmf_lock);
849 cmd = (std->state == STMF_STATE_ONLINE) ? STMF_CMD_LU_ONLINE :
850 STMF_CMD_LU_OFFLINE;
851 ctl_ret = stmf_ctl(cmd, (void *)ilu->ilu_lu, &ssi);
852 if (ctl_ret == STMF_ALREADY)
853 ret = 0;
854 else if (ctl_ret == STMF_BUSY)
855 ret = EBUSY;
856 else if (ctl_ret != STMF_SUCCESS)
857 ret = EIO;
858 mutex_enter(&stmf_state.stmf_lock);
859 stmf_state.stmf_inventory_locked = 0;
860 mutex_exit(&stmf_state.stmf_lock);
861 break;
862
863 case STMF_IOCTL_SET_STMF_PROPS:
864 if ((ibuf == NULL) ||
865 (iocd->stmf_ibuf_size < sizeof (stmf_set_props_t))) {
866 ret = EINVAL;
867 break;
868 }
869 stmf_set_props = (stmf_set_props_t *)ibuf;
870 mutex_enter(&stmf_state.stmf_lock);
871 if ((stmf_set_props->default_lu_state_value ==
872 STMF_STATE_OFFLINE) ||
873 (stmf_set_props->default_lu_state_value ==
874 STMF_STATE_ONLINE)) {
875 stmf_state.stmf_default_lu_state =
876 stmf_set_props->default_lu_state_value;
877 }
878 if ((stmf_set_props->default_target_state_value ==
879 STMF_STATE_OFFLINE) ||
880 (stmf_set_props->default_target_state_value ==
881 STMF_STATE_ONLINE)) {
882 stmf_state.stmf_default_lport_state =
883 stmf_set_props->default_target_state_value;
884 }
885
886 mutex_exit(&stmf_state.stmf_lock);
887 break;
888
889 case STMF_IOCTL_SET_TARGET_PORT_STATE:
890 ssi.st_rflags = STMF_RFLAG_USER_REQUEST;
891 ssi.st_additional_info = NULL;
892 std = (stmf_state_desc_t *)ibuf;
893 if ((ibuf == NULL) ||
894 (iocd->stmf_ibuf_size < sizeof (stmf_state_desc_t))) {
895 ret = EINVAL;
896 break;
897 }
898 p_id = std->ident;
899 mutex_enter(&stmf_state.stmf_lock);
900 if (stmf_state.stmf_inventory_locked) {
901 mutex_exit(&stmf_state.stmf_lock);
902 ret = EBUSY;
903 break;
904 }
905 for (ilport = stmf_state.stmf_ilportlist; ilport;
906 ilport = ilport->ilport_next) {
907 uint8_t *id;
908 id = (uint8_t *)ilport->ilport_lport->lport_id;
909 if ((id[3] == p_id[3]) &&
910 (bcmp(id+4, p_id+4, id[3]) == 0)) {
911 break;
912 }
913 }
914 if (ilport == NULL) {
915 mutex_exit(&stmf_state.stmf_lock);
916 ret = ENOENT;
917 break;
918 }
919 stmf_state.stmf_inventory_locked = 1;
920 mutex_exit(&stmf_state.stmf_lock);
921 cmd = (std->state == STMF_STATE_ONLINE) ?
922 STMF_CMD_LPORT_ONLINE : STMF_CMD_LPORT_OFFLINE;
923 ctl_ret = stmf_ctl(cmd, (void *)ilport->ilport_lport, &ssi);
924 if (ctl_ret == STMF_ALREADY)
925 ret = 0;
926 else if (ctl_ret == STMF_BUSY)
927 ret = EBUSY;
928 else if (ctl_ret != STMF_SUCCESS)
929 ret = EIO;
930 mutex_enter(&stmf_state.stmf_lock);
931 stmf_state.stmf_inventory_locked = 0;
932 mutex_exit(&stmf_state.stmf_lock);
933 break;
934
935 case STMF_IOCTL_ADD_HG_ENTRY:
936 idtype = STMF_ID_TYPE_HOST;
937 /* FALLTHROUGH */
938 case STMF_IOCTL_ADD_TG_ENTRY:
939 if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) {
940 ret = EACCES;
941 iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT;
942 break;
943 }
944 if (cmd == STMF_IOCTL_ADD_TG_ENTRY) {
945 idtype = STMF_ID_TYPE_TARGET;
946 }
947 grp_entry = (stmf_group_op_data_t *)ibuf;
948 if ((ibuf == NULL) ||
949 (iocd->stmf_ibuf_size < sizeof (stmf_group_op_data_t))) {
950 ret = EINVAL;
951 break;
952 }
953 if (grp_entry->group.name[0] == '*') {
954 ret = EINVAL;
955 break; /* not allowed */
956 }
957 mutex_enter(&stmf_state.stmf_lock);
958 ret = stmf_add_group_member(grp_entry->group.name,
959 grp_entry->group.name_size,
960 grp_entry->ident + 4,
961 grp_entry->ident[3],
962 idtype,
963 &iocd->stmf_error);
964 mutex_exit(&stmf_state.stmf_lock);
965 break;
966 case STMF_IOCTL_REMOVE_HG_ENTRY:
967 idtype = STMF_ID_TYPE_HOST;
968 /* FALLTHROUGH */
969 case STMF_IOCTL_REMOVE_TG_ENTRY:
970 if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) {
971 ret = EACCES;
972 iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT;
973 break;
974 }
975 if (cmd == STMF_IOCTL_REMOVE_TG_ENTRY) {
976 idtype = STMF_ID_TYPE_TARGET;
977 }
978 grp_entry = (stmf_group_op_data_t *)ibuf;
979 if ((ibuf == NULL) ||
980 (iocd->stmf_ibuf_size < sizeof (stmf_group_op_data_t))) {
981 ret = EINVAL;
982 break;
983 }
984 if (grp_entry->group.name[0] == '*') {
985 ret = EINVAL;
986 break; /* not allowed */
987 }
988 mutex_enter(&stmf_state.stmf_lock);
989 ret = stmf_remove_group_member(grp_entry->group.name,
990 grp_entry->group.name_size,
991 grp_entry->ident + 4,
992 grp_entry->ident[3],
993 idtype,
994 &iocd->stmf_error);
995 mutex_exit(&stmf_state.stmf_lock);
996 break;
997 case STMF_IOCTL_CREATE_HOST_GROUP:
998 idtype = STMF_ID_TYPE_HOST_GROUP;
999 /* FALLTHROUGH */
1000 case STMF_IOCTL_CREATE_TARGET_GROUP:
1001 if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) {
1002 ret = EACCES;
1003 iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT;
1004 break;
1005 }
1006 grpname = (stmf_group_name_t *)ibuf;
1007
1008 if (cmd == STMF_IOCTL_CREATE_TARGET_GROUP)
1009 idtype = STMF_ID_TYPE_TARGET_GROUP;
1010 if ((ibuf == NULL) ||
1011 (iocd->stmf_ibuf_size < sizeof (stmf_group_name_t))) {
1012 ret = EINVAL;
1013 break;
1014 }
1015 if (grpname->name[0] == '*') {
1016 ret = EINVAL;
1017 break; /* not allowed */
1018 }
1019 mutex_enter(&stmf_state.stmf_lock);
1020 ret = stmf_add_group(grpname->name,
1021 grpname->name_size, idtype, &iocd->stmf_error);
1022 mutex_exit(&stmf_state.stmf_lock);
1023 break;
1024 case STMF_IOCTL_REMOVE_HOST_GROUP:
1025 idtype = STMF_ID_TYPE_HOST_GROUP;
1026 /* FALLTHROUGH */
1027 case STMF_IOCTL_REMOVE_TARGET_GROUP:
1028 if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) {
1029 ret = EACCES;
1030 iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT;
1031 break;
1032 }
1033 grpname = (stmf_group_name_t *)ibuf;
1034 if (cmd == STMF_IOCTL_REMOVE_TARGET_GROUP)
1035 idtype = STMF_ID_TYPE_TARGET_GROUP;
1036 if ((ibuf == NULL) ||
1037 (iocd->stmf_ibuf_size < sizeof (stmf_group_name_t))) {
1038 ret = EINVAL;
1039 break;
1040 }
1041 if (grpname->name[0] == '*') {
1042 ret = EINVAL;
1043 break; /* not allowed */
1044 }
1045 mutex_enter(&stmf_state.stmf_lock);
1046 ret = stmf_remove_group(grpname->name,
1047 grpname->name_size, idtype, &iocd->stmf_error);
1048 mutex_exit(&stmf_state.stmf_lock);
1049 break;
1050 case STMF_IOCTL_VALIDATE_VIEW:
1051 case STMF_IOCTL_ADD_VIEW_ENTRY:
1052 if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) {
1053 ret = EACCES;
1054 iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT;
1055 break;
1056 }
1057 ve = (stmf_view_op_entry_t *)ibuf;
1058 if ((ibuf == NULL) ||
1059 (iocd->stmf_ibuf_size < sizeof (stmf_view_op_entry_t))) {
1060 ret = EINVAL;
1061 break;
1062 }
1063 if (!ve->ve_lu_number_valid)
1064 ve->ve_lu_nbr[2] = 0xFF;
1065 if (ve->ve_all_hosts) {
1066 ve->ve_host_group.name[0] = '*';
1067 ve->ve_host_group.name_size = 1;
1068 }
1069 if (ve->ve_all_targets) {
1070 ve->ve_target_group.name[0] = '*';
1071 ve->ve_target_group.name_size = 1;
1072 }
1073 if (ve->ve_ndx_valid)
1074 veid = ve->ve_ndx;
1075 else
1076 veid = 0xffffffff;
1077 mutex_enter(&stmf_state.stmf_lock);
1078 if (cmd == STMF_IOCTL_ADD_VIEW_ENTRY) {
1079 ret = stmf_add_ve(ve->ve_host_group.name,
1080 ve->ve_host_group.name_size,
1081 ve->ve_target_group.name,
1082 ve->ve_target_group.name_size,
1083 ve->ve_guid,
1084 &veid,
1085 ve->ve_lu_nbr,
1086 &iocd->stmf_error);
1087 } else { /* STMF_IOCTL_VALIDATE_VIEW */
1088 ret = stmf_validate_lun_ve(ve->ve_host_group.name,
1089 ve->ve_host_group.name_size,
1090 ve->ve_target_group.name,
1091 ve->ve_target_group.name_size,
1092 ve->ve_lu_nbr,
1093 &iocd->stmf_error);
1094 }
1095 mutex_exit(&stmf_state.stmf_lock);
1096 if (ret == 0 &&
1097 (!ve->ve_ndx_valid || !ve->ve_lu_number_valid) &&
1098 iocd->stmf_obuf_size >= sizeof (stmf_view_op_entry_t)) {
1099 stmf_view_op_entry_t *ve_ret =
1100 (stmf_view_op_entry_t *)obuf;
1101 iocd->stmf_obuf_nentries = 1;
1102 iocd->stmf_obuf_max_nentries = 1;
1103 if (!ve->ve_ndx_valid) {
1104 ve_ret->ve_ndx = veid;
1105 ve_ret->ve_ndx_valid = 1;
1106 }
1107 if (!ve->ve_lu_number_valid) {
1108 ve_ret->ve_lu_number_valid = 1;
1109 bcopy(ve->ve_lu_nbr, ve_ret->ve_lu_nbr, 8);
1110 }
1111 }
1112 break;
1113 case STMF_IOCTL_REMOVE_VIEW_ENTRY:
1114 if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) {
1115 ret = EACCES;
1116 iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT;
1117 break;
1118 }
1119 ve = (stmf_view_op_entry_t *)ibuf;
1120 if ((ibuf == NULL) ||
1121 (iocd->stmf_ibuf_size < sizeof (stmf_view_op_entry_t))) {
1122 ret = EINVAL;
1123 break;
1124 }
1125 if (!ve->ve_ndx_valid) {
1126 ret = EINVAL;
1127 break;
1128 }
1129 mutex_enter(&stmf_state.stmf_lock);
1130 ret = stmf_remove_ve_by_id(ve->ve_guid, ve->ve_ndx,
1131 &iocd->stmf_error);
1132 mutex_exit(&stmf_state.stmf_lock);
1133 break;
1134 case STMF_IOCTL_GET_HG_LIST:
1135 id_list = &stmf_state.stmf_hg_list;
1136 /* FALLTHROUGH */
1137 case STMF_IOCTL_GET_TG_LIST:
1138 if (cmd == STMF_IOCTL_GET_TG_LIST)
1139 id_list = &stmf_state.stmf_tg_list;
1140 mutex_enter(&stmf_state.stmf_lock);
1141 iocd->stmf_obuf_max_nentries = id_list->id_count;
1142 n = min(id_list->id_count,
1143 (iocd->stmf_obuf_size)/sizeof (stmf_group_name_t));
1144 iocd->stmf_obuf_nentries = n;
1145 id_entry = id_list->idl_head;
1146 grpname = (stmf_group_name_t *)obuf;
1147 for (i = 0; i < n; i++) {
1148 if (id_entry->id_data[0] == '*') {
1149 if (iocd->stmf_obuf_nentries > 0) {
1150 iocd->stmf_obuf_nentries--;
1151 }
1152 id_entry = id_entry->id_next;
1153 continue;
1154 }
1155 grpname->name_size = id_entry->id_data_size;
1156 bcopy(id_entry->id_data, grpname->name,
1157 id_entry->id_data_size);
1158 grpname++;
1159 id_entry = id_entry->id_next;
1160 }
1161 mutex_exit(&stmf_state.stmf_lock);
1162 break;
1163 case STMF_IOCTL_GET_HG_ENTRIES:
1164 id_list = &stmf_state.stmf_hg_list;
1165 /* FALLTHROUGH */
1166 case STMF_IOCTL_GET_TG_ENTRIES:
1167 grpname = (stmf_group_name_t *)ibuf;
1168 if ((ibuf == NULL) ||
1169 (iocd->stmf_ibuf_size < sizeof (stmf_group_name_t))) {
1170 ret = EINVAL;
1171 break;
1172 }
1173 if (cmd == STMF_IOCTL_GET_TG_ENTRIES) {
1174 id_list = &stmf_state.stmf_tg_list;
1175 }
1176 mutex_enter(&stmf_state.stmf_lock);
1177 id_entry = stmf_lookup_id(id_list, grpname->name_size,
1178 grpname->name);
1179 if (!id_entry)
1180 ret = ENODEV;
1181 else {
1182 stmf_ge_ident_t *grp_entry;
1183 id_list = (stmf_id_list_t *)id_entry->id_impl_specific;
1184 iocd->stmf_obuf_max_nentries = id_list->id_count;
1185 n = min(id_list->id_count,
1186 iocd->stmf_obuf_size/sizeof (stmf_ge_ident_t));
1187 iocd->stmf_obuf_nentries = n;
1188 id_entry = id_list->idl_head;
1189 grp_entry = (stmf_ge_ident_t *)obuf;
1190 for (i = 0; i < n; i++) {
1191 bcopy(id_entry->id_data, grp_entry->ident,
1192 id_entry->id_data_size);
1193 grp_entry->ident_size = id_entry->id_data_size;
1194 id_entry = id_entry->id_next;
1195 grp_entry++;
1196 }
1197 }
1198 mutex_exit(&stmf_state.stmf_lock);
1199 break;
1200
1201 case STMF_IOCTL_GET_VE_LIST:
1202 n = iocd->stmf_obuf_size/sizeof (stmf_view_op_entry_t);
1203 mutex_enter(&stmf_state.stmf_lock);
1204 ve = (stmf_view_op_entry_t *)obuf;
1205 for (id_entry = stmf_state.stmf_luid_list.idl_head;
1206 id_entry; id_entry = id_entry->id_next) {
1207 for (view_entry = (stmf_view_entry_t *)
1208 id_entry->id_impl_specific; view_entry;
1209 view_entry = view_entry->ve_next) {
1210 iocd->stmf_obuf_max_nentries++;
1211 if (iocd->stmf_obuf_nentries >= n)
1212 continue;
1213 ve->ve_ndx_valid = 1;
1214 ve->ve_ndx = view_entry->ve_id;
1215 ve->ve_lu_number_valid = 1;
1216 bcopy(view_entry->ve_lun, ve->ve_lu_nbr, 8);
1217 bcopy(view_entry->ve_luid->id_data, ve->ve_guid,
1218 view_entry->ve_luid->id_data_size);
1219 if (view_entry->ve_hg->id_data[0] == '*') {
1220 ve->ve_all_hosts = 1;
1221 } else {
1222 bcopy(view_entry->ve_hg->id_data,
1223 ve->ve_host_group.name,
1224 view_entry->ve_hg->id_data_size);
1225 ve->ve_host_group.name_size =
1226 view_entry->ve_hg->id_data_size;
1227 }
1228
1229 if (view_entry->ve_tg->id_data[0] == '*') {
1230 ve->ve_all_targets = 1;
1231 } else {
1232 bcopy(view_entry->ve_tg->id_data,
1233 ve->ve_target_group.name,
1234 view_entry->ve_tg->id_data_size);
1235 ve->ve_target_group.name_size =
1236 view_entry->ve_tg->id_data_size;
1237 }
1238 ve++;
1239 iocd->stmf_obuf_nentries++;
1240 }
1241 }
1242 mutex_exit(&stmf_state.stmf_lock);
1243 break;
1244
1245 case STMF_IOCTL_LU_VE_LIST:
1246 p_id = (uint8_t *)ibuf;
1247 if ((iocd->stmf_ibuf_size != 16) ||
1248 (iocd->stmf_obuf_size < sizeof (stmf_view_op_entry_t))) {
1249 ret = EINVAL;
1250 break;
1251 }
1252
1253 n = iocd->stmf_obuf_size/sizeof (stmf_view_op_entry_t);
1254 mutex_enter(&stmf_state.stmf_lock);
1255 ve = (stmf_view_op_entry_t *)obuf;
1256 for (id_entry = stmf_state.stmf_luid_list.idl_head;
1257 id_entry; id_entry = id_entry->id_next) {
1258 if (bcmp(id_entry->id_data, p_id, 16) != 0)
1259 continue;
1260 for (view_entry = (stmf_view_entry_t *)
1261 id_entry->id_impl_specific; view_entry;
1262 view_entry = view_entry->ve_next) {
1263 iocd->stmf_obuf_max_nentries++;
1264 if (iocd->stmf_obuf_nentries >= n)
1265 continue;
1266 ve->ve_ndx_valid = 1;
1267 ve->ve_ndx = view_entry->ve_id;
1268 ve->ve_lu_number_valid = 1;
1269 bcopy(view_entry->ve_lun, ve->ve_lu_nbr, 8);
1270 bcopy(view_entry->ve_luid->id_data, ve->ve_guid,
1271 view_entry->ve_luid->id_data_size);
1272 if (view_entry->ve_hg->id_data[0] == '*') {
1273 ve->ve_all_hosts = 1;
1274 } else {
1275 bcopy(view_entry->ve_hg->id_data,
1276 ve->ve_host_group.name,
1277 view_entry->ve_hg->id_data_size);
1278 ve->ve_host_group.name_size =
1279 view_entry->ve_hg->id_data_size;
1280 }
1281
1282 if (view_entry->ve_tg->id_data[0] == '*') {
1283 ve->ve_all_targets = 1;
1284 } else {
1285 bcopy(view_entry->ve_tg->id_data,
1286 ve->ve_target_group.name,
1287 view_entry->ve_tg->id_data_size);
1288 ve->ve_target_group.name_size =
1289 view_entry->ve_tg->id_data_size;
1290 }
1291 ve++;
1292 iocd->stmf_obuf_nentries++;
1293 }
1294 break;
1295 }
1296 mutex_exit(&stmf_state.stmf_lock);
1297 break;
1298
1299 case STMF_IOCTL_LOAD_PP_DATA:
1300 if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) {
1301 ret = EACCES;
1302 iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT;
1303 break;
1304 }
1305 ppi = (stmf_ppioctl_data_t *)ibuf;
1306 if ((ppi == NULL) ||
1307 (iocd->stmf_ibuf_size < sizeof (stmf_ppioctl_data_t))) {
1308 ret = EINVAL;
1309 break;
1310 }
1311 /* returned token */
1312 ppi_token = (uint64_t *)obuf;
1313 if ((ppi_token == NULL) ||
1314 (iocd->stmf_obuf_size < sizeof (uint64_t))) {
1315 ret = EINVAL;
1316 break;
1317 }
1318 ret = stmf_load_ppd_ioctl(ppi, ppi_token, &iocd->stmf_error);
1319 break;
1320
1321 case STMF_IOCTL_GET_PP_DATA:
1322 if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) {
1323 ret = EACCES;
1324 iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT;
1325 break;
1326 }
1327 ppi = (stmf_ppioctl_data_t *)ibuf;
1328 if (ppi == NULL ||
1329 (iocd->stmf_ibuf_size < sizeof (stmf_ppioctl_data_t))) {
1330 ret = EINVAL;
1331 break;
1332 }
1333 ppi_out = (stmf_ppioctl_data_t *)obuf;
1334 if ((ppi_out == NULL) ||
1335 (iocd->stmf_obuf_size < sizeof (stmf_ppioctl_data_t))) {
1336 ret = EINVAL;
1337 break;
1338 }
1339 ret = stmf_get_ppd_ioctl(ppi, ppi_out, &iocd->stmf_error);
1340 break;
1341
1342 case STMF_IOCTL_CLEAR_PP_DATA:
1343 if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) {
1344 ret = EACCES;
1345 iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT;
1346 break;
1347 }
1348 ppi = (stmf_ppioctl_data_t *)ibuf;
1349 if ((ppi == NULL) ||
1350 (iocd->stmf_ibuf_size < sizeof (stmf_ppioctl_data_t))) {
1351 ret = EINVAL;
1352 break;
1353 }
1354 ret = stmf_delete_ppd_ioctl(ppi);
1355 break;
1356
1357 case STMF_IOCTL_CLEAR_TRACE:
1358 stmf_trace_clear();
1359 break;
1360
1361 case STMF_IOCTL_ADD_TRACE:
1362 if (iocd->stmf_ibuf_size && ibuf) {
1363 ((uint8_t *)ibuf)[iocd->stmf_ibuf_size - 1] = 0;
1364 stmf_trace("\nstradm", "%s\n", ibuf);
1365 }
1366 break;
1367
1368 case STMF_IOCTL_GET_TRACE_POSITION:
1369 if (obuf && (iocd->stmf_obuf_size > 3)) {
1370 mutex_enter(&trace_buf_lock);
1371 *((int *)obuf) = trace_buf_curndx;
1372 mutex_exit(&trace_buf_lock);
1373 } else {
1374 ret = EINVAL;
1375 }
1376 break;
1377
1378 case STMF_IOCTL_GET_TRACE:
1379 if ((iocd->stmf_obuf_size == 0) || (iocd->stmf_ibuf_size < 4)) {
1380 ret = EINVAL;
1381 break;
1382 }
1383 i = *((int *)ibuf);
1384 if ((i > trace_buf_size) || ((i + iocd->stmf_obuf_size) >
1385 trace_buf_size)) {
1386 ret = EINVAL;
1387 break;
1388 }
1389 mutex_enter(&trace_buf_lock);
1390 bcopy(stmf_trace_buf + i, obuf, iocd->stmf_obuf_size);
1391 mutex_exit(&trace_buf_lock);
1392 break;
1393
1394 default:
1395 ret = ENOTTY;
1396 }
1397
1398 if (ret == 0) {
1399 ret = stmf_copyout_iocdata(data, mode, iocd, obuf);
1400 } else if (iocd->stmf_error) {
1401 (void) stmf_copyout_iocdata(data, mode, iocd, obuf);
1402 }
1403 if (obuf) {
1404 kmem_free(obuf, iocd->stmf_obuf_size);
1405 obuf = NULL;
1406 }
1407 if (ibuf) {
1408 kmem_free(ibuf, iocd->stmf_ibuf_size);
1409 ibuf = NULL;
1410 }
1411 kmem_free(iocd, sizeof (stmf_iocdata_t));
1412 return (ret);
1413 }
1414
1415 static int
1416 stmf_get_service_state()
1417 {
1418 stmf_i_local_port_t *ilport;
1419 stmf_i_lu_t *ilu;
1420 int online = 0;
1421 int offline = 0;
1422 int onlining = 0;
1423 int offlining = 0;
1424
1425 ASSERT(mutex_owned(&stmf_state.stmf_lock));
1426 for (ilport = stmf_state.stmf_ilportlist; ilport != NULL;
1427 ilport = ilport->ilport_next) {
1428 if (ilport->ilport_state == STMF_STATE_OFFLINE)
1429 offline++;
1430 else if (ilport->ilport_state == STMF_STATE_ONLINE)
1431 online++;
1432 else if (ilport->ilport_state == STMF_STATE_ONLINING)
1433 onlining++;
1434 else if (ilport->ilport_state == STMF_STATE_OFFLINING)
1435 offlining++;
1436 }
1437
1438 for (ilu = stmf_state.stmf_ilulist; ilu != NULL;
1439 ilu = ilu->ilu_next) {
1440 if (ilu->ilu_state == STMF_STATE_OFFLINE)
1441 offline++;
1442 else if (ilu->ilu_state == STMF_STATE_ONLINE)
1443 online++;
1444 else if (ilu->ilu_state == STMF_STATE_ONLINING)
1445 onlining++;
1446 else if (ilu->ilu_state == STMF_STATE_OFFLINING)
1447 offlining++;
1448 }
1449
1450 if (stmf_state.stmf_service_running) {
1451 if (onlining)
1452 return (STMF_STATE_ONLINING);
1453 else
1454 return (STMF_STATE_ONLINE);
1455 }
1456
1457 if (offlining) {
1458 return (STMF_STATE_OFFLINING);
1459 }
1460
1461 return (STMF_STATE_OFFLINE);
1462 }
1463
1464 static int
1465 stmf_set_stmf_state(stmf_state_desc_t *std)
1466 {
1467 stmf_i_local_port_t *ilport;
1468 stmf_i_lu_t *ilu;
1469 stmf_state_change_info_t ssi;
1470 int svc_state;
1471
1472 ssi.st_rflags = STMF_RFLAG_USER_REQUEST;
1473 ssi.st_additional_info = NULL;
1474
1475 mutex_enter(&stmf_state.stmf_lock);
1476 if (!stmf_state.stmf_exclusive_open) {
1477 mutex_exit(&stmf_state.stmf_lock);
1478 return (EACCES);
1479 }
1480
1481 if (stmf_state.stmf_inventory_locked) {
1482 mutex_exit(&stmf_state.stmf_lock);
1483 return (EBUSY);
1484 }
1485
1486 if ((std->state != STMF_STATE_ONLINE) &&
1487 (std->state != STMF_STATE_OFFLINE)) {
1488 mutex_exit(&stmf_state.stmf_lock);
1489 return (EINVAL);
1490 }
1491
1492 svc_state = stmf_get_service_state();
1493 if ((svc_state == STMF_STATE_OFFLINING) ||
1494 (svc_state == STMF_STATE_ONLINING)) {
1495 mutex_exit(&stmf_state.stmf_lock);
1496 return (EBUSY);
1497 }
1498
1499 if (svc_state == STMF_STATE_OFFLINE) {
1500 if (std->config_state == STMF_CONFIG_INIT) {
1501 if (std->state != STMF_STATE_OFFLINE) {
1502 mutex_exit(&stmf_state.stmf_lock);
1503 return (EINVAL);
1504 }
1505 stmf_state.stmf_config_state = STMF_CONFIG_INIT;
1506 stmf_delete_all_ppds();
1507 stmf_view_clear_config();
1508 stmf_view_init();
1509 mutex_exit(&stmf_state.stmf_lock);
1510 return (0);
1511 }
1512 if ((stmf_state.stmf_config_state == STMF_CONFIG_INIT) ||
1513 (stmf_state.stmf_config_state == STMF_CONFIG_NONE)) {
1514 if (std->config_state != STMF_CONFIG_INIT_DONE) {
1515 mutex_exit(&stmf_state.stmf_lock);
1516 return (EINVAL);
1517 }
1518 stmf_state.stmf_config_state = STMF_CONFIG_INIT_DONE;
1519 }
1520 if (std->state == STMF_STATE_OFFLINE) {
1521 mutex_exit(&stmf_state.stmf_lock);
1522 return (0);
1523 }
1524 if (stmf_state.stmf_config_state == STMF_CONFIG_INIT) {
1525 mutex_exit(&stmf_state.stmf_lock);
1526 return (EINVAL);
1527 }
1528 stmf_state.stmf_inventory_locked = 1;
1529 stmf_state.stmf_service_running = 1;
1530 mutex_exit(&stmf_state.stmf_lock);
1531
1532 for (ilport = stmf_state.stmf_ilportlist; ilport != NULL;
1533 ilport = ilport->ilport_next) {
1534 if (stmf_state.stmf_default_lport_state !=
1535 STMF_STATE_ONLINE)
1536 continue;
1537 (void) stmf_ctl(STMF_CMD_LPORT_ONLINE,
1538 ilport->ilport_lport, &ssi);
1539 }
1540
1541 for (ilu = stmf_state.stmf_ilulist; ilu != NULL;
1542 ilu = ilu->ilu_next) {
1543 if (stmf_state.stmf_default_lu_state !=
1544 STMF_STATE_ONLINE)
1545 continue;
1546 (void) stmf_ctl(STMF_CMD_LU_ONLINE, ilu->ilu_lu, &ssi);
1547 }
1548 mutex_enter(&stmf_state.stmf_lock);
1549 stmf_state.stmf_inventory_locked = 0;
1550 mutex_exit(&stmf_state.stmf_lock);
1551 return (0);
1552 }
1553
1554 /* svc_state is STMF_STATE_ONLINE here */
1555 if ((std->state != STMF_STATE_OFFLINE) ||
1556 (std->config_state == STMF_CONFIG_INIT)) {
1557 mutex_exit(&stmf_state.stmf_lock);
1558 return (EACCES);
1559 }
1560
1561 stmf_state.stmf_inventory_locked = 1;
1562 stmf_state.stmf_service_running = 0;
1563
1564 mutex_exit(&stmf_state.stmf_lock);
1565 for (ilport = stmf_state.stmf_ilportlist; ilport != NULL;
1566 ilport = ilport->ilport_next) {
1567 if (ilport->ilport_state != STMF_STATE_ONLINE)
1568 continue;
1569 (void) stmf_ctl(STMF_CMD_LPORT_OFFLINE,
1570 ilport->ilport_lport, &ssi);
1571 }
1572
1573 for (ilu = stmf_state.stmf_ilulist; ilu != NULL;
1574 ilu = ilu->ilu_next) {
1575 if (ilu->ilu_state != STMF_STATE_ONLINE)
1576 continue;
1577 (void) stmf_ctl(STMF_CMD_LU_OFFLINE, ilu->ilu_lu, &ssi);
1578 }
1579 mutex_enter(&stmf_state.stmf_lock);
1580 stmf_state.stmf_inventory_locked = 0;
1581 mutex_exit(&stmf_state.stmf_lock);
1582 return (0);
1583 }
1584
1585 static int
1586 stmf_get_stmf_state(stmf_state_desc_t *std)
1587 {
1588 mutex_enter(&stmf_state.stmf_lock);
1589 std->state = stmf_get_service_state();
1590 std->config_state = stmf_state.stmf_config_state;
1591 mutex_exit(&stmf_state.stmf_lock);
1592
1593 return (0);
1594 }
1595 /*
1596 * handles registration message from pppt for a logical unit
1597 */
1598 stmf_status_t
1599 stmf_ic_lu_reg(stmf_ic_reg_dereg_lun_msg_t *msg, uint32_t type)
1600 {
1601 stmf_i_lu_provider_t *ilp;
1602 stmf_lu_provider_t *lp;
1603 mutex_enter(&stmf_state.stmf_lock);
1604 for (ilp = stmf_state.stmf_ilplist; ilp != NULL; ilp = ilp->ilp_next) {
1605 if (strcmp(msg->icrl_lu_provider_name,
1606 ilp->ilp_lp->lp_name) == 0) {
1607 lp = ilp->ilp_lp;
1608 mutex_exit(&stmf_state.stmf_lock);
1609 lp->lp_proxy_msg(msg->icrl_lun_id, msg->icrl_cb_arg,
1610 msg->icrl_cb_arg_len, type);
1611 return (STMF_SUCCESS);
1612 }
1613 }
1614 mutex_exit(&stmf_state.stmf_lock);
1615 return (STMF_SUCCESS);
1616 }
1617
1618 /*
1619 * handles de-registration message from pppt for a logical unit
1620 */
1621 stmf_status_t
1622 stmf_ic_lu_dereg(stmf_ic_reg_dereg_lun_msg_t *msg)
1623 {
1624 stmf_i_lu_provider_t *ilp;
1625 stmf_lu_provider_t *lp;
1626 mutex_enter(&stmf_state.stmf_lock);
1627 for (ilp = stmf_state.stmf_ilplist; ilp != NULL; ilp = ilp->ilp_next) {
1628 if (strcmp(msg->icrl_lu_provider_name,
1629 ilp->ilp_lp->lp_name) == 0) {
1630 lp = ilp->ilp_lp;
1631 mutex_exit(&stmf_state.stmf_lock);
1632 lp->lp_proxy_msg(msg->icrl_lun_id, NULL, 0,
1633 STMF_MSG_LU_DEREGISTER);
1634 return (STMF_SUCCESS);
1635 }
1636 }
1637 mutex_exit(&stmf_state.stmf_lock);
1638 return (STMF_SUCCESS);
1639 }
1640
1641 /*
1642 * helper function to find a task that matches a task_msgid
1643 */
1644 scsi_task_t *
1645 find_task_from_msgid(uint8_t *lu_id, stmf_ic_msgid_t task_msgid)
1646 {
1647 stmf_i_lu_t *ilu;
1648 stmf_i_scsi_task_t *itask;
1649
1650 mutex_enter(&stmf_state.stmf_lock);
1651 for (ilu = stmf_state.stmf_ilulist; ilu != NULL; ilu = ilu->ilu_next) {
1652 if (bcmp(lu_id, ilu->ilu_lu->lu_id->ident, 16) == 0) {
1653 break;
1654 }
1655 }
1656
1657 if (ilu == NULL) {
1658 mutex_exit(&stmf_state.stmf_lock);
1659 return (NULL);
1660 }
1661
1662 mutex_enter(&ilu->ilu_task_lock);
1663 for (itask = ilu->ilu_tasks; itask != NULL;
1664 itask = itask->itask_lu_next) {
1665 if (itask->itask_flags & (ITASK_IN_FREE_LIST |
1666 ITASK_BEING_ABORTED)) {
1667 continue;
1668 }
1669 if (itask->itask_proxy_msg_id == task_msgid) {
1670 break;
1671 }
1672 }
1673 mutex_exit(&ilu->ilu_task_lock);
1674 mutex_exit(&stmf_state.stmf_lock);
1675
1676 if (itask != NULL) {
1677 return (itask->itask_task);
1678 } else {
1679 /* task not found. Likely already aborted. */
1680 return (NULL);
1681 }
1682 }
1683
1684 /*
1685 * message received from pppt/ic
1686 */
1687 stmf_status_t
1688 stmf_msg_rx(stmf_ic_msg_t *msg)
1689 {
1690 mutex_enter(&stmf_state.stmf_lock);
1691 if (stmf_state.stmf_alua_state != 1) {
1692 mutex_exit(&stmf_state.stmf_lock);
1693 cmn_err(CE_WARN, "stmf alua state is disabled");
1694 ic_msg_free(msg);
1695 return (STMF_FAILURE);
1696 }
1697 mutex_exit(&stmf_state.stmf_lock);
1698
1699 switch (msg->icm_msg_type) {
1700 case STMF_ICM_REGISTER_LUN:
1701 (void) stmf_ic_lu_reg(
1702 (stmf_ic_reg_dereg_lun_msg_t *)msg->icm_msg,
1703 STMF_MSG_LU_REGISTER);
1704 break;
1705 case STMF_ICM_LUN_ACTIVE:
1706 (void) stmf_ic_lu_reg(
1707 (stmf_ic_reg_dereg_lun_msg_t *)msg->icm_msg,
1708 STMF_MSG_LU_ACTIVE);
1709 break;
1710 case STMF_ICM_DEREGISTER_LUN:
1711 (void) stmf_ic_lu_dereg(
1712 (stmf_ic_reg_dereg_lun_msg_t *)msg->icm_msg);
1713 break;
1714 case STMF_ICM_SCSI_DATA:
1715 (void) stmf_ic_rx_scsi_data(
1716 (stmf_ic_scsi_data_msg_t *)msg->icm_msg);
1717 break;
1718 case STMF_ICM_SCSI_STATUS:
1719 (void) stmf_ic_rx_scsi_status(
1720 (stmf_ic_scsi_status_msg_t *)msg->icm_msg);
1721 break;
1722 case STMF_ICM_STATUS:
1723 (void) stmf_ic_rx_status(
1724 (stmf_ic_status_msg_t *)msg->icm_msg);
1725 break;
1726 default:
1727 cmn_err(CE_WARN, "unknown message received %d",
1728 msg->icm_msg_type);
1729 ic_msg_free(msg);
1730 return (STMF_FAILURE);
1731 }
1732 ic_msg_free(msg);
1733 return (STMF_SUCCESS);
1734 }
1735
1736 stmf_status_t
1737 stmf_ic_rx_status(stmf_ic_status_msg_t *msg)
1738 {
1739 stmf_i_local_port_t *ilport;
1740
1741 if (msg->ics_msg_type != STMF_ICM_REGISTER_PROXY_PORT) {
1742 /* for now, ignore other message status */
1743 return (STMF_SUCCESS);
1744 }
1745
1746 if (msg->ics_status != STMF_SUCCESS) {
1747 return (STMF_SUCCESS);
1748 }
1749
1750 mutex_enter(&stmf_state.stmf_lock);
1751 for (ilport = stmf_state.stmf_ilportlist; ilport != NULL;
1752 ilport = ilport->ilport_next) {
1753 if (msg->ics_msgid == ilport->ilport_reg_msgid) {
1754 ilport->ilport_proxy_registered = 1;
1755 break;
1756 }
1757 }
1758 mutex_exit(&stmf_state.stmf_lock);
1759 return (STMF_SUCCESS);
1760 }
1761
1762 /*
1763 * handles scsi status message from pppt
1764 */
1765 stmf_status_t
1766 stmf_ic_rx_scsi_status(stmf_ic_scsi_status_msg_t *msg)
1767 {
1768 scsi_task_t *task;
1769
1770 /* is this a task management command */
1771 if (msg->icss_task_msgid & MSG_ID_TM_BIT) {
1772 return (STMF_SUCCESS);
1773 }
1774
1775 task = find_task_from_msgid(msg->icss_lun_id, msg->icss_task_msgid);
1776
1777 if (task == NULL) {
1778 return (STMF_SUCCESS);
1779 }
1780
1781 task->task_scsi_status = msg->icss_status;
1782 task->task_sense_data = msg->icss_sense;
1783 task->task_sense_length = msg->icss_sense_len;
1784 (void) stmf_send_scsi_status(task, STMF_IOF_LU_DONE);
1785
1786 return (STMF_SUCCESS);
1787 }
1788
1789 /*
1790 * handles scsi data message from pppt
1791 */
1792 stmf_status_t
1793 stmf_ic_rx_scsi_data(stmf_ic_scsi_data_msg_t *msg)
1794 {
1795 stmf_i_scsi_task_t *itask;
1796 scsi_task_t *task;
1797 stmf_xfer_data_t *xd = NULL;
1798 stmf_data_buf_t *dbuf;
1799 uint32_t sz, minsz, xd_sz, asz;
1800
1801 /* is this a task management command */
1802 if (msg->icsd_task_msgid & MSG_ID_TM_BIT) {
1803 return (STMF_SUCCESS);
1804 }
1805
1806 task = find_task_from_msgid(msg->icsd_lun_id, msg->icsd_task_msgid);
1807 if (task == NULL) {
1808 stmf_ic_msg_t *ic_xfer_done_msg = NULL;
1809 static uint64_t data_msg_id;
1810 stmf_status_t ic_ret = STMF_FAILURE;
1811 mutex_enter(&stmf_state.stmf_lock);
1812 data_msg_id = stmf_proxy_msg_id++;
1813 mutex_exit(&stmf_state.stmf_lock);
1814 /*
1815 * send xfer done status to pppt
1816 * for now, set the session id to 0 as we cannot
1817 * ascertain it since we cannot find the task
1818 */
1819 ic_xfer_done_msg = ic_scsi_data_xfer_done_msg_alloc(
1820 msg->icsd_task_msgid, 0, STMF_FAILURE, data_msg_id);
1821 if (ic_xfer_done_msg) {
1822 ic_ret = ic_tx_msg(ic_xfer_done_msg);
1823 if (ic_ret != STMF_IC_MSG_SUCCESS) {
1824 cmn_err(CE_WARN, "unable to xmit proxy msg");
1825 }
1826 }
1827 return (STMF_FAILURE);
1828 }
1829
1830 itask = (stmf_i_scsi_task_t *)task->task_stmf_private;
1831 dbuf = itask->itask_proxy_dbuf;
1832
1833 task->task_cmd_xfer_length += msg->icsd_data_len;
1834
1835 if (task->task_additional_flags &
1836 TASK_AF_NO_EXPECTED_XFER_LENGTH) {
1837 task->task_expected_xfer_length =
1838 task->task_cmd_xfer_length;
1839 }
1840
1841 sz = min(task->task_expected_xfer_length,
1842 task->task_cmd_xfer_length);
1843
1844 xd_sz = msg->icsd_data_len;
1845 asz = xd_sz + sizeof (*xd) - 4;
1846 xd = (stmf_xfer_data_t *)kmem_zalloc(asz, KM_NOSLEEP);
1847
1848 if (xd == NULL) {
1849 stmf_abort(STMF_QUEUE_TASK_ABORT, task,
1850 STMF_ALLOC_FAILURE, NULL);
1851 return (STMF_FAILURE);
1852 }
1853
1854 xd->alloc_size = asz;
1855 xd->size_left = xd_sz;
1856 bcopy(msg->icsd_data, xd->buf, xd_sz);
1857
1858 sz = min(sz, xd->size_left);
1859 xd->size_left = sz;
1860 minsz = min(512, sz);
1861
1862 if (dbuf == NULL)
1863 dbuf = stmf_alloc_dbuf(task, sz, &minsz, 0);
1864 if (dbuf == NULL) {
1865 kmem_free(xd, xd->alloc_size);
1866 stmf_abort(STMF_QUEUE_TASK_ABORT, task,
1867 STMF_ALLOC_FAILURE, NULL);
1868 return (STMF_FAILURE);
1869 }
1870 dbuf->db_lu_private = xd;
1871 dbuf->db_relative_offset = task->task_nbytes_transferred;
1872 stmf_xd_to_dbuf(dbuf, 0);
1873
1874 dbuf->db_flags = DB_DIRECTION_TO_RPORT;
1875 (void) stmf_xfer_data(task, dbuf, 0);
1876 return (STMF_SUCCESS);
1877 }
1878
1879 stmf_status_t
1880 stmf_proxy_scsi_cmd(scsi_task_t *task, stmf_data_buf_t *dbuf)
1881 {
1882 stmf_i_scsi_task_t *itask =
1883 (stmf_i_scsi_task_t *)task->task_stmf_private;
1884 stmf_i_local_port_t *ilport =
1885 (stmf_i_local_port_t *)task->task_lport->lport_stmf_private;
1886 stmf_ic_msg_t *ic_cmd_msg;
1887 stmf_ic_msg_status_t ic_ret;
1888 stmf_status_t ret = STMF_FAILURE;
1889
1890 if (stmf_state.stmf_alua_state != 1) {
1891 cmn_err(CE_WARN, "stmf alua state is disabled");
1892 return (STMF_FAILURE);
1893 }
1894
1895 if (ilport->ilport_proxy_registered == 0) {
1896 return (STMF_FAILURE);
1897 }
1898
1899 mutex_enter(&stmf_state.stmf_lock);
1900 itask->itask_proxy_msg_id = stmf_proxy_msg_id++;
1901 mutex_exit(&stmf_state.stmf_lock);
1902 itask->itask_proxy_dbuf = dbuf;
1903
1904 /*
1905 * stmf will now take over the task handling for this task
1906 * but it still needs to be treated differently from other
1907 * default handled tasks, hence the ITASK_PROXY_TASK.
1908 * If this is a task management function, we're really just
1909 * duping the command to the peer. Set the TM bit so that
1910 * we can recognize this on return since we won't be completing
1911 * the proxied task in that case.
1912 */
1913 if (task->task_mgmt_function) {
1914 itask->itask_proxy_msg_id |= MSG_ID_TM_BIT;
1915 } else {
1916 uint32_t new, old;
1917 do {
1918 new = old = itask->itask_flags;
1919 if (new & ITASK_BEING_ABORTED)
1920 return (STMF_FAILURE);
1921 new |= ITASK_DEFAULT_HANDLING | ITASK_PROXY_TASK;
1922 } while (atomic_cas_32(&itask->itask_flags, old, new) != old);
1923 }
1924 if (dbuf) {
1925 ic_cmd_msg = ic_scsi_cmd_msg_alloc(itask->itask_proxy_msg_id,
1926 task, dbuf->db_data_size, dbuf->db_sglist[0].seg_addr,
1927 itask->itask_proxy_msg_id);
1928 } else {
1929 ic_cmd_msg = ic_scsi_cmd_msg_alloc(itask->itask_proxy_msg_id,
1930 task, 0, NULL, itask->itask_proxy_msg_id);
1931 }
1932 if (ic_cmd_msg) {
1933 ic_ret = ic_tx_msg(ic_cmd_msg);
1934 if (ic_ret == STMF_IC_MSG_SUCCESS) {
1935 ret = STMF_SUCCESS;
1936 }
1937 }
1938 return (ret);
1939 }
1940
1941
1942 stmf_status_t
1943 pppt_modload()
1944 {
1945 int error;
1946
1947 if (pppt_mod == NULL && ((pppt_mod =
1948 ddi_modopen("drv/pppt", KRTLD_MODE_FIRST, &error)) == NULL)) {
1949 cmn_err(CE_WARN, "Unable to load pppt");
1950 return (STMF_FAILURE);
1951 }
1952
1953 if (ic_reg_port_msg_alloc == NULL && ((ic_reg_port_msg_alloc =
1954 (stmf_ic_reg_port_msg_alloc_func_t)
1955 ddi_modsym(pppt_mod, "stmf_ic_reg_port_msg_alloc",
1956 &error)) == NULL)) {
1957 cmn_err(CE_WARN,
1958 "Unable to find symbol - stmf_ic_reg_port_msg_alloc");
1959 return (STMF_FAILURE);
1960 }
1961
1962
1963 if (ic_dereg_port_msg_alloc == NULL && ((ic_dereg_port_msg_alloc =
1964 (stmf_ic_dereg_port_msg_alloc_func_t)
1965 ddi_modsym(pppt_mod, "stmf_ic_dereg_port_msg_alloc",
1966 &error)) == NULL)) {
1967 cmn_err(CE_WARN,
1968 "Unable to find symbol - stmf_ic_dereg_port_msg_alloc");
1969 return (STMF_FAILURE);
1970 }
1971
1972 if (ic_reg_lun_msg_alloc == NULL && ((ic_reg_lun_msg_alloc =
1973 (stmf_ic_reg_lun_msg_alloc_func_t)
1974 ddi_modsym(pppt_mod, "stmf_ic_reg_lun_msg_alloc",
1975 &error)) == NULL)) {
1976 cmn_err(CE_WARN,
1977 "Unable to find symbol - stmf_ic_reg_lun_msg_alloc");
1978 return (STMF_FAILURE);
1979 }
1980
1981 if (ic_lun_active_msg_alloc == NULL && ((ic_lun_active_msg_alloc =
1982 (stmf_ic_lun_active_msg_alloc_func_t)
1983 ddi_modsym(pppt_mod, "stmf_ic_lun_active_msg_alloc",
1984 &error)) == NULL)) {
1985 cmn_err(CE_WARN,
1986 "Unable to find symbol - stmf_ic_lun_active_msg_alloc");
1987 return (STMF_FAILURE);
1988 }
1989
1990 if (ic_dereg_lun_msg_alloc == NULL && ((ic_dereg_lun_msg_alloc =
1991 (stmf_ic_dereg_lun_msg_alloc_func_t)
1992 ddi_modsym(pppt_mod, "stmf_ic_dereg_lun_msg_alloc",
1993 &error)) == NULL)) {
1994 cmn_err(CE_WARN,
1995 "Unable to find symbol - stmf_ic_dereg_lun_msg_alloc");
1996 return (STMF_FAILURE);
1997 }
1998
1999 if (ic_scsi_cmd_msg_alloc == NULL && ((ic_scsi_cmd_msg_alloc =
2000 (stmf_ic_scsi_cmd_msg_alloc_func_t)
2001 ddi_modsym(pppt_mod, "stmf_ic_scsi_cmd_msg_alloc",
2002 &error)) == NULL)) {
2003 cmn_err(CE_WARN,
2004 "Unable to find symbol - stmf_ic_scsi_cmd_msg_alloc");
2005 return (STMF_FAILURE);
2006 }
2007
2008 if (ic_scsi_data_xfer_done_msg_alloc == NULL &&
2009 ((ic_scsi_data_xfer_done_msg_alloc =
2010 (stmf_ic_scsi_data_xfer_done_msg_alloc_func_t)
2011 ddi_modsym(pppt_mod, "stmf_ic_scsi_data_xfer_done_msg_alloc",
2012 &error)) == NULL)) {
2013 cmn_err(CE_WARN,
2014 "Unable to find symbol -"
2015 "stmf_ic_scsi_data_xfer_done_msg_alloc");
2016 return (STMF_FAILURE);
2017 }
2018
2019 if (ic_session_reg_msg_alloc == NULL &&
2020 ((ic_session_reg_msg_alloc =
2021 (stmf_ic_session_create_msg_alloc_func_t)
2022 ddi_modsym(pppt_mod, "stmf_ic_session_create_msg_alloc",
2023 &error)) == NULL)) {
2024 cmn_err(CE_WARN,
2025 "Unable to find symbol -"
2026 "stmf_ic_session_create_msg_alloc");
2027 return (STMF_FAILURE);
2028 }
2029
2030 if (ic_session_dereg_msg_alloc == NULL &&
2031 ((ic_session_dereg_msg_alloc =
2032 (stmf_ic_session_destroy_msg_alloc_func_t)
2033 ddi_modsym(pppt_mod, "stmf_ic_session_destroy_msg_alloc",
2034 &error)) == NULL)) {
2035 cmn_err(CE_WARN,
2036 "Unable to find symbol -"
2037 "stmf_ic_session_destroy_msg_alloc");
2038 return (STMF_FAILURE);
2039 }
2040
2041 if (ic_tx_msg == NULL && ((ic_tx_msg =
2042 (stmf_ic_tx_msg_func_t)ddi_modsym(pppt_mod, "stmf_ic_tx_msg",
2043 &error)) == NULL)) {
2044 cmn_err(CE_WARN, "Unable to find symbol - stmf_ic_tx_msg");
2045 return (STMF_FAILURE);
2046 }
2047
2048 if (ic_msg_free == NULL && ((ic_msg_free =
2049 (stmf_ic_msg_free_func_t)ddi_modsym(pppt_mod, "stmf_ic_msg_free",
2050 &error)) == NULL)) {
2051 cmn_err(CE_WARN, "Unable to find symbol - stmf_ic_msg_free");
2052 return (STMF_FAILURE);
2053 }
2054 return (STMF_SUCCESS);
2055 }
2056
2057 static void
2058 stmf_get_alua_state(stmf_alua_state_desc_t *alua_state)
2059 {
2060 mutex_enter(&stmf_state.stmf_lock);
2061 alua_state->alua_node = stmf_state.stmf_alua_node;
2062 alua_state->alua_state = stmf_state.stmf_alua_state;
2063 mutex_exit(&stmf_state.stmf_lock);
2064 }
2065
2066
2067 static int
2068 stmf_set_alua_state(stmf_alua_state_desc_t *alua_state)
2069 {
2070 stmf_i_local_port_t *ilport;
2071 stmf_i_lu_t *ilu;
2072 stmf_lu_t *lu;
2073 stmf_ic_msg_status_t ic_ret;
2074 stmf_ic_msg_t *ic_reg_lun, *ic_reg_port;
2075 stmf_local_port_t *lport;
2076 int ret = 0;
2077
2078 if (alua_state->alua_state > 1 || alua_state->alua_node > 1) {
2079 return (EINVAL);
2080 }
2081
2082 mutex_enter(&stmf_state.stmf_lock);
2083 if (alua_state->alua_state == 1) {
2084 if (pppt_modload() == STMF_FAILURE) {
2085 ret = EIO;
2086 goto err;
2087 }
2088 if (alua_state->alua_node != 0) {
2089 /* reset existing rtpids to new base */
2090 stmf_rtpid_counter = 255;
2091 }
2092 stmf_state.stmf_alua_node = alua_state->alua_node;
2093 stmf_state.stmf_alua_state = 1;
2094 /* register existing local ports with ppp */
2095 for (ilport = stmf_state.stmf_ilportlist; ilport != NULL;
2096 ilport = ilport->ilport_next) {
2097 /* skip standby ports and non-alua participants */
2098 if (ilport->ilport_standby == 1 ||
2099 ilport->ilport_alua == 0) {
2100 continue;
2101 }
2102 if (alua_state->alua_node != 0) {
2103 ilport->ilport_rtpid =
2104 atomic_add_16_nv(&stmf_rtpid_counter, 1);
2105 }
2106 lport = ilport->ilport_lport;
2107 ic_reg_port = ic_reg_port_msg_alloc(
2108 lport->lport_id, ilport->ilport_rtpid,
2109 0, NULL, stmf_proxy_msg_id);
2110 if (ic_reg_port) {
2111 ic_ret = ic_tx_msg(ic_reg_port);
2112 if (ic_ret == STMF_IC_MSG_SUCCESS) {
2113 ilport->ilport_reg_msgid =
2114 stmf_proxy_msg_id++;
2115 } else {
2116 cmn_err(CE_WARN,
2117 "error on port registration "
2118 "port - %s",
2119 ilport->ilport_kstat_tgt_name);
2120 }
2121 }
2122 }
2123 /* register existing logical units */
2124 for (ilu = stmf_state.stmf_ilulist; ilu != NULL;
2125 ilu = ilu->ilu_next) {
2126 if (ilu->ilu_access != STMF_LU_ACTIVE) {
2127 continue;
2128 }
2129 /* register with proxy module */
2130 lu = ilu->ilu_lu;
2131 if (lu->lu_lp && lu->lu_lp->lp_lpif_rev == LPIF_REV_2 &&
2132 lu->lu_lp->lp_alua_support) {
2133 ilu->ilu_alua = 1;
2134 /* allocate the register message */
2135 ic_reg_lun = ic_reg_lun_msg_alloc(
2136 lu->lu_id->ident, lu->lu_lp->lp_name,
2137 lu->lu_proxy_reg_arg_len,
2138 (uint8_t *)lu->lu_proxy_reg_arg,
2139 stmf_proxy_msg_id);
2140 /* send the message */
2141 if (ic_reg_lun) {
2142 ic_ret = ic_tx_msg(ic_reg_lun);
2143 if (ic_ret == STMF_IC_MSG_SUCCESS) {
2144 stmf_proxy_msg_id++;
2145 }
2146 }
2147 }
2148 }
2149 } else {
2150 stmf_state.stmf_alua_state = 0;
2151 }
2152
2153 err:
2154 mutex_exit(&stmf_state.stmf_lock);
2155 return (ret);
2156 }
2157
2158
2159 typedef struct {
2160 void *bp; /* back pointer from internal struct to main struct */
2161 int alloc_size;
2162 } __istmf_t;
2163
2164 typedef struct {
2165 __istmf_t *fp; /* Framework private */
2166 void *cp; /* Caller private */
2167 void *ss; /* struct specific */
2168 } __stmf_t;
2169
2170 static struct {
2171 int shared;
2172 int fw_private;
2173 } stmf_sizes[] = { { 0, 0 },
2174 { GET_STRUCT_SIZE(stmf_lu_provider_t),
2175 GET_STRUCT_SIZE(stmf_i_lu_provider_t) },
2176 { GET_STRUCT_SIZE(stmf_port_provider_t),
2177 GET_STRUCT_SIZE(stmf_i_port_provider_t) },
2178 { GET_STRUCT_SIZE(stmf_local_port_t),
2179 GET_STRUCT_SIZE(stmf_i_local_port_t) },
2180 { GET_STRUCT_SIZE(stmf_lu_t),
2181 GET_STRUCT_SIZE(stmf_i_lu_t) },
2182 { GET_STRUCT_SIZE(stmf_scsi_session_t),
2183 GET_STRUCT_SIZE(stmf_i_scsi_session_t) },
2184 { GET_STRUCT_SIZE(scsi_task_t),
2185 GET_STRUCT_SIZE(stmf_i_scsi_task_t) },
2186 { GET_STRUCT_SIZE(stmf_data_buf_t),
2187 GET_STRUCT_SIZE(__istmf_t) },
2188 { GET_STRUCT_SIZE(stmf_dbuf_store_t),
2189 GET_STRUCT_SIZE(__istmf_t) }
2190
2191 };
2192
2193 void *
2194 stmf_alloc(stmf_struct_id_t struct_id, int additional_size, int flags)
2195 {
2196 int stmf_size;
2197 int kmem_flag;
2198 __stmf_t *sh;
2199
2200 if ((struct_id == 0) || (struct_id >= STMF_MAX_STRUCT_IDS))
2201 return (NULL);
2202
2203 if ((curthread->t_flag & T_INTR_THREAD) || (flags & AF_FORCE_NOSLEEP)) {
2204 kmem_flag = KM_NOSLEEP;
2205 } else {
2206 kmem_flag = KM_SLEEP;
2207 }
2208
2209 additional_size = (additional_size + 7) & (~7);
2210 stmf_size = stmf_sizes[struct_id].shared +
2211 stmf_sizes[struct_id].fw_private + additional_size;
2212
2213 if (flags & AF_DONTZERO)
2214 sh = (__stmf_t *)kmem_alloc(stmf_size, kmem_flag);
2215 else
2216 sh = (__stmf_t *)kmem_zalloc(stmf_size, kmem_flag);
2217
2218 if (sh == NULL)
2219 return (NULL);
2220
2221 /*
2222 * In principle, the implementation inside stmf_alloc should not
2223 * be changed anyway. But the original order of framework private
2224 * data and caller private data does not support sglist in the caller
2225 * private data.
2226 * To work around this, the memory segments of framework private
2227 * data and caller private data are re-ordered here.
2228 * A better solution is to provide a specific interface to allocate
2229 * the sglist, then we will not need this workaround any more.
2230 * But before the new interface is available, the memory segment
2231 * ordering should be kept as is.
2232 */
2233 sh->cp = GET_BYTE_OFFSET(sh, stmf_sizes[struct_id].shared);
2234 sh->fp = (__istmf_t *)GET_BYTE_OFFSET(sh,
2235 stmf_sizes[struct_id].shared + additional_size);
2236
2237 sh->fp->bp = sh;
2238 /* Just store the total size instead of storing additional size */
2239 sh->fp->alloc_size = stmf_size;
2240
2241 return (sh);
2242 }
2243
2244 void
2245 stmf_free(void *ptr)
2246 {
2247 __stmf_t *sh = (__stmf_t *)ptr;
2248
2249 /*
2250 * So far we dont need any struct specific processing. If such
2251 * a need ever arises, then store the struct id in the framework
2252 * private section and get it here as sh->fp->struct_id.
2253 */
2254 kmem_free(ptr, sh->fp->alloc_size);
2255 }
2256
2257 /*
2258 * Given a pointer to stmf_lu_t, verifies if this lu is registered with the
2259 * framework and returns a pointer to framework private data for the lu.
2260 * Returns NULL if the lu was not found.
2261 */
2262 stmf_i_lu_t *
2263 stmf_lookup_lu(stmf_lu_t *lu)
2264 {
2265 stmf_i_lu_t *ilu;
2266 ASSERT(mutex_owned(&stmf_state.stmf_lock));
2267
2268 for (ilu = stmf_state.stmf_ilulist; ilu != NULL; ilu = ilu->ilu_next) {
2269 if (ilu->ilu_lu == lu)
2270 return (ilu);
2271 }
2272 return (NULL);
2273 }
2274
2275 /*
2276 * Given a pointer to stmf_local_port_t, verifies if this lport is registered
2277 * with the framework and returns a pointer to framework private data for
2278 * the lport.
2279 * Returns NULL if the lport was not found.
2280 */
2281 stmf_i_local_port_t *
2282 stmf_lookup_lport(stmf_local_port_t *lport)
2283 {
2284 stmf_i_local_port_t *ilport;
2285 ASSERT(mutex_owned(&stmf_state.stmf_lock));
2286
2287 for (ilport = stmf_state.stmf_ilportlist; ilport != NULL;
2288 ilport = ilport->ilport_next) {
2289 if (ilport->ilport_lport == lport)
2290 return (ilport);
2291 }
2292 return (NULL);
2293 }
2294
2295 stmf_status_t
2296 stmf_register_lu_provider(stmf_lu_provider_t *lp)
2297 {
2298 stmf_i_lu_provider_t *ilp = (stmf_i_lu_provider_t *)lp->lp_stmf_private;
2299 stmf_pp_data_t *ppd;
2300 uint32_t cb_flags;
2301
2302 if (lp->lp_lpif_rev != LPIF_REV_1 && lp->lp_lpif_rev != LPIF_REV_2)
2303 return (STMF_FAILURE);
2304
2305 mutex_enter(&stmf_state.stmf_lock);
2306 ilp->ilp_next = stmf_state.stmf_ilplist;
2307 stmf_state.stmf_ilplist = ilp;
2308 stmf_state.stmf_nlps++;
2309
2310 /* See if we need to do a callback */
2311 for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = ppd->ppd_next) {
2312 if (strcmp(ppd->ppd_name, lp->lp_name) == 0) {
2313 break;
2314 }
2315 }
2316 if ((ppd == NULL) || (ppd->ppd_nv == NULL)) {
2317 goto rlp_bail_out;
2318 }
2319 ilp->ilp_ppd = ppd;
2320 ppd->ppd_provider = ilp;
2321 if (lp->lp_cb == NULL)
2322 goto rlp_bail_out;
2323 ilp->ilp_cb_in_progress = 1;
2324 cb_flags = STMF_PCB_PREG_COMPLETE;
2325 if (stmf_state.stmf_config_state == STMF_CONFIG_INIT)
2326 cb_flags |= STMF_PCB_STMF_ONLINING;
2327 mutex_exit(&stmf_state.stmf_lock);
2328 lp->lp_cb(lp, STMF_PROVIDER_DATA_UPDATED, ppd->ppd_nv, cb_flags);
2329 mutex_enter(&stmf_state.stmf_lock);
2330 ilp->ilp_cb_in_progress = 0;
2331
2332 rlp_bail_out:
2333 mutex_exit(&stmf_state.stmf_lock);
2334
2335 return (STMF_SUCCESS);
2336 }
2337
2338 stmf_status_t
2339 stmf_deregister_lu_provider(stmf_lu_provider_t *lp)
2340 {
2341 stmf_i_lu_provider_t **ppilp;
2342 stmf_i_lu_provider_t *ilp = (stmf_i_lu_provider_t *)lp->lp_stmf_private;
2343
2344 mutex_enter(&stmf_state.stmf_lock);
2345 if (ilp->ilp_nlus || ilp->ilp_cb_in_progress) {
2346 mutex_exit(&stmf_state.stmf_lock);
2347 return (STMF_BUSY);
2348 }
2349 for (ppilp = &stmf_state.stmf_ilplist; *ppilp != NULL;
2350 ppilp = &((*ppilp)->ilp_next)) {
2351 if (*ppilp == ilp) {
2352 *ppilp = ilp->ilp_next;
2353 stmf_state.stmf_nlps--;
2354 if (ilp->ilp_ppd) {
2355 ilp->ilp_ppd->ppd_provider = NULL;
2356 ilp->ilp_ppd = NULL;
2357 }
2358 mutex_exit(&stmf_state.stmf_lock);
2359 return (STMF_SUCCESS);
2360 }
2361 }
2362 mutex_exit(&stmf_state.stmf_lock);
2363 return (STMF_NOT_FOUND);
2364 }
2365
2366 stmf_status_t
2367 stmf_register_port_provider(stmf_port_provider_t *pp)
2368 {
2369 stmf_i_port_provider_t *ipp =
2370 (stmf_i_port_provider_t *)pp->pp_stmf_private;
2371 stmf_pp_data_t *ppd;
2372 uint32_t cb_flags;
2373
2374 if (pp->pp_portif_rev != PORTIF_REV_1)
2375 return (STMF_FAILURE);
2376
2377 mutex_enter(&stmf_state.stmf_lock);
2378 ipp->ipp_next = stmf_state.stmf_ipplist;
2379 stmf_state.stmf_ipplist = ipp;
2380 stmf_state.stmf_npps++;
2381 /* See if we need to do a callback */
2382 for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = ppd->ppd_next) {
2383 if (strcmp(ppd->ppd_name, pp->pp_name) == 0) {
2384 break;
2385 }
2386 }
2387 if ((ppd == NULL) || (ppd->ppd_nv == NULL)) {
2388 goto rpp_bail_out;
2389 }
2390 ipp->ipp_ppd = ppd;
2391 ppd->ppd_provider = ipp;
2392 if (pp->pp_cb == NULL)
2393 goto rpp_bail_out;
2394 ipp->ipp_cb_in_progress = 1;
2395 cb_flags = STMF_PCB_PREG_COMPLETE;
2396 if (stmf_state.stmf_config_state == STMF_CONFIG_INIT)
2397 cb_flags |= STMF_PCB_STMF_ONLINING;
2398 mutex_exit(&stmf_state.stmf_lock);
2399 pp->pp_cb(pp, STMF_PROVIDER_DATA_UPDATED, ppd->ppd_nv, cb_flags);
2400 mutex_enter(&stmf_state.stmf_lock);
2401 ipp->ipp_cb_in_progress = 0;
2402
2403 rpp_bail_out:
2404 mutex_exit(&stmf_state.stmf_lock);
2405
2406 return (STMF_SUCCESS);
2407 }
2408
2409 stmf_status_t
2410 stmf_deregister_port_provider(stmf_port_provider_t *pp)
2411 {
2412 stmf_i_port_provider_t *ipp =
2413 (stmf_i_port_provider_t *)pp->pp_stmf_private;
2414 stmf_i_port_provider_t **ppipp;
2415
2416 mutex_enter(&stmf_state.stmf_lock);
2417 if (ipp->ipp_npps || ipp->ipp_cb_in_progress) {
2418 mutex_exit(&stmf_state.stmf_lock);
2419 return (STMF_BUSY);
2420 }
2421 for (ppipp = &stmf_state.stmf_ipplist; *ppipp != NULL;
2422 ppipp = &((*ppipp)->ipp_next)) {
2423 if (*ppipp == ipp) {
2424 *ppipp = ipp->ipp_next;
2425 stmf_state.stmf_npps--;
2426 if (ipp->ipp_ppd) {
2427 ipp->ipp_ppd->ppd_provider = NULL;
2428 ipp->ipp_ppd = NULL;
2429 }
2430 mutex_exit(&stmf_state.stmf_lock);
2431 return (STMF_SUCCESS);
2432 }
2433 }
2434 mutex_exit(&stmf_state.stmf_lock);
2435 return (STMF_NOT_FOUND);
2436 }
2437
2438 int
2439 stmf_load_ppd_ioctl(stmf_ppioctl_data_t *ppi, uint64_t *ppi_token,
2440 uint32_t *err_ret)
2441 {
2442 stmf_i_port_provider_t *ipp;
2443 stmf_i_lu_provider_t *ilp;
2444 stmf_pp_data_t *ppd;
2445 nvlist_t *nv;
2446 int s;
2447 int ret;
2448
2449 *err_ret = 0;
2450
2451 if ((ppi->ppi_lu_provider + ppi->ppi_port_provider) != 1) {
2452 return (EINVAL);
2453 }
2454
2455 mutex_enter(&stmf_state.stmf_lock);
2456 for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = ppd->ppd_next) {
2457 if (ppi->ppi_lu_provider) {
2458 if (!ppd->ppd_lu_provider)
2459 continue;
2460 } else if (ppi->ppi_port_provider) {
2461 if (!ppd->ppd_port_provider)
2462 continue;
2463 }
2464 if (strncmp(ppi->ppi_name, ppd->ppd_name, 254) == 0)
2465 break;
2466 }
2467
2468 if (ppd == NULL) {
2469 /* New provider */
2470 s = strlen(ppi->ppi_name);
2471 if (s > 254) {
2472 mutex_exit(&stmf_state.stmf_lock);
2473 return (EINVAL);
2474 }
2475 s += sizeof (stmf_pp_data_t) - 7;
2476
2477 ppd = kmem_zalloc(s, KM_NOSLEEP);
2478 if (ppd == NULL) {
2479 mutex_exit(&stmf_state.stmf_lock);
2480 return (ENOMEM);
2481 }
2482 ppd->ppd_alloc_size = s;
2483 (void) strcpy(ppd->ppd_name, ppi->ppi_name);
2484
2485 /* See if this provider already exists */
2486 if (ppi->ppi_lu_provider) {
2487 ppd->ppd_lu_provider = 1;
2488 for (ilp = stmf_state.stmf_ilplist; ilp != NULL;
2489 ilp = ilp->ilp_next) {
2490 if (strcmp(ppi->ppi_name,
2491 ilp->ilp_lp->lp_name) == 0) {
2492 ppd->ppd_provider = ilp;
2493 ilp->ilp_ppd = ppd;
2494 break;
2495 }
2496 }
2497 } else {
2498 ppd->ppd_port_provider = 1;
2499 for (ipp = stmf_state.stmf_ipplist; ipp != NULL;
2500 ipp = ipp->ipp_next) {
2501 if (strcmp(ppi->ppi_name,
2502 ipp->ipp_pp->pp_name) == 0) {
2503 ppd->ppd_provider = ipp;
2504 ipp->ipp_ppd = ppd;
2505 break;
2506 }
2507 }
2508 }
2509
2510 /* Link this ppd in */
2511 ppd->ppd_next = stmf_state.stmf_ppdlist;
2512 stmf_state.stmf_ppdlist = ppd;
2513 }
2514
2515 /*
2516 * User is requesting that the token be checked.
2517 * If there was another set after the user's get
2518 * it's an error
2519 */
2520 if (ppi->ppi_token_valid) {
2521 if (ppi->ppi_token != ppd->ppd_token) {
2522 *err_ret = STMF_IOCERR_PPD_UPDATED;
2523 mutex_exit(&stmf_state.stmf_lock);
2524 return (EINVAL);
2525 }
2526 }
2527
2528 if ((ret = nvlist_unpack((char *)ppi->ppi_data,
2529 (size_t)ppi->ppi_data_size, &nv, KM_NOSLEEP)) != 0) {
2530 mutex_exit(&stmf_state.stmf_lock);
2531 return (ret);
2532 }
2533
2534 /* Free any existing lists and add this one to the ppd */
2535 if (ppd->ppd_nv)
2536 nvlist_free(ppd->ppd_nv);
2537 ppd->ppd_nv = nv;
2538
2539 /* set the token for writes */
2540 ppd->ppd_token++;
2541 /* return token to caller */
2542 if (ppi_token) {
2543 *ppi_token = ppd->ppd_token;
2544 }
2545
2546 /* If there is a provider registered, do the notifications */
2547 if (ppd->ppd_provider) {
2548 uint32_t cb_flags = 0;
2549
2550 if (stmf_state.stmf_config_state == STMF_CONFIG_INIT)
2551 cb_flags |= STMF_PCB_STMF_ONLINING;
2552 if (ppi->ppi_lu_provider) {
2553 ilp = (stmf_i_lu_provider_t *)ppd->ppd_provider;
2554 if (ilp->ilp_lp->lp_cb == NULL)
2555 goto bail_out;
2556 ilp->ilp_cb_in_progress = 1;
2557 mutex_exit(&stmf_state.stmf_lock);
2558 ilp->ilp_lp->lp_cb(ilp->ilp_lp,
2559 STMF_PROVIDER_DATA_UPDATED, ppd->ppd_nv, cb_flags);
2560 mutex_enter(&stmf_state.stmf_lock);
2561 ilp->ilp_cb_in_progress = 0;
2562 } else {
2563 ipp = (stmf_i_port_provider_t *)ppd->ppd_provider;
2564 if (ipp->ipp_pp->pp_cb == NULL)
2565 goto bail_out;
2566 ipp->ipp_cb_in_progress = 1;
2567 mutex_exit(&stmf_state.stmf_lock);
2568 ipp->ipp_pp->pp_cb(ipp->ipp_pp,
2569 STMF_PROVIDER_DATA_UPDATED, ppd->ppd_nv, cb_flags);
2570 mutex_enter(&stmf_state.stmf_lock);
2571 ipp->ipp_cb_in_progress = 0;
2572 }
2573 }
2574
2575 bail_out:
2576 mutex_exit(&stmf_state.stmf_lock);
2577
2578 return (0);
2579 }
2580
2581 void
2582 stmf_delete_ppd(stmf_pp_data_t *ppd)
2583 {
2584 stmf_pp_data_t **pppd;
2585
2586 ASSERT(mutex_owned(&stmf_state.stmf_lock));
2587 if (ppd->ppd_provider) {
2588 if (ppd->ppd_lu_provider) {
2589 ((stmf_i_lu_provider_t *)
2590 ppd->ppd_provider)->ilp_ppd = NULL;
2591 } else {
2592 ((stmf_i_port_provider_t *)
2593 ppd->ppd_provider)->ipp_ppd = NULL;
2594 }
2595 ppd->ppd_provider = NULL;
2596 }
2597
2598 for (pppd = &stmf_state.stmf_ppdlist; *pppd != NULL;
2599 pppd = &((*pppd)->ppd_next)) {
2600 if (*pppd == ppd)
2601 break;
2602 }
2603
2604 if (*pppd == NULL)
2605 return;
2606
2607 *pppd = ppd->ppd_next;
2608 if (ppd->ppd_nv)
2609 nvlist_free(ppd->ppd_nv);
2610
2611 kmem_free(ppd, ppd->ppd_alloc_size);
2612 }
2613
2614 int
2615 stmf_delete_ppd_ioctl(stmf_ppioctl_data_t *ppi)
2616 {
2617 stmf_pp_data_t *ppd;
2618 int ret = ENOENT;
2619
2620 if ((ppi->ppi_lu_provider + ppi->ppi_port_provider) != 1) {
2621 return (EINVAL);
2622 }
2623
2624 mutex_enter(&stmf_state.stmf_lock);
2625
2626 for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = ppd->ppd_next) {
2627 if (ppi->ppi_lu_provider) {
2628 if (!ppd->ppd_lu_provider)
2629 continue;
2630 } else if (ppi->ppi_port_provider) {
2631 if (!ppd->ppd_port_provider)
2632 continue;
2633 }
2634 if (strncmp(ppi->ppi_name, ppd->ppd_name, 254) == 0)
2635 break;
2636 }
2637
2638 if (ppd) {
2639 ret = 0;
2640 stmf_delete_ppd(ppd);
2641 }
2642 mutex_exit(&stmf_state.stmf_lock);
2643
2644 return (ret);
2645 }
2646
2647 int
2648 stmf_get_ppd_ioctl(stmf_ppioctl_data_t *ppi, stmf_ppioctl_data_t *ppi_out,
2649 uint32_t *err_ret)
2650 {
2651 stmf_pp_data_t *ppd;
2652 size_t req_size;
2653 int ret = ENOENT;
2654 char *bufp = (char *)ppi_out->ppi_data;
2655
2656 if ((ppi->ppi_lu_provider + ppi->ppi_port_provider) != 1) {
2657 return (EINVAL);
2658 }
2659
2660 mutex_enter(&stmf_state.stmf_lock);
2661
2662 for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = ppd->ppd_next) {
2663 if (ppi->ppi_lu_provider) {
2664 if (!ppd->ppd_lu_provider)
2665 continue;
2666 } else if (ppi->ppi_port_provider) {
2667 if (!ppd->ppd_port_provider)
2668 continue;
2669 }
2670 if (strncmp(ppi->ppi_name, ppd->ppd_name, 254) == 0)
2671 break;
2672 }
2673
2674 if (ppd && ppd->ppd_nv) {
2675 ppi_out->ppi_token = ppd->ppd_token;
2676 if ((ret = nvlist_size(ppd->ppd_nv, &req_size,
2677 NV_ENCODE_XDR)) != 0) {
2678 goto done;
2679 }
2680 ppi_out->ppi_data_size = req_size;
2681 if (req_size > ppi->ppi_data_size) {
2682 *err_ret = STMF_IOCERR_INSUFFICIENT_BUF;
2683 ret = EINVAL;
2684 goto done;
2685 }
2686
2687 if ((ret = nvlist_pack(ppd->ppd_nv, &bufp, &req_size,
2688 NV_ENCODE_XDR, 0)) != 0) {
2689 goto done;
2690 }
2691 ret = 0;
2692 }
2693
2694 done:
2695 mutex_exit(&stmf_state.stmf_lock);
2696
2697 return (ret);
2698 }
2699
2700 void
2701 stmf_delete_all_ppds()
2702 {
2703 stmf_pp_data_t *ppd, *nppd;
2704
2705 ASSERT(mutex_owned(&stmf_state.stmf_lock));
2706 for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = nppd) {
2707 nppd = ppd->ppd_next;
2708 stmf_delete_ppd(ppd);
2709 }
2710 }
2711
2712 /*
2713 * 16 is the max string length of a protocol_ident, increase
2714 * the size if needed.
2715 */
2716 #define STMF_KSTAT_LU_SZ (STMF_GUID_INPUT + 1 + 256)
2717 #define STMF_KSTAT_TGT_SZ (256 * 2 + 16)
2718
2719 /*
2720 * This array matches the Protocol Identifier in stmf_ioctl.h
2721 */
2722 #define MAX_PROTO_STR_LEN 32
2723
2724 char *protocol_ident[PROTOCOL_ANY] = {
2725 "Fibre Channel",
2726 "Parallel SCSI",
2727 "SSA",
2728 "IEEE_1394",
2729 "SRP",
2730 "iSCSI",
2731 "SAS",
2732 "ADT",
2733 "ATAPI",
2734 "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN"
2735 };
2736
2737 /*
2738 * Update the lun wait/run queue count
2739 */
2740 static void
2741 stmf_update_kstat_lu_q(scsi_task_t *task, void func())
2742 {
2743 stmf_i_lu_t *ilu;
2744 kstat_io_t *kip;
2745
2746 if (task->task_lu == dlun0)
2747 return;
2748 ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private;
2749 if (ilu != NULL && ilu->ilu_kstat_io != NULL) {
2750 kip = KSTAT_IO_PTR(ilu->ilu_kstat_io);
2751 if (kip != NULL) {
2752 func(kip);
2753 }
2754 }
2755 }
2756
2757 /*
2758 * Update the target(lport) wait/run queue count
2759 */
2760 static void
2761 stmf_update_kstat_lport_q(scsi_task_t *task, void func())
2762 {
2763 stmf_i_local_port_t *ilp;
2764 kstat_io_t *kip;
2765
2766 ilp = (stmf_i_local_port_t *)task->task_lport->lport_stmf_private;
2767 if (ilp != NULL && ilp->ilport_kstat_io != NULL) {
2768 kip = KSTAT_IO_PTR(ilp->ilport_kstat_io);
2769 if (kip != NULL) {
2770 mutex_enter(ilp->ilport_kstat_io->ks_lock);
2771 func(kip);
2772 mutex_exit(ilp->ilport_kstat_io->ks_lock);
2773 }
2774 }
2775 }
2776
2777 static void
2778 stmf_update_kstat_lport_io(scsi_task_t *task, stmf_data_buf_t *dbuf)
2779 {
2780 stmf_i_local_port_t *ilp;
2781 kstat_io_t *kip;
2782
2783 ilp = (stmf_i_local_port_t *)task->task_lport->lport_stmf_private;
2784 if (ilp != NULL && ilp->ilport_kstat_io != NULL) {
2785 kip = KSTAT_IO_PTR(ilp->ilport_kstat_io);
2786 if (kip != NULL) {
2787 mutex_enter(ilp->ilport_kstat_io->ks_lock);
2788 STMF_UPDATE_KSTAT_IO(kip, dbuf);
2789 mutex_exit(ilp->ilport_kstat_io->ks_lock);
2790 }
2791 }
2792 }
2793
2794 static void
2795 stmf_update_kstat_lu_io(scsi_task_t *task, stmf_data_buf_t *dbuf)
2796 {
2797 stmf_i_lu_t *ilu;
2798 kstat_io_t *kip;
2799
2800 ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private;
2801 if (ilu != NULL && ilu->ilu_kstat_io != NULL) {
2802 kip = KSTAT_IO_PTR(ilu->ilu_kstat_io);
2803 if (kip != NULL) {
2804 mutex_enter(ilu->ilu_kstat_io->ks_lock);
2805 STMF_UPDATE_KSTAT_IO(kip, dbuf);
2806 mutex_exit(ilu->ilu_kstat_io->ks_lock);
2807 }
2808 }
2809 }
2810
2811 static void
2812 stmf_create_kstat_lu(stmf_i_lu_t *ilu)
2813 {
2814 char ks_nm[KSTAT_STRLEN];
2815 stmf_kstat_lu_info_t *ks_lu;
2816
2817 /* create kstat lun info */
2818 ks_lu = (stmf_kstat_lu_info_t *)kmem_zalloc(STMF_KSTAT_LU_SZ,
2819 KM_NOSLEEP);
2820 if (ks_lu == NULL) {
2821 cmn_err(CE_WARN, "STMF: kmem_zalloc failed");
2822 return;
2823 }
2824
2825 bzero(ks_nm, sizeof (ks_nm));
2826 (void) sprintf(ks_nm, "stmf_lu_%"PRIxPTR"", (uintptr_t)ilu);
2827 if ((ilu->ilu_kstat_info = kstat_create(STMF_MODULE_NAME, 0,
2828 ks_nm, "misc", KSTAT_TYPE_NAMED,
2829 sizeof (stmf_kstat_lu_info_t) / sizeof (kstat_named_t),
2830 KSTAT_FLAG_VIRTUAL)) == NULL) {
2831 kmem_free(ks_lu, STMF_KSTAT_LU_SZ);
2832 cmn_err(CE_WARN, "STMF: kstat_create lu failed");
2833 return;
2834 }
2835
2836 ilu->ilu_kstat_info->ks_data_size = STMF_KSTAT_LU_SZ;
2837 ilu->ilu_kstat_info->ks_data = ks_lu;
2838
2839 kstat_named_init(&ks_lu->i_lun_guid, "lun-guid",
2840 KSTAT_DATA_STRING);
2841 kstat_named_init(&ks_lu->i_lun_alias, "lun-alias",
2842 KSTAT_DATA_STRING);
2843
2844 /* convert guid to hex string */
2845 int i;
2846 uint8_t *p = ilu->ilu_lu->lu_id->ident;
2847 bzero(ilu->ilu_ascii_hex_guid, sizeof (ilu->ilu_ascii_hex_guid));
2848 for (i = 0; i < STMF_GUID_INPUT / 2; i++) {
2849 (void) sprintf(&ilu->ilu_ascii_hex_guid[i * 2], "%02x", p[i]);
2850 }
2851 kstat_named_setstr(&ks_lu->i_lun_guid,
2852 (const char *)ilu->ilu_ascii_hex_guid);
2853 kstat_named_setstr(&ks_lu->i_lun_alias,
2854 (const char *)ilu->ilu_lu->lu_alias);
2855 kstat_install(ilu->ilu_kstat_info);
2856
2857 /* create kstat lun io */
2858 bzero(ks_nm, sizeof (ks_nm));
2859 (void) sprintf(ks_nm, "stmf_lu_io_%"PRIxPTR"", (uintptr_t)ilu);
2860 if ((ilu->ilu_kstat_io = kstat_create(STMF_MODULE_NAME, 0,
2861 ks_nm, "io", KSTAT_TYPE_IO, 1, 0)) == NULL) {
2862 cmn_err(CE_WARN, "STMF: kstat_create lu_io failed");
2863 return;
2864 }
2865 mutex_init(&ilu->ilu_kstat_lock, NULL, MUTEX_DRIVER, 0);
2866 ilu->ilu_kstat_io->ks_lock = &ilu->ilu_kstat_lock;
2867 kstat_install(ilu->ilu_kstat_io);
2868 }
2869
2870 static void
2871 stmf_create_kstat_lport(stmf_i_local_port_t *ilport)
2872 {
2873 char ks_nm[KSTAT_STRLEN];
2874 stmf_kstat_tgt_info_t *ks_tgt;
2875 int id, len;
2876
2877 /* create kstat lport info */
2878 ks_tgt = (stmf_kstat_tgt_info_t *)kmem_zalloc(STMF_KSTAT_TGT_SZ,
2879 KM_NOSLEEP);
2880 if (ks_tgt == NULL) {
2881 cmn_err(CE_WARN, "STMF: kmem_zalloc failed");
2882 return;
2883 }
2884
2885 bzero(ks_nm, sizeof (ks_nm));
2886 (void) sprintf(ks_nm, "stmf_tgt_%"PRIxPTR"", (uintptr_t)ilport);
2887 if ((ilport->ilport_kstat_info = kstat_create(STMF_MODULE_NAME,
2888 0, ks_nm, "misc", KSTAT_TYPE_NAMED,
2889 sizeof (stmf_kstat_tgt_info_t) / sizeof (kstat_named_t),
2890 KSTAT_FLAG_VIRTUAL)) == NULL) {
2891 kmem_free(ks_tgt, STMF_KSTAT_TGT_SZ);
2892 cmn_err(CE_WARN, "STMF: kstat_create target failed");
2893 return;
2894 }
2895
2896 ilport->ilport_kstat_info->ks_data_size = STMF_KSTAT_TGT_SZ;
2897 ilport->ilport_kstat_info->ks_data = ks_tgt;
2898
2899 kstat_named_init(&ks_tgt->i_tgt_name, "target-name",
2900 KSTAT_DATA_STRING);
2901 kstat_named_init(&ks_tgt->i_tgt_alias, "target-alias",
2902 KSTAT_DATA_STRING);
2903 kstat_named_init(&ks_tgt->i_protocol, "protocol",
2904 KSTAT_DATA_STRING);
2905
2906 /* ident might not be null terminated */
2907 len = ilport->ilport_lport->lport_id->ident_length;
2908 bcopy(ilport->ilport_lport->lport_id->ident,
2909 ilport->ilport_kstat_tgt_name, len);
2910 ilport->ilport_kstat_tgt_name[len + 1] = NULL;
2911 kstat_named_setstr(&ks_tgt->i_tgt_name,
2912 (const char *)ilport->ilport_kstat_tgt_name);
2913 kstat_named_setstr(&ks_tgt->i_tgt_alias,
2914 (const char *)ilport->ilport_lport->lport_alias);
2915 /* protocol */
2916 if ((id = ilport->ilport_lport->lport_id->protocol_id) > PROTOCOL_ANY) {
2917 cmn_err(CE_WARN, "STMF: protocol_id out of bound");
2918 id = PROTOCOL_ANY;
2919 }
2920 kstat_named_setstr(&ks_tgt->i_protocol, protocol_ident[id]);
2921 kstat_install(ilport->ilport_kstat_info);
2922
2923 /* create kstat lport io */
2924 bzero(ks_nm, sizeof (ks_nm));
2925 (void) sprintf(ks_nm, "stmf_tgt_io_%"PRIxPTR"", (uintptr_t)ilport);
2926 if ((ilport->ilport_kstat_io = kstat_create(STMF_MODULE_NAME, 0,
2927 ks_nm, "io", KSTAT_TYPE_IO, 1, 0)) == NULL) {
2928 cmn_err(CE_WARN, "STMF: kstat_create target_io failed");
2929 return;
2930 }
2931 mutex_init(&ilport->ilport_kstat_lock, NULL, MUTEX_DRIVER, 0);
2932 ilport->ilport_kstat_io->ks_lock = &ilport->ilport_kstat_lock;
2933 kstat_install(ilport->ilport_kstat_io);
2934 }
2935
2936 /*
2937 * set the asymmetric access state for a logical unit
2938 * caller is responsible for establishing SCSI unit attention on
2939 * state change
2940 */
2941 stmf_status_t
2942 stmf_set_lu_access(stmf_lu_t *lu, uint8_t access_state)
2943 {
2944 stmf_i_lu_t *ilu;
2945 uint8_t *p1, *p2;
2946
2947 if ((access_state != STMF_LU_STANDBY) &&
2948 (access_state != STMF_LU_ACTIVE)) {
2949 return (STMF_INVALID_ARG);
2950 }
2951
2952 p1 = &lu->lu_id->ident[0];
2953 mutex_enter(&stmf_state.stmf_lock);
2954 if (stmf_state.stmf_inventory_locked) {
2955 mutex_exit(&stmf_state.stmf_lock);
2956 return (STMF_BUSY);
2957 }
2958
2959 for (ilu = stmf_state.stmf_ilulist; ilu != NULL; ilu = ilu->ilu_next) {
2960 p2 = &ilu->ilu_lu->lu_id->ident[0];
2961 if (bcmp(p1, p2, 16) == 0) {
2962 break;
2963 }
2964 }
2965
2966 if (!ilu) {
2967 ilu = (stmf_i_lu_t *)lu->lu_stmf_private;
2968 } else {
2969 /*
2970 * We're changing access state on an existing logical unit
2971 * Send the proxy registration message for this logical unit
2972 * if we're in alua mode.
2973 * If the requested state is STMF_LU_ACTIVE, we want to register
2974 * this logical unit.
2975 * If the requested state is STMF_LU_STANDBY, we're going to
2976 * abort all tasks for this logical unit.
2977 */
2978 if (stmf_state.stmf_alua_state == 1 &&
2979 access_state == STMF_LU_ACTIVE) {
2980 stmf_ic_msg_status_t ic_ret = STMF_IC_MSG_SUCCESS;
2981 stmf_ic_msg_t *ic_reg_lun;
2982 if (lu->lu_lp && lu->lu_lp->lp_lpif_rev == LPIF_REV_2 &&
2983 lu->lu_lp->lp_alua_support) {
2984 ilu->ilu_alua = 1;
2985 /* allocate the register message */
2986 ic_reg_lun = ic_lun_active_msg_alloc(p1,
2987 lu->lu_lp->lp_name,
2988 lu->lu_proxy_reg_arg_len,
2989 (uint8_t *)lu->lu_proxy_reg_arg,
2990 stmf_proxy_msg_id);
2991 /* send the message */
2992 if (ic_reg_lun) {
2993 ic_ret = ic_tx_msg(ic_reg_lun);
2994 if (ic_ret == STMF_IC_MSG_SUCCESS) {
2995 stmf_proxy_msg_id++;
2996 }
2997 }
2998 }
2999 } else if (stmf_state.stmf_alua_state == 1 &&
3000 access_state == STMF_LU_STANDBY) {
3001 /* abort all tasks for this lu */
3002 stmf_task_lu_killall(lu, NULL, STMF_ABORTED);
3003 }
3004 }
3005
3006 ilu->ilu_access = access_state;
3007
3008 mutex_exit(&stmf_state.stmf_lock);
3009 return (STMF_SUCCESS);
3010 }
3011
3012
3013 stmf_status_t
3014 stmf_register_lu(stmf_lu_t *lu)
3015 {
3016 stmf_i_lu_t *ilu;
3017 uint8_t *p1, *p2;
3018 stmf_state_change_info_t ssci;
3019 stmf_id_data_t *luid;
3020
3021 if ((lu->lu_id->ident_type != ID_TYPE_NAA) ||
3022 (lu->lu_id->ident_length != 16) ||
3023 ((lu->lu_id->ident[0] & 0xf0) != 0x60)) {
3024 return (STMF_INVALID_ARG);
3025 }
3026 p1 = &lu->lu_id->ident[0];
3027 mutex_enter(&stmf_state.stmf_lock);
3028 if (stmf_state.stmf_inventory_locked) {
3029 mutex_exit(&stmf_state.stmf_lock);
3030 return (STMF_BUSY);
3031 }
3032
3033 for (ilu = stmf_state.stmf_ilulist; ilu != NULL; ilu = ilu->ilu_next) {
3034 p2 = &ilu->ilu_lu->lu_id->ident[0];
3035 if (bcmp(p1, p2, 16) == 0) {
3036 mutex_exit(&stmf_state.stmf_lock);
3037 return (STMF_ALREADY);
3038 }
3039 }
3040
3041 ilu = (stmf_i_lu_t *)lu->lu_stmf_private;
3042 luid = stmf_lookup_id(&stmf_state.stmf_luid_list,
3043 lu->lu_id->ident_length, lu->lu_id->ident);
3044 if (luid) {
3045 luid->id_pt_to_object = (void *)ilu;
3046 ilu->ilu_luid = luid;
3047 }
3048 ilu->ilu_alias = NULL;
3049
3050 ilu->ilu_next = stmf_state.stmf_ilulist;
3051 ilu->ilu_prev = NULL;
3052 if (ilu->ilu_next)
3053 ilu->ilu_next->ilu_prev = ilu;
3054 stmf_state.stmf_ilulist = ilu;
3055 stmf_state.stmf_nlus++;
3056 if (lu->lu_lp) {
3057 ((stmf_i_lu_provider_t *)
3058 (lu->lu_lp->lp_stmf_private))->ilp_nlus++;
3059 }
3060 ilu->ilu_cur_task_cntr = &ilu->ilu_task_cntr1;
3061 STMF_EVENT_ALLOC_HANDLE(ilu->ilu_event_hdl);
3062 stmf_create_kstat_lu(ilu);
3063 /*
3064 * register with proxy module if available and logical unit
3065 * is in active state
3066 */
3067 if (stmf_state.stmf_alua_state == 1 &&
3068 ilu->ilu_access == STMF_LU_ACTIVE) {
3069 stmf_ic_msg_status_t ic_ret = STMF_IC_MSG_SUCCESS;
3070 stmf_ic_msg_t *ic_reg_lun;
3071 if (lu->lu_lp && lu->lu_lp->lp_lpif_rev == LPIF_REV_2 &&
3072 lu->lu_lp->lp_alua_support) {
3073 ilu->ilu_alua = 1;
3074 /* allocate the register message */
3075 ic_reg_lun = ic_reg_lun_msg_alloc(p1,
3076 lu->lu_lp->lp_name, lu->lu_proxy_reg_arg_len,
3077 (uint8_t *)lu->lu_proxy_reg_arg, stmf_proxy_msg_id);
3078 /* send the message */
3079 if (ic_reg_lun) {
3080 ic_ret = ic_tx_msg(ic_reg_lun);
3081 if (ic_ret == STMF_IC_MSG_SUCCESS) {
3082 stmf_proxy_msg_id++;
3083 }
3084 }
3085 }
3086 }
3087 mutex_exit(&stmf_state.stmf_lock);
3088
3089 /* check the default state for lu */
3090 if (stmf_state.stmf_default_lu_state == STMF_STATE_OFFLINE) {
3091 ilu->ilu_prev_state = STMF_STATE_OFFLINE;
3092 } else {
3093 ilu->ilu_prev_state = STMF_STATE_ONLINE;
3094 if (stmf_state.stmf_service_running) {
3095 ssci.st_rflags = 0;
3096 ssci.st_additional_info = NULL;
3097 (void) stmf_ctl(STMF_CMD_LU_ONLINE, lu, &ssci);
3098 }
3099 }
3100
3101 /* XXX: Generate event */
3102 return (STMF_SUCCESS);
3103 }
3104
3105 stmf_status_t
3106 stmf_deregister_lu(stmf_lu_t *lu)
3107 {
3108 stmf_i_lu_t *ilu;
3109
3110 mutex_enter(&stmf_state.stmf_lock);
3111 if (stmf_state.stmf_inventory_locked) {
3112 mutex_exit(&stmf_state.stmf_lock);
3113 return (STMF_BUSY);
3114 }
3115 ilu = stmf_lookup_lu(lu);
3116 if (ilu == NULL) {
3117 mutex_exit(&stmf_state.stmf_lock);
3118 return (STMF_INVALID_ARG);
3119 }
3120 if (ilu->ilu_state == STMF_STATE_OFFLINE) {
3121 ASSERT(ilu->ilu_ntasks == ilu->ilu_ntasks_free);
3122 while (ilu->ilu_flags & ILU_STALL_DEREGISTER) {
3123 cv_wait(&stmf_state.stmf_cv, &stmf_state.stmf_lock);
3124 }
3125 if (ilu->ilu_ntasks) {
3126 stmf_i_scsi_task_t *itask, *nitask;
3127
3128 nitask = ilu->ilu_tasks;
3129 do {
3130 itask = nitask;
3131 nitask = itask->itask_lu_next;
3132 lu->lu_task_free(itask->itask_task);
3133 stmf_free(itask->itask_task);
3134 } while (nitask != NULL);
3135
3136 ilu->ilu_tasks = ilu->ilu_free_tasks = NULL;
3137 ilu->ilu_ntasks = ilu->ilu_ntasks_free = 0;
3138 }
3139 /* de-register with proxy if available */
3140 if (ilu->ilu_access == STMF_LU_ACTIVE &&
3141 stmf_state.stmf_alua_state == 1) {
3142 /* de-register with proxy module */
3143 stmf_ic_msg_status_t ic_ret = STMF_IC_MSG_SUCCESS;
3144 stmf_ic_msg_t *ic_dereg_lun;
3145 if (lu->lu_lp && lu->lu_lp->lp_lpif_rev == LPIF_REV_2 &&
3146 lu->lu_lp->lp_alua_support) {
3147 ilu->ilu_alua = 1;
3148 /* allocate the de-register message */
3149 ic_dereg_lun = ic_dereg_lun_msg_alloc(
3150 lu->lu_id->ident, lu->lu_lp->lp_name, 0,
3151 NULL, stmf_proxy_msg_id);
3152 /* send the message */
3153 if (ic_dereg_lun) {
3154 ic_ret = ic_tx_msg(ic_dereg_lun);
3155 if (ic_ret == STMF_IC_MSG_SUCCESS) {
3156 stmf_proxy_msg_id++;
3157 }
3158 }
3159 }
3160 }
3161
3162 if (ilu->ilu_next)
3163 ilu->ilu_next->ilu_prev = ilu->ilu_prev;
3164 if (ilu->ilu_prev)
3165 ilu->ilu_prev->ilu_next = ilu->ilu_next;
3166 else
3167 stmf_state.stmf_ilulist = ilu->ilu_next;
3168 stmf_state.stmf_nlus--;
3169
3170 if (ilu == stmf_state.stmf_svc_ilu_draining) {
3171 stmf_state.stmf_svc_ilu_draining = ilu->ilu_next;
3172 }
3173 if (ilu == stmf_state.stmf_svc_ilu_timing) {
3174 stmf_state.stmf_svc_ilu_timing = ilu->ilu_next;
3175 }
3176 if (lu->lu_lp) {
3177 ((stmf_i_lu_provider_t *)
3178 (lu->lu_lp->lp_stmf_private))->ilp_nlus--;
3179 }
3180 if (ilu->ilu_luid) {
3181 ((stmf_id_data_t *)ilu->ilu_luid)->id_pt_to_object =
3182 NULL;
3183 ilu->ilu_luid = NULL;
3184 }
3185 STMF_EVENT_FREE_HANDLE(ilu->ilu_event_hdl);
3186 } else {
3187 mutex_exit(&stmf_state.stmf_lock);
3188 return (STMF_BUSY);
3189 }
3190 if (ilu->ilu_kstat_info) {
3191 kmem_free(ilu->ilu_kstat_info->ks_data,
3192 ilu->ilu_kstat_info->ks_data_size);
3193 kstat_delete(ilu->ilu_kstat_info);
3194 }
3195 if (ilu->ilu_kstat_io) {
3196 kstat_delete(ilu->ilu_kstat_io);
3197 mutex_destroy(&ilu->ilu_kstat_lock);
3198 }
3199 stmf_delete_itl_kstat_by_guid(ilu->ilu_ascii_hex_guid);
3200 mutex_exit(&stmf_state.stmf_lock);
3201 return (STMF_SUCCESS);
3202 }
3203
3204 void
3205 stmf_set_port_standby(stmf_local_port_t *lport, uint16_t rtpid)
3206 {
3207 stmf_i_local_port_t *ilport =
3208 (stmf_i_local_port_t *)lport->lport_stmf_private;
3209 ilport->ilport_rtpid = rtpid;
3210 ilport->ilport_standby = 1;
3211 }
3212
3213 void
3214 stmf_set_port_alua(stmf_local_port_t *lport)
3215 {
3216 stmf_i_local_port_t *ilport =
3217 (stmf_i_local_port_t *)lport->lport_stmf_private;
3218 ilport->ilport_alua = 1;
3219 }
3220
3221 stmf_status_t
3222 stmf_register_local_port(stmf_local_port_t *lport)
3223 {
3224 stmf_i_local_port_t *ilport;
3225 stmf_state_change_info_t ssci;
3226 int start_workers = 0;
3227
3228 mutex_enter(&stmf_state.stmf_lock);
3229 if (stmf_state.stmf_inventory_locked) {
3230 mutex_exit(&stmf_state.stmf_lock);
3231 return (STMF_BUSY);
3232 }
3233 ilport = (stmf_i_local_port_t *)lport->lport_stmf_private;
3234 rw_init(&ilport->ilport_lock, NULL, RW_DRIVER, NULL);
3235
3236 ilport->ilport_instance =
3237 id_alloc_nosleep(stmf_state.stmf_ilport_inst_space);
3238 if (ilport->ilport_instance == -1) {
3239 mutex_exit(&stmf_state.stmf_lock);
3240 return (STMF_FAILURE);
3241 }
3242 ilport->ilport_next = stmf_state.stmf_ilportlist;
3243 ilport->ilport_prev = NULL;
3244 if (ilport->ilport_next)
3245 ilport->ilport_next->ilport_prev = ilport;
3246 stmf_state.stmf_ilportlist = ilport;
3247 stmf_state.stmf_nlports++;
3248 if (lport->lport_pp) {
3249 ((stmf_i_port_provider_t *)
3250 (lport->lport_pp->pp_stmf_private))->ipp_npps++;
3251 }
3252 ilport->ilport_tg =
3253 stmf_lookup_group_for_target(lport->lport_id->ident,
3254 lport->lport_id->ident_length);
3255
3256 /*
3257 * rtpid will/must be set if this is a standby port
3258 * only register ports that are not standby (proxy) ports
3259 * and ports that are alua participants (ilport_alua == 1)
3260 */
3261 if (ilport->ilport_standby == 0) {
3262 ilport->ilport_rtpid = atomic_add_16_nv(&stmf_rtpid_counter, 1);
3263 }
3264
3265 if (stmf_state.stmf_alua_state == 1 &&
3266 ilport->ilport_standby == 0 &&
3267 ilport->ilport_alua == 1) {
3268 stmf_ic_msg_t *ic_reg_port;
3269 stmf_ic_msg_status_t ic_ret;
3270 stmf_local_port_t *lport;
3271 lport = ilport->ilport_lport;
3272 ic_reg_port = ic_reg_port_msg_alloc(
3273 lport->lport_id, ilport->ilport_rtpid,
3274 0, NULL, stmf_proxy_msg_id);
3275 if (ic_reg_port) {
3276 ic_ret = ic_tx_msg(ic_reg_port);
3277 if (ic_ret == STMF_IC_MSG_SUCCESS) {
3278 ilport->ilport_reg_msgid = stmf_proxy_msg_id++;
3279 } else {
3280 cmn_err(CE_WARN, "error on port registration "
3281 "port - %s", ilport->ilport_kstat_tgt_name);
3282 }
3283 }
3284 }
3285 STMF_EVENT_ALLOC_HANDLE(ilport->ilport_event_hdl);
3286 stmf_create_kstat_lport(ilport);
3287 if (stmf_workers_state == STMF_WORKERS_DISABLED) {
3288 stmf_workers_state = STMF_WORKERS_ENABLING;
3289 start_workers = 1;
3290 }
3291 mutex_exit(&stmf_state.stmf_lock);
3292
3293 if (start_workers)
3294 stmf_worker_init();
3295
3296 /* the default state of LPORT */
3297
3298 if (stmf_state.stmf_default_lport_state == STMF_STATE_OFFLINE) {
3299 ilport->ilport_prev_state = STMF_STATE_OFFLINE;
3300 } else {
3301 ilport->ilport_prev_state = STMF_STATE_ONLINE;
3302 if (stmf_state.stmf_service_running) {
3303 ssci.st_rflags = 0;
3304 ssci.st_additional_info = NULL;
3305 (void) stmf_ctl(STMF_CMD_LPORT_ONLINE, lport, &ssci);
3306 }
3307 }
3308
3309 /* XXX: Generate event */
3310 return (STMF_SUCCESS);
3311 }
3312
3313 stmf_status_t
3314 stmf_deregister_local_port(stmf_local_port_t *lport)
3315 {
3316 stmf_i_local_port_t *ilport;
3317
3318 mutex_enter(&stmf_state.stmf_lock);
3319 if (stmf_state.stmf_inventory_locked) {
3320 mutex_exit(&stmf_state.stmf_lock);
3321 return (STMF_BUSY);
3322 }
3323
3324 /* dequeue all object requests from active queue */
3325 stmf_svc_kill_obj_requests(lport);
3326
3327 ilport = (stmf_i_local_port_t *)lport->lport_stmf_private;
3328
3329 /*
3330 * deregister ports that are not standby (proxy)
3331 */
3332 if (stmf_state.stmf_alua_state == 1 &&
3333 ilport->ilport_standby == 0 &&
3334 ilport->ilport_alua == 1) {
3335 stmf_ic_msg_t *ic_dereg_port;
3336 stmf_ic_msg_status_t ic_ret;
3337 ic_dereg_port = ic_dereg_port_msg_alloc(
3338 lport->lport_id, 0, NULL, stmf_proxy_msg_id);
3339 if (ic_dereg_port) {
3340 ic_ret = ic_tx_msg(ic_dereg_port);
3341 if (ic_ret == STMF_IC_MSG_SUCCESS) {
3342 stmf_proxy_msg_id++;
3343 }
3344 }
3345 }
3346
3347 if (ilport->ilport_nsessions == 0) {
3348 if (ilport->ilport_next)
3349 ilport->ilport_next->ilport_prev = ilport->ilport_prev;
3350 if (ilport->ilport_prev)
3351 ilport->ilport_prev->ilport_next = ilport->ilport_next;
3352 else
3353 stmf_state.stmf_ilportlist = ilport->ilport_next;
3354 id_free(stmf_state.stmf_ilport_inst_space,
3355 ilport->ilport_instance);
3356 rw_destroy(&ilport->ilport_lock);
3357 stmf_state.stmf_nlports--;
3358 if (lport->lport_pp) {
3359 ((stmf_i_port_provider_t *)
3360 (lport->lport_pp->pp_stmf_private))->ipp_npps--;
3361 }
3362 ilport->ilport_tg = NULL;
3363 STMF_EVENT_FREE_HANDLE(ilport->ilport_event_hdl);
3364 } else {
3365 mutex_exit(&stmf_state.stmf_lock);
3366 return (STMF_BUSY);
3367 }
3368 if (ilport->ilport_kstat_info) {
3369 kmem_free(ilport->ilport_kstat_info->ks_data,
3370 ilport->ilport_kstat_info->ks_data_size);
3371 kstat_delete(ilport->ilport_kstat_info);
3372 }
3373 if (ilport->ilport_kstat_io) {
3374 kstat_delete(ilport->ilport_kstat_io);
3375 mutex_destroy(&ilport->ilport_kstat_lock);
3376 }
3377 stmf_delete_itl_kstat_by_lport(ilport->ilport_kstat_tgt_name);
3378 mutex_exit(&stmf_state.stmf_lock);
3379 return (STMF_SUCCESS);
3380 }
3381
3382 /*
3383 * Rport id/instance mappings remain valid until STMF is unloaded
3384 */
3385 static int
3386 stmf_irport_compare(const void *void_irport1, const void *void_irport2)
3387 {
3388 const stmf_i_remote_port_t *irport1 = void_irport1;
3389 const stmf_i_remote_port_t *irport2 = void_irport2;
3390 int result;
3391
3392 /* Sort by code set then ident */
3393 if (irport1->irport_id->code_set <
3394 irport2->irport_id->code_set) {
3395 return (-1);
3396 } else if (irport1->irport_id->code_set >
3397 irport2->irport_id->code_set) {
3398 return (1);
3399 }
3400
3401 /* Next by ident length */
3402 if (irport1->irport_id->ident_length <
3403 irport2->irport_id->ident_length) {
3404 return (-1);
3405 } else if (irport1->irport_id->ident_length >
3406 irport2->irport_id->ident_length) {
3407 return (1);
3408 }
3409
3410 /* Code set and ident length both match, now compare idents */
3411 result = memcmp(irport1->irport_id->ident,
3412 irport2->irport_id->ident,
3413 irport1->irport_id->ident_length);
3414
3415 if (result < 0) {
3416 return (-1);
3417 } else if (result > 0) {
3418 return (1);
3419 }
3420
3421 return (0);
3422 }
3423
3424 static stmf_i_remote_port_t *
3425 stmf_irport_create(scsi_devid_desc_t *rport_devid)
3426 {
3427 int alloc_len;
3428 stmf_i_remote_port_t *irport;
3429
3430 /*
3431 * Lookup will bump the refcnt if there's an existing rport
3432 * context for this identifier.
3433 */
3434 ASSERT(mutex_owned(&stmf_state.stmf_lock));
3435
3436 alloc_len = sizeof (*irport) + sizeof (scsi_devid_desc_t) +
3437 rport_devid->ident_length - 1;
3438 irport = kmem_zalloc(alloc_len, KM_NOSLEEP);
3439 if (irport == NULL) {
3440 return (NULL);
3441 }
3442
3443 irport->irport_instance =
3444 id_alloc_nosleep(stmf_state.stmf_irport_inst_space);
3445 if (irport->irport_instance == -1) {
3446 kmem_free(irport, alloc_len);
3447 return (NULL);
3448 }
3449
3450 irport->irport_id =
3451 (struct scsi_devid_desc *)(irport + 1); /* Ptr. Arith. */
3452 bcopy(rport_devid, irport->irport_id,
3453 sizeof (scsi_devid_desc_t) + rport_devid->ident_length - 1);
3454 irport->irport_refcnt = 1;
3455 mutex_init(&irport->irport_mutex, NULL, MUTEX_DEFAULT, NULL);
3456
3457 return (irport);
3458 }
3459
3460 static void
3461 stmf_irport_destroy(stmf_i_remote_port_t *irport)
3462 {
3463 id_free(stmf_state.stmf_irport_inst_space, irport->irport_instance);
3464 mutex_destroy(&irport->irport_mutex);
3465 kmem_free(irport, sizeof (*irport) + sizeof (scsi_devid_desc_t) +
3466 irport->irport_id->ident_length - 1);
3467 }
3468
3469 static stmf_i_remote_port_t *
3470 stmf_irport_register(scsi_devid_desc_t *rport_devid)
3471 {
3472 stmf_i_remote_port_t *irport;
3473
3474 mutex_enter(&stmf_state.stmf_lock);
3475
3476 /*
3477 * Lookup will bump the refcnt if there's an existing rport
3478 * context for this identifier.
3479 */
3480 if ((irport = stmf_irport_lookup_locked(rport_devid)) != NULL) {
3481 mutex_exit(&stmf_state.stmf_lock);
3482 return (irport);
3483 }
3484
3485 irport = stmf_irport_create(rport_devid);
3486 if (irport == NULL) {
3487 mutex_exit(&stmf_state.stmf_lock);
3488 return (NULL);
3489 }
3490
3491 avl_add(&stmf_state.stmf_irportlist, irport);
3492 mutex_exit(&stmf_state.stmf_lock);
3493
3494 return (irport);
3495 }
3496
3497 static stmf_i_remote_port_t *
3498 stmf_irport_lookup_locked(scsi_devid_desc_t *rport_devid)
3499 {
3500 stmf_i_remote_port_t *irport;
3501 stmf_i_remote_port_t tmp_irport;
3502
3503 ASSERT(mutex_owned(&stmf_state.stmf_lock));
3504 tmp_irport.irport_id = rport_devid;
3505 irport = avl_find(&stmf_state.stmf_irportlist, &tmp_irport, NULL);
3506 if (irport != NULL) {
3507 mutex_enter(&irport->irport_mutex);
3508 irport->irport_refcnt++;
3509 mutex_exit(&irport->irport_mutex);
3510 }
3511
3512 return (irport);
3513 }
3514
3515 static void
3516 stmf_irport_deregister(stmf_i_remote_port_t *irport)
3517 {
3518 /*
3519 * If we were actually going to remove unreferenced remote ports
3520 * we would want to acquire stmf_state.stmf_lock before getting
3521 * the irport mutex.
3522 *
3523 * Instead we're just going to leave it there even if unreferenced.
3524 */
3525 mutex_enter(&irport->irport_mutex);
3526 irport->irport_refcnt--;
3527 mutex_exit(&irport->irport_mutex);
3528 }
3529
3530 /*
3531 * Port provider has to make sure that register/deregister session and
3532 * port are serialized calls.
3533 */
3534 stmf_status_t
3535 stmf_register_scsi_session(stmf_local_port_t *lport, stmf_scsi_session_t *ss)
3536 {
3537 stmf_i_scsi_session_t *iss;
3538 stmf_i_local_port_t *ilport = (stmf_i_local_port_t *)
3539 lport->lport_stmf_private;
3540 uint8_t lun[8];
3541
3542 /*
3543 * Port state has to be online to register a scsi session. It is
3544 * possible that we started an offline operation and a new SCSI
3545 * session started at the same time (in that case also we are going
3546 * to fail the registeration). But any other state is simply
3547 * a bad port provider implementation.
3548 */
3549 if (ilport->ilport_state != STMF_STATE_ONLINE) {
3550 if (ilport->ilport_state != STMF_STATE_OFFLINING) {
3551 stmf_trace(lport->lport_alias, "Port is trying to "
3552 "register a session while the state is neither "
3553 "online nor offlining");
3554 }
3555 return (STMF_FAILURE);
3556 }
3557 bzero(lun, 8);
3558 iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private;
3559 if ((iss->iss_irport = stmf_irport_register(ss->ss_rport_id)) == NULL) {
3560 stmf_trace(lport->lport_alias, "Could not register "
3561 "remote port during session registration");
3562 return (STMF_FAILURE);
3563 }
3564
3565 iss->iss_flags |= ISS_BEING_CREATED;
3566
3567 if (ss->ss_rport == NULL) {
3568 iss->iss_flags |= ISS_NULL_TPTID;
3569 ss->ss_rport = stmf_scsilib_devid_to_remote_port(
3570 ss->ss_rport_id);
3571 if (ss->ss_rport == NULL) {
3572 iss->iss_flags &= ~(ISS_NULL_TPTID | ISS_BEING_CREATED);
3573 stmf_trace(lport->lport_alias, "Device id to "
3574 "remote port conversion failed");
3575 return (STMF_FAILURE);
3576 }
3577 } else {
3578 if (!stmf_scsilib_tptid_validate(ss->ss_rport->rport_tptid,
3579 ss->ss_rport->rport_tptid_sz, NULL)) {
3580 iss->iss_flags &= ~ISS_BEING_CREATED;
3581 stmf_trace(lport->lport_alias, "Remote port "
3582 "transport id validation failed");
3583 return (STMF_FAILURE);
3584 }
3585 }
3586
3587 /* sessions use the ilport_lock. No separate lock is required */
3588 iss->iss_lockp = &ilport->ilport_lock;
3589
3590 if (iss->iss_sm != NULL)
3591 cmn_err(CE_PANIC, "create lun map called with non NULL map");
3592 iss->iss_sm = (stmf_lun_map_t *)kmem_zalloc(sizeof (stmf_lun_map_t),
3593 KM_SLEEP);
3594
3595 mutex_enter(&stmf_state.stmf_lock);
3596 rw_enter(&ilport->ilport_lock, RW_WRITER);
3597 (void) stmf_session_create_lun_map(ilport, iss);
3598 ilport->ilport_nsessions++;
3599 iss->iss_next = ilport->ilport_ss_list;
3600 ilport->ilport_ss_list = iss;
3601 rw_exit(&ilport->ilport_lock);
3602 mutex_exit(&stmf_state.stmf_lock);
3603
3604 iss->iss_creation_time = ddi_get_time();
3605 ss->ss_session_id = atomic_add_64_nv(&stmf_session_counter, 1);
3606 iss->iss_flags &= ~ISS_BEING_CREATED;
3607 /* XXX should we remove ISS_LUN_INVENTORY_CHANGED on new session? */
3608 iss->iss_flags &= ~ISS_LUN_INVENTORY_CHANGED;
3609 DTRACE_PROBE2(session__online, stmf_local_port_t *, lport,
3610 stmf_scsi_session_t *, ss);
3611 return (STMF_SUCCESS);
3612 }
3613
3614 void
3615 stmf_deregister_scsi_session(stmf_local_port_t *lport, stmf_scsi_session_t *ss)
3616 {
3617 stmf_i_local_port_t *ilport = (stmf_i_local_port_t *)
3618 lport->lport_stmf_private;
3619 stmf_i_scsi_session_t *iss, **ppss;
3620 int found = 0;
3621 stmf_ic_msg_t *ic_session_dereg;
3622 stmf_status_t ic_ret = STMF_FAILURE;
3623
3624 DTRACE_PROBE2(session__offline, stmf_local_port_t *, lport,
3625 stmf_scsi_session_t *, ss);
3626
3627 iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private;
3628 if (ss->ss_rport_alias) {
3629 ss->ss_rport_alias = NULL;
3630 }
3631
3632 try_dereg_ss_again:
3633 mutex_enter(&stmf_state.stmf_lock);
3634 atomic_and_32(&iss->iss_flags,
3635 ~(ISS_LUN_INVENTORY_CHANGED | ISS_GOT_INITIAL_LUNS));
3636 if (iss->iss_flags & ISS_EVENT_ACTIVE) {
3637 mutex_exit(&stmf_state.stmf_lock);
3638 delay(1);
3639 goto try_dereg_ss_again;
3640 }
3641
3642 /* dereg proxy session if not standby port */
3643 if (stmf_state.stmf_alua_state == 1 &&
3644 ilport->ilport_standby == 0 &&
3645 ilport->ilport_alua == 1) {
3646 ic_session_dereg = ic_session_dereg_msg_alloc(
3647 ss, stmf_proxy_msg_id);
3648 if (ic_session_dereg) {
3649 ic_ret = ic_tx_msg(ic_session_dereg);
3650 if (ic_ret == STMF_IC_MSG_SUCCESS) {
3651 stmf_proxy_msg_id++;
3652 }
3653 }
3654 }
3655
3656 rw_enter(&ilport->ilport_lock, RW_WRITER);
3657 for (ppss = &ilport->ilport_ss_list; *ppss != NULL;
3658 ppss = &((*ppss)->iss_next)) {
3659 if (iss == (*ppss)) {
3660 *ppss = (*ppss)->iss_next;
3661 found = 1;
3662 break;
3663 }
3664 }
3665 if (!found) {
3666 cmn_err(CE_PANIC, "Deregister session called for non existent"
3667 " session");
3668 }
3669 ilport->ilport_nsessions--;
3670
3671 stmf_irport_deregister(iss->iss_irport);
3672 (void) stmf_session_destroy_lun_map(ilport, iss);
3673 rw_exit(&ilport->ilport_lock);
3674 mutex_exit(&stmf_state.stmf_lock);
3675
3676 if (iss->iss_flags & ISS_NULL_TPTID) {
3677 stmf_remote_port_free(ss->ss_rport);
3678 }
3679 }
3680
3681 stmf_i_scsi_session_t *
3682 stmf_session_id_to_issptr(uint64_t session_id, int stay_locked)
3683 {
3684 stmf_i_local_port_t *ilport;
3685 stmf_i_scsi_session_t *iss;
3686
3687 mutex_enter(&stmf_state.stmf_lock);
3688 for (ilport = stmf_state.stmf_ilportlist; ilport != NULL;
3689 ilport = ilport->ilport_next) {
3690 rw_enter(&ilport->ilport_lock, RW_WRITER);
3691 for (iss = ilport->ilport_ss_list; iss != NULL;
3692 iss = iss->iss_next) {
3693 if (iss->iss_ss->ss_session_id == session_id) {
3694 if (!stay_locked)
3695 rw_exit(&ilport->ilport_lock);
3696 mutex_exit(&stmf_state.stmf_lock);
3697 return (iss);
3698 }
3699 }
3700 rw_exit(&ilport->ilport_lock);
3701 }
3702 mutex_exit(&stmf_state.stmf_lock);
3703 return (NULL);
3704 }
3705
3706 #define MAX_ALIAS 128
3707
3708 static int
3709 stmf_itl_kstat_compare(const void *itl_kstat_1, const void *itl_kstat_2)
3710 {
3711 const stmf_i_itl_kstat_t *kstat_nm1 = itl_kstat_1;
3712 const stmf_i_itl_kstat_t *kstat_nm2 = itl_kstat_2;
3713 int ret;
3714
3715 ret = strcmp(kstat_nm1->iitl_kstat_nm, kstat_nm2->iitl_kstat_nm);
3716 if (ret < 0) {
3717 return (-1);
3718 } else if (ret > 0) {
3719 return (1);
3720 }
3721 return (0);
3722 }
3723
3724 static stmf_i_itl_kstat_t *
3725 stmf_itl_kstat_lookup(char *kstat_nm)
3726 {
3727 stmf_i_itl_kstat_t tmp;
3728 stmf_i_itl_kstat_t *itl_kstat;
3729
3730 ASSERT(mutex_owned(&stmf_state.stmf_lock));
3731 (void) strcpy(tmp.iitl_kstat_nm, kstat_nm);
3732 itl_kstat = avl_find(&stmf_state.stmf_itl_kstat_list, &tmp, NULL);
3733 return (itl_kstat);
3734 }
3735
3736 static void
3737 stmf_delete_itl_kstat_by_lport(char *tgt)
3738 {
3739 stmf_i_itl_kstat_t *ks_itl, *next;
3740
3741 ASSERT(mutex_owned(&stmf_state.stmf_lock));
3742 ks_itl = avl_first(&stmf_state.stmf_itl_kstat_list);
3743 for (; ks_itl != NULL; ks_itl = next) {
3744 next = AVL_NEXT(&stmf_state.stmf_itl_kstat_list, ks_itl);
3745 if (strcmp(ks_itl->iitl_kstat_lport, tgt) == 0) {
3746 stmf_teardown_itl_kstats(ks_itl);
3747 avl_remove(&stmf_state.stmf_itl_kstat_list, ks_itl);
3748 kmem_free(ks_itl, sizeof (stmf_i_itl_kstat_t));
3749 }
3750 }
3751 }
3752
3753 static void
3754 stmf_delete_itl_kstat_by_guid(char *guid)
3755 {
3756 stmf_i_itl_kstat_t *ks_itl, *next;
3757
3758 ASSERT(mutex_owned(&stmf_state.stmf_lock));
3759 ks_itl = avl_first(&stmf_state.stmf_itl_kstat_list);
3760 for (; ks_itl != NULL; ks_itl = next) {
3761 next = AVL_NEXT(&stmf_state.stmf_itl_kstat_list, ks_itl);
3762 if (strcmp(ks_itl->iitl_kstat_guid, guid) == 0) {
3763 stmf_teardown_itl_kstats(ks_itl);
3764 avl_remove(&stmf_state.stmf_itl_kstat_list, ks_itl);
3765 kmem_free(ks_itl, sizeof (stmf_i_itl_kstat_t));
3766 }
3767 }
3768 }
3769
3770 static stmf_i_itl_kstat_t *
3771 stmf_itl_kstat_create(stmf_itl_data_t *itl, char *nm,
3772 scsi_devid_desc_t *lport, scsi_devid_desc_t *lun)
3773 {
3774 stmf_i_itl_kstat_t *ks_itl;
3775 int i, len;
3776
3777 ASSERT(mutex_owned(&stmf_state.stmf_lock));
3778 if ((ks_itl = stmf_itl_kstat_lookup(nm)) != NULL)
3779 return (ks_itl);
3780
3781 len = sizeof (stmf_i_itl_kstat_t);
3782 ks_itl = kmem_zalloc(len, KM_NOSLEEP);
3783 if (ks_itl == NULL)
3784 return (NULL);
3785
3786 (void) strcpy(ks_itl->iitl_kstat_nm, nm);
3787 bcopy(lport->ident, ks_itl->iitl_kstat_lport, lport->ident_length);
3788 ks_itl->iitl_kstat_lport[lport->ident_length] = '\0';
3789 for (i = 0; i < STMF_GUID_INPUT / 2; i++) {
3790 (void) sprintf(&ks_itl->iitl_kstat_guid[i * 2], "%02x",
3791 lun->ident[i]);
3792 }
3793 ks_itl->iitl_kstat_strbuf = itl->itl_kstat_strbuf;
3794 ks_itl->iitl_kstat_strbuflen = itl->itl_kstat_strbuflen;
3795 ks_itl->iitl_kstat_info = itl->itl_kstat_info;
3796 ks_itl->iitl_kstat_taskq = itl->itl_kstat_taskq;
3797 ks_itl->iitl_kstat_lu_xfer = itl->itl_kstat_lu_xfer;
3798 ks_itl->iitl_kstat_lport_xfer = itl->itl_kstat_lport_xfer;
3799 avl_add(&stmf_state.stmf_itl_kstat_list, ks_itl);
3800
3801 return (ks_itl);
3802 }
3803
3804 stmf_status_t
3805 stmf_setup_itl_kstats(stmf_itl_data_t *itl)
3806 {
3807 char ks_itl_id[32];
3808 char ks_nm[KSTAT_STRLEN];
3809 char ks_itl_nm[KSTAT_STRLEN];
3810 stmf_kstat_itl_info_t *ks_itl;
3811 stmf_scsi_session_t *ss;
3812 stmf_i_scsi_session_t *iss;
3813 stmf_i_local_port_t *ilport;
3814 char *strbuf;
3815 int id, len, i;
3816 char *rport_alias;
3817 char *lport_alias;
3818 char *lu_alias;
3819 stmf_i_itl_kstat_t *tmp_kstat;
3820
3821 /*
3822 * Allocate enough memory in the ITL to hold the relevant
3823 * identifiers.
3824 * rport and lport identifiers come from the stmf_scsi_session_t.
3825 * ident might not be null terminated.
3826 */
3827 ss = itl->itl_session->iss_ss;
3828 iss = ss->ss_stmf_private;
3829 ilport = ss->ss_lport->lport_stmf_private;
3830 (void) snprintf(ks_itl_id, 32, "%d.%d.%d",
3831 iss->iss_irport->irport_instance, ilport->ilport_instance,
3832 itl->itl_lun);
3833
3834 (void) snprintf(ks_itl_nm, KSTAT_STRLEN, "itl_%s", ks_itl_id);
3835 /*
3836 * let's verify this itl_kstat already exist
3837 */
3838 if ((tmp_kstat = stmf_itl_kstat_lookup(ks_itl_nm)) != NULL) {
3839 itl->itl_kstat_strbuf = tmp_kstat->iitl_kstat_strbuf;
3840 itl->itl_kstat_strbuflen = tmp_kstat->iitl_kstat_strbuflen;
3841 itl->itl_kstat_info = tmp_kstat->iitl_kstat_info;
3842 itl->itl_kstat_taskq = tmp_kstat->iitl_kstat_taskq;
3843 itl->itl_kstat_lu_xfer = tmp_kstat->iitl_kstat_lu_xfer;
3844 itl->itl_kstat_lport_xfer = tmp_kstat->iitl_kstat_lport_xfer;
3845 return (STMF_SUCCESS);
3846 }
3847
3848 /* New itl_kstat */
3849 rport_alias = (ss->ss_rport_alias == NULL) ?
3850 "" : ss->ss_rport_alias;
3851 lport_alias = (ss->ss_lport->lport_alias == NULL) ?
3852 "" : ss->ss_lport->lport_alias;
3853 lu_alias = (itl->itl_ilu->ilu_lu->lu_alias == NULL) ?
3854 "" : itl->itl_ilu->ilu_lu->lu_alias;
3855
3856 itl->itl_kstat_strbuflen = (ss->ss_rport_id->ident_length + 1) +
3857 (strnlen(rport_alias, MAX_ALIAS) + 1) +
3858 (ss->ss_lport->lport_id->ident_length + 1) +
3859 (strnlen(lport_alias, MAX_ALIAS) + 1) +
3860 (STMF_GUID_INPUT + 1) +
3861 (strnlen(lu_alias, MAX_ALIAS) + 1) +
3862 MAX_PROTO_STR_LEN;
3863 itl->itl_kstat_strbuf = kmem_zalloc(itl->itl_kstat_strbuflen,
3864 KM_NOSLEEP);
3865 if (itl->itl_kstat_strbuf == NULL) {
3866 return (STMF_ALLOC_FAILURE);
3867 }
3868
3869 ks_itl = (stmf_kstat_itl_info_t *)kmem_zalloc(sizeof (*ks_itl),
3870 KM_NOSLEEP);
3871 if (ks_itl == NULL) {
3872 kmem_free(itl->itl_kstat_strbuf, itl->itl_kstat_strbuflen);
3873 return (STMF_ALLOC_FAILURE);
3874 }
3875
3876 if ((itl->itl_kstat_info = kstat_create(STMF_MODULE_NAME,
3877 0, ks_itl_nm, "misc", KSTAT_TYPE_NAMED,
3878 sizeof (stmf_kstat_itl_info_t) / sizeof (kstat_named_t),
3879 KSTAT_FLAG_VIRTUAL)) == NULL) {
3880 goto itl_kstat_cleanup;
3881 }
3882
3883 itl->itl_kstat_info->ks_data_size += itl->itl_kstat_strbuflen;
3884 itl->itl_kstat_info->ks_data = ks_itl;
3885
3886 kstat_named_init(&ks_itl->i_rport_name, "rport-name",
3887 KSTAT_DATA_STRING);
3888 kstat_named_init(&ks_itl->i_rport_alias, "rport-alias",
3889 KSTAT_DATA_STRING);
3890 kstat_named_init(&ks_itl->i_lport_name, "lport-name",
3891 KSTAT_DATA_STRING);
3892 kstat_named_init(&ks_itl->i_lport_alias, "lport-alias",
3893 KSTAT_DATA_STRING);
3894 kstat_named_init(&ks_itl->i_protocol, "protocol",
3895 KSTAT_DATA_STRING);
3896 kstat_named_init(&ks_itl->i_lu_guid, "lu-guid",
3897 KSTAT_DATA_STRING);
3898 kstat_named_init(&ks_itl->i_lu_alias, "lu-alias",
3899 KSTAT_DATA_STRING);
3900 kstat_named_init(&ks_itl->i_lu_number, "lu-number",
3901 KSTAT_DATA_UINT64);
3902 kstat_named_init(&ks_itl->i_task_waitq_elapsed, "task-waitq-elapsed",
3903 KSTAT_DATA_UINT64);
3904 kstat_named_init(&ks_itl->i_task_read_elapsed, "task-read-elapsed",
3905 KSTAT_DATA_UINT64);
3906 kstat_named_init(&ks_itl->i_task_write_elapsed, "task-write-elapsed",
3907 KSTAT_DATA_UINT64);
3908 kstat_named_init(&ks_itl->i_lu_read_elapsed, "lu-read-elapsed",
3909 KSTAT_DATA_UINT64);
3910 kstat_named_init(&ks_itl->i_lu_write_elapsed, "lu-write-elapsed",
3911 KSTAT_DATA_UINT64);
3912 kstat_named_init(&ks_itl->i_lport_read_elapsed, "lport-read-elapsed",
3913 KSTAT_DATA_UINT64);
3914 kstat_named_init(&ks_itl->i_lport_write_elapsed, "lport-write-elapsed",
3915 KSTAT_DATA_UINT64);
3916
3917 strbuf = itl->itl_kstat_strbuf;
3918
3919 /* Rport */
3920 len = ss->ss_rport_id->ident_length;
3921 bcopy(ss->ss_rport_id->ident, strbuf, len);
3922 strbuf += len;
3923 *strbuf = '\0';
3924 kstat_named_setstr(&ks_itl->i_rport_name, strbuf - len);
3925 strbuf++;
3926
3927 len = strnlen(rport_alias, MAX_ALIAS);
3928 (void) strncpy(strbuf, rport_alias, len + 1);
3929 kstat_named_setstr(&ks_itl->i_rport_alias, strbuf);
3930 strbuf += len + 1;
3931
3932 /* Lport */
3933 len = ss->ss_lport->lport_id->ident_length;
3934 bcopy(ss->ss_lport->lport_id->ident, strbuf, len);
3935 strbuf += len;
3936 *strbuf = '\0';
3937 kstat_named_setstr(&ks_itl->i_lport_name, strbuf - len);
3938 strbuf++;
3939
3940 len = strnlen(lport_alias, MAX_ALIAS);
3941 (void) strncpy(strbuf, lport_alias, len + 1);
3942 kstat_named_setstr(&ks_itl->i_lport_alias, strbuf);
3943 strbuf += len + 1;
3944
3945 id = (ss->ss_lport->lport_id->protocol_id > PROTOCOL_ANY) ?
3946 PROTOCOL_ANY : ss->ss_lport->lport_id->protocol_id;
3947 kstat_named_setstr(&ks_itl->i_protocol, protocol_ident[id]);
3948
3949 /* LU */
3950 for (i = 0; i < STMF_GUID_INPUT / 2; i++) {
3951 (void) sprintf(&strbuf[i * 2], "%02x",
3952 itl->itl_ilu->ilu_lu->lu_id->ident[i]);
3953 }
3954 kstat_named_setstr(&ks_itl->i_lu_guid, strbuf);
3955 strbuf += STMF_GUID_INPUT + 1;
3956
3957 len = strnlen(lu_alias, MAX_ALIAS);
3958 (void) strncpy(strbuf, lu_alias, len + 1);
3959 kstat_named_setstr(&ks_itl->i_lu_alias, strbuf);
3960 strbuf += len + 1;
3961
3962 ks_itl->i_lu_number.value.ui64 = itl->itl_lun;
3963
3964 /* Now create the I/O kstats */
3965 (void) snprintf(ks_nm, KSTAT_STRLEN, "itl_tasks_%s", ks_itl_id);
3966 if ((itl->itl_kstat_taskq = kstat_create(STMF_MODULE_NAME, 0,
3967 ks_nm, "io", KSTAT_TYPE_IO, 1, 0)) == NULL) {
3968 goto itl_kstat_cleanup;
3969 }
3970
3971 (void) snprintf(ks_nm, KSTAT_STRLEN, "itl_lu_%s", ks_itl_id);
3972 if ((itl->itl_kstat_lu_xfer = kstat_create(STMF_MODULE_NAME, 0,
3973 ks_nm, "io", KSTAT_TYPE_IO, 1, 0)) == NULL) {
3974 goto itl_kstat_cleanup;
3975 }
3976
3977 (void) snprintf(ks_nm, KSTAT_STRLEN, "itl_lport_%s", ks_itl_id);
3978 if ((itl->itl_kstat_lport_xfer = kstat_create(STMF_MODULE_NAME, 0,
3979 ks_nm, "io", KSTAT_TYPE_IO, 1, 0)) == NULL) {
3980 goto itl_kstat_cleanup;
3981 }
3982
3983 /* Install all the kstats */
3984 kstat_install(itl->itl_kstat_info);
3985 kstat_install(itl->itl_kstat_taskq);
3986 kstat_install(itl->itl_kstat_lu_xfer);
3987 kstat_install(itl->itl_kstat_lport_xfer);
3988
3989 /* Add new itl_kstat to stmf_itl_kstat_list */
3990 if (stmf_itl_kstat_create(itl, ks_itl_nm, ss->ss_lport->lport_id,
3991 itl->itl_ilu->ilu_lu->lu_id) != NULL)
3992 return (STMF_SUCCESS);
3993
3994 itl_kstat_cleanup:
3995 if (itl->itl_kstat_taskq)
3996 kstat_delete(itl->itl_kstat_taskq);
3997 if (itl->itl_kstat_lu_xfer)
3998 kstat_delete(itl->itl_kstat_lu_xfer);
3999 if (itl->itl_kstat_lport_xfer)
4000 kstat_delete(itl->itl_kstat_lport_xfer);
4001 if (itl->itl_kstat_info)
4002 kstat_delete(itl->itl_kstat_info);
4003 kmem_free(ks_itl, sizeof (*ks_itl));
4004 kmem_free(itl->itl_kstat_strbuf, itl->itl_kstat_strbuflen);
4005 cmn_err(CE_WARN, "STMF: kstat_create itl failed");
4006 return (STMF_ALLOC_FAILURE);
4007 }
4008
4009 static void
4010 stmf_teardown_itl_kstats(stmf_i_itl_kstat_t *ks)
4011 {
4012 kstat_delete(ks->iitl_kstat_lport_xfer);
4013 kstat_delete(ks->iitl_kstat_lu_xfer);
4014 kstat_delete(ks->iitl_kstat_taskq);
4015 kmem_free(ks->iitl_kstat_info->ks_data, sizeof (stmf_kstat_itl_info_t));
4016 kstat_delete(ks->iitl_kstat_info);
4017 kmem_free(ks->iitl_kstat_strbuf, ks->iitl_kstat_strbuflen);
4018 }
4019
4020 void
4021 stmf_release_itl_handle(stmf_lu_t *lu, stmf_itl_data_t *itl)
4022 {
4023 stmf_itl_data_t **itlpp;
4024 stmf_i_lu_t *ilu;
4025
4026 ASSERT(itl->itl_flags & STMF_ITL_BEING_TERMINATED);
4027
4028 ilu = (stmf_i_lu_t *)lu->lu_stmf_private;
4029 mutex_enter(&ilu->ilu_task_lock);
4030 for (itlpp = &ilu->ilu_itl_list; (*itlpp) != NULL;
4031 itlpp = &(*itlpp)->itl_next) {
4032 if ((*itlpp) == itl)
4033 break;
4034 }
4035 ASSERT((*itlpp) != NULL);
4036 *itlpp = itl->itl_next;
4037 mutex_exit(&ilu->ilu_task_lock);
4038 lu->lu_abort(lu, STMF_LU_ITL_HANDLE_REMOVED, itl->itl_handle,
4039 (uint32_t)itl->itl_hdlrm_reason);
4040
4041 kmem_free(itl, sizeof (*itl));
4042 }
4043
4044 stmf_status_t
4045 stmf_register_itl_handle(stmf_lu_t *lu, uint8_t *lun,
4046 stmf_scsi_session_t *ss, uint64_t session_id, void *itl_handle)
4047 {
4048 stmf_itl_data_t *itl;
4049 stmf_i_scsi_session_t *iss;
4050 stmf_lun_map_ent_t *lun_map_ent;
4051 stmf_i_lu_t *ilu;
4052 uint16_t n;
4053
4054 ilu = (stmf_i_lu_t *)lu->lu_stmf_private;
4055 if (ss == NULL) {
4056 iss = stmf_session_id_to_issptr(session_id, 1);
4057 if (iss == NULL)
4058 return (STMF_NOT_FOUND);
4059 } else {
4060 iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private;
4061 }
4062
4063 /*
4064 * Acquire stmf_lock for stmf_itl_kstat_lookup.
4065 */
4066 mutex_enter(&stmf_state.stmf_lock);
4067 rw_enter(iss->iss_lockp, RW_WRITER);
4068 n = ((uint16_t)lun[1] | (((uint16_t)(lun[0] & 0x3F)) << 8));
4069 lun_map_ent = (stmf_lun_map_ent_t *)
4070 stmf_get_ent_from_map(iss->iss_sm, n);
4071 if ((lun_map_ent == NULL) || (lun_map_ent->ent_lu != lu)) {
4072 rw_exit(iss->iss_lockp);
4073 mutex_exit(&stmf_state.stmf_lock);
4074 return (STMF_NOT_FOUND);
4075 }
4076 if (lun_map_ent->ent_itl_datap != NULL) {
4077 rw_exit(iss->iss_lockp);
4078 mutex_exit(&stmf_state.stmf_lock);
4079 return (STMF_ALREADY);
4080 }
4081
4082 itl = (stmf_itl_data_t *)kmem_zalloc(sizeof (*itl), KM_NOSLEEP);
4083 if (itl == NULL) {
4084 rw_exit(iss->iss_lockp);
4085 mutex_exit(&stmf_state.stmf_lock);
4086 return (STMF_ALLOC_FAILURE);
4087 }
4088
4089 itl->itl_ilu = ilu;
4090 itl->itl_session = iss;
4091 itl->itl_counter = 1;
4092 itl->itl_lun = n;
4093 itl->itl_handle = itl_handle;
4094
4095 if (stmf_setup_itl_kstats(itl) != STMF_SUCCESS) {
4096 kmem_free(itl, sizeof (*itl));
4097 rw_exit(iss->iss_lockp);
4098 mutex_exit(&stmf_state.stmf_lock);
4099 return (STMF_ALLOC_FAILURE);
4100 }
4101
4102 mutex_enter(&ilu->ilu_task_lock);
4103 itl->itl_next = ilu->ilu_itl_list;
4104 ilu->ilu_itl_list = itl;
4105 mutex_exit(&ilu->ilu_task_lock);
4106 lun_map_ent->ent_itl_datap = itl;
4107 rw_exit(iss->iss_lockp);
4108 mutex_exit(&stmf_state.stmf_lock);
4109
4110 return (STMF_SUCCESS);
4111 }
4112
4113 void
4114 stmf_do_itl_dereg(stmf_lu_t *lu, stmf_itl_data_t *itl, uint8_t hdlrm_reason)
4115 {
4116 uint8_t old, new;
4117
4118 do {
4119 old = new = itl->itl_flags;
4120 if (old & STMF_ITL_BEING_TERMINATED)
4121 return;
4122 new |= STMF_ITL_BEING_TERMINATED;
4123 } while (atomic_cas_8(&itl->itl_flags, old, new) != old);
4124 itl->itl_hdlrm_reason = hdlrm_reason;
4125
4126 ASSERT(itl->itl_counter);
4127
4128 if (atomic_add_32_nv(&itl->itl_counter, -1))
4129 return;
4130
4131 drv_usecwait(10);
4132 if (itl->itl_counter)
4133 return;
4134
4135 stmf_release_itl_handle(lu, itl);
4136 }
4137
4138 stmf_status_t
4139 stmf_deregister_all_lu_itl_handles(stmf_lu_t *lu)
4140 {
4141 stmf_i_lu_t *ilu;
4142 stmf_i_local_port_t *ilport;
4143 stmf_i_scsi_session_t *iss;
4144 stmf_lun_map_t *lm;
4145 stmf_lun_map_ent_t *ent;
4146 uint32_t nmaps, nu;
4147 stmf_itl_data_t **itl_list;
4148 int i;
4149
4150 ilu = (stmf_i_lu_t *)lu->lu_stmf_private;
4151
4152 dereg_itl_start:;
4153 nmaps = ilu->ilu_ref_cnt;
4154 if (nmaps == 0)
4155 return (STMF_NOT_FOUND);
4156 itl_list = (stmf_itl_data_t **)kmem_zalloc(
4157 nmaps * sizeof (stmf_itl_data_t *), KM_SLEEP);
4158 mutex_enter(&stmf_state.stmf_lock);
4159 if (nmaps != ilu->ilu_ref_cnt) {
4160 /* Something changed, start all over */
4161 mutex_exit(&stmf_state.stmf_lock);
4162 kmem_free(itl_list, nmaps * sizeof (stmf_itl_data_t *));
4163 goto dereg_itl_start;
4164 }
4165 nu = 0;
4166 for (ilport = stmf_state.stmf_ilportlist; ilport != NULL;
4167 ilport = ilport->ilport_next) {
4168 rw_enter(&ilport->ilport_lock, RW_WRITER);
4169 for (iss = ilport->ilport_ss_list; iss != NULL;
4170 iss = iss->iss_next) {
4171 lm = iss->iss_sm;
4172 if (!lm)
4173 continue;
4174 for (i = 0; i < lm->lm_nentries; i++) {
4175 if (lm->lm_plus[i] == NULL)
4176 continue;
4177 ent = (stmf_lun_map_ent_t *)lm->lm_plus[i];
4178 if ((ent->ent_lu == lu) &&
4179 (ent->ent_itl_datap)) {
4180 itl_list[nu++] = ent->ent_itl_datap;
4181 ent->ent_itl_datap = NULL;
4182 if (nu == nmaps) {
4183 rw_exit(&ilport->ilport_lock);
4184 goto dai_scan_done;
4185 }
4186 }
4187 } /* lun table for a session */
4188 } /* sessions */
4189 rw_exit(&ilport->ilport_lock);
4190 } /* ports */
4191
4192 dai_scan_done:
4193 mutex_exit(&stmf_state.stmf_lock);
4194
4195 for (i = 0; i < nu; i++) {
4196 stmf_do_itl_dereg(lu, itl_list[i],
4197 STMF_ITL_REASON_DEREG_REQUEST);
4198 }
4199 kmem_free(itl_list, nmaps * sizeof (stmf_itl_data_t *));
4200
4201 return (STMF_SUCCESS);
4202 }
4203
4204 stmf_status_t
4205 stmf_deregister_itl_handle(stmf_lu_t *lu, uint8_t *lun,
4206 stmf_scsi_session_t *ss, uint64_t session_id, void *itl_handle)
4207 {
4208 stmf_i_scsi_session_t *iss;
4209 stmf_itl_data_t *itl;
4210 stmf_lun_map_ent_t *ent;
4211 stmf_lun_map_t *lm;
4212 int i;
4213 uint16_t n;
4214
4215 if (ss == NULL) {
4216 if (session_id == STMF_SESSION_ID_NONE)
4217 return (STMF_INVALID_ARG);
4218 iss = stmf_session_id_to_issptr(session_id, 1);
4219 if (iss == NULL)
4220 return (STMF_NOT_FOUND);
4221 } else {
4222 iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private;
4223 rw_enter(iss->iss_lockp, RW_WRITER);
4224 }
4225 lm = iss->iss_sm;
4226 if (lm == NULL) {
4227 rw_exit(iss->iss_lockp);
4228 return (STMF_NOT_FOUND);
4229 }
4230
4231 if (lun) {
4232 n = ((uint16_t)lun[1] | (((uint16_t)(lun[0] & 0x3F)) << 8));
4233 ent = (stmf_lun_map_ent_t *)
4234 stmf_get_ent_from_map(iss->iss_sm, n);
4235 } else {
4236 if (itl_handle == NULL) {
4237 rw_exit(iss->iss_lockp);
4238 return (STMF_INVALID_ARG);
4239 }
4240 ent = NULL;
4241 for (i = 0; i < lm->lm_nentries; i++) {
4242 if (lm->lm_plus[i] == NULL)
4243 continue;
4244 ent = (stmf_lun_map_ent_t *)lm->lm_plus[i];
4245 if (ent->ent_itl_datap &&
4246 (ent->ent_itl_datap->itl_handle == itl_handle)) {
4247 break;
4248 }
4249 }
4250 }
4251 if ((ent == NULL) || (ent->ent_lu != lu) ||
4252 (ent->ent_itl_datap == NULL)) {
4253 rw_exit(iss->iss_lockp);
4254 return (STMF_NOT_FOUND);
4255 }
4256 itl = ent->ent_itl_datap;
4257 ent->ent_itl_datap = NULL;
4258 rw_exit(iss->iss_lockp);
4259 stmf_do_itl_dereg(lu, itl, STMF_ITL_REASON_DEREG_REQUEST);
4260
4261 return (STMF_SUCCESS);
4262 }
4263
4264 stmf_status_t
4265 stmf_get_itl_handle(stmf_lu_t *lu, uint8_t *lun, stmf_scsi_session_t *ss,
4266 uint64_t session_id, void **itl_handle_retp)
4267 {
4268 stmf_i_scsi_session_t *iss;
4269 stmf_lun_map_ent_t *ent;
4270 stmf_lun_map_t *lm;
4271 stmf_status_t ret;
4272 int i;
4273 uint16_t n;
4274
4275 if (ss == NULL) {
4276 iss = stmf_session_id_to_issptr(session_id, 1);
4277 if (iss == NULL)
4278 return (STMF_NOT_FOUND);
4279 } else {
4280 iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private;
4281 rw_enter(iss->iss_lockp, RW_WRITER);
4282 }
4283
4284 ent = NULL;
4285 if (lun == NULL) {
4286 lm = iss->iss_sm;
4287 for (i = 0; i < lm->lm_nentries; i++) {
4288 if (lm->lm_plus[i] == NULL)
4289 continue;
4290 ent = (stmf_lun_map_ent_t *)lm->lm_plus[i];
4291 if (ent->ent_lu == lu)
4292 break;
4293 }
4294 } else {
4295 n = ((uint16_t)lun[1] | (((uint16_t)(lun[0] & 0x3F)) << 8));
4296 ent = (stmf_lun_map_ent_t *)
4297 stmf_get_ent_from_map(iss->iss_sm, n);
4298 if (lu && (ent->ent_lu != lu))
4299 ent = NULL;
4300 }
4301 if (ent && ent->ent_itl_datap) {
4302 *itl_handle_retp = ent->ent_itl_datap->itl_handle;
4303 ret = STMF_SUCCESS;
4304 } else {
4305 ret = STMF_NOT_FOUND;
4306 }
4307
4308 rw_exit(iss->iss_lockp);
4309 return (ret);
4310 }
4311
4312 stmf_data_buf_t *
4313 stmf_alloc_dbuf(scsi_task_t *task, uint32_t size, uint32_t *pminsize,
4314 uint32_t flags)
4315 {
4316 stmf_i_scsi_task_t *itask =
4317 (stmf_i_scsi_task_t *)task->task_stmf_private;
4318 stmf_local_port_t *lport = task->task_lport;
4319 stmf_data_buf_t *dbuf;
4320 uint8_t ndx;
4321
4322 ndx = stmf_first_zero[itask->itask_allocated_buf_map];
4323 if (ndx == 0xff)
4324 return (NULL);
4325 dbuf = itask->itask_dbufs[ndx] = lport->lport_ds->ds_alloc_data_buf(
4326 task, size, pminsize, flags);
4327 if (dbuf) {
4328 task->task_cur_nbufs++;
4329 itask->itask_allocated_buf_map |= (1 << ndx);
4330 dbuf->db_flags &= ~DB_LPORT_XFER_ACTIVE;
4331 dbuf->db_handle = ndx;
4332 return (dbuf);
4333 }
4334
4335 return (NULL);
4336 }
4337
4338 stmf_status_t
4339 stmf_setup_dbuf(scsi_task_t *task, stmf_data_buf_t *dbuf, uint32_t flags)
4340 {
4341 stmf_i_scsi_task_t *itask =
4342 (stmf_i_scsi_task_t *)task->task_stmf_private;
4343 stmf_local_port_t *lport = task->task_lport;
4344 uint8_t ndx;
4345 stmf_status_t ret;
4346
4347 ASSERT(task->task_additional_flags & TASK_AF_ACCEPT_LU_DBUF);
4348 ASSERT(lport->lport_ds->ds_setup_dbuf != NULL);
4349 ASSERT(dbuf->db_flags & DB_LU_DATA_BUF);
4350
4351 if ((task->task_additional_flags & TASK_AF_ACCEPT_LU_DBUF) == 0)
4352 return (STMF_FAILURE);
4353 if (lport->lport_ds->ds_setup_dbuf == NULL)
4354 return (STMF_FAILURE);
4355
4356 ndx = stmf_first_zero[itask->itask_allocated_buf_map];
4357 if (ndx == 0xff)
4358 return (STMF_FAILURE);
4359 ret = lport->lport_ds->ds_setup_dbuf(task, dbuf, flags);
4360 if (ret == STMF_FAILURE)
4361 return (STMF_FAILURE);
4362 itask->itask_dbufs[ndx] = dbuf;
4363 task->task_cur_nbufs++;
4364 itask->itask_allocated_buf_map |= (1 << ndx);
4365 dbuf->db_handle = ndx;
4366
4367 return (STMF_SUCCESS);
4368 }
4369
4370 void
4371 stmf_teardown_dbuf(scsi_task_t *task, stmf_data_buf_t *dbuf)
4372 {
4373 stmf_i_scsi_task_t *itask =
4374 (stmf_i_scsi_task_t *)task->task_stmf_private;
4375 stmf_local_port_t *lport = task->task_lport;
4376
4377 ASSERT(task->task_additional_flags & TASK_AF_ACCEPT_LU_DBUF);
4378 ASSERT(lport->lport_ds->ds_teardown_dbuf != NULL);
4379 ASSERT(dbuf->db_flags & DB_LU_DATA_BUF);
4380
4381 itask->itask_allocated_buf_map &= ~(1 << dbuf->db_handle);
4382 task->task_cur_nbufs--;
4383 lport->lport_ds->ds_teardown_dbuf(lport->lport_ds, dbuf);
4384 }
4385
4386 void
4387 stmf_free_dbuf(scsi_task_t *task, stmf_data_buf_t *dbuf)
4388 {
4389 stmf_i_scsi_task_t *itask =
4390 (stmf_i_scsi_task_t *)task->task_stmf_private;
4391 stmf_local_port_t *lport = task->task_lport;
4392
4393 itask->itask_allocated_buf_map &= ~(1 << dbuf->db_handle);
4394 task->task_cur_nbufs--;
4395 lport->lport_ds->ds_free_data_buf(lport->lport_ds, dbuf);
4396 }
4397
4398 stmf_data_buf_t *
4399 stmf_handle_to_buf(scsi_task_t *task, uint8_t h)
4400 {
4401 stmf_i_scsi_task_t *itask;
4402
4403 itask = (stmf_i_scsi_task_t *)task->task_stmf_private;
4404 if (h > 3)
4405 return (NULL);
4406 return (itask->itask_dbufs[h]);
4407 }
4408
4409 /* ARGSUSED */
4410 struct scsi_task *
4411 stmf_task_alloc(struct stmf_local_port *lport, stmf_scsi_session_t *ss,
4412 uint8_t *lun, uint16_t cdb_length_in, uint16_t ext_id)
4413 {
4414 stmf_lu_t *lu;
4415 stmf_i_scsi_session_t *iss;
4416 stmf_i_lu_t *ilu;
4417 stmf_i_scsi_task_t *itask;
4418 stmf_i_scsi_task_t **ppitask;
4419 scsi_task_t *task;
4420 uint8_t *l;
4421 stmf_lun_map_ent_t *lun_map_ent;
4422 uint16_t cdb_length;
4423 uint16_t luNbr;
4424 uint8_t new_task = 0;
4425
4426 /*
4427 * We allocate 7 extra bytes for CDB to provide a cdb pointer which
4428 * is guaranteed to be 8 byte aligned. Some LU providers like OSD
4429 * depend upon this alignment.
4430 */
4431 if (cdb_length_in >= 16)
4432 cdb_length = cdb_length_in + 7;
4433 else
4434 cdb_length = 16 + 7;
4435 iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private;
4436 luNbr = ((uint16_t)lun[1] | (((uint16_t)(lun[0] & 0x3F)) << 8));
4437 rw_enter(iss->iss_lockp, RW_READER);
4438 lun_map_ent =
4439 (stmf_lun_map_ent_t *)stmf_get_ent_from_map(iss->iss_sm, luNbr);
4440 if (!lun_map_ent) {
4441 lu = dlun0;
4442 } else {
4443 lu = lun_map_ent->ent_lu;
4444 }
4445 ilu = lu->lu_stmf_private;
4446 if (ilu->ilu_flags & ILU_RESET_ACTIVE) {
4447 rw_exit(iss->iss_lockp);
4448 return (NULL);
4449 }
4450 do {
4451 if (ilu->ilu_free_tasks == NULL) {
4452 new_task = 1;
4453 break;
4454 }
4455 mutex_enter(&ilu->ilu_task_lock);
4456 for (ppitask = &ilu->ilu_free_tasks; (*ppitask != NULL) &&
4457 ((*ppitask)->itask_cdb_buf_size < cdb_length);
4458 ppitask = &((*ppitask)->itask_lu_free_next))
4459 ;
4460 if (*ppitask) {
4461 itask = *ppitask;
4462 *ppitask = (*ppitask)->itask_lu_free_next;
4463 ilu->ilu_ntasks_free--;
4464 if (ilu->ilu_ntasks_free < ilu->ilu_ntasks_min_free)
4465 ilu->ilu_ntasks_min_free = ilu->ilu_ntasks_free;
4466 } else {
4467 new_task = 1;
4468 }
4469 mutex_exit(&ilu->ilu_task_lock);
4470 /* CONSTCOND */
4471 } while (0);
4472
4473 if (!new_task) {
4474 /*
4475 * Save the task_cdb pointer and zero per cmd fields.
4476 * We know the task_cdb_length is large enough by task
4477 * selection process above.
4478 */
4479 uint8_t *save_cdb;
4480 uintptr_t t_start, t_end;
4481
4482 task = itask->itask_task;
4483 save_cdb = task->task_cdb; /* save */
4484 t_start = (uintptr_t)&task->task_flags;
4485 t_end = (uintptr_t)&task->task_extended_cmd;
4486 bzero((void *)t_start, (size_t)(t_end - t_start));
4487 task->task_cdb = save_cdb; /* restore */
4488 itask->itask_ncmds = 0;
4489 } else {
4490 task = (scsi_task_t *)stmf_alloc(STMF_STRUCT_SCSI_TASK,
4491 cdb_length, AF_FORCE_NOSLEEP);
4492 if (task == NULL) {
4493 rw_exit(iss->iss_lockp);
4494 return (NULL);
4495 }
4496 task->task_lu = lu;
4497 l = task->task_lun_no;
4498 l[0] = lun[0];
4499 l[1] = lun[1];
4500 l[2] = lun[2];
4501 l[3] = lun[3];
4502 l[4] = lun[4];
4503 l[5] = lun[5];
4504 l[6] = lun[6];
4505 l[7] = lun[7];
4506 task->task_cdb = (uint8_t *)task->task_port_private;
4507 if ((ulong_t)(task->task_cdb) & 7ul) {
4508 task->task_cdb = (uint8_t *)(((ulong_t)
4509 (task->task_cdb) + 7ul) & ~(7ul));
4510 }
4511 itask = (stmf_i_scsi_task_t *)task->task_stmf_private;
4512 itask->itask_cdb_buf_size = cdb_length;
4513 mutex_init(&itask->itask_audit_mutex, NULL, MUTEX_DRIVER, NULL);
4514 }
4515 task->task_session = ss;
4516 task->task_lport = lport;
4517 task->task_cdb_length = cdb_length_in;
4518 itask->itask_flags = ITASK_IN_TRANSITION;
4519 itask->itask_waitq_time = 0;
4520 itask->itask_lu_read_time = itask->itask_lu_write_time = 0;
4521 itask->itask_lport_read_time = itask->itask_lport_write_time = 0;
4522 itask->itask_read_xfer = itask->itask_write_xfer = 0;
4523 itask->itask_audit_index = 0;
4524
4525 if (new_task) {
4526 if (lu->lu_task_alloc(task) != STMF_SUCCESS) {
4527 rw_exit(iss->iss_lockp);
4528 stmf_free(task);
4529 return (NULL);
4530 }
4531 mutex_enter(&ilu->ilu_task_lock);
4532 if (ilu->ilu_flags & ILU_RESET_ACTIVE) {
4533 mutex_exit(&ilu->ilu_task_lock);
4534 rw_exit(iss->iss_lockp);
4535 stmf_free(task);
4536 return (NULL);
4537 }
4538 itask->itask_lu_next = ilu->ilu_tasks;
4539 if (ilu->ilu_tasks)
4540 ilu->ilu_tasks->itask_lu_prev = itask;
4541 ilu->ilu_tasks = itask;
4542 /* kmem_zalloc automatically makes itask->itask_lu_prev NULL */
4543 ilu->ilu_ntasks++;
4544 mutex_exit(&ilu->ilu_task_lock);
4545 }
4546
4547 itask->itask_ilu_task_cntr = ilu->ilu_cur_task_cntr;
4548 atomic_add_32(itask->itask_ilu_task_cntr, 1);
4549 itask->itask_start_time = ddi_get_lbolt();
4550
4551 if ((lun_map_ent != NULL) && ((itask->itask_itl_datap =
4552 lun_map_ent->ent_itl_datap) != NULL)) {
4553 atomic_add_32(&itask->itask_itl_datap->itl_counter, 1);
4554 task->task_lu_itl_handle = itask->itask_itl_datap->itl_handle;
4555 } else {
4556 itask->itask_itl_datap = NULL;
4557 task->task_lu_itl_handle = NULL;
4558 }
4559
4560 rw_exit(iss->iss_lockp);
4561 return (task);
4562 }
4563
4564 static void
4565 stmf_task_lu_free(scsi_task_t *task, stmf_i_scsi_session_t *iss)
4566 {
4567 stmf_i_scsi_task_t *itask =
4568 (stmf_i_scsi_task_t *)task->task_stmf_private;
4569 stmf_i_lu_t *ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private;
4570
4571 ASSERT(rw_lock_held(iss->iss_lockp));
4572 itask->itask_flags = ITASK_IN_FREE_LIST;
4573 itask->itask_proxy_msg_id = 0;
4574 mutex_enter(&ilu->ilu_task_lock);
4575 itask->itask_lu_free_next = ilu->ilu_free_tasks;
4576 ilu->ilu_free_tasks = itask;
4577 ilu->ilu_ntasks_free++;
4578 mutex_exit(&ilu->ilu_task_lock);
4579 atomic_add_32(itask->itask_ilu_task_cntr, -1);
4580 }
4581
4582 void
4583 stmf_task_lu_check_freelist(stmf_i_lu_t *ilu)
4584 {
4585 uint32_t num_to_release, ndx;
4586 stmf_i_scsi_task_t *itask;
4587 stmf_lu_t *lu = ilu->ilu_lu;
4588
4589 ASSERT(ilu->ilu_ntasks_min_free <= ilu->ilu_ntasks_free);
4590
4591 /* free half of the minimal free of the free tasks */
4592 num_to_release = (ilu->ilu_ntasks_min_free + 1) / 2;
4593 if (!num_to_release) {
4594 return;
4595 }
4596 for (ndx = 0; ndx < num_to_release; ndx++) {
4597 mutex_enter(&ilu->ilu_task_lock);
4598 itask = ilu->ilu_free_tasks;
4599 if (itask == NULL) {
4600 mutex_exit(&ilu->ilu_task_lock);
4601 break;
4602 }
4603 ilu->ilu_free_tasks = itask->itask_lu_free_next;
4604 ilu->ilu_ntasks_free--;
4605 mutex_exit(&ilu->ilu_task_lock);
4606
4607 lu->lu_task_free(itask->itask_task);
4608 mutex_enter(&ilu->ilu_task_lock);
4609 if (itask->itask_lu_next)
4610 itask->itask_lu_next->itask_lu_prev =
4611 itask->itask_lu_prev;
4612 if (itask->itask_lu_prev)
4613 itask->itask_lu_prev->itask_lu_next =
4614 itask->itask_lu_next;
4615 else
4616 ilu->ilu_tasks = itask->itask_lu_next;
4617
4618 ilu->ilu_ntasks--;
4619 mutex_exit(&ilu->ilu_task_lock);
4620 stmf_free(itask->itask_task);
4621 }
4622 }
4623
4624 /*
4625 * Called with stmf_lock held
4626 */
4627 void
4628 stmf_check_freetask()
4629 {
4630 stmf_i_lu_t *ilu;
4631 clock_t endtime = ddi_get_lbolt() + drv_usectohz(10000);
4632
4633 /* stmf_svc_ilu_draining may get changed after stmf_lock is released */
4634 while ((ilu = stmf_state.stmf_svc_ilu_draining) != NULL) {
4635 stmf_state.stmf_svc_ilu_draining = ilu->ilu_next;
4636 if (!ilu->ilu_ntasks_min_free) {
4637 ilu->ilu_ntasks_min_free = ilu->ilu_ntasks_free;
4638 continue;
4639 }
4640 ilu->ilu_flags |= ILU_STALL_DEREGISTER;
4641 mutex_exit(&stmf_state.stmf_lock);
4642 stmf_task_lu_check_freelist(ilu);
4643 /*
4644 * we do not care about the accuracy of
4645 * ilu_ntasks_min_free, so we don't lock here
4646 */
4647 ilu->ilu_ntasks_min_free = ilu->ilu_ntasks_free;
4648 mutex_enter(&stmf_state.stmf_lock);
4649 ilu->ilu_flags &= ~ILU_STALL_DEREGISTER;
4650 cv_broadcast(&stmf_state.stmf_cv);
4651 if (ddi_get_lbolt() >= endtime)
4652 break;
4653 }
4654 }
4655
4656 void
4657 stmf_do_ilu_timeouts(stmf_i_lu_t *ilu)
4658 {
4659 clock_t l = ddi_get_lbolt();
4660 clock_t ps = drv_usectohz(1000000);
4661 stmf_i_scsi_task_t *itask;
4662 scsi_task_t *task;
4663 uint32_t to;
4664
4665 mutex_enter(&ilu->ilu_task_lock);
4666 for (itask = ilu->ilu_tasks; itask != NULL;
4667 itask = itask->itask_lu_next) {
4668 if (itask->itask_flags & (ITASK_IN_FREE_LIST |
4669 ITASK_BEING_ABORTED)) {
4670 continue;
4671 }
4672 task = itask->itask_task;
4673 if (task->task_timeout == 0)
4674 to = stmf_default_task_timeout;
4675 else
4676 to = task->task_timeout;
4677 if ((itask->itask_start_time + (to * ps)) > l)
4678 continue;
4679 stmf_abort(STMF_QUEUE_TASK_ABORT, task,
4680 STMF_TIMEOUT, NULL);
4681 }
4682 mutex_exit(&ilu->ilu_task_lock);
4683 }
4684
4685 /*
4686 * Called with stmf_lock held
4687 */
4688 void
4689 stmf_check_ilu_timing()
4690 {
4691 stmf_i_lu_t *ilu;
4692 clock_t endtime = ddi_get_lbolt() + drv_usectohz(10000);
4693
4694 /* stmf_svc_ilu_timing may get changed after stmf_lock is released */
4695 while ((ilu = stmf_state.stmf_svc_ilu_timing) != NULL) {
4696 stmf_state.stmf_svc_ilu_timing = ilu->ilu_next;
4697 if (ilu->ilu_cur_task_cntr == (&ilu->ilu_task_cntr1)) {
4698 if (ilu->ilu_task_cntr2 == 0) {
4699 ilu->ilu_cur_task_cntr = &ilu->ilu_task_cntr2;
4700 continue;
4701 }
4702 } else {
4703 if (ilu->ilu_task_cntr1 == 0) {
4704 ilu->ilu_cur_task_cntr = &ilu->ilu_task_cntr1;
4705 continue;
4706 }
4707 }
4708 /*
4709 * If we are here then it means that there is some slowdown
4710 * in tasks on this lu. We need to check.
4711 */
4712 ilu->ilu_flags |= ILU_STALL_DEREGISTER;
4713 mutex_exit(&stmf_state.stmf_lock);
4714 stmf_do_ilu_timeouts(ilu);
4715 mutex_enter(&stmf_state.stmf_lock);
4716 ilu->ilu_flags &= ~ILU_STALL_DEREGISTER;
4717 cv_broadcast(&stmf_state.stmf_cv);
4718 if (ddi_get_lbolt() >= endtime)
4719 break;
4720 }
4721 }
4722
4723 /*
4724 * Kills all tasks on a lu except tm_task
4725 */
4726 void
4727 stmf_task_lu_killall(stmf_lu_t *lu, scsi_task_t *tm_task, stmf_status_t s)
4728 {
4729 stmf_i_lu_t *ilu = (stmf_i_lu_t *)lu->lu_stmf_private;
4730 stmf_i_scsi_task_t *itask;
4731
4732 mutex_enter(&ilu->ilu_task_lock);
4733
4734 for (itask = ilu->ilu_tasks; itask != NULL;
4735 itask = itask->itask_lu_next) {
4736 if (itask->itask_flags & ITASK_IN_FREE_LIST)
4737 continue;
4738 if (itask->itask_task == tm_task)
4739 continue;
4740 stmf_abort(STMF_QUEUE_TASK_ABORT, itask->itask_task, s, NULL);
4741 }
4742 mutex_exit(&ilu->ilu_task_lock);
4743 }
4744
4745 void
4746 stmf_free_task_bufs(stmf_i_scsi_task_t *itask, stmf_local_port_t *lport)
4747 {
4748 int i;
4749 uint8_t map;
4750
4751 if ((map = itask->itask_allocated_buf_map) == 0)
4752 return;
4753 for (i = 0; i < 4; i++) {
4754 if (map & 1) {
4755 stmf_data_buf_t *dbuf;
4756
4757 dbuf = itask->itask_dbufs[i];
4758 if (dbuf->db_xfer_start_timestamp) {
4759 stmf_lport_xfer_done(itask, dbuf);
4760 }
4761 if (dbuf->db_flags & DB_LU_DATA_BUF) {
4762 /*
4763 * LU needs to clean up buffer.
4764 * LU is required to free the buffer
4765 * in the xfer_done handler.
4766 */
4767 scsi_task_t *task = itask->itask_task;
4768 stmf_lu_t *lu = task->task_lu;
4769
4770 lu->lu_dbuf_free(task, dbuf);
4771 ASSERT(((itask->itask_allocated_buf_map>>i)
4772 & 1) == 0); /* must be gone */
4773 } else {
4774 ASSERT(dbuf->db_lu_private == NULL);
4775 dbuf->db_lu_private = NULL;
4776 lport->lport_ds->ds_free_data_buf(
4777 lport->lport_ds, dbuf);
4778 }
4779 }
4780 map >>= 1;
4781 }
4782 itask->itask_allocated_buf_map = 0;
4783 }
4784
4785 void
4786 stmf_task_free(scsi_task_t *task)
4787 {
4788 stmf_local_port_t *lport = task->task_lport;
4789 stmf_i_scsi_task_t *itask = (stmf_i_scsi_task_t *)
4790 task->task_stmf_private;
4791 stmf_i_scsi_session_t *iss = (stmf_i_scsi_session_t *)
4792 task->task_session->ss_stmf_private;
4793
4794 stmf_task_audit(itask, TE_TASK_FREE, CMD_OR_IOF_NA, NULL);
4795
4796 stmf_free_task_bufs(itask, lport);
4797 stmf_itl_task_done(itask);
4798 DTRACE_PROBE2(stmf__task__end, scsi_task_t *, task,
4799 hrtime_t,
4800 itask->itask_done_timestamp - itask->itask_start_timestamp);
4801 if (itask->itask_itl_datap) {
4802 if (atomic_add_32_nv(&itask->itask_itl_datap->itl_counter,
4803 -1) == 0) {
4804 stmf_release_itl_handle(task->task_lu,
4805 itask->itask_itl_datap);
4806 }
4807 }
4808
4809 rw_enter(iss->iss_lockp, RW_READER);
4810 lport->lport_task_free(task);
4811 if (itask->itask_worker) {
4812 atomic_add_32(&stmf_cur_ntasks, -1);
4813 atomic_add_32(&itask->itask_worker->worker_ref_count, -1);
4814 }
4815 /*
4816 * After calling stmf_task_lu_free, the task pointer can no longer
4817 * be trusted.
4818 */
4819 stmf_task_lu_free(task, iss);
4820 rw_exit(iss->iss_lockp);
4821 }
4822
4823 void
4824 stmf_post_task(scsi_task_t *task, stmf_data_buf_t *dbuf)
4825 {
4826 stmf_i_scsi_task_t *itask = (stmf_i_scsi_task_t *)
4827 task->task_stmf_private;
4828 stmf_i_lu_t *ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private;
4829 int nv;
4830 uint32_t old, new;
4831 uint32_t ct;
4832 stmf_worker_t *w, *w1;
4833 uint8_t tm;
4834
4835 if (task->task_max_nbufs > 4)
4836 task->task_max_nbufs = 4;
4837 task->task_cur_nbufs = 0;
4838 /* Latest value of currently running tasks */
4839 ct = atomic_add_32_nv(&stmf_cur_ntasks, 1);
4840
4841 /* Select the next worker using round robin */
4842 nv = (int)atomic_add_32_nv((uint32_t *)&stmf_worker_sel_counter, 1);
4843 if (nv >= stmf_nworkers_accepting_cmds) {
4844 int s = nv;
4845 do {
4846 nv -= stmf_nworkers_accepting_cmds;
4847 } while (nv >= stmf_nworkers_accepting_cmds);
4848 if (nv < 0)
4849 nv = 0;
4850 /* Its ok if this cas fails */
4851 (void) atomic_cas_32((uint32_t *)&stmf_worker_sel_counter,
4852 s, nv);
4853 }
4854 w = &stmf_workers[nv];
4855
4856 /*
4857 * A worker can be pinned by interrupt. So select the next one
4858 * if it has lower load.
4859 */
4860 if ((nv + 1) >= stmf_nworkers_accepting_cmds) {
4861 w1 = stmf_workers;
4862 } else {
4863 w1 = &stmf_workers[nv + 1];
4864 }
4865 if (w1->worker_queue_depth < w->worker_queue_depth)
4866 w = w1;
4867
4868 mutex_enter(&w->worker_lock);
4869 if (((w->worker_flags & STMF_WORKER_STARTED) == 0) ||
4870 (w->worker_flags & STMF_WORKER_TERMINATE)) {
4871 /*
4872 * Maybe we are in the middle of a change. Just go to
4873 * the 1st worker.
4874 */
4875 mutex_exit(&w->worker_lock);
4876 w = stmf_workers;
4877 mutex_enter(&w->worker_lock);
4878 }
4879 itask->itask_worker = w;
4880 /*
4881 * Track max system load inside the worker as we already have the
4882 * worker lock (no point implementing another lock). The service
4883 * thread will do the comparisons and figure out the max overall
4884 * system load.
4885 */
4886 if (w->worker_max_sys_qdepth_pu < ct)
4887 w->worker_max_sys_qdepth_pu = ct;
4888
4889 do {
4890 old = new = itask->itask_flags;
4891 new |= ITASK_KNOWN_TO_TGT_PORT | ITASK_IN_WORKER_QUEUE;
4892 if (task->task_mgmt_function) {
4893 tm = task->task_mgmt_function;
4894 if ((tm == TM_TARGET_RESET) ||
4895 (tm == TM_TARGET_COLD_RESET) ||
4896 (tm == TM_TARGET_WARM_RESET)) {
4897 new |= ITASK_DEFAULT_HANDLING;
4898 }
4899 } else if (task->task_cdb[0] == SCMD_REPORT_LUNS) {
4900 new |= ITASK_DEFAULT_HANDLING;
4901 }
4902 new &= ~ITASK_IN_TRANSITION;
4903 } while (atomic_cas_32(&itask->itask_flags, old, new) != old);
4904
4905 stmf_itl_task_start(itask);
4906
4907 itask->itask_worker_next = NULL;
4908 if (w->worker_task_tail) {
4909 w->worker_task_tail->itask_worker_next = itask;
4910 } else {
4911 w->worker_task_head = itask;
4912 }
4913 w->worker_task_tail = itask;
4914 if (++(w->worker_queue_depth) > w->worker_max_qdepth_pu) {
4915 w->worker_max_qdepth_pu = w->worker_queue_depth;
4916 }
4917 /* Measure task waitq time */
4918 itask->itask_waitq_enter_timestamp = gethrtime();
4919 atomic_add_32(&w->worker_ref_count, 1);
4920 itask->itask_cmd_stack[0] = ITASK_CMD_NEW_TASK;
4921 itask->itask_ncmds = 1;
4922 stmf_task_audit(itask, TE_TASK_START, CMD_OR_IOF_NA, dbuf);
4923 if (dbuf) {
4924 itask->itask_allocated_buf_map = 1;
4925 itask->itask_dbufs[0] = dbuf;
4926 dbuf->db_handle = 0;
4927 } else {
4928 itask->itask_allocated_buf_map = 0;
4929 itask->itask_dbufs[0] = NULL;
4930 }
4931
4932 if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0) {
4933 w->worker_signal_timestamp = gethrtime();
4934 DTRACE_PROBE2(worker__signal, stmf_worker_t *, w,
4935 scsi_task_t *, task);
4936 cv_signal(&w->worker_cv);
4937 }
4938 mutex_exit(&w->worker_lock);
4939
4940 /*
4941 * This can only happen if during stmf_task_alloc(), ILU_RESET_ACTIVE
4942 * was set between checking of ILU_RESET_ACTIVE and clearing of the
4943 * ITASK_IN_FREE_LIST flag. Take care of these "sneaked-in" tasks here.
4944 */
4945 if (ilu->ilu_flags & ILU_RESET_ACTIVE) {
4946 stmf_abort(STMF_QUEUE_TASK_ABORT, task, STMF_ABORTED, NULL);
4947 }
4948 }
4949
4950 static void
4951 stmf_task_audit(stmf_i_scsi_task_t *itask,
4952 task_audit_event_t te, uint32_t cmd_or_iof, stmf_data_buf_t *dbuf)
4953 {
4954 stmf_task_audit_rec_t *ar;
4955
4956 mutex_enter(&itask->itask_audit_mutex);
4957 ar = &itask->itask_audit_records[itask->itask_audit_index++];
4958 itask->itask_audit_index &= (ITASK_TASK_AUDIT_DEPTH - 1);
4959 ar->ta_event = te;
4960 ar->ta_cmd_or_iof = cmd_or_iof;
4961 ar->ta_itask_flags = itask->itask_flags;
4962 ar->ta_dbuf = dbuf;
4963 gethrestime(&ar->ta_timestamp);
4964 mutex_exit(&itask->itask_audit_mutex);
4965 }
4966
4967
4968 /*
4969 * ++++++++++++++ ABORT LOGIC ++++++++++++++++++++
4970 * Once ITASK_BEING_ABORTED is set, ITASK_KNOWN_TO_LU can be reset already
4971 * i.e. before ITASK_BEING_ABORTED being set. But if it was not, it cannot
4972 * be reset until the LU explicitly calls stmf_task_lu_aborted(). Of course
4973 * the LU will make this call only if we call the LU's abort entry point.
4974 * we will only call that entry point if ITASK_KNOWN_TO_LU was set.
4975 *
4976 * Same logic applies for the port.
4977 *
4978 * Also ITASK_BEING_ABORTED will not be allowed to set if both KNOWN_TO_LU
4979 * and KNOWN_TO_TGT_PORT are reset.
4980 *
4981 * +++++++++++++++++++++++++++++++++++++++++++++++
4982 */
4983
4984 stmf_status_t
4985 stmf_xfer_data(scsi_task_t *task, stmf_data_buf_t *dbuf, uint32_t ioflags)
4986 {
4987 stmf_status_t ret = STMF_SUCCESS;
4988
4989 stmf_i_scsi_task_t *itask =
4990 (stmf_i_scsi_task_t *)task->task_stmf_private;
4991
4992 stmf_task_audit(itask, TE_XFER_START, ioflags, dbuf);
4993
4994 if (ioflags & STMF_IOF_LU_DONE) {
4995 uint32_t new, old;
4996 do {
4997 new = old = itask->itask_flags;
4998 if (new & ITASK_BEING_ABORTED)
4999 return (STMF_ABORTED);
5000 new &= ~ITASK_KNOWN_TO_LU;
5001 } while (atomic_cas_32(&itask->itask_flags, old, new) != old);
5002 }
5003 if (itask->itask_flags & ITASK_BEING_ABORTED)
5004 return (STMF_ABORTED);
5005 #ifdef DEBUG
5006 if (!(ioflags & STMF_IOF_STATS_ONLY) && stmf_drop_buf_counter > 0) {
5007 if (atomic_add_32_nv((uint32_t *)&stmf_drop_buf_counter, -1) ==
5008 1)
5009 return (STMF_SUCCESS);
5010 }
5011 #endif
5012
5013 stmf_update_kstat_lu_io(task, dbuf);
5014 stmf_update_kstat_lport_io(task, dbuf);
5015 stmf_lport_xfer_start(itask, dbuf);
5016 if (ioflags & STMF_IOF_STATS_ONLY) {
5017 stmf_lport_xfer_done(itask, dbuf);
5018 return (STMF_SUCCESS);
5019 }
5020
5021 dbuf->db_flags |= DB_LPORT_XFER_ACTIVE;
5022 ret = task->task_lport->lport_xfer_data(task, dbuf, ioflags);
5023
5024 /*
5025 * Port provider may have already called the buffer callback in
5026 * which case dbuf->db_xfer_start_timestamp will be 0.
5027 */
5028 if (ret != STMF_SUCCESS) {
5029 dbuf->db_flags &= ~DB_LPORT_XFER_ACTIVE;
5030 if (dbuf->db_xfer_start_timestamp != 0)
5031 stmf_lport_xfer_done(itask, dbuf);
5032 }
5033
5034 return (ret);
5035 }
5036
5037 void
5038 stmf_data_xfer_done(scsi_task_t *task, stmf_data_buf_t *dbuf, uint32_t iof)
5039 {
5040 stmf_i_scsi_task_t *itask =
5041 (stmf_i_scsi_task_t *)task->task_stmf_private;
5042 stmf_i_local_port_t *ilport;
5043 stmf_worker_t *w = itask->itask_worker;
5044 uint32_t new, old;
5045 uint8_t update_queue_flags, free_it, queue_it;
5046
5047 stmf_lport_xfer_done(itask, dbuf);
5048
5049 stmf_task_audit(itask, TE_XFER_DONE, iof, dbuf);
5050
5051 /* Guard against unexpected completions from the lport */
5052 if (dbuf->db_flags & DB_LPORT_XFER_ACTIVE) {
5053 dbuf->db_flags &= ~DB_LPORT_XFER_ACTIVE;
5054 } else {
5055 /*
5056 * This should never happen.
5057 */
5058 ilport = task->task_lport->lport_stmf_private;
5059 ilport->ilport_unexpected_comp++;
5060 cmn_err(CE_PANIC, "Unexpected xfer completion task %p dbuf %p",
5061 (void *)task, (void *)dbuf);
5062 return;
5063 }
5064
5065 mutex_enter(&w->worker_lock);
5066 do {
5067 new = old = itask->itask_flags;
5068 if (old & ITASK_BEING_ABORTED) {
5069 mutex_exit(&w->worker_lock);
5070 return;
5071 }
5072 free_it = 0;
5073 if (iof & STMF_IOF_LPORT_DONE) {
5074 new &= ~ITASK_KNOWN_TO_TGT_PORT;
5075 task->task_completion_status = dbuf->db_xfer_status;
5076 free_it = 1;
5077 }
5078 /*
5079 * If the task is known to LU then queue it. But if
5080 * it is already queued (multiple completions) then
5081 * just update the buffer information by grabbing the
5082 * worker lock. If the task is not known to LU,
5083 * completed/aborted, then see if we need to
5084 * free this task.
5085 */
5086 if (old & ITASK_KNOWN_TO_LU) {
5087 free_it = 0;
5088 update_queue_flags = 1;
5089 if (old & ITASK_IN_WORKER_QUEUE) {
5090 queue_it = 0;
5091 } else {
5092 queue_it = 1;
5093 new |= ITASK_IN_WORKER_QUEUE;
5094 }
5095 } else {
5096 update_queue_flags = 0;
5097 queue_it = 0;
5098 }
5099 } while (atomic_cas_32(&itask->itask_flags, old, new) != old);
5100
5101 if (update_queue_flags) {
5102 uint8_t cmd = (dbuf->db_handle << 5) | ITASK_CMD_DATA_XFER_DONE;
5103
5104 ASSERT(itask->itask_ncmds < ITASK_MAX_NCMDS);
5105 itask->itask_cmd_stack[itask->itask_ncmds++] = cmd;
5106 if (queue_it) {
5107 itask->itask_worker_next = NULL;
5108 if (w->worker_task_tail) {
5109 w->worker_task_tail->itask_worker_next = itask;
5110 } else {
5111 w->worker_task_head = itask;
5112 }
5113 w->worker_task_tail = itask;
5114 /* Measure task waitq time */
5115 itask->itask_waitq_enter_timestamp = gethrtime();
5116 if (++(w->worker_queue_depth) >
5117 w->worker_max_qdepth_pu) {
5118 w->worker_max_qdepth_pu = w->worker_queue_depth;
5119 }
5120 if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0)
5121 cv_signal(&w->worker_cv);
5122 }
5123 }
5124 mutex_exit(&w->worker_lock);
5125
5126 if (free_it) {
5127 if ((itask->itask_flags & (ITASK_KNOWN_TO_LU |
5128 ITASK_KNOWN_TO_TGT_PORT | ITASK_IN_WORKER_QUEUE |
5129 ITASK_BEING_ABORTED)) == 0) {
5130 stmf_task_free(task);
5131 }
5132 }
5133 }
5134
5135 stmf_status_t
5136 stmf_send_scsi_status(scsi_task_t *task, uint32_t ioflags)
5137 {
5138 DTRACE_PROBE1(scsi__send__status, scsi_task_t *, task);
5139
5140 stmf_i_scsi_task_t *itask =
5141 (stmf_i_scsi_task_t *)task->task_stmf_private;
5142
5143 stmf_task_audit(itask, TE_SEND_STATUS, ioflags, NULL);
5144
5145 if (ioflags & STMF_IOF_LU_DONE) {
5146 uint32_t new, old;
5147 do {
5148 new = old = itask->itask_flags;
5149 if (new & ITASK_BEING_ABORTED)
5150 return (STMF_ABORTED);
5151 new &= ~ITASK_KNOWN_TO_LU;
5152 } while (atomic_cas_32(&itask->itask_flags, old, new) != old);
5153 }
5154
5155 if (!(itask->itask_flags & ITASK_KNOWN_TO_TGT_PORT)) {
5156 return (STMF_SUCCESS);
5157 }
5158
5159 if (itask->itask_flags & ITASK_BEING_ABORTED)
5160 return (STMF_ABORTED);
5161
5162 if (task->task_additional_flags & TASK_AF_NO_EXPECTED_XFER_LENGTH) {
5163 task->task_status_ctrl = 0;
5164 task->task_resid = 0;
5165 } else if (task->task_cmd_xfer_length >
5166 task->task_expected_xfer_length) {
5167 task->task_status_ctrl = TASK_SCTRL_OVER;
5168 task->task_resid = task->task_cmd_xfer_length -
5169 task->task_expected_xfer_length;
5170 } else if (task->task_nbytes_transferred <
5171 task->task_expected_xfer_length) {
5172 task->task_status_ctrl = TASK_SCTRL_UNDER;
5173 task->task_resid = task->task_expected_xfer_length -
5174 task->task_nbytes_transferred;
5175 } else {
5176 task->task_status_ctrl = 0;
5177 task->task_resid = 0;
5178 }
5179 return (task->task_lport->lport_send_status(task, ioflags));
5180 }
5181
5182 void
5183 stmf_send_status_done(scsi_task_t *task, stmf_status_t s, uint32_t iof)
5184 {
5185 stmf_i_scsi_task_t *itask =
5186 (stmf_i_scsi_task_t *)task->task_stmf_private;
5187 stmf_worker_t *w = itask->itask_worker;
5188 uint32_t new, old;
5189 uint8_t free_it, queue_it;
5190
5191 stmf_task_audit(itask, TE_SEND_STATUS_DONE, iof, NULL);
5192
5193 mutex_enter(&w->worker_lock);
5194 do {
5195 new = old = itask->itask_flags;
5196 if (old & ITASK_BEING_ABORTED) {
5197 mutex_exit(&w->worker_lock);
5198 return;
5199 }
5200 free_it = 0;
5201 if (iof & STMF_IOF_LPORT_DONE) {
5202 new &= ~ITASK_KNOWN_TO_TGT_PORT;
5203 free_it = 1;
5204 }
5205 /*
5206 * If the task is known to LU then queue it. But if
5207 * it is already queued (multiple completions) then
5208 * just update the buffer information by grabbing the
5209 * worker lock. If the task is not known to LU,
5210 * completed/aborted, then see if we need to
5211 * free this task.
5212 */
5213 if (old & ITASK_KNOWN_TO_LU) {
5214 free_it = 0;
5215 queue_it = 1;
5216 if (old & ITASK_IN_WORKER_QUEUE) {
5217 cmn_err(CE_PANIC, "status completion received"
5218 " when task is already in worker queue "
5219 " task = %p", (void *)task);
5220 }
5221 new |= ITASK_IN_WORKER_QUEUE;
5222 } else {
5223 queue_it = 0;
5224 }
5225 } while (atomic_cas_32(&itask->itask_flags, old, new) != old);
5226 task->task_completion_status = s;
5227
5228
5229 if (queue_it) {
5230 ASSERT(itask->itask_ncmds < ITASK_MAX_NCMDS);
5231 itask->itask_cmd_stack[itask->itask_ncmds++] =
5232 ITASK_CMD_STATUS_DONE;
5233 itask->itask_worker_next = NULL;
5234 if (w->worker_task_tail) {
5235 w->worker_task_tail->itask_worker_next = itask;
5236 } else {
5237 w->worker_task_head = itask;
5238 }
5239 w->worker_task_tail = itask;
5240 /* Measure task waitq time */
5241 itask->itask_waitq_enter_timestamp = gethrtime();
5242 if (++(w->worker_queue_depth) > w->worker_max_qdepth_pu) {
5243 w->worker_max_qdepth_pu = w->worker_queue_depth;
5244 }
5245 if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0)
5246 cv_signal(&w->worker_cv);
5247 }
5248 mutex_exit(&w->worker_lock);
5249
5250 if (free_it) {
5251 if ((itask->itask_flags & (ITASK_KNOWN_TO_LU |
5252 ITASK_KNOWN_TO_TGT_PORT | ITASK_IN_WORKER_QUEUE |
5253 ITASK_BEING_ABORTED)) == 0) {
5254 stmf_task_free(task);
5255 } else {
5256 cmn_err(CE_PANIC, "LU is done with the task but LPORT "
5257 " is not done, itask %p itask_flags %x",
5258 (void *)itask, itask->itask_flags);
5259 }
5260 }
5261 }
5262
5263 void
5264 stmf_task_lu_done(scsi_task_t *task)
5265 {
5266 stmf_i_scsi_task_t *itask =
5267 (stmf_i_scsi_task_t *)task->task_stmf_private;
5268 stmf_worker_t *w = itask->itask_worker;
5269 uint32_t new, old;
5270
5271 mutex_enter(&w->worker_lock);
5272 do {
5273 new = old = itask->itask_flags;
5274 if (old & ITASK_BEING_ABORTED) {
5275 mutex_exit(&w->worker_lock);
5276 return;
5277 }
5278 if (old & ITASK_IN_WORKER_QUEUE) {
5279 cmn_err(CE_PANIC, "task_lu_done received"
5280 " when task is in worker queue "
5281 " task = %p", (void *)task);
5282 }
5283 new &= ~ITASK_KNOWN_TO_LU;
5284 } while (atomic_cas_32(&itask->itask_flags, old, new) != old);
5285
5286 mutex_exit(&w->worker_lock);
5287
5288 if ((itask->itask_flags & (ITASK_KNOWN_TO_LU |
5289 ITASK_KNOWN_TO_TGT_PORT | ITASK_IN_WORKER_QUEUE |
5290 ITASK_BEING_ABORTED)) == 0) {
5291 stmf_task_free(task);
5292 } else {
5293 cmn_err(CE_PANIC, "stmf_lu_done should be the last stage but "
5294 " the task is still not done, task = %p", (void *)task);
5295 }
5296 }
5297
5298 void
5299 stmf_queue_task_for_abort(scsi_task_t *task, stmf_status_t s)
5300 {
5301 stmf_i_scsi_task_t *itask =
5302 (stmf_i_scsi_task_t *)task->task_stmf_private;
5303 stmf_worker_t *w;
5304 uint32_t old, new;
5305
5306 stmf_task_audit(itask, TE_TASK_ABORT, CMD_OR_IOF_NA, NULL);
5307
5308 do {
5309 old = new = itask->itask_flags;
5310 if ((old & ITASK_BEING_ABORTED) ||
5311 ((old & (ITASK_KNOWN_TO_TGT_PORT |
5312 ITASK_KNOWN_TO_LU)) == 0)) {
5313 return;
5314 }
5315 new |= ITASK_BEING_ABORTED;
5316 } while (atomic_cas_32(&itask->itask_flags, old, new) != old);
5317 task->task_completion_status = s;
5318 itask->itask_start_time = ddi_get_lbolt();
5319
5320 if (((w = itask->itask_worker) == NULL) ||
5321 (itask->itask_flags & ITASK_IN_TRANSITION)) {
5322 return;
5323 }
5324
5325 /* Queue it and get out */
5326 mutex_enter(&w->worker_lock);
5327 if (itask->itask_flags & ITASK_IN_WORKER_QUEUE) {
5328 mutex_exit(&w->worker_lock);
5329 return;
5330 }
5331 atomic_or_32(&itask->itask_flags, ITASK_IN_WORKER_QUEUE);
5332 itask->itask_worker_next = NULL;
5333 if (w->worker_task_tail) {
5334 w->worker_task_tail->itask_worker_next = itask;
5335 } else {
5336 w->worker_task_head = itask;
5337 }
5338 w->worker_task_tail = itask;
5339 if (++(w->worker_queue_depth) > w->worker_max_qdepth_pu) {
5340 w->worker_max_qdepth_pu = w->worker_queue_depth;
5341 }
5342 if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0)
5343 cv_signal(&w->worker_cv);
5344 mutex_exit(&w->worker_lock);
5345 }
5346
5347 void
5348 stmf_abort(int abort_cmd, scsi_task_t *task, stmf_status_t s, void *arg)
5349 {
5350 stmf_i_scsi_task_t *itask = NULL;
5351 uint32_t old, new, f, rf;
5352
5353 DTRACE_PROBE2(scsi__task__abort, scsi_task_t *, task,
5354 stmf_status_t, s);
5355
5356 switch (abort_cmd) {
5357 case STMF_QUEUE_ABORT_LU:
5358 stmf_task_lu_killall((stmf_lu_t *)arg, task, s);
5359 return;
5360 case STMF_QUEUE_TASK_ABORT:
5361 stmf_queue_task_for_abort(task, s);
5362 return;
5363 case STMF_REQUEUE_TASK_ABORT_LPORT:
5364 rf = ITASK_TGT_PORT_ABORT_CALLED;
5365 f = ITASK_KNOWN_TO_TGT_PORT;
5366 break;
5367 case STMF_REQUEUE_TASK_ABORT_LU:
5368 rf = ITASK_LU_ABORT_CALLED;
5369 f = ITASK_KNOWN_TO_LU;
5370 break;
5371 default:
5372 return;
5373 }
5374 itask = (stmf_i_scsi_task_t *)task->task_stmf_private;
5375 f |= ITASK_BEING_ABORTED | rf;
5376 do {
5377 old = new = itask->itask_flags;
5378 if ((old & f) != f) {
5379 return;
5380 }
5381 new &= ~rf;
5382 } while (atomic_cas_32(&itask->itask_flags, old, new) != old);
5383 }
5384
5385 void
5386 stmf_task_lu_aborted(scsi_task_t *task, stmf_status_t s, uint32_t iof)
5387 {
5388 char info[STMF_CHANGE_INFO_LEN];
5389 stmf_i_scsi_task_t *itask = TASK_TO_ITASK(task);
5390 unsigned long long st;
5391
5392 stmf_task_audit(itask, TE_TASK_LU_ABORTED, iof, NULL);
5393
5394 st = s; /* gcc fix */
5395 if ((s != STMF_ABORT_SUCCESS) && (s != STMF_NOT_FOUND)) {
5396 (void) snprintf(info, sizeof (info),
5397 "task %p, lu failed to abort ret=%llx", (void *)task, st);
5398 } else if ((iof & STMF_IOF_LU_DONE) == 0) {
5399 (void) snprintf(info, sizeof (info),
5400 "Task aborted but LU is not finished, task ="
5401 "%p, s=%llx, iof=%x", (void *)task, st, iof);
5402 } else {
5403 /*
5404 * LU abort successfully
5405 */
5406 atomic_and_32(&itask->itask_flags, ~ITASK_KNOWN_TO_LU);
5407 return;
5408 }
5409
5410 stmf_abort_task_offline(task, 1, info);
5411 }
5412
5413 void
5414 stmf_task_lport_aborted(scsi_task_t *task, stmf_status_t s, uint32_t iof)
5415 {
5416 char info[STMF_CHANGE_INFO_LEN];
5417 stmf_i_scsi_task_t *itask = TASK_TO_ITASK(task);
5418 unsigned long long st;
5419 uint32_t old, new;
5420
5421 stmf_task_audit(itask, TE_TASK_LPORT_ABORTED, iof, NULL);
5422
5423 st = s;
5424 if ((s != STMF_ABORT_SUCCESS) && (s != STMF_NOT_FOUND)) {
5425 (void) snprintf(info, sizeof (info),
5426 "task %p, tgt port failed to abort ret=%llx", (void *)task,
5427 st);
5428 } else if ((iof & STMF_IOF_LPORT_DONE) == 0) {
5429 (void) snprintf(info, sizeof (info),
5430 "Task aborted but tgt port is not finished, "
5431 "task=%p, s=%llx, iof=%x", (void *)task, st, iof);
5432 } else {
5433 /*
5434 * LPORT abort successfully
5435 */
5436 do {
5437 old = new = itask->itask_flags;
5438 if (!(old & ITASK_KNOWN_TO_TGT_PORT))
5439 return;
5440 new &= ~ITASK_KNOWN_TO_TGT_PORT;
5441 } while (atomic_cas_32(&itask->itask_flags, old, new) != old);
5442 return;
5443 }
5444
5445 stmf_abort_task_offline(task, 0, info);
5446 }
5447
5448 stmf_status_t
5449 stmf_task_poll_lu(scsi_task_t *task, uint32_t timeout)
5450 {
5451 stmf_i_scsi_task_t *itask = (stmf_i_scsi_task_t *)
5452 task->task_stmf_private;
5453 stmf_worker_t *w = itask->itask_worker;
5454 int i;
5455
5456 ASSERT(itask->itask_flags & ITASK_KNOWN_TO_LU);
5457 mutex_enter(&w->worker_lock);
5458 if (itask->itask_ncmds >= ITASK_MAX_NCMDS) {
5459 mutex_exit(&w->worker_lock);
5460 return (STMF_BUSY);
5461 }
5462 for (i = 0; i < itask->itask_ncmds; i++) {
5463 if (itask->itask_cmd_stack[i] == ITASK_CMD_POLL_LU) {
5464 mutex_exit(&w->worker_lock);
5465 return (STMF_SUCCESS);
5466 }
5467 }
5468 itask->itask_cmd_stack[itask->itask_ncmds++] = ITASK_CMD_POLL_LU;
5469 if (timeout == ITASK_DEFAULT_POLL_TIMEOUT) {
5470 itask->itask_poll_timeout = ddi_get_lbolt() + 1;
5471 } else {
5472 clock_t t = drv_usectohz(timeout * 1000);
5473 if (t == 0)
5474 t = 1;
5475 itask->itask_poll_timeout = ddi_get_lbolt() + t;
5476 }
5477 if ((itask->itask_flags & ITASK_IN_WORKER_QUEUE) == 0) {
5478 itask->itask_worker_next = NULL;
5479 if (w->worker_task_tail) {
5480 w->worker_task_tail->itask_worker_next = itask;
5481 } else {
5482 w->worker_task_head = itask;
5483 }
5484 w->worker_task_tail = itask;
5485 if (++(w->worker_queue_depth) > w->worker_max_qdepth_pu) {
5486 w->worker_max_qdepth_pu = w->worker_queue_depth;
5487 }
5488 atomic_or_32(&itask->itask_flags, ITASK_IN_WORKER_QUEUE);
5489 if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0)
5490 cv_signal(&w->worker_cv);
5491 }
5492 mutex_exit(&w->worker_lock);
5493 return (STMF_SUCCESS);
5494 }
5495
5496 stmf_status_t
5497 stmf_task_poll_lport(scsi_task_t *task, uint32_t timeout)
5498 {
5499 stmf_i_scsi_task_t *itask = (stmf_i_scsi_task_t *)
5500 task->task_stmf_private;
5501 stmf_worker_t *w = itask->itask_worker;
5502 int i;
5503
5504 ASSERT(itask->itask_flags & ITASK_KNOWN_TO_TGT_PORT);
5505 mutex_enter(&w->worker_lock);
5506 if (itask->itask_ncmds >= ITASK_MAX_NCMDS) {
5507 mutex_exit(&w->worker_lock);
5508 return (STMF_BUSY);
5509 }
5510 for (i = 0; i < itask->itask_ncmds; i++) {
5511 if (itask->itask_cmd_stack[i] == ITASK_CMD_POLL_LPORT) {
5512 mutex_exit(&w->worker_lock);
5513 return (STMF_SUCCESS);
5514 }
5515 }
5516 itask->itask_cmd_stack[itask->itask_ncmds++] = ITASK_CMD_POLL_LPORT;
5517 if (timeout == ITASK_DEFAULT_POLL_TIMEOUT) {
5518 itask->itask_poll_timeout = ddi_get_lbolt() + 1;
5519 } else {
5520 clock_t t = drv_usectohz(timeout * 1000);
5521 if (t == 0)
5522 t = 1;
5523 itask->itask_poll_timeout = ddi_get_lbolt() + t;
5524 }
5525 if ((itask->itask_flags & ITASK_IN_WORKER_QUEUE) == 0) {
5526 itask->itask_worker_next = NULL;
5527 if (w->worker_task_tail) {
5528 w->worker_task_tail->itask_worker_next = itask;
5529 } else {
5530 w->worker_task_head = itask;
5531 }
5532 w->worker_task_tail = itask;
5533 if (++(w->worker_queue_depth) > w->worker_max_qdepth_pu) {
5534 w->worker_max_qdepth_pu = w->worker_queue_depth;
5535 }
5536 if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0)
5537 cv_signal(&w->worker_cv);
5538 }
5539 mutex_exit(&w->worker_lock);
5540 return (STMF_SUCCESS);
5541 }
5542
5543 void
5544 stmf_do_task_abort(scsi_task_t *task)
5545 {
5546 stmf_i_scsi_task_t *itask = TASK_TO_ITASK(task);
5547 stmf_lu_t *lu;
5548 stmf_local_port_t *lport;
5549 unsigned long long ret;
5550 uint32_t old, new;
5551 uint8_t call_lu_abort, call_port_abort;
5552 char info[STMF_CHANGE_INFO_LEN];
5553
5554 lu = task->task_lu;
5555 lport = task->task_lport;
5556 do {
5557 old = new = itask->itask_flags;
5558 if ((old & (ITASK_KNOWN_TO_LU | ITASK_LU_ABORT_CALLED)) ==
5559 ITASK_KNOWN_TO_LU) {
5560 new |= ITASK_LU_ABORT_CALLED;
5561 call_lu_abort = 1;
5562 } else {
5563 call_lu_abort = 0;
5564 }
5565 } while (atomic_cas_32(&itask->itask_flags, old, new) != old);
5566
5567 if (call_lu_abort) {
5568 if ((itask->itask_flags & ITASK_DEFAULT_HANDLING) == 0) {
5569 ret = lu->lu_abort(lu, STMF_LU_ABORT_TASK, task, 0);
5570 } else {
5571 ret = dlun0->lu_abort(lu, STMF_LU_ABORT_TASK, task, 0);
5572 }
5573 if ((ret == STMF_ABORT_SUCCESS) || (ret == STMF_NOT_FOUND)) {
5574 stmf_task_lu_aborted(task, ret, STMF_IOF_LU_DONE);
5575 } else if (ret == STMF_BUSY) {
5576 atomic_and_32(&itask->itask_flags,
5577 ~ITASK_LU_ABORT_CALLED);
5578 } else if (ret != STMF_SUCCESS) {
5579 (void) snprintf(info, sizeof (info),
5580 "Abort failed by LU %p, ret %llx", (void *)lu, ret);
5581 stmf_abort_task_offline(task, 1, info);
5582 }
5583 } else if (itask->itask_flags & ITASK_KNOWN_TO_LU) {
5584 if (ddi_get_lbolt() > (itask->itask_start_time +
5585 STMF_SEC2TICK(lu->lu_abort_timeout?
5586 lu->lu_abort_timeout : ITASK_DEFAULT_ABORT_TIMEOUT))) {
5587 (void) snprintf(info, sizeof (info),
5588 "lu abort timed out");
5589 stmf_abort_task_offline(itask->itask_task, 1, info);
5590 }
5591 }
5592
5593 do {
5594 old = new = itask->itask_flags;
5595 if ((old & (ITASK_KNOWN_TO_TGT_PORT |
5596 ITASK_TGT_PORT_ABORT_CALLED)) == ITASK_KNOWN_TO_TGT_PORT) {
5597 new |= ITASK_TGT_PORT_ABORT_CALLED;
5598 call_port_abort = 1;
5599 } else {
5600 call_port_abort = 0;
5601 }
5602 } while (atomic_cas_32(&itask->itask_flags, old, new) != old);
5603 if (call_port_abort) {
5604 ret = lport->lport_abort(lport, STMF_LPORT_ABORT_TASK, task, 0);
5605 if ((ret == STMF_ABORT_SUCCESS) || (ret == STMF_NOT_FOUND)) {
5606 stmf_task_lport_aborted(task, ret, STMF_IOF_LPORT_DONE);
5607 } else if (ret == STMF_BUSY) {
5608 atomic_and_32(&itask->itask_flags,
5609 ~ITASK_TGT_PORT_ABORT_CALLED);
5610 } else if (ret != STMF_SUCCESS) {
5611 (void) snprintf(info, sizeof (info),
5612 "Abort failed by tgt port %p ret %llx",
5613 (void *)lport, ret);
5614 stmf_abort_task_offline(task, 0, info);
5615 }
5616 } else if (itask->itask_flags & ITASK_KNOWN_TO_TGT_PORT) {
5617 if (ddi_get_lbolt() > (itask->itask_start_time +
5618 STMF_SEC2TICK(lport->lport_abort_timeout?
5619 lport->lport_abort_timeout :
5620 ITASK_DEFAULT_ABORT_TIMEOUT))) {
5621 (void) snprintf(info, sizeof (info),
5622 "lport abort timed out");
5623 stmf_abort_task_offline(itask->itask_task, 0, info);
5624 }
5625 }
5626 }
5627
5628 stmf_status_t
5629 stmf_ctl(int cmd, void *obj, void *arg)
5630 {
5631 stmf_status_t ret;
5632 stmf_i_lu_t *ilu;
5633 stmf_i_local_port_t *ilport;
5634 stmf_state_change_info_t *ssci = (stmf_state_change_info_t *)arg;
5635
5636 mutex_enter(&stmf_state.stmf_lock);
5637 ret = STMF_INVALID_ARG;
5638 if (cmd & STMF_CMD_LU_OP) {
5639 ilu = stmf_lookup_lu((stmf_lu_t *)obj);
5640 if (ilu == NULL) {
5641 goto stmf_ctl_lock_exit;
5642 }
5643 DTRACE_PROBE3(lu__state__change,
5644 stmf_lu_t *, ilu->ilu_lu,
5645 int, cmd, stmf_state_change_info_t *, ssci);
5646 } else if (cmd & STMF_CMD_LPORT_OP) {
5647 ilport = stmf_lookup_lport((stmf_local_port_t *)obj);
5648 if (ilport == NULL) {
5649 goto stmf_ctl_lock_exit;
5650 }
5651 DTRACE_PROBE3(lport__state__change,
5652 stmf_local_port_t *, ilport->ilport_lport,
5653 int, cmd, stmf_state_change_info_t *, ssci);
5654 } else {
5655 goto stmf_ctl_lock_exit;
5656 }
5657
5658 switch (cmd) {
5659 case STMF_CMD_LU_ONLINE:
5660 switch (ilu->ilu_state) {
5661 case STMF_STATE_OFFLINE:
5662 ret = STMF_SUCCESS;
5663 break;
5664 case STMF_STATE_ONLINE:
5665 case STMF_STATE_ONLINING:
5666 ret = STMF_ALREADY;
5667 break;
5668 case STMF_STATE_OFFLINING:
5669 ret = STMF_BUSY;
5670 break;
5671 default:
5672 ret = STMF_BADSTATE;
5673 break;
5674 }
5675 if (ret != STMF_SUCCESS)
5676 goto stmf_ctl_lock_exit;
5677
5678 ilu->ilu_state = STMF_STATE_ONLINING;
5679 mutex_exit(&stmf_state.stmf_lock);
5680 stmf_svc_queue(cmd, obj, (stmf_state_change_info_t *)arg);
5681 break;
5682
5683 case STMF_CMD_LU_ONLINE_COMPLETE:
5684 if (ilu->ilu_state != STMF_STATE_ONLINING) {
5685 ret = STMF_BADSTATE;
5686 goto stmf_ctl_lock_exit;
5687 }
5688 if (((stmf_change_status_t *)arg)->st_completion_status ==
5689 STMF_SUCCESS) {
5690 ilu->ilu_state = STMF_STATE_ONLINE;
5691 mutex_exit(&stmf_state.stmf_lock);
5692 ((stmf_lu_t *)obj)->lu_ctl((stmf_lu_t *)obj,
5693 STMF_ACK_LU_ONLINE_COMPLETE, arg);
5694 mutex_enter(&stmf_state.stmf_lock);
5695 stmf_add_lu_to_active_sessions((stmf_lu_t *)obj);
5696 } else {
5697 /* XXX: should throw a meesage an record more data */
5698 ilu->ilu_state = STMF_STATE_OFFLINE;
5699 }
5700 ret = STMF_SUCCESS;
5701 goto stmf_ctl_lock_exit;
5702
5703 case STMF_CMD_LU_OFFLINE:
5704 switch (ilu->ilu_state) {
5705 case STMF_STATE_ONLINE:
5706 ret = STMF_SUCCESS;
5707 break;
5708 case STMF_STATE_OFFLINE:
5709 case STMF_STATE_OFFLINING:
5710 ret = STMF_ALREADY;
5711 break;
5712 case STMF_STATE_ONLINING:
5713 ret = STMF_BUSY;
5714 break;
5715 default:
5716 ret = STMF_BADSTATE;
5717 break;
5718 }
5719 if (ret != STMF_SUCCESS)
5720 goto stmf_ctl_lock_exit;
5721 ilu->ilu_state = STMF_STATE_OFFLINING;
5722 mutex_exit(&stmf_state.stmf_lock);
5723 stmf_svc_queue(cmd, obj, (stmf_state_change_info_t *)arg);
5724 break;
5725
5726 case STMF_CMD_LU_OFFLINE_COMPLETE:
5727 if (ilu->ilu_state != STMF_STATE_OFFLINING) {
5728 ret = STMF_BADSTATE;
5729 goto stmf_ctl_lock_exit;
5730 }
5731 if (((stmf_change_status_t *)arg)->st_completion_status ==
5732 STMF_SUCCESS) {
5733 ilu->ilu_state = STMF_STATE_OFFLINE;
5734 mutex_exit(&stmf_state.stmf_lock);
5735 ((stmf_lu_t *)obj)->lu_ctl((stmf_lu_t *)obj,
5736 STMF_ACK_LU_OFFLINE_COMPLETE, arg);
5737 mutex_enter(&stmf_state.stmf_lock);
5738 } else {
5739 ilu->ilu_state = STMF_STATE_ONLINE;
5740 stmf_add_lu_to_active_sessions((stmf_lu_t *)obj);
5741 }
5742 mutex_exit(&stmf_state.stmf_lock);
5743 break;
5744
5745 /*
5746 * LPORT_ONLINE/OFFLINE has nothing to do with link offline/online.
5747 * It's related with hardware disable/enable.
5748 */
5749 case STMF_CMD_LPORT_ONLINE:
5750 switch (ilport->ilport_state) {
5751 case STMF_STATE_OFFLINE:
5752 ret = STMF_SUCCESS;
5753 break;
5754 case STMF_STATE_ONLINE:
5755 case STMF_STATE_ONLINING:
5756 ret = STMF_ALREADY;
5757 break;
5758 case STMF_STATE_OFFLINING:
5759 ret = STMF_BUSY;
5760 break;
5761 default:
5762 ret = STMF_BADSTATE;
5763 break;
5764 }
5765 if (ret != STMF_SUCCESS)
5766 goto stmf_ctl_lock_exit;
5767
5768 /*
5769 * Only user request can recover the port from the
5770 * FORCED_OFFLINE state
5771 */
5772 if (ilport->ilport_flags & ILPORT_FORCED_OFFLINE) {
5773 if (!(ssci->st_rflags & STMF_RFLAG_USER_REQUEST)) {
5774 ret = STMF_FAILURE;
5775 goto stmf_ctl_lock_exit;
5776 }
5777 }
5778
5779 /*
5780 * Avoid too frequent request to online
5781 */
5782 if (ssci->st_rflags & STMF_RFLAG_USER_REQUEST) {
5783 ilport->ilport_online_times = 0;
5784 ilport->ilport_avg_interval = 0;
5785 }
5786 if ((ilport->ilport_avg_interval < STMF_AVG_ONLINE_INTERVAL) &&
5787 (ilport->ilport_online_times >= 4)) {
5788 ret = STMF_FAILURE;
5789 ilport->ilport_flags |= ILPORT_FORCED_OFFLINE;
5790 stmf_trace(NULL, "stmf_ctl: too frequent request to "
5791 "online the port");
5792 cmn_err(CE_WARN, "stmf_ctl: too frequent request to "
5793 "online the port, set FORCED_OFFLINE now");
5794 goto stmf_ctl_lock_exit;
5795 }
5796 if (ilport->ilport_online_times > 0) {
5797 if (ilport->ilport_online_times == 1) {
5798 ilport->ilport_avg_interval = ddi_get_lbolt() -
5799 ilport->ilport_last_online_clock;
5800 } else {
5801 ilport->ilport_avg_interval =
5802 (ilport->ilport_avg_interval +
5803 ddi_get_lbolt() -
5804 ilport->ilport_last_online_clock) >> 1;
5805 }
5806 }
5807 ilport->ilport_last_online_clock = ddi_get_lbolt();
5808 ilport->ilport_online_times++;
5809
5810 /*
5811 * Submit online service request
5812 */
5813 ilport->ilport_flags &= ~ILPORT_FORCED_OFFLINE;
5814 ilport->ilport_state = STMF_STATE_ONLINING;
5815 mutex_exit(&stmf_state.stmf_lock);
5816 stmf_svc_queue(cmd, obj, (stmf_state_change_info_t *)arg);
5817 break;
5818
5819 case STMF_CMD_LPORT_ONLINE_COMPLETE:
5820 if (ilport->ilport_state != STMF_STATE_ONLINING) {
5821 ret = STMF_BADSTATE;
5822 goto stmf_ctl_lock_exit;
5823 }
5824 if (((stmf_change_status_t *)arg)->st_completion_status ==
5825 STMF_SUCCESS) {
5826 ilport->ilport_state = STMF_STATE_ONLINE;
5827 mutex_exit(&stmf_state.stmf_lock);
5828 ((stmf_local_port_t *)obj)->lport_ctl(
5829 (stmf_local_port_t *)obj,
5830 STMF_ACK_LPORT_ONLINE_COMPLETE, arg);
5831 mutex_enter(&stmf_state.stmf_lock);
5832 } else {
5833 ilport->ilport_state = STMF_STATE_OFFLINE;
5834 }
5835 ret = STMF_SUCCESS;
5836 goto stmf_ctl_lock_exit;
5837
5838 case STMF_CMD_LPORT_OFFLINE:
5839 switch (ilport->ilport_state) {
5840 case STMF_STATE_ONLINE:
5841 ret = STMF_SUCCESS;
5842 break;
5843 case STMF_STATE_OFFLINE:
5844 case STMF_STATE_OFFLINING:
5845 ret = STMF_ALREADY;
5846 break;
5847 case STMF_STATE_ONLINING:
5848 ret = STMF_BUSY;
5849 break;
5850 default:
5851 ret = STMF_BADSTATE;
5852 break;
5853 }
5854 if (ret != STMF_SUCCESS)
5855 goto stmf_ctl_lock_exit;
5856
5857 ilport->ilport_state = STMF_STATE_OFFLINING;
5858 mutex_exit(&stmf_state.stmf_lock);
5859 stmf_svc_queue(cmd, obj, (stmf_state_change_info_t *)arg);
5860 break;
5861
5862 case STMF_CMD_LPORT_OFFLINE_COMPLETE:
5863 if (ilport->ilport_state != STMF_STATE_OFFLINING) {
5864 ret = STMF_BADSTATE;
5865 goto stmf_ctl_lock_exit;
5866 }
5867 if (((stmf_change_status_t *)arg)->st_completion_status ==
5868 STMF_SUCCESS) {
5869 ilport->ilport_state = STMF_STATE_OFFLINE;
5870 mutex_exit(&stmf_state.stmf_lock);
5871 ((stmf_local_port_t *)obj)->lport_ctl(
5872 (stmf_local_port_t *)obj,
5873 STMF_ACK_LPORT_OFFLINE_COMPLETE, arg);
5874 mutex_enter(&stmf_state.stmf_lock);
5875 } else {
5876 ilport->ilport_state = STMF_STATE_ONLINE;
5877 }
5878 mutex_exit(&stmf_state.stmf_lock);
5879 break;
5880
5881 default:
5882 cmn_err(CE_WARN, "Invalid ctl cmd received %x", cmd);
5883 ret = STMF_INVALID_ARG;
5884 goto stmf_ctl_lock_exit;
5885 }
5886
5887 return (STMF_SUCCESS);
5888
5889 stmf_ctl_lock_exit:;
5890 mutex_exit(&stmf_state.stmf_lock);
5891 return (ret);
5892 }
5893
5894 /* ARGSUSED */
5895 stmf_status_t
5896 stmf_info_impl(uint32_t cmd, void *arg1, void *arg2, uint8_t *buf,
5897 uint32_t *bufsizep)
5898 {
5899 return (STMF_NOT_SUPPORTED);
5900 }
5901
5902 /* ARGSUSED */
5903 stmf_status_t
5904 stmf_info(uint32_t cmd, void *arg1, void *arg2, uint8_t *buf,
5905 uint32_t *bufsizep)
5906 {
5907 uint32_t cl = SI_GET_CLASS(cmd);
5908
5909 if (cl == SI_STMF) {
5910 return (stmf_info_impl(cmd, arg1, arg2, buf, bufsizep));
5911 }
5912 if (cl == SI_LPORT) {
5913 return (((stmf_local_port_t *)arg1)->lport_info(cmd, arg1,
5914 arg2, buf, bufsizep));
5915 } else if (cl == SI_LU) {
5916 return (((stmf_lu_t *)arg1)->lu_info(cmd, arg1, arg2, buf,
5917 bufsizep));
5918 }
5919
5920 return (STMF_NOT_SUPPORTED);
5921 }
5922
5923 /*
5924 * Used by port providers. pwwn is 8 byte wwn, sdid is the devid used by
5925 * stmf to register local ports. The ident should have 20 bytes in buffer
5926 * space to convert the wwn to "wwn.xxxxxxxxxxxxxxxx" string.
5927 */
5928 void
5929 stmf_wwn_to_devid_desc(scsi_devid_desc_t *sdid, uint8_t *wwn,
5930 uint8_t protocol_id)
5931 {
5932 char wwn_str[20+1];
5933
5934 sdid->protocol_id = protocol_id;
5935 sdid->piv = 1;
5936 sdid->code_set = CODE_SET_ASCII;
5937 sdid->association = ID_IS_TARGET_PORT;
5938 sdid->ident_length = 20;
5939 /* Convert wwn value to "wwn.XXXXXXXXXXXXXXXX" format */
5940 (void) snprintf(wwn_str, sizeof (wwn_str),
5941 "wwn.%02X%02X%02X%02X%02X%02X%02X%02X",
5942 wwn[0], wwn[1], wwn[2], wwn[3], wwn[4], wwn[5], wwn[6], wwn[7]);
5943 bcopy(wwn_str, (char *)sdid->ident, 20);
5944 }
5945
5946
5947 stmf_xfer_data_t *
5948 stmf_prepare_tpgs_data(uint8_t ilu_alua)
5949 {
5950 stmf_xfer_data_t *xd;
5951 stmf_i_local_port_t *ilport;
5952 uint8_t *p;
5953 uint32_t sz, asz, nports = 0, nports_standby = 0;
5954
5955 mutex_enter(&stmf_state.stmf_lock);
5956 /* check if any ports are standby and create second group */
5957 for (ilport = stmf_state.stmf_ilportlist; ilport;
5958 ilport = ilport->ilport_next) {
5959 if (ilport->ilport_standby == 1) {
5960 nports_standby++;
5961 } else {
5962 nports++;
5963 }
5964 }
5965
5966 /* The spec only allows for 255 ports to be reported per group */
5967 nports = min(nports, 255);
5968 nports_standby = min(nports_standby, 255);
5969 sz = (nports * 4) + 12;
5970 if (nports_standby && ilu_alua) {
5971 sz += (nports_standby * 4) + 8;
5972 }
5973 asz = sz + sizeof (*xd) - 4;
5974 xd = (stmf_xfer_data_t *)kmem_zalloc(asz, KM_NOSLEEP);
5975 if (xd == NULL) {
5976 mutex_exit(&stmf_state.stmf_lock);
5977 return (NULL);
5978 }
5979 xd->alloc_size = asz;
5980 xd->size_left = sz;
5981
5982 p = xd->buf;
5983
5984 *((uint32_t *)p) = BE_32(sz - 4);
5985 p += 4;
5986 p[0] = 0x80; /* PREF */
5987 p[1] = 5; /* AO_SUP, S_SUP */
5988 if (stmf_state.stmf_alua_node == 1) {
5989 p[3] = 1; /* Group 1 */
5990 } else {
5991 p[3] = 0; /* Group 0 */
5992 }
5993 p[7] = nports & 0xff;
5994 p += 8;
5995 for (ilport = stmf_state.stmf_ilportlist; ilport;
5996 ilport = ilport->ilport_next) {
5997 if (ilport->ilport_standby == 1) {
5998 continue;
5999 }
6000 ((uint16_t *)p)[1] = BE_16(ilport->ilport_rtpid);
6001 p += 4;
6002 }
6003 if (nports_standby && ilu_alua) {
6004 p[0] = 0x02; /* Non PREF, Standby */
6005 p[1] = 5; /* AO_SUP, S_SUP */
6006 if (stmf_state.stmf_alua_node == 1) {
6007 p[3] = 0; /* Group 0 */
6008 } else {
6009 p[3] = 1; /* Group 1 */
6010 }
6011 p[7] = nports_standby & 0xff;
6012 p += 8;
6013 for (ilport = stmf_state.stmf_ilportlist; ilport;
6014 ilport = ilport->ilport_next) {
6015 if (ilport->ilport_standby == 0) {
6016 continue;
6017 }
6018 ((uint16_t *)p)[1] = BE_16(ilport->ilport_rtpid);
6019 p += 4;
6020 }
6021 }
6022
6023 mutex_exit(&stmf_state.stmf_lock);
6024
6025 return (xd);
6026 }
6027
6028 struct scsi_devid_desc *
6029 stmf_scsilib_get_devid_desc(uint16_t rtpid)
6030 {
6031 scsi_devid_desc_t *devid = NULL;
6032 stmf_i_local_port_t *ilport;
6033
6034 mutex_enter(&stmf_state.stmf_lock);
6035
6036 for (ilport = stmf_state.stmf_ilportlist; ilport;
6037 ilport = ilport->ilport_next) {
6038 if (ilport->ilport_rtpid == rtpid) {
6039 scsi_devid_desc_t *id = ilport->ilport_lport->lport_id;
6040 uint32_t id_sz = sizeof (scsi_devid_desc_t) +
6041 id->ident_length;
6042 devid = (scsi_devid_desc_t *)kmem_zalloc(id_sz,
6043 KM_NOSLEEP);
6044 if (devid != NULL) {
6045 bcopy(id, devid, id_sz);
6046 }
6047 break;
6048 }
6049 }
6050
6051 mutex_exit(&stmf_state.stmf_lock);
6052 return (devid);
6053 }
6054
6055 uint16_t
6056 stmf_scsilib_get_lport_rtid(struct scsi_devid_desc *devid)
6057 {
6058 stmf_i_local_port_t *ilport;
6059 scsi_devid_desc_t *id;
6060 uint16_t rtpid = 0;
6061
6062 mutex_enter(&stmf_state.stmf_lock);
6063 for (ilport = stmf_state.stmf_ilportlist; ilport;
6064 ilport = ilport->ilport_next) {
6065 id = ilport->ilport_lport->lport_id;
6066 if ((devid->ident_length == id->ident_length) &&
6067 (memcmp(devid->ident, id->ident, id->ident_length) == 0)) {
6068 rtpid = ilport->ilport_rtpid;
6069 break;
6070 }
6071 }
6072 mutex_exit(&stmf_state.stmf_lock);
6073 return (rtpid);
6074 }
6075
6076 static uint16_t stmf_lu_id_gen_number = 0;
6077
6078 stmf_status_t
6079 stmf_scsilib_uniq_lu_id(uint32_t company_id, scsi_devid_desc_t *lu_id)
6080 {
6081 return (stmf_scsilib_uniq_lu_id2(company_id, 0, lu_id));
6082 }
6083
6084 stmf_status_t
6085 stmf_scsilib_uniq_lu_id2(uint32_t company_id, uint32_t host_id,
6086 scsi_devid_desc_t *lu_id)
6087 {
6088 uint8_t *p;
6089 struct timeval32 timestamp32;
6090 uint32_t *t = (uint32_t *)×tamp32;
6091 struct ether_addr mac;
6092 uint8_t *e = (uint8_t *)&mac;
6093 int hid = (int)host_id;
6094
6095 if (company_id == COMPANY_ID_NONE)
6096 company_id = COMPANY_ID_SUN;
6097
6098 if (lu_id->ident_length != 0x10)
6099 return (STMF_INVALID_ARG);
6100
6101 p = (uint8_t *)lu_id;
6102
6103 atomic_add_16(&stmf_lu_id_gen_number, 1);
6104
6105 p[0] = 0xf1; p[1] = 3; p[2] = 0; p[3] = 0x10;
6106 p[4] = ((company_id >> 20) & 0xf) | 0x60;
6107 p[5] = (company_id >> 12) & 0xff;
6108 p[6] = (company_id >> 4) & 0xff;
6109 p[7] = (company_id << 4) & 0xf0;
6110 if (hid == 0 && !localetheraddr((struct ether_addr *)NULL, &mac)) {
6111 hid = BE_32((int)zone_get_hostid(NULL));
6112 }
6113 if (hid != 0) {
6114 e[0] = (hid >> 24) & 0xff;
6115 e[1] = (hid >> 16) & 0xff;
6116 e[2] = (hid >> 8) & 0xff;
6117 e[3] = hid & 0xff;
6118 e[4] = e[5] = 0;
6119 }
6120 bcopy(e, p+8, 6);
6121 uniqtime32(×tamp32);
6122 *t = BE_32(*t);
6123 bcopy(t, p+14, 4);
6124 p[18] = (stmf_lu_id_gen_number >> 8) & 0xff;
6125 p[19] = stmf_lu_id_gen_number & 0xff;
6126
6127 return (STMF_SUCCESS);
6128 }
6129
6130 /*
6131 * saa is sense key, ASC, ASCQ
6132 */
6133 void
6134 stmf_scsilib_send_status(scsi_task_t *task, uint8_t st, uint32_t saa)
6135 {
6136 uint8_t sd[18];
6137 task->task_scsi_status = st;
6138 if (st == 2) {
6139 bzero(sd, 18);
6140 sd[0] = 0x70;
6141 sd[2] = (saa >> 16) & 0xf;
6142 sd[7] = 10;
6143 sd[12] = (saa >> 8) & 0xff;
6144 sd[13] = saa & 0xff;
6145 task->task_sense_data = sd;
6146 task->task_sense_length = 18;
6147 } else {
6148 task->task_sense_data = NULL;
6149 task->task_sense_length = 0;
6150 }
6151 (void) stmf_send_scsi_status(task, STMF_IOF_LU_DONE);
6152 }
6153
6154 uint32_t
6155 stmf_scsilib_prepare_vpd_page83(scsi_task_t *task, uint8_t *page,
6156 uint32_t page_len, uint8_t byte0, uint32_t vpd_mask)
6157 {
6158 uint8_t *p = NULL;
6159 uint8_t small_buf[32];
6160 uint32_t sz = 0;
6161 uint32_t n = 4;
6162 uint32_t m = 0;
6163 uint32_t last_bit = 0;
6164
6165 if (page_len < 4)
6166 return (0);
6167 if (page_len > 65535)
6168 page_len = 65535;
6169
6170 page[0] = byte0;
6171 page[1] = 0x83;
6172
6173 /* CONSTCOND */
6174 while (1) {
6175 m += sz;
6176 if (sz && (page_len > n)) {
6177 uint32_t copysz;
6178 copysz = page_len > (n + sz) ? sz : page_len - n;
6179 bcopy(p, page + n, copysz);
6180 n += copysz;
6181 }
6182 vpd_mask &= ~last_bit;
6183 if (vpd_mask == 0)
6184 break;
6185
6186 if (vpd_mask & STMF_VPD_LU_ID) {
6187 last_bit = STMF_VPD_LU_ID;
6188 sz = task->task_lu->lu_id->ident_length + 4;
6189 p = (uint8_t *)task->task_lu->lu_id;
6190 continue;
6191 } else if (vpd_mask & STMF_VPD_TARGET_ID) {
6192 last_bit = STMF_VPD_TARGET_ID;
6193 sz = task->task_lport->lport_id->ident_length + 4;
6194 p = (uint8_t *)task->task_lport->lport_id;
6195 continue;
6196 } else if (vpd_mask & STMF_VPD_TP_GROUP) {
6197 stmf_i_local_port_t *ilport;
6198 last_bit = STMF_VPD_TP_GROUP;
6199 p = small_buf;
6200 bzero(p, 8);
6201 p[0] = 1;
6202 p[1] = 0x15;
6203 p[3] = 4;
6204 ilport = (stmf_i_local_port_t *)
6205 task->task_lport->lport_stmf_private;
6206 /*
6207 * If we're in alua mode, group 1 contains all alua
6208 * participating ports and all standby ports
6209 * > 255. Otherwise, if we're in alua mode, any local
6210 * ports (non standby/pppt) are also in group 1 if the
6211 * alua node is 1. Otherwise the group is 0.
6212 */
6213 if ((stmf_state.stmf_alua_state &&
6214 (ilport->ilport_alua || ilport->ilport_standby) &&
6215 ilport->ilport_rtpid > 255) ||
6216 (stmf_state.stmf_alua_node == 1 &&
6217 ilport->ilport_standby != 1)) {
6218 p[7] = 1; /* Group 1 */
6219 }
6220 sz = 8;
6221 continue;
6222 } else if (vpd_mask & STMF_VPD_RELATIVE_TP_ID) {
6223 stmf_i_local_port_t *ilport;
6224
6225 last_bit = STMF_VPD_RELATIVE_TP_ID;
6226 p = small_buf;
6227 bzero(p, 8);
6228 p[0] = 1;
6229 p[1] = 0x14;
6230 p[3] = 4;
6231 ilport = (stmf_i_local_port_t *)
6232 task->task_lport->lport_stmf_private;
6233 p[6] = (ilport->ilport_rtpid >> 8) & 0xff;
6234 p[7] = ilport->ilport_rtpid & 0xff;
6235 sz = 8;
6236 continue;
6237 } else {
6238 cmn_err(CE_WARN, "Invalid vpd_mask");
6239 break;
6240 }
6241 }
6242
6243 page[2] = (m >> 8) & 0xff;
6244 page[3] = m & 0xff;
6245
6246 return (n);
6247 }
6248
6249 void
6250 stmf_scsilib_handle_report_tpgs(scsi_task_t *task, stmf_data_buf_t *dbuf)
6251 {
6252 stmf_i_scsi_task_t *itask =
6253 (stmf_i_scsi_task_t *)task->task_stmf_private;
6254 stmf_i_lu_t *ilu =
6255 (stmf_i_lu_t *)task->task_lu->lu_stmf_private;
6256 stmf_xfer_data_t *xd;
6257 uint32_t sz, minsz;
6258
6259 itask->itask_flags |= ITASK_DEFAULT_HANDLING;
6260 task->task_cmd_xfer_length =
6261 ((((uint32_t)task->task_cdb[6]) << 24) |
6262 (((uint32_t)task->task_cdb[7]) << 16) |
6263 (((uint32_t)task->task_cdb[8]) << 8) |
6264 ((uint32_t)task->task_cdb[9]));
6265
6266 if (task->task_additional_flags &
6267 TASK_AF_NO_EXPECTED_XFER_LENGTH) {
6268 task->task_expected_xfer_length =
6269 task->task_cmd_xfer_length;
6270 }
6271
6272 if (task->task_cmd_xfer_length == 0) {
6273 stmf_scsilib_send_status(task, STATUS_GOOD, 0);
6274 return;
6275 }
6276 if (task->task_cmd_xfer_length < 4) {
6277 stmf_scsilib_send_status(task, STATUS_CHECK,
6278 STMF_SAA_INVALID_FIELD_IN_CDB);
6279 return;
6280 }
6281
6282 sz = min(task->task_expected_xfer_length,
6283 task->task_cmd_xfer_length);
6284
6285 xd = stmf_prepare_tpgs_data(ilu->ilu_alua);
6286
6287 if (xd == NULL) {
6288 stmf_abort(STMF_QUEUE_TASK_ABORT, task,
6289 STMF_ALLOC_FAILURE, NULL);
6290 return;
6291 }
6292
6293 sz = min(sz, xd->size_left);
6294 xd->size_left = sz;
6295 minsz = min(512, sz);
6296
6297 if (dbuf == NULL)
6298 dbuf = stmf_alloc_dbuf(task, sz, &minsz, 0);
6299 if (dbuf == NULL) {
6300 kmem_free(xd, xd->alloc_size);
6301 stmf_abort(STMF_QUEUE_TASK_ABORT, task,
6302 STMF_ALLOC_FAILURE, NULL);
6303 return;
6304 }
6305 dbuf->db_lu_private = xd;
6306 stmf_xd_to_dbuf(dbuf, 1);
6307
6308 dbuf->db_flags = DB_DIRECTION_TO_RPORT;
6309 (void) stmf_xfer_data(task, dbuf, 0);
6310
6311 }
6312
6313 void
6314 stmf_scsilib_handle_task_mgmt(scsi_task_t *task)
6315 {
6316
6317 switch (task->task_mgmt_function) {
6318 /*
6319 * For now we will abort all I/Os on the LU in case of ABORT_TASK_SET
6320 * and ABORT_TASK. But unlike LUN_RESET we will not reset LU state
6321 * in these cases. This needs to be changed to abort only the required
6322 * set.
6323 */
6324 case TM_ABORT_TASK:
6325 case TM_ABORT_TASK_SET:
6326 case TM_CLEAR_TASK_SET:
6327 case TM_LUN_RESET:
6328 stmf_handle_lun_reset(task);
6329 /* issue the reset to the proxy node as well */
6330 if (stmf_state.stmf_alua_state == 1) {
6331 (void) stmf_proxy_scsi_cmd(task, NULL);
6332 }
6333 return;
6334 case TM_TARGET_RESET:
6335 case TM_TARGET_COLD_RESET:
6336 case TM_TARGET_WARM_RESET:
6337 stmf_handle_target_reset(task);
6338 return;
6339 default:
6340 /* We dont support this task mgmt function */
6341 stmf_scsilib_send_status(task, STATUS_CHECK,
6342 STMF_SAA_INVALID_FIELD_IN_CMD_IU);
6343 return;
6344 }
6345 }
6346
6347 void
6348 stmf_handle_lun_reset(scsi_task_t *task)
6349 {
6350 stmf_i_scsi_task_t *itask;
6351 stmf_i_lu_t *ilu;
6352
6353 itask = (stmf_i_scsi_task_t *)task->task_stmf_private;
6354 ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private;
6355
6356 /*
6357 * To sync with target reset, grab this lock. The LU is not going
6358 * anywhere as there is atleast one task pending (this task).
6359 */
6360 mutex_enter(&stmf_state.stmf_lock);
6361
6362 if (ilu->ilu_flags & ILU_RESET_ACTIVE) {
6363 mutex_exit(&stmf_state.stmf_lock);
6364 stmf_scsilib_send_status(task, STATUS_CHECK,
6365 STMF_SAA_OPERATION_IN_PROGRESS);
6366 return;
6367 }
6368 atomic_or_32(&ilu->ilu_flags, ILU_RESET_ACTIVE);
6369 mutex_exit(&stmf_state.stmf_lock);
6370
6371 /*
6372 * Mark this task as the one causing LU reset so that we know who
6373 * was responsible for setting the ILU_RESET_ACTIVE. In case this
6374 * task itself gets aborted, we will clear ILU_RESET_ACTIVE.
6375 */
6376 itask->itask_flags |= ITASK_DEFAULT_HANDLING | ITASK_CAUSING_LU_RESET;
6377
6378 /* Initiatiate abort on all commands on this LU except this one */
6379 stmf_abort(STMF_QUEUE_ABORT_LU, task, STMF_ABORTED, task->task_lu);
6380
6381 /* Start polling on this task */
6382 if (stmf_task_poll_lu(task, ITASK_DEFAULT_POLL_TIMEOUT)
6383 != STMF_SUCCESS) {
6384 stmf_abort(STMF_QUEUE_TASK_ABORT, task, STMF_ALLOC_FAILURE,
6385 NULL);
6386 return;
6387 }
6388 }
6389
6390 void
6391 stmf_handle_target_reset(scsi_task_t *task)
6392 {
6393 stmf_i_scsi_task_t *itask;
6394 stmf_i_lu_t *ilu;
6395 stmf_i_scsi_session_t *iss;
6396 stmf_lun_map_t *lm;
6397 stmf_lun_map_ent_t *lm_ent;
6398 int i, lf;
6399
6400 itask = (stmf_i_scsi_task_t *)task->task_stmf_private;
6401 iss = (stmf_i_scsi_session_t *)task->task_session->ss_stmf_private;
6402 ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private;
6403
6404 /*
6405 * To sync with LUN reset, grab this lock. The session is not going
6406 * anywhere as there is atleast one task pending (this task).
6407 */
6408 mutex_enter(&stmf_state.stmf_lock);
6409
6410 /* Grab the session lock as a writer to prevent any changes in it */
6411 rw_enter(iss->iss_lockp, RW_WRITER);
6412
6413 if (iss->iss_flags & ISS_RESET_ACTIVE) {
6414 rw_exit(iss->iss_lockp);
6415 mutex_exit(&stmf_state.stmf_lock);
6416 stmf_scsilib_send_status(task, STATUS_CHECK,
6417 STMF_SAA_OPERATION_IN_PROGRESS);
6418 return;
6419 }
6420 atomic_or_32(&iss->iss_flags, ISS_RESET_ACTIVE);
6421
6422 /*
6423 * Now go through each LUN in this session and make sure all of them
6424 * can be reset.
6425 */
6426 lm = iss->iss_sm;
6427 for (i = 0, lf = 0; i < lm->lm_nentries; i++) {
6428 if (lm->lm_plus[i] == NULL)
6429 continue;
6430 lf++;
6431 lm_ent = (stmf_lun_map_ent_t *)lm->lm_plus[i];
6432 ilu = (stmf_i_lu_t *)(lm_ent->ent_lu->lu_stmf_private);
6433 if (ilu->ilu_flags & ILU_RESET_ACTIVE) {
6434 atomic_and_32(&iss->iss_flags, ~ISS_RESET_ACTIVE);
6435 rw_exit(iss->iss_lockp);
6436 mutex_exit(&stmf_state.stmf_lock);
6437 stmf_scsilib_send_status(task, STATUS_CHECK,
6438 STMF_SAA_OPERATION_IN_PROGRESS);
6439 return;
6440 }
6441 }
6442 if (lf == 0) {
6443 /* No luns in this session */
6444 atomic_and_32(&iss->iss_flags, ~ISS_RESET_ACTIVE);
6445 rw_exit(iss->iss_lockp);
6446 mutex_exit(&stmf_state.stmf_lock);
6447 stmf_scsilib_send_status(task, STATUS_GOOD, 0);
6448 return;
6449 }
6450
6451 /* ok, start the damage */
6452 itask->itask_flags |= ITASK_DEFAULT_HANDLING |
6453 ITASK_CAUSING_TARGET_RESET;
6454 for (i = 0; i < lm->lm_nentries; i++) {
6455 if (lm->lm_plus[i] == NULL)
6456 continue;
6457 lm_ent = (stmf_lun_map_ent_t *)lm->lm_plus[i];
6458 ilu = (stmf_i_lu_t *)(lm_ent->ent_lu->lu_stmf_private);
6459 atomic_or_32(&ilu->ilu_flags, ILU_RESET_ACTIVE);
6460 }
6461
6462 for (i = 0; i < lm->lm_nentries; i++) {
6463 if (lm->lm_plus[i] == NULL)
6464 continue;
6465 lm_ent = (stmf_lun_map_ent_t *)lm->lm_plus[i];
6466 stmf_abort(STMF_QUEUE_ABORT_LU, task, STMF_ABORTED,
6467 lm_ent->ent_lu);
6468 }
6469
6470 rw_exit(iss->iss_lockp);
6471 mutex_exit(&stmf_state.stmf_lock);
6472
6473 /* Start polling on this task */
6474 if (stmf_task_poll_lu(task, ITASK_DEFAULT_POLL_TIMEOUT)
6475 != STMF_SUCCESS) {
6476 stmf_abort(STMF_QUEUE_TASK_ABORT, task, STMF_ALLOC_FAILURE,
6477 NULL);
6478 return;
6479 }
6480 }
6481
6482 int
6483 stmf_handle_cmd_during_ic(stmf_i_scsi_task_t *itask)
6484 {
6485 scsi_task_t *task = itask->itask_task;
6486 stmf_i_scsi_session_t *iss = (stmf_i_scsi_session_t *)
6487 task->task_session->ss_stmf_private;
6488
6489 rw_enter(iss->iss_lockp, RW_WRITER);
6490 if (((iss->iss_flags & ISS_LUN_INVENTORY_CHANGED) == 0) ||
6491 (task->task_cdb[0] == SCMD_INQUIRY)) {
6492 rw_exit(iss->iss_lockp);
6493 return (0);
6494 }
6495 atomic_and_32(&iss->iss_flags,
6496 ~(ISS_LUN_INVENTORY_CHANGED | ISS_GOT_INITIAL_LUNS));
6497 rw_exit(iss->iss_lockp);
6498
6499 if (task->task_cdb[0] == SCMD_REPORT_LUNS) {
6500 return (0);
6501 }
6502 stmf_scsilib_send_status(task, STATUS_CHECK,
6503 STMF_SAA_REPORT_LUN_DATA_HAS_CHANGED);
6504 return (1);
6505 }
6506
6507 void
6508 stmf_worker_init()
6509 {
6510 uint32_t i;
6511
6512 /* Make local copy of global tunables */
6513 stmf_i_max_nworkers = stmf_max_nworkers;
6514 stmf_i_min_nworkers = stmf_min_nworkers;
6515
6516 ASSERT(stmf_workers == NULL);
6517 if (stmf_i_min_nworkers < 4) {
6518 stmf_i_min_nworkers = 4;
6519 }
6520 if (stmf_i_max_nworkers < stmf_i_min_nworkers) {
6521 stmf_i_max_nworkers = stmf_i_min_nworkers;
6522 }
6523 stmf_workers = (stmf_worker_t *)kmem_zalloc(
6524 sizeof (stmf_worker_t) * stmf_i_max_nworkers, KM_SLEEP);
6525 for (i = 0; i < stmf_i_max_nworkers; i++) {
6526 stmf_worker_t *w = &stmf_workers[i];
6527 mutex_init(&w->worker_lock, NULL, MUTEX_DRIVER, NULL);
6528 cv_init(&w->worker_cv, NULL, CV_DRIVER, NULL);
6529 }
6530 stmf_worker_mgmt_delay = drv_usectohz(20 * 1000);
6531 stmf_workers_state = STMF_WORKERS_ENABLED;
6532
6533 /* Workers will be started by stmf_worker_mgmt() */
6534
6535 /* Lets wait for atleast one worker to start */
6536 while (stmf_nworkers_cur == 0)
6537 delay(drv_usectohz(20 * 1000));
6538 stmf_worker_mgmt_delay = drv_usectohz(3 * 1000 * 1000);
6539 }
6540
6541 stmf_status_t
6542 stmf_worker_fini()
6543 {
6544 int i;
6545 clock_t sb;
6546
6547 if (stmf_workers_state == STMF_WORKERS_DISABLED)
6548 return (STMF_SUCCESS);
6549 ASSERT(stmf_workers);
6550 stmf_workers_state = STMF_WORKERS_DISABLED;
6551 stmf_worker_mgmt_delay = drv_usectohz(20 * 1000);
6552 cv_signal(&stmf_state.stmf_cv);
6553
6554 sb = ddi_get_lbolt() + drv_usectohz(10 * 1000 * 1000);
6555 /* Wait for all the threads to die */
6556 while (stmf_nworkers_cur != 0) {
6557 if (ddi_get_lbolt() > sb) {
6558 stmf_workers_state = STMF_WORKERS_ENABLED;
6559 return (STMF_BUSY);
6560 }
6561 delay(drv_usectohz(100 * 1000));
6562 }
6563 for (i = 0; i < stmf_i_max_nworkers; i++) {
6564 stmf_worker_t *w = &stmf_workers[i];
6565 mutex_destroy(&w->worker_lock);
6566 cv_destroy(&w->worker_cv);
6567 }
6568 kmem_free(stmf_workers, sizeof (stmf_worker_t) * stmf_i_max_nworkers);
6569 stmf_workers = NULL;
6570
6571 return (STMF_SUCCESS);
6572 }
6573
6574 void
6575 stmf_worker_task(void *arg)
6576 {
6577 stmf_worker_t *w;
6578 stmf_i_scsi_session_t *iss;
6579 scsi_task_t *task;
6580 stmf_i_scsi_task_t *itask;
6581 stmf_data_buf_t *dbuf;
6582 stmf_lu_t *lu;
6583 clock_t wait_timer = 0;
6584 clock_t wait_ticks, wait_delta = 0;
6585 uint32_t old, new;
6586 uint8_t curcmd;
6587 uint8_t abort_free;
6588 uint8_t wait_queue;
6589 uint8_t dec_qdepth;
6590
6591 w = (stmf_worker_t *)arg;
6592 wait_ticks = drv_usectohz(10000);
6593
6594 DTRACE_PROBE1(worker__create, stmf_worker_t, w);
6595 mutex_enter(&w->worker_lock);
6596 w->worker_flags |= STMF_WORKER_STARTED | STMF_WORKER_ACTIVE;
6597 stmf_worker_loop:;
6598 if ((w->worker_ref_count == 0) &&
6599 (w->worker_flags & STMF_WORKER_TERMINATE)) {
6600 w->worker_flags &= ~(STMF_WORKER_STARTED |
6601 STMF_WORKER_ACTIVE | STMF_WORKER_TERMINATE);
6602 w->worker_tid = NULL;
6603 mutex_exit(&w->worker_lock);
6604 DTRACE_PROBE1(worker__destroy, stmf_worker_t, w);
6605 thread_exit();
6606 }
6607 /* CONSTCOND */
6608 while (1) {
6609 dec_qdepth = 0;
6610 if (wait_timer && (ddi_get_lbolt() >= wait_timer)) {
6611 wait_timer = 0;
6612 wait_delta = 0;
6613 if (w->worker_wait_head) {
6614 ASSERT(w->worker_wait_tail);
6615 if (w->worker_task_head == NULL)
6616 w->worker_task_head =
6617 w->worker_wait_head;
6618 else
6619 w->worker_task_tail->itask_worker_next =
6620 w->worker_wait_head;
6621 w->worker_task_tail = w->worker_wait_tail;
6622 w->worker_wait_head = w->worker_wait_tail =
6623 NULL;
6624 }
6625 }
6626 if ((itask = w->worker_task_head) == NULL) {
6627 break;
6628 }
6629 task = itask->itask_task;
6630 DTRACE_PROBE2(worker__active, stmf_worker_t, w,
6631 scsi_task_t *, task);
6632 w->worker_task_head = itask->itask_worker_next;
6633 if (w->worker_task_head == NULL)
6634 w->worker_task_tail = NULL;
6635
6636 wait_queue = 0;
6637 abort_free = 0;
6638 if (itask->itask_ncmds > 0) {
6639 curcmd = itask->itask_cmd_stack[itask->itask_ncmds - 1];
6640 } else {
6641 ASSERT(itask->itask_flags & ITASK_BEING_ABORTED);
6642 }
6643 do {
6644 old = itask->itask_flags;
6645 if (old & ITASK_BEING_ABORTED) {
6646 itask->itask_ncmds = 1;
6647 curcmd = itask->itask_cmd_stack[0] =
6648 ITASK_CMD_ABORT;
6649 goto out_itask_flag_loop;
6650 } else if ((curcmd & ITASK_CMD_MASK) ==
6651 ITASK_CMD_NEW_TASK) {
6652 /*
6653 * set ITASK_KSTAT_IN_RUNQ, this flag
6654 * will not reset until task completed
6655 */
6656 new = old | ITASK_KNOWN_TO_LU |
6657 ITASK_KSTAT_IN_RUNQ;
6658 } else {
6659 goto out_itask_flag_loop;
6660 }
6661 } while (atomic_cas_32(&itask->itask_flags, old, new) != old);
6662
6663 out_itask_flag_loop:
6664
6665 /*
6666 * Decide if this task needs to go to a queue and/or if
6667 * we can decrement the itask_cmd_stack.
6668 */
6669 if (curcmd == ITASK_CMD_ABORT) {
6670 if (itask->itask_flags & (ITASK_KNOWN_TO_LU |
6671 ITASK_KNOWN_TO_TGT_PORT)) {
6672 wait_queue = 1;
6673 } else {
6674 abort_free = 1;
6675 }
6676 } else if ((curcmd & ITASK_CMD_POLL) &&
6677 (itask->itask_poll_timeout > ddi_get_lbolt())) {
6678 wait_queue = 1;
6679 }
6680
6681 if (wait_queue) {
6682 itask->itask_worker_next = NULL;
6683 if (w->worker_wait_tail) {
6684 w->worker_wait_tail->itask_worker_next = itask;
6685 } else {
6686 w->worker_wait_head = itask;
6687 }
6688 w->worker_wait_tail = itask;
6689 if (wait_timer == 0) {
6690 wait_timer = ddi_get_lbolt() + wait_ticks;
6691 wait_delta = wait_ticks;
6692 }
6693 } else if ((--(itask->itask_ncmds)) != 0) {
6694 itask->itask_worker_next = NULL;
6695 if (w->worker_task_tail) {
6696 w->worker_task_tail->itask_worker_next = itask;
6697 } else {
6698 w->worker_task_head = itask;
6699 }
6700 w->worker_task_tail = itask;
6701 } else {
6702 atomic_and_32(&itask->itask_flags,
6703 ~ITASK_IN_WORKER_QUEUE);
6704 /*
6705 * This is where the queue depth should go down by
6706 * one but we delay that on purpose to account for
6707 * the call into the provider. The actual decrement
6708 * happens after the worker has done its job.
6709 */
6710 dec_qdepth = 1;
6711 itask->itask_waitq_time +=
6712 gethrtime() - itask->itask_waitq_enter_timestamp;
6713 }
6714
6715 /* We made it here means we are going to call LU */
6716 if ((itask->itask_flags & ITASK_DEFAULT_HANDLING) == 0)
6717 lu = task->task_lu;
6718 else
6719 lu = dlun0;
6720 dbuf = itask->itask_dbufs[ITASK_CMD_BUF_NDX(curcmd)];
6721 mutex_exit(&w->worker_lock);
6722 curcmd &= ITASK_CMD_MASK;
6723 stmf_task_audit(itask, TE_PROCESS_CMD, curcmd, dbuf);
6724 switch (curcmd) {
6725 case ITASK_CMD_NEW_TASK:
6726 iss = (stmf_i_scsi_session_t *)
6727 task->task_session->ss_stmf_private;
6728 stmf_itl_lu_new_task(itask);
6729 if (iss->iss_flags & ISS_LUN_INVENTORY_CHANGED) {
6730 if (stmf_handle_cmd_during_ic(itask))
6731 break;
6732 }
6733 #ifdef DEBUG
6734 if (stmf_drop_task_counter > 0) {
6735 if (atomic_add_32_nv(
6736 (uint32_t *)&stmf_drop_task_counter,
6737 -1) == 1) {
6738 break;
6739 }
6740 }
6741 #endif
6742 DTRACE_PROBE1(scsi__task__start, scsi_task_t *, task);
6743 lu->lu_new_task(task, dbuf);
6744 break;
6745 case ITASK_CMD_DATA_XFER_DONE:
6746 lu->lu_dbuf_xfer_done(task, dbuf);
6747 break;
6748 case ITASK_CMD_STATUS_DONE:
6749 lu->lu_send_status_done(task);
6750 break;
6751 case ITASK_CMD_ABORT:
6752 if (abort_free) {
6753 stmf_task_free(task);
6754 } else {
6755 stmf_do_task_abort(task);
6756 }
6757 break;
6758 case ITASK_CMD_POLL_LU:
6759 if (!wait_queue) {
6760 lu->lu_task_poll(task);
6761 }
6762 break;
6763 case ITASK_CMD_POLL_LPORT:
6764 if (!wait_queue)
6765 task->task_lport->lport_task_poll(task);
6766 break;
6767 case ITASK_CMD_SEND_STATUS:
6768 /* case ITASK_CMD_XFER_DATA: */
6769 break;
6770 }
6771 mutex_enter(&w->worker_lock);
6772 if (dec_qdepth) {
6773 w->worker_queue_depth--;
6774 }
6775 }
6776 if ((w->worker_flags & STMF_WORKER_TERMINATE) && (wait_timer == 0)) {
6777 if (w->worker_ref_count == 0)
6778 goto stmf_worker_loop;
6779 else {
6780 wait_timer = ddi_get_lbolt() + 1;
6781 wait_delta = 1;
6782 }
6783 }
6784 w->worker_flags &= ~STMF_WORKER_ACTIVE;
6785 if (wait_timer) {
6786 DTRACE_PROBE1(worker__timed__sleep, stmf_worker_t, w);
6787 (void) cv_reltimedwait(&w->worker_cv, &w->worker_lock,
6788 wait_delta, TR_CLOCK_TICK);
6789 } else {
6790 DTRACE_PROBE1(worker__sleep, stmf_worker_t, w);
6791 cv_wait(&w->worker_cv, &w->worker_lock);
6792 }
6793 DTRACE_PROBE1(worker__wakeup, stmf_worker_t, w);
6794 w->worker_flags |= STMF_WORKER_ACTIVE;
6795 goto stmf_worker_loop;
6796 }
6797
6798 void
6799 stmf_worker_mgmt()
6800 {
6801 int i;
6802 int workers_needed;
6803 uint32_t qd;
6804 clock_t tps, d = 0;
6805 uint32_t cur_max_ntasks = 0;
6806 stmf_worker_t *w;
6807
6808 /* Check if we are trying to increase the # of threads */
6809 for (i = stmf_nworkers_cur; i < stmf_nworkers_needed; i++) {
6810 if (stmf_workers[i].worker_flags & STMF_WORKER_STARTED) {
6811 stmf_nworkers_cur++;
6812 stmf_nworkers_accepting_cmds++;
6813 } else {
6814 /* Wait for transition to complete */
6815 return;
6816 }
6817 }
6818 /* Check if we are trying to decrease the # of workers */
6819 for (i = (stmf_nworkers_cur - 1); i >= stmf_nworkers_needed; i--) {
6820 if ((stmf_workers[i].worker_flags & STMF_WORKER_STARTED) == 0) {
6821 stmf_nworkers_cur--;
6822 /*
6823 * stmf_nworkers_accepting_cmds has already been
6824 * updated by the request to reduce the # of workers.
6825 */
6826 } else {
6827 /* Wait for transition to complete */
6828 return;
6829 }
6830 }
6831 /* Check if we are being asked to quit */
6832 if (stmf_workers_state != STMF_WORKERS_ENABLED) {
6833 if (stmf_nworkers_cur) {
6834 workers_needed = 0;
6835 goto worker_mgmt_trigger_change;
6836 }
6837 return;
6838 }
6839 /* Check if we are starting */
6840 if (stmf_nworkers_cur < stmf_i_min_nworkers) {
6841 workers_needed = stmf_i_min_nworkers;
6842 goto worker_mgmt_trigger_change;
6843 }
6844
6845 tps = drv_usectohz(1 * 1000 * 1000);
6846 if ((stmf_wm_last != 0) &&
6847 ((d = ddi_get_lbolt() - stmf_wm_last) > tps)) {
6848 qd = 0;
6849 for (i = 0; i < stmf_nworkers_accepting_cmds; i++) {
6850 qd += stmf_workers[i].worker_max_qdepth_pu;
6851 stmf_workers[i].worker_max_qdepth_pu = 0;
6852 if (stmf_workers[i].worker_max_sys_qdepth_pu >
6853 cur_max_ntasks) {
6854 cur_max_ntasks =
6855 stmf_workers[i].worker_max_sys_qdepth_pu;
6856 }
6857 stmf_workers[i].worker_max_sys_qdepth_pu = 0;
6858 }
6859 }
6860 stmf_wm_last = ddi_get_lbolt();
6861 if (d <= tps) {
6862 /* still ramping up */
6863 return;
6864 }
6865 /* max qdepth cannot be more than max tasks */
6866 if (qd > cur_max_ntasks)
6867 qd = cur_max_ntasks;
6868
6869 /* See if we have more workers */
6870 if (qd < stmf_nworkers_accepting_cmds) {
6871 /*
6872 * Since we dont reduce the worker count right away, monitor
6873 * the highest load during the scale_down_delay.
6874 */
6875 if (qd > stmf_worker_scale_down_qd)
6876 stmf_worker_scale_down_qd = qd;
6877 if (stmf_worker_scale_down_timer == 0) {
6878 stmf_worker_scale_down_timer = ddi_get_lbolt() +
6879 drv_usectohz(stmf_worker_scale_down_delay *
6880 1000 * 1000);
6881 return;
6882 }
6883 if (ddi_get_lbolt() < stmf_worker_scale_down_timer) {
6884 return;
6885 }
6886 /* Its time to reduce the workers */
6887 if (stmf_worker_scale_down_qd < stmf_i_min_nworkers)
6888 stmf_worker_scale_down_qd = stmf_i_min_nworkers;
6889 if (stmf_worker_scale_down_qd > stmf_i_max_nworkers)
6890 stmf_worker_scale_down_qd = stmf_i_max_nworkers;
6891 if (stmf_worker_scale_down_qd == stmf_nworkers_cur)
6892 return;
6893 workers_needed = stmf_worker_scale_down_qd;
6894 stmf_worker_scale_down_qd = 0;
6895 goto worker_mgmt_trigger_change;
6896 }
6897 stmf_worker_scale_down_qd = 0;
6898 stmf_worker_scale_down_timer = 0;
6899 if (qd > stmf_i_max_nworkers)
6900 qd = stmf_i_max_nworkers;
6901 if (qd < stmf_i_min_nworkers)
6902 qd = stmf_i_min_nworkers;
6903 if (qd == stmf_nworkers_cur)
6904 return;
6905 workers_needed = qd;
6906 goto worker_mgmt_trigger_change;
6907
6908 /* NOTREACHED */
6909 return;
6910
6911 worker_mgmt_trigger_change:
6912 ASSERT(workers_needed != stmf_nworkers_cur);
6913 if (workers_needed > stmf_nworkers_cur) {
6914 stmf_nworkers_needed = workers_needed;
6915 for (i = stmf_nworkers_cur; i < workers_needed; i++) {
6916 w = &stmf_workers[i];
6917 w->worker_tid = thread_create(NULL, 0, stmf_worker_task,
6918 (void *)&stmf_workers[i], 0, &p0, TS_RUN,
6919 minclsyspri);
6920 }
6921 return;
6922 }
6923 /* At this point we know that we are decreasing the # of workers */
6924 stmf_nworkers_accepting_cmds = workers_needed;
6925 stmf_nworkers_needed = workers_needed;
6926 /* Signal the workers that its time to quit */
6927 for (i = (stmf_nworkers_cur - 1); i >= stmf_nworkers_needed; i--) {
6928 w = &stmf_workers[i];
6929 ASSERT(w && (w->worker_flags & STMF_WORKER_STARTED));
6930 mutex_enter(&w->worker_lock);
6931 w->worker_flags |= STMF_WORKER_TERMINATE;
6932 if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0)
6933 cv_signal(&w->worker_cv);
6934 mutex_exit(&w->worker_lock);
6935 }
6936 }
6937
6938 /*
6939 * Fills out a dbuf from stmf_xfer_data_t (contained in the db_lu_private).
6940 * If all the data has been filled out, frees the xd and makes
6941 * db_lu_private NULL.
6942 */
6943 void
6944 stmf_xd_to_dbuf(stmf_data_buf_t *dbuf, int set_rel_off)
6945 {
6946 stmf_xfer_data_t *xd;
6947 uint8_t *p;
6948 int i;
6949 uint32_t s;
6950
6951 xd = (stmf_xfer_data_t *)dbuf->db_lu_private;
6952 dbuf->db_data_size = 0;
6953 if (set_rel_off)
6954 dbuf->db_relative_offset = xd->size_done;
6955 for (i = 0; i < dbuf->db_sglist_length; i++) {
6956 s = min(xd->size_left, dbuf->db_sglist[i].seg_length);
6957 p = &xd->buf[xd->size_done];
6958 bcopy(p, dbuf->db_sglist[i].seg_addr, s);
6959 xd->size_left -= s;
6960 xd->size_done += s;
6961 dbuf->db_data_size += s;
6962 if (xd->size_left == 0) {
6963 kmem_free(xd, xd->alloc_size);
6964 dbuf->db_lu_private = NULL;
6965 return;
6966 }
6967 }
6968 }
6969
6970 /* ARGSUSED */
6971 stmf_status_t
6972 stmf_dlun0_task_alloc(scsi_task_t *task)
6973 {
6974 return (STMF_SUCCESS);
6975 }
6976
6977 void
6978 stmf_dlun0_new_task(scsi_task_t *task, stmf_data_buf_t *dbuf)
6979 {
6980 uint8_t *cdbp = (uint8_t *)&task->task_cdb[0];
6981 stmf_i_scsi_session_t *iss;
6982 uint32_t sz, minsz;
6983 uint8_t *p;
6984 stmf_xfer_data_t *xd;
6985 uint8_t inq_page_length = 31;
6986
6987 if (task->task_mgmt_function) {
6988 stmf_scsilib_handle_task_mgmt(task);
6989 return;
6990 }
6991
6992 switch (cdbp[0]) {
6993 case SCMD_INQUIRY:
6994 /*
6995 * Basic protocol checks. In addition, only reply to
6996 * standard inquiry. Otherwise, the LU provider needs
6997 * to respond.
6998 */
6999
7000 if (cdbp[2] || (cdbp[1] & 1) || cdbp[5]) {
7001 stmf_scsilib_send_status(task, STATUS_CHECK,
7002 STMF_SAA_INVALID_FIELD_IN_CDB);
7003 return;
7004 }
7005
7006 task->task_cmd_xfer_length =
7007 (((uint32_t)cdbp[3]) << 8) | cdbp[4];
7008
7009 if (task->task_additional_flags &
7010 TASK_AF_NO_EXPECTED_XFER_LENGTH) {
7011 task->task_expected_xfer_length =
7012 task->task_cmd_xfer_length;
7013 }
7014
7015 sz = min(task->task_expected_xfer_length,
7016 min(36, task->task_cmd_xfer_length));
7017 minsz = 36;
7018
7019 if (sz == 0) {
7020 stmf_scsilib_send_status(task, STATUS_GOOD, 0);
7021 return;
7022 }
7023
7024 if (dbuf && (dbuf->db_sglist[0].seg_length < 36)) {
7025 /*
7026 * Ignore any preallocated dbuf if the size is less
7027 * than 36. It will be freed during the task_free.
7028 */
7029 dbuf = NULL;
7030 }
7031 if (dbuf == NULL)
7032 dbuf = stmf_alloc_dbuf(task, minsz, &minsz, 0);
7033 if ((dbuf == NULL) || (dbuf->db_sglist[0].seg_length < sz)) {
7034 stmf_abort(STMF_QUEUE_TASK_ABORT, task,
7035 STMF_ALLOC_FAILURE, NULL);
7036 return;
7037 }
7038 dbuf->db_lu_private = NULL;
7039
7040 p = dbuf->db_sglist[0].seg_addr;
7041
7042 /*
7043 * Standard inquiry handling only.
7044 */
7045
7046 bzero(p, inq_page_length + 5);
7047
7048 p[0] = DPQ_SUPPORTED | DTYPE_UNKNOWN;
7049 p[2] = 5;
7050 p[3] = 0x12;
7051 p[4] = inq_page_length;
7052 p[6] = 0x80;
7053
7054 (void) strncpy((char *)p+8, "SUN ", 8);
7055 (void) strncpy((char *)p+16, "COMSTAR ", 16);
7056 (void) strncpy((char *)p+32, "1.0 ", 4);
7057
7058 dbuf->db_data_size = sz;
7059 dbuf->db_relative_offset = 0;
7060 dbuf->db_flags = DB_DIRECTION_TO_RPORT;
7061 (void) stmf_xfer_data(task, dbuf, 0);
7062
7063 return;
7064
7065 case SCMD_REPORT_LUNS:
7066 task->task_cmd_xfer_length =
7067 ((((uint32_t)task->task_cdb[6]) << 24) |
7068 (((uint32_t)task->task_cdb[7]) << 16) |
7069 (((uint32_t)task->task_cdb[8]) << 8) |
7070 ((uint32_t)task->task_cdb[9]));
7071
7072 if (task->task_additional_flags &
7073 TASK_AF_NO_EXPECTED_XFER_LENGTH) {
7074 task->task_expected_xfer_length =
7075 task->task_cmd_xfer_length;
7076 }
7077
7078 sz = min(task->task_expected_xfer_length,
7079 task->task_cmd_xfer_length);
7080
7081 if (sz < 16) {
7082 stmf_scsilib_send_status(task, STATUS_CHECK,
7083 STMF_SAA_INVALID_FIELD_IN_CDB);
7084 return;
7085 }
7086
7087 iss = (stmf_i_scsi_session_t *)
7088 task->task_session->ss_stmf_private;
7089 rw_enter(iss->iss_lockp, RW_WRITER);
7090 xd = stmf_session_prepare_report_lun_data(iss->iss_sm);
7091 rw_exit(iss->iss_lockp);
7092
7093 if (xd == NULL) {
7094 stmf_abort(STMF_QUEUE_TASK_ABORT, task,
7095 STMF_ALLOC_FAILURE, NULL);
7096 return;
7097 }
7098
7099 sz = min(sz, xd->size_left);
7100 xd->size_left = sz;
7101 minsz = min(512, sz);
7102
7103 if (dbuf == NULL)
7104 dbuf = stmf_alloc_dbuf(task, sz, &minsz, 0);
7105 if (dbuf == NULL) {
7106 kmem_free(xd, xd->alloc_size);
7107 stmf_abort(STMF_QUEUE_TASK_ABORT, task,
7108 STMF_ALLOC_FAILURE, NULL);
7109 return;
7110 }
7111 dbuf->db_lu_private = xd;
7112 stmf_xd_to_dbuf(dbuf, 1);
7113
7114 atomic_and_32(&iss->iss_flags,
7115 ~(ISS_LUN_INVENTORY_CHANGED | ISS_GOT_INITIAL_LUNS));
7116 dbuf->db_flags = DB_DIRECTION_TO_RPORT;
7117 (void) stmf_xfer_data(task, dbuf, 0);
7118 return;
7119 }
7120
7121 stmf_scsilib_send_status(task, STATUS_CHECK, STMF_SAA_INVALID_OPCODE);
7122 }
7123
7124 void
7125 stmf_dlun0_dbuf_done(scsi_task_t *task, stmf_data_buf_t *dbuf)
7126 {
7127 stmf_i_scsi_task_t *itask =
7128 (stmf_i_scsi_task_t *)task->task_stmf_private;
7129
7130 if (dbuf->db_xfer_status != STMF_SUCCESS) {
7131 stmf_abort(STMF_QUEUE_TASK_ABORT, task,
7132 dbuf->db_xfer_status, NULL);
7133 return;
7134 }
7135 task->task_nbytes_transferred += dbuf->db_data_size;
7136 if (dbuf->db_lu_private) {
7137 /* There is more */
7138 stmf_xd_to_dbuf(dbuf, 1);
7139 (void) stmf_xfer_data(task, dbuf, 0);
7140 return;
7141 }
7142
7143 stmf_free_dbuf(task, dbuf);
7144 /*
7145 * If this is a proxy task, it will need to be completed from the
7146 * proxy port provider. This message lets pppt know that the xfer
7147 * is complete. When we receive the status from pppt, we will
7148 * then relay that status back to the lport.
7149 */
7150 if (itask->itask_flags & ITASK_PROXY_TASK) {
7151 stmf_ic_msg_t *ic_xfer_done_msg = NULL;
7152 stmf_status_t ic_ret = STMF_FAILURE;
7153 uint64_t session_msg_id;
7154 mutex_enter(&stmf_state.stmf_lock);
7155 session_msg_id = stmf_proxy_msg_id++;
7156 mutex_exit(&stmf_state.stmf_lock);
7157 /* send xfer done status to pppt */
7158 ic_xfer_done_msg = ic_scsi_data_xfer_done_msg_alloc(
7159 itask->itask_proxy_msg_id,
7160 task->task_session->ss_session_id,
7161 STMF_SUCCESS, session_msg_id);
7162 if (ic_xfer_done_msg) {
7163 ic_ret = ic_tx_msg(ic_xfer_done_msg);
7164 if (ic_ret != STMF_IC_MSG_SUCCESS) {
7165 cmn_err(CE_WARN, "unable to xmit session msg");
7166 }
7167 }
7168 /* task will be completed from pppt */
7169 return;
7170 }
7171 stmf_scsilib_send_status(task, STATUS_GOOD, 0);
7172 }
7173
7174 /* ARGSUSED */
7175 void
7176 stmf_dlun0_status_done(scsi_task_t *task)
7177 {
7178 }
7179
7180 /* ARGSUSED */
7181 void
7182 stmf_dlun0_task_free(scsi_task_t *task)
7183 {
7184 }
7185
7186 /* ARGSUSED */
7187 stmf_status_t
7188 stmf_dlun0_abort(struct stmf_lu *lu, int abort_cmd, void *arg, uint32_t flags)
7189 {
7190 scsi_task_t *task = (scsi_task_t *)arg;
7191 stmf_i_scsi_task_t *itask =
7192 (stmf_i_scsi_task_t *)task->task_stmf_private;
7193 stmf_i_lu_t *ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private;
7194 int i;
7195 uint8_t map;
7196
7197 if ((task->task_mgmt_function) && (itask->itask_flags &
7198 (ITASK_CAUSING_LU_RESET | ITASK_CAUSING_TARGET_RESET))) {
7199 switch (task->task_mgmt_function) {
7200 case TM_ABORT_TASK:
7201 case TM_ABORT_TASK_SET:
7202 case TM_CLEAR_TASK_SET:
7203 case TM_LUN_RESET:
7204 atomic_and_32(&ilu->ilu_flags, ~ILU_RESET_ACTIVE);
7205 break;
7206 case TM_TARGET_RESET:
7207 case TM_TARGET_COLD_RESET:
7208 case TM_TARGET_WARM_RESET:
7209 stmf_abort_target_reset(task);
7210 break;
7211 }
7212 return (STMF_ABORT_SUCCESS);
7213 }
7214
7215 /*
7216 * OK so its not a task mgmt. Make sure we free any xd sitting
7217 * inside any dbuf.
7218 */
7219 if ((map = itask->itask_allocated_buf_map) != 0) {
7220 for (i = 0; i < 4; i++) {
7221 if ((map & 1) &&
7222 ((itask->itask_dbufs[i])->db_lu_private)) {
7223 stmf_xfer_data_t *xd;
7224 stmf_data_buf_t *dbuf;
7225
7226 dbuf = itask->itask_dbufs[i];
7227 xd = (stmf_xfer_data_t *)dbuf->db_lu_private;
7228 dbuf->db_lu_private = NULL;
7229 kmem_free(xd, xd->alloc_size);
7230 }
7231 map >>= 1;
7232 }
7233 }
7234 return (STMF_ABORT_SUCCESS);
7235 }
7236
7237 void
7238 stmf_dlun0_task_poll(struct scsi_task *task)
7239 {
7240 /* Right now we only do this for handling task management functions */
7241 ASSERT(task->task_mgmt_function);
7242
7243 switch (task->task_mgmt_function) {
7244 case TM_ABORT_TASK:
7245 case TM_ABORT_TASK_SET:
7246 case TM_CLEAR_TASK_SET:
7247 case TM_LUN_RESET:
7248 (void) stmf_lun_reset_poll(task->task_lu, task, 0);
7249 return;
7250 case TM_TARGET_RESET:
7251 case TM_TARGET_COLD_RESET:
7252 case TM_TARGET_WARM_RESET:
7253 stmf_target_reset_poll(task);
7254 return;
7255 }
7256 }
7257
7258 /* ARGSUSED */
7259 void
7260 stmf_dlun0_ctl(struct stmf_lu *lu, int cmd, void *arg)
7261 {
7262 /* This function will never be called */
7263 cmn_err(CE_WARN, "stmf_dlun0_ctl called with cmd %x", cmd);
7264 }
7265
7266 void
7267 stmf_dlun_init()
7268 {
7269 stmf_i_lu_t *ilu;
7270
7271 dlun0 = stmf_alloc(STMF_STRUCT_STMF_LU, 0, 0);
7272 dlun0->lu_task_alloc = stmf_dlun0_task_alloc;
7273 dlun0->lu_new_task = stmf_dlun0_new_task;
7274 dlun0->lu_dbuf_xfer_done = stmf_dlun0_dbuf_done;
7275 dlun0->lu_send_status_done = stmf_dlun0_status_done;
7276 dlun0->lu_task_free = stmf_dlun0_task_free;
7277 dlun0->lu_abort = stmf_dlun0_abort;
7278 dlun0->lu_task_poll = stmf_dlun0_task_poll;
7279 dlun0->lu_ctl = stmf_dlun0_ctl;
7280
7281 ilu = (stmf_i_lu_t *)dlun0->lu_stmf_private;
7282 ilu->ilu_cur_task_cntr = &ilu->ilu_task_cntr1;
7283 }
7284
7285 stmf_status_t
7286 stmf_dlun_fini()
7287 {
7288 stmf_i_lu_t *ilu;
7289
7290 ilu = (stmf_i_lu_t *)dlun0->lu_stmf_private;
7291
7292 ASSERT(ilu->ilu_ntasks == ilu->ilu_ntasks_free);
7293 if (ilu->ilu_ntasks) {
7294 stmf_i_scsi_task_t *itask, *nitask;
7295
7296 nitask = ilu->ilu_tasks;
7297 do {
7298 itask = nitask;
7299 nitask = itask->itask_lu_next;
7300 dlun0->lu_task_free(itask->itask_task);
7301 stmf_free(itask->itask_task);
7302 } while (nitask != NULL);
7303
7304 }
7305 stmf_free(dlun0);
7306 return (STMF_SUCCESS);
7307 }
7308
7309 void
7310 stmf_abort_target_reset(scsi_task_t *task)
7311 {
7312 stmf_i_scsi_session_t *iss = (stmf_i_scsi_session_t *)
7313 task->task_session->ss_stmf_private;
7314 stmf_lun_map_t *lm;
7315 stmf_lun_map_ent_t *lm_ent;
7316 stmf_i_lu_t *ilu;
7317 int i;
7318
7319 rw_enter(iss->iss_lockp, RW_READER);
7320 lm = iss->iss_sm;
7321 for (i = 0; i < lm->lm_nentries; i++) {
7322 if (lm->lm_plus[i] == NULL)
7323 continue;
7324 lm_ent = (stmf_lun_map_ent_t *)lm->lm_plus[i];
7325 ilu = (stmf_i_lu_t *)lm_ent->ent_lu->lu_stmf_private;
7326 if (ilu->ilu_flags & ILU_RESET_ACTIVE) {
7327 atomic_and_32(&ilu->ilu_flags, ~ILU_RESET_ACTIVE);
7328 }
7329 }
7330 atomic_and_32(&iss->iss_flags, ~ISS_RESET_ACTIVE);
7331 rw_exit(iss->iss_lockp);
7332 }
7333
7334 /*
7335 * The return value is only used by function managing target reset.
7336 */
7337 stmf_status_t
7338 stmf_lun_reset_poll(stmf_lu_t *lu, struct scsi_task *task, int target_reset)
7339 {
7340 stmf_i_lu_t *ilu = (stmf_i_lu_t *)lu->lu_stmf_private;
7341 int ntasks_pending;
7342
7343 ntasks_pending = ilu->ilu_ntasks - ilu->ilu_ntasks_free;
7344 /*
7345 * This function is also used during Target reset. The idea is that
7346 * once all the commands are aborted, call the LU's reset entry
7347 * point (abort entry point with a reset flag). But if this Task
7348 * mgmt is running on this LU then all the tasks cannot be aborted.
7349 * one task (this task) will still be running which is OK.
7350 */
7351 if ((ntasks_pending == 0) || ((task->task_lu == lu) &&
7352 (ntasks_pending == 1))) {
7353 stmf_status_t ret;
7354
7355 if ((task->task_mgmt_function == TM_LUN_RESET) ||
7356 (task->task_mgmt_function == TM_TARGET_RESET) ||
7357 (task->task_mgmt_function == TM_TARGET_WARM_RESET) ||
7358 (task->task_mgmt_function == TM_TARGET_COLD_RESET)) {
7359 ret = lu->lu_abort(lu, STMF_LU_RESET_STATE, task, 0);
7360 } else {
7361 ret = STMF_SUCCESS;
7362 }
7363 if (ret == STMF_SUCCESS) {
7364 atomic_and_32(&ilu->ilu_flags, ~ILU_RESET_ACTIVE);
7365 }
7366 if (target_reset) {
7367 return (ret);
7368 }
7369 if (ret == STMF_SUCCESS) {
7370 stmf_scsilib_send_status(task, STATUS_GOOD, 0);
7371 return (ret);
7372 }
7373 if (ret != STMF_BUSY) {
7374 stmf_abort(STMF_QUEUE_TASK_ABORT, task, ret, NULL);
7375 return (ret);
7376 }
7377 }
7378
7379 if (target_reset) {
7380 /* Tell target reset polling code that we are not done */
7381 return (STMF_BUSY);
7382 }
7383
7384 if (stmf_task_poll_lu(task, ITASK_DEFAULT_POLL_TIMEOUT)
7385 != STMF_SUCCESS) {
7386 stmf_abort(STMF_QUEUE_TASK_ABORT, task,
7387 STMF_ALLOC_FAILURE, NULL);
7388 return (STMF_SUCCESS);
7389 }
7390
7391 return (STMF_SUCCESS);
7392 }
7393
7394 void
7395 stmf_target_reset_poll(struct scsi_task *task)
7396 {
7397 stmf_i_scsi_session_t *iss = (stmf_i_scsi_session_t *)
7398 task->task_session->ss_stmf_private;
7399 stmf_lun_map_t *lm;
7400 stmf_lun_map_ent_t *lm_ent;
7401 stmf_i_lu_t *ilu;
7402 stmf_status_t ret;
7403 int i;
7404 int not_done = 0;
7405
7406 ASSERT(iss->iss_flags & ISS_RESET_ACTIVE);
7407
7408 rw_enter(iss->iss_lockp, RW_READER);
7409 lm = iss->iss_sm;
7410 for (i = 0; i < lm->lm_nentries; i++) {
7411 if (lm->lm_plus[i] == NULL)
7412 continue;
7413 lm_ent = (stmf_lun_map_ent_t *)lm->lm_plus[i];
7414 ilu = (stmf_i_lu_t *)lm_ent->ent_lu->lu_stmf_private;
7415 if (ilu->ilu_flags & ILU_RESET_ACTIVE) {
7416 rw_exit(iss->iss_lockp);
7417 ret = stmf_lun_reset_poll(lm_ent->ent_lu, task, 1);
7418 rw_enter(iss->iss_lockp, RW_READER);
7419 if (ret == STMF_SUCCESS)
7420 continue;
7421 not_done = 1;
7422 if (ret != STMF_BUSY) {
7423 rw_exit(iss->iss_lockp);
7424 stmf_abort(STMF_QUEUE_TASK_ABORT, task,
7425 STMF_ABORTED, NULL);
7426 return;
7427 }
7428 }
7429 }
7430 rw_exit(iss->iss_lockp);
7431
7432 if (not_done) {
7433 if (stmf_task_poll_lu(task, ITASK_DEFAULT_POLL_TIMEOUT)
7434 != STMF_SUCCESS) {
7435 stmf_abort(STMF_QUEUE_TASK_ABORT, task,
7436 STMF_ALLOC_FAILURE, NULL);
7437 return;
7438 }
7439 return;
7440 }
7441
7442 atomic_and_32(&iss->iss_flags, ~ISS_RESET_ACTIVE);
7443
7444 stmf_scsilib_send_status(task, STATUS_GOOD, 0);
7445 }
7446
7447 stmf_status_t
7448 stmf_lu_add_event(stmf_lu_t *lu, int eventid)
7449 {
7450 stmf_i_lu_t *ilu = (stmf_i_lu_t *)lu->lu_stmf_private;
7451
7452 if ((eventid < 0) || (eventid >= STMF_MAX_NUM_EVENTS)) {
7453 return (STMF_INVALID_ARG);
7454 }
7455
7456 STMF_EVENT_ADD(ilu->ilu_event_hdl, eventid);
7457 return (STMF_SUCCESS);
7458 }
7459
7460 stmf_status_t
7461 stmf_lu_remove_event(stmf_lu_t *lu, int eventid)
7462 {
7463 stmf_i_lu_t *ilu = (stmf_i_lu_t *)lu->lu_stmf_private;
7464
7465 if (eventid == STMF_EVENT_ALL) {
7466 STMF_EVENT_CLEAR_ALL(ilu->ilu_event_hdl);
7467 return (STMF_SUCCESS);
7468 }
7469
7470 if ((eventid < 0) || (eventid >= STMF_MAX_NUM_EVENTS)) {
7471 return (STMF_INVALID_ARG);
7472 }
7473
7474 STMF_EVENT_REMOVE(ilu->ilu_event_hdl, eventid);
7475 return (STMF_SUCCESS);
7476 }
7477
7478 stmf_status_t
7479 stmf_lport_add_event(stmf_local_port_t *lport, int eventid)
7480 {
7481 stmf_i_local_port_t *ilport =
7482 (stmf_i_local_port_t *)lport->lport_stmf_private;
7483
7484 if ((eventid < 0) || (eventid >= STMF_MAX_NUM_EVENTS)) {
7485 return (STMF_INVALID_ARG);
7486 }
7487
7488 STMF_EVENT_ADD(ilport->ilport_event_hdl, eventid);
7489 return (STMF_SUCCESS);
7490 }
7491
7492 stmf_status_t
7493 stmf_lport_remove_event(stmf_local_port_t *lport, int eventid)
7494 {
7495 stmf_i_local_port_t *ilport =
7496 (stmf_i_local_port_t *)lport->lport_stmf_private;
7497
7498 if (eventid == STMF_EVENT_ALL) {
7499 STMF_EVENT_CLEAR_ALL(ilport->ilport_event_hdl);
7500 return (STMF_SUCCESS);
7501 }
7502
7503 if ((eventid < 0) || (eventid >= STMF_MAX_NUM_EVENTS)) {
7504 return (STMF_INVALID_ARG);
7505 }
7506
7507 STMF_EVENT_REMOVE(ilport->ilport_event_hdl, eventid);
7508 return (STMF_SUCCESS);
7509 }
7510
7511 void
7512 stmf_generate_lu_event(stmf_i_lu_t *ilu, int eventid, void *arg, uint32_t flags)
7513 {
7514 if (STMF_EVENT_ENABLED(ilu->ilu_event_hdl, eventid) &&
7515 (ilu->ilu_lu->lu_event_handler != NULL)) {
7516 ilu->ilu_lu->lu_event_handler(ilu->ilu_lu, eventid, arg, flags);
7517 }
7518 }
7519
7520 void
7521 stmf_generate_lport_event(stmf_i_local_port_t *ilport, int eventid, void *arg,
7522 uint32_t flags)
7523 {
7524 if (STMF_EVENT_ENABLED(ilport->ilport_event_hdl, eventid) &&
7525 (ilport->ilport_lport->lport_event_handler != NULL)) {
7526 ilport->ilport_lport->lport_event_handler(
7527 ilport->ilport_lport, eventid, arg, flags);
7528 }
7529 }
7530
7531 /*
7532 * With the possibility of having multiple itl sessions pointing to the
7533 * same itl_kstat_info, the ilu_kstat_lock mutex is used to synchronize
7534 * the kstat update of the ilu_kstat_io, itl_kstat_taskq and itl_kstat_lu_xfer
7535 * statistics.
7536 */
7537 void
7538 stmf_itl_task_start(stmf_i_scsi_task_t *itask)
7539 {
7540 stmf_itl_data_t *itl = itask->itask_itl_datap;
7541 scsi_task_t *task = itask->itask_task;
7542 stmf_i_lu_t *ilu;
7543
7544 if (itl == NULL || task->task_lu == dlun0)
7545 return;
7546 ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private;
7547 mutex_enter(ilu->ilu_kstat_io->ks_lock);
7548 itask->itask_start_timestamp = gethrtime();
7549 kstat_waitq_enter(KSTAT_IO_PTR(itl->itl_kstat_taskq));
7550 stmf_update_kstat_lu_q(itask->itask_task, kstat_waitq_enter);
7551 mutex_exit(ilu->ilu_kstat_io->ks_lock);
7552
7553 stmf_update_kstat_lport_q(itask->itask_task, kstat_waitq_enter);
7554 }
7555
7556 void
7557 stmf_itl_lu_new_task(stmf_i_scsi_task_t *itask)
7558 {
7559 stmf_itl_data_t *itl = itask->itask_itl_datap;
7560 scsi_task_t *task = itask->itask_task;
7561 stmf_i_lu_t *ilu;
7562
7563 if (itl == NULL || task->task_lu == dlun0)
7564 return;
7565 ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private;
7566 mutex_enter(ilu->ilu_kstat_io->ks_lock);
7567 kstat_waitq_to_runq(KSTAT_IO_PTR(itl->itl_kstat_taskq));
7568 stmf_update_kstat_lu_q(itask->itask_task, kstat_waitq_to_runq);
7569 mutex_exit(ilu->ilu_kstat_io->ks_lock);
7570
7571 stmf_update_kstat_lport_q(itask->itask_task, kstat_waitq_to_runq);
7572 }
7573
7574 void
7575 stmf_itl_task_done(stmf_i_scsi_task_t *itask)
7576 {
7577 stmf_itl_data_t *itl = itask->itask_itl_datap;
7578 scsi_task_t *task = itask->itask_task;
7579 kstat_io_t *kip;
7580 hrtime_t elapsed_time;
7581 stmf_kstat_itl_info_t *itli;
7582 stmf_i_lu_t *ilu;
7583
7584 if (itl == NULL || task->task_lu == dlun0)
7585 return;
7586 ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private;
7587
7588 mutex_enter(ilu->ilu_kstat_io->ks_lock);
7589 itli = (stmf_kstat_itl_info_t *)KSTAT_NAMED_PTR(itl->itl_kstat_info);
7590 kip = KSTAT_IO_PTR(itl->itl_kstat_taskq);
7591
7592 itli->i_task_waitq_elapsed.value.ui64 += itask->itask_waitq_time;
7593
7594 itask->itask_done_timestamp = gethrtime();
7595 elapsed_time =
7596 itask->itask_done_timestamp - itask->itask_start_timestamp;
7597
7598 if (task->task_flags & TF_READ_DATA) {
7599 kip->reads++;
7600 kip->nread += itask->itask_read_xfer;
7601 itli->i_task_read_elapsed.value.ui64 += elapsed_time;
7602 itli->i_lu_read_elapsed.value.ui64 +=
7603 itask->itask_lu_read_time;
7604 itli->i_lport_read_elapsed.value.ui64 +=
7605 itask->itask_lport_read_time;
7606 }
7607
7608 if (task->task_flags & TF_WRITE_DATA) {
7609 kip->writes++;
7610 kip->nwritten += itask->itask_write_xfer;
7611 itli->i_task_write_elapsed.value.ui64 += elapsed_time;
7612 itli->i_lu_write_elapsed.value.ui64 +=
7613 itask->itask_lu_write_time;
7614 itli->i_lport_write_elapsed.value.ui64 +=
7615 itask->itask_lport_write_time;
7616 }
7617
7618 if (itask->itask_flags & ITASK_KSTAT_IN_RUNQ) {
7619 kstat_runq_exit(kip);
7620 stmf_update_kstat_lu_q(task, kstat_runq_exit);
7621 mutex_exit(ilu->ilu_kstat_io->ks_lock);
7622 stmf_update_kstat_lport_q(task, kstat_runq_exit);
7623 } else {
7624 kstat_waitq_exit(kip);
7625 stmf_update_kstat_lu_q(task, kstat_waitq_exit);
7626 mutex_exit(ilu->ilu_kstat_io->ks_lock);
7627 stmf_update_kstat_lport_q(task, kstat_waitq_exit);
7628 }
7629 }
7630
7631 void
7632 stmf_lu_xfer_start(scsi_task_t *task)
7633 {
7634 stmf_i_scsi_task_t *itask = task->task_stmf_private;
7635 stmf_itl_data_t *itl = itask->itask_itl_datap;
7636 stmf_i_lu_t *ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private;
7637 kstat_io_t *kip;
7638
7639 if (itl == NULL || task->task_lu == dlun0)
7640 return;
7641
7642 kip = KSTAT_IO_PTR(itl->itl_kstat_lu_xfer);
7643 mutex_enter(ilu->ilu_kstat_io->ks_lock);
7644 kstat_runq_enter(kip);
7645 mutex_exit(ilu->ilu_kstat_io->ks_lock);
7646 }
7647
7648 void
7649 stmf_lu_xfer_done(scsi_task_t *task, boolean_t read, uint64_t xfer_bytes,
7650 hrtime_t elapsed_time)
7651 {
7652 stmf_i_scsi_task_t *itask = task->task_stmf_private;
7653 stmf_itl_data_t *itl = itask->itask_itl_datap;
7654 stmf_i_lu_t *ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private;
7655 kstat_io_t *kip;
7656
7657 if (itl == NULL || task->task_lu == dlun0)
7658 return;
7659
7660 if (read) {
7661 atomic_add_64((uint64_t *)&itask->itask_lu_read_time,
7662 elapsed_time);
7663 } else {
7664 atomic_add_64((uint64_t *)&itask->itask_lu_write_time,
7665 elapsed_time);
7666 }
7667
7668 kip = KSTAT_IO_PTR(itl->itl_kstat_lu_xfer);
7669 mutex_enter(ilu->ilu_kstat_io->ks_lock);
7670 kstat_runq_exit(kip);
7671 if (read) {
7672 kip->reads++;
7673 kip->nread += xfer_bytes;
7674 } else {
7675 kip->writes++;
7676 kip->nwritten += xfer_bytes;
7677 }
7678 mutex_exit(ilu->ilu_kstat_io->ks_lock);
7679 }
7680
7681 static void
7682 stmf_lport_xfer_start(stmf_i_scsi_task_t *itask, stmf_data_buf_t *dbuf)
7683 {
7684 stmf_itl_data_t *itl = itask->itask_itl_datap;
7685
7686 if (itl == NULL)
7687 return;
7688
7689 DTRACE_PROBE2(scsi__xfer__start, scsi_task_t *, itask->itask_task,
7690 stmf_data_buf_t *, dbuf);
7691
7692 dbuf->db_xfer_start_timestamp = gethrtime();
7693 }
7694
7695 static void
7696 stmf_lport_xfer_done(stmf_i_scsi_task_t *itask, stmf_data_buf_t *dbuf)
7697 {
7698 stmf_itl_data_t *itl = itask->itask_itl_datap;
7699 scsi_task_t *task;
7700 stmf_i_local_port_t *ilp;
7701 kstat_io_t *kip;
7702 hrtime_t elapsed_time;
7703 uint64_t xfer_size;
7704
7705 if (itl == NULL)
7706 return;
7707
7708 task = (scsi_task_t *)itask->itask_task;
7709 ilp = (stmf_i_local_port_t *)task->task_lport->lport_stmf_private;
7710 xfer_size = (dbuf->db_xfer_status == STMF_SUCCESS) ?
7711 dbuf->db_data_size : 0;
7712
7713 elapsed_time = gethrtime() - dbuf->db_xfer_start_timestamp;
7714 if (dbuf->db_flags & DB_DIRECTION_TO_RPORT) {
7715 atomic_add_64((uint64_t *)&itask->itask_lport_read_time,
7716 elapsed_time);
7717 atomic_add_64((uint64_t *)&itask->itask_read_xfer,
7718 xfer_size);
7719 } else {
7720 atomic_add_64((uint64_t *)&itask->itask_lport_write_time,
7721 elapsed_time);
7722 atomic_add_64((uint64_t *)&itask->itask_write_xfer,
7723 xfer_size);
7724 }
7725
7726 DTRACE_PROBE3(scsi__xfer__end, scsi_task_t *, itask->itask_task,
7727 stmf_data_buf_t *, dbuf, hrtime_t, elapsed_time);
7728
7729 kip = KSTAT_IO_PTR(itl->itl_kstat_lport_xfer);
7730 mutex_enter(ilp->ilport_kstat_io->ks_lock);
7731 if (dbuf->db_flags & DB_DIRECTION_TO_RPORT) {
7732 kip->reads++;
7733 kip->nread += xfer_size;
7734 } else {
7735 kip->writes++;
7736 kip->nwritten += xfer_size;
7737 }
7738 mutex_exit(ilp->ilport_kstat_io->ks_lock);
7739
7740 dbuf->db_xfer_start_timestamp = 0;
7741 }
7742
7743 void
7744 stmf_svc_init()
7745 {
7746 if (stmf_state.stmf_svc_flags & STMF_SVC_STARTED)
7747 return;
7748 stmf_state.stmf_svc_tailp = &stmf_state.stmf_svc_active;
7749 stmf_state.stmf_svc_taskq = ddi_taskq_create(0, "STMF_SVC_TASKQ", 1,
7750 TASKQ_DEFAULTPRI, 0);
7751 (void) ddi_taskq_dispatch(stmf_state.stmf_svc_taskq,
7752 stmf_svc, 0, DDI_SLEEP);
7753 }
7754
7755 stmf_status_t
7756 stmf_svc_fini()
7757 {
7758 uint32_t i;
7759
7760 mutex_enter(&stmf_state.stmf_lock);
7761 if (stmf_state.stmf_svc_flags & STMF_SVC_STARTED) {
7762 stmf_state.stmf_svc_flags |= STMF_SVC_TERMINATE;
7763 cv_signal(&stmf_state.stmf_cv);
7764 }
7765 mutex_exit(&stmf_state.stmf_lock);
7766
7767 /* Wait for 5 seconds */
7768 for (i = 0; i < 500; i++) {
7769 if (stmf_state.stmf_svc_flags & STMF_SVC_STARTED)
7770 delay(drv_usectohz(10000));
7771 else
7772 break;
7773 }
7774 if (i == 500)
7775 return (STMF_BUSY);
7776
7777 ddi_taskq_destroy(stmf_state.stmf_svc_taskq);
7778
7779 return (STMF_SUCCESS);
7780 }
7781
7782 struct stmf_svc_clocks {
7783 clock_t drain_start, drain_next;
7784 clock_t timing_start, timing_next;
7785 clock_t worker_delay;
7786 };
7787
7788 /* ARGSUSED */
7789 void
7790 stmf_svc(void *arg)
7791 {
7792 stmf_svc_req_t *req;
7793 stmf_lu_t *lu;
7794 stmf_i_lu_t *ilu;
7795 stmf_local_port_t *lport;
7796 struct stmf_svc_clocks clks = { 0 };
7797
7798 mutex_enter(&stmf_state.stmf_lock);
7799 stmf_state.stmf_svc_flags |= STMF_SVC_STARTED | STMF_SVC_ACTIVE;
7800
7801 while (!(stmf_state.stmf_svc_flags & STMF_SVC_TERMINATE)) {
7802 if (stmf_state.stmf_svc_active == NULL) {
7803 stmf_svc_timeout(&clks);
7804 continue;
7805 }
7806
7807 /*
7808 * Pop the front request from the active list. After this,
7809 * the request will no longer be referenced by global state,
7810 * so it should be safe to access it without holding the
7811 * stmf state lock.
7812 */
7813 req = stmf_state.stmf_svc_active;
7814 stmf_state.stmf_svc_active = req->svc_next;
7815
7816 if (stmf_state.stmf_svc_active == NULL)
7817 stmf_state.stmf_svc_tailp = &stmf_state.stmf_svc_active;
7818
7819 switch (req->svc_cmd) {
7820 case STMF_CMD_LPORT_ONLINE:
7821 /* Fallthrough */
7822 case STMF_CMD_LPORT_OFFLINE:
7823 mutex_exit(&stmf_state.stmf_lock);
7824 lport = (stmf_local_port_t *)req->svc_obj;
7825 lport->lport_ctl(lport, req->svc_cmd, &req->svc_info);
7826 break;
7827 case STMF_CMD_LU_ONLINE:
7828 mutex_exit(&stmf_state.stmf_lock);
7829 lu = (stmf_lu_t *)req->svc_obj;
7830 lu->lu_ctl(lu, req->svc_cmd, &req->svc_info);
7831 break;
7832 case STMF_CMD_LU_OFFLINE:
7833 /* Remove all mappings of this LU */
7834 stmf_session_lu_unmapall((stmf_lu_t *)req->svc_obj);
7835 /* Kill all the pending I/Os for this LU */
7836 mutex_exit(&stmf_state.stmf_lock);
7837 stmf_task_lu_killall((stmf_lu_t *)req->svc_obj, NULL,
7838 STMF_ABORTED);
7839 lu = (stmf_lu_t *)req->svc_obj;
7840 ilu = (stmf_i_lu_t *)lu->lu_stmf_private;
7841 if (ilu->ilu_ntasks != ilu->ilu_ntasks_free)
7842 break;
7843 lu->lu_ctl(lu, req->svc_cmd, &req->svc_info);
7844 break;
7845 default:
7846 cmn_err(CE_PANIC, "stmf_svc: unknown cmd %d",
7847 req->svc_cmd);
7848 }
7849
7850 mutex_enter(&stmf_state.stmf_lock);
7851 }
7852
7853 stmf_state.stmf_svc_flags &= ~(STMF_SVC_STARTED | STMF_SVC_ACTIVE);
7854 mutex_exit(&stmf_state.stmf_lock);
7855 }
7856
7857 static void
7858 stmf_svc_timeout(struct stmf_svc_clocks *clks)
7859 {
7860 clock_t td;
7861 stmf_i_local_port_t *ilport, *next_ilport;
7862 stmf_i_scsi_session_t *iss;
7863
7864 ASSERT(mutex_owned(&stmf_state.stmf_lock));
7865
7866 td = drv_usectohz(20000);
7867
7868 /* Do timeouts */
7869 if (stmf_state.stmf_nlus &&
7870 ((!clks->timing_next) || (ddi_get_lbolt() >= clks->timing_next))) {
7871 if (!stmf_state.stmf_svc_ilu_timing) {
7872 /* we are starting a new round */
7873 stmf_state.stmf_svc_ilu_timing =
7874 stmf_state.stmf_ilulist;
7875 clks->timing_start = ddi_get_lbolt();
7876 }
7877
7878 stmf_check_ilu_timing();
7879 if (!stmf_state.stmf_svc_ilu_timing) {
7880 /* we finished a complete round */
7881 clks->timing_next =
7882 clks->timing_start + drv_usectohz(5*1000*1000);
7883 } else {
7884 /* we still have some ilu items to check */
7885 clks->timing_next =
7886 ddi_get_lbolt() + drv_usectohz(1*1000*1000);
7887 }
7888
7889 if (stmf_state.stmf_svc_active)
7890 return;
7891 }
7892
7893 /* Check if there are free tasks to clear */
7894 if (stmf_state.stmf_nlus &&
7895 ((!clks->drain_next) || (ddi_get_lbolt() >= clks->drain_next))) {
7896 if (!stmf_state.stmf_svc_ilu_draining) {
7897 /* we are starting a new round */
7898 stmf_state.stmf_svc_ilu_draining =
7899 stmf_state.stmf_ilulist;
7900 clks->drain_start = ddi_get_lbolt();
7901 }
7902
7903 stmf_check_freetask();
7904 if (!stmf_state.stmf_svc_ilu_draining) {
7905 /* we finished a complete round */
7906 clks->drain_next =
7907 clks->drain_start + drv_usectohz(10*1000*1000);
7908 } else {
7909 /* we still have some ilu items to check */
7910 clks->drain_next =
7911 ddi_get_lbolt() + drv_usectohz(1*1000*1000);
7912 }
7913
7914 if (stmf_state.stmf_svc_active)
7915 return;
7916 }
7917
7918 /* Check if we need to run worker_mgmt */
7919 if (ddi_get_lbolt() > clks->worker_delay) {
7920 stmf_worker_mgmt();
7921 clks->worker_delay = ddi_get_lbolt() +
7922 stmf_worker_mgmt_delay;
7923 }
7924
7925 /* Check if any active session got its 1st LUN */
7926 if (stmf_state.stmf_process_initial_luns) {
7927 int stmf_level = 0;
7928 int port_level;
7929
7930 for (ilport = stmf_state.stmf_ilportlist; ilport;
7931 ilport = next_ilport) {
7932 int ilport_lock_held;
7933 next_ilport = ilport->ilport_next;
7934
7935 if ((ilport->ilport_flags &
7936 ILPORT_SS_GOT_INITIAL_LUNS) == 0)
7937 continue;
7938
7939 port_level = 0;
7940 rw_enter(&ilport->ilport_lock, RW_READER);
7941 ilport_lock_held = 1;
7942
7943 for (iss = ilport->ilport_ss_list; iss;
7944 iss = iss->iss_next) {
7945 if ((iss->iss_flags &
7946 ISS_GOT_INITIAL_LUNS) == 0)
7947 continue;
7948
7949 port_level++;
7950 stmf_level++;
7951 atomic_and_32(&iss->iss_flags,
7952 ~ISS_GOT_INITIAL_LUNS);
7953 atomic_or_32(&iss->iss_flags,
7954 ISS_EVENT_ACTIVE);
7955 rw_exit(&ilport->ilport_lock);
7956 ilport_lock_held = 0;
7957 mutex_exit(&stmf_state.stmf_lock);
7958 stmf_generate_lport_event(ilport,
7959 LPORT_EVENT_INITIAL_LUN_MAPPED,
7960 iss->iss_ss, 0);
7961 atomic_and_32(&iss->iss_flags,
7962 ~ISS_EVENT_ACTIVE);
7963 mutex_enter(&stmf_state.stmf_lock);
7964 /*
7965 * scan all the ilports again as the
7966 * ilport list might have changed.
7967 */
7968 next_ilport = stmf_state.stmf_ilportlist;
7969 break;
7970 }
7971
7972 if (port_level == 0)
7973 atomic_and_32(&ilport->ilport_flags,
7974 ~ILPORT_SS_GOT_INITIAL_LUNS);
7975 /* drop the lock if we are holding it. */
7976 if (ilport_lock_held == 1)
7977 rw_exit(&ilport->ilport_lock);
7978
7979 /* Max 4 session at a time */
7980 if (stmf_level >= 4)
7981 break;
7982 }
7983
7984 if (stmf_level == 0)
7985 stmf_state.stmf_process_initial_luns = 0;
7986 }
7987
7988 stmf_state.stmf_svc_flags &= ~STMF_SVC_ACTIVE;
7989 (void) cv_reltimedwait(&stmf_state.stmf_cv,
7990 &stmf_state.stmf_lock, td, TR_CLOCK_TICK);
7991 stmf_state.stmf_svc_flags |= STMF_SVC_ACTIVE;
7992 }
7993
7994 void
7995 stmf_svc_queue(int cmd, void *obj, stmf_state_change_info_t *info)
7996 {
7997 stmf_svc_req_t *req;
7998 int s;
7999
8000 ASSERT(!mutex_owned(&stmf_state.stmf_lock));
8001 s = sizeof (stmf_svc_req_t);
8002 if (info->st_additional_info) {
8003 s += strlen(info->st_additional_info) + 1;
8004 }
8005 req = kmem_zalloc(s, KM_SLEEP);
8006
8007 req->svc_cmd = cmd;
8008 req->svc_obj = obj;
8009 req->svc_info.st_rflags = info->st_rflags;
8010 if (info->st_additional_info) {
8011 req->svc_info.st_additional_info = (char *)(GET_BYTE_OFFSET(req,
8012 sizeof (stmf_svc_req_t)));
8013 (void) strcpy(req->svc_info.st_additional_info,
8014 info->st_additional_info);
8015 }
8016 req->svc_req_alloc_size = s;
8017 req->svc_next = NULL;
8018
8019 mutex_enter(&stmf_state.stmf_lock);
8020 *stmf_state.stmf_svc_tailp = req;
8021 stmf_state.stmf_svc_tailp = &req->svc_next;
8022 if ((stmf_state.stmf_svc_flags & STMF_SVC_ACTIVE) == 0) {
8023 cv_signal(&stmf_state.stmf_cv);
8024 }
8025 mutex_exit(&stmf_state.stmf_lock);
8026 }
8027
8028 static void
8029 stmf_svc_kill_obj_requests(void *obj)
8030 {
8031 stmf_svc_req_t *prev_req = NULL;
8032 stmf_svc_req_t *next_req;
8033 stmf_svc_req_t *req;
8034
8035 ASSERT(mutex_owned(&stmf_state.stmf_lock));
8036
8037 for (req = stmf_state.stmf_svc_active; req != NULL; req = next_req) {
8038 next_req = req->svc_next;
8039
8040 if (req->svc_obj == obj) {
8041 if (prev_req != NULL)
8042 prev_req->svc_next = next_req;
8043 else
8044 stmf_state.stmf_svc_active = next_req;
8045
8046 if (next_req == NULL)
8047 stmf_state.stmf_svc_tailp = (prev_req != NULL) ?
8048 &prev_req->svc_next :
8049 &stmf_state.stmf_svc_active;
8050
8051 kmem_free(req, req->svc_req_alloc_size);
8052 } else {
8053 prev_req = req;
8054 }
8055 }
8056 }
8057
8058 void
8059 stmf_trace(caddr_t ident, const char *fmt, ...)
8060 {
8061 va_list args;
8062 char tbuf[160];
8063 int len;
8064
8065 if (!stmf_trace_on)
8066 return;
8067 len = snprintf(tbuf, 158, "%s:%07lu: ", ident ? ident : "",
8068 ddi_get_lbolt());
8069 va_start(args, fmt);
8070 len += vsnprintf(tbuf + len, 158 - len, fmt, args);
8071 va_end(args);
8072
8073 if (len > 158) {
8074 len = 158;
8075 }
8076 tbuf[len++] = '\n';
8077 tbuf[len] = 0;
8078
8079 mutex_enter(&trace_buf_lock);
8080 bcopy(tbuf, &stmf_trace_buf[trace_buf_curndx], len+1);
8081 trace_buf_curndx += len;
8082 if (trace_buf_curndx > (trace_buf_size - 320))
8083 trace_buf_curndx = 0;
8084 mutex_exit(&trace_buf_lock);
8085 }
8086
8087 void
8088 stmf_trace_clear()
8089 {
8090 if (!stmf_trace_on)
8091 return;
8092 mutex_enter(&trace_buf_lock);
8093 trace_buf_curndx = 0;
8094 if (trace_buf_size > 0)
8095 stmf_trace_buf[0] = 0;
8096 mutex_exit(&trace_buf_lock);
8097 }
8098
8099 static void
8100 stmf_abort_task_offline(scsi_task_t *task, int offline_lu, char *info)
8101 {
8102 stmf_state_change_info_t change_info;
8103 void *ctl_private;
8104 uint32_t ctl_cmd;
8105 int msg = 0;
8106
8107 stmf_trace("FROM STMF", "abort_task_offline called for %s: %s",
8108 offline_lu ? "LU" : "LPORT", info ? info : "no additional info");
8109 change_info.st_additional_info = info;
8110 if (offline_lu) {
8111 change_info.st_rflags = STMF_RFLAG_RESET |
8112 STMF_RFLAG_LU_ABORT;
8113 ctl_private = task->task_lu;
8114 if (((stmf_i_lu_t *)
8115 task->task_lu->lu_stmf_private)->ilu_state ==
8116 STMF_STATE_ONLINE) {
8117 msg = 1;
8118 }
8119 ctl_cmd = STMF_CMD_LU_OFFLINE;
8120 } else {
8121 change_info.st_rflags = STMF_RFLAG_RESET |
8122 STMF_RFLAG_LPORT_ABORT;
8123 ctl_private = task->task_lport;
8124 if (((stmf_i_local_port_t *)
8125 task->task_lport->lport_stmf_private)->ilport_state ==
8126 STMF_STATE_ONLINE) {
8127 msg = 1;
8128 }
8129 ctl_cmd = STMF_CMD_LPORT_OFFLINE;
8130 }
8131
8132 if (msg) {
8133 stmf_trace(0, "Calling stmf_ctl to offline %s : %s",
8134 offline_lu ? "LU" : "LPORT", info ? info :
8135 "<no additional info>");
8136 }
8137 (void) stmf_ctl(ctl_cmd, ctl_private, &change_info);
8138 }
8139
8140 static char
8141 stmf_ctoi(char c)
8142 {
8143 if ((c >= '0') && (c <= '9'))
8144 c -= '0';
8145 else if ((c >= 'A') && (c <= 'F'))
8146 c = c - 'A' + 10;
8147 else if ((c >= 'a') && (c <= 'f'))
8148 c = c - 'a' + 10;
8149 else
8150 c = -1;
8151 return (c);
8152 }
8153
8154 /* Convert from Hex value in ASCII format to the equivalent bytes */
8155 static boolean_t
8156 stmf_base16_str_to_binary(char *c, int dplen, uint8_t *dp)
8157 {
8158 int ii;
8159
8160 for (ii = 0; ii < dplen; ii++) {
8161 char nibble1, nibble2;
8162 char enc_char = *c++;
8163 nibble1 = stmf_ctoi(enc_char);
8164
8165 enc_char = *c++;
8166 nibble2 = stmf_ctoi(enc_char);
8167 if (nibble1 == -1 || nibble2 == -1)
8168 return (B_FALSE);
8169
8170 dp[ii] = (nibble1 << 4) | nibble2;
8171 }
8172 return (B_TRUE);
8173 }
8174
8175 boolean_t
8176 stmf_scsilib_tptid_validate(scsi_transport_id_t *tptid, uint32_t total_sz,
8177 uint16_t *tptid_sz)
8178 {
8179 uint16_t tpd_len = SCSI_TPTID_SIZE;
8180
8181 if (tptid_sz)
8182 *tptid_sz = 0;
8183 if (total_sz < sizeof (scsi_transport_id_t))
8184 return (B_FALSE);
8185
8186 switch (tptid->protocol_id) {
8187
8188 case PROTOCOL_FIBRE_CHANNEL:
8189 /* FC Transport ID validation checks. SPC3 rev23, Table 284 */
8190 if (total_sz < tpd_len || tptid->format_code != 0)
8191 return (B_FALSE);
8192 break;
8193
8194 case PROTOCOL_iSCSI:
8195 {
8196 iscsi_transport_id_t *iscsiid;
8197 uint16_t adn_len, name_len;
8198
8199 /* Check for valid format code, SPC3 rev 23 Table 288 */
8200 if ((total_sz < tpd_len) ||
8201 (tptid->format_code != 0 && tptid->format_code != 1))
8202 return (B_FALSE);
8203
8204 iscsiid = (iscsi_transport_id_t *)tptid;
8205 adn_len = READ_SCSI16(iscsiid->add_len, uint16_t);
8206 tpd_len = sizeof (iscsi_transport_id_t) + adn_len - 1;
8207
8208 /*
8209 * iSCSI Transport ID validation checks.
8210 * As per SPC3 rev 23 Section 7.5.4.6 and Table 289 & Table 290
8211 */
8212 if (adn_len < 20 || (adn_len % 4 != 0))
8213 return (B_FALSE);
8214
8215 name_len = strnlen(iscsiid->iscsi_name, adn_len);
8216 if (name_len == 0 || name_len >= adn_len)
8217 return (B_FALSE);
8218
8219 /* If the format_code is 1 check for ISID seperator */
8220 if ((tptid->format_code == 1) && (strstr(iscsiid->iscsi_name,
8221 SCSI_TPTID_ISCSI_ISID_SEPERATOR) == NULL))
8222 return (B_FALSE);
8223
8224 }
8225 break;
8226
8227 case PROTOCOL_SRP:
8228 /* SRP Transport ID validation checks. SPC3 rev23, Table 287 */
8229 if (total_sz < tpd_len || tptid->format_code != 0)
8230 return (B_FALSE);
8231 break;
8232
8233 case PROTOCOL_PARALLEL_SCSI:
8234 case PROTOCOL_SSA:
8235 case PROTOCOL_IEEE_1394:
8236 case PROTOCOL_SAS:
8237 case PROTOCOL_ADT:
8238 case PROTOCOL_ATAPI:
8239 default:
8240 {
8241 stmf_dflt_scsi_tptid_t *dflttpd;
8242
8243 tpd_len = sizeof (stmf_dflt_scsi_tptid_t);
8244 if (total_sz < tpd_len)
8245 return (B_FALSE);
8246 dflttpd = (stmf_dflt_scsi_tptid_t *)tptid;
8247 tpd_len = tpd_len + SCSI_READ16(&dflttpd->ident_len) - 1;
8248 if (total_sz < tpd_len)
8249 return (B_FALSE);
8250 }
8251 break;
8252 }
8253 if (tptid_sz)
8254 *tptid_sz = tpd_len;
8255 return (B_TRUE);
8256 }
8257
8258 boolean_t
8259 stmf_scsilib_tptid_compare(scsi_transport_id_t *tpd1,
8260 scsi_transport_id_t *tpd2)
8261 {
8262 if ((tpd1->protocol_id != tpd2->protocol_id) ||
8263 (tpd1->format_code != tpd2->format_code))
8264 return (B_FALSE);
8265
8266 switch (tpd1->protocol_id) {
8267
8268 case PROTOCOL_iSCSI:
8269 {
8270 iscsi_transport_id_t *iscsitpd1, *iscsitpd2;
8271 uint16_t len;
8272
8273 iscsitpd1 = (iscsi_transport_id_t *)tpd1;
8274 iscsitpd2 = (iscsi_transport_id_t *)tpd2;
8275 len = SCSI_READ16(&iscsitpd1->add_len);
8276 if ((memcmp(iscsitpd1->add_len, iscsitpd2->add_len, 2) != 0) ||
8277 (memcmp(iscsitpd1->iscsi_name, iscsitpd2->iscsi_name, len)
8278 != 0))
8279 return (B_FALSE);
8280 }
8281 break;
8282
8283 case PROTOCOL_SRP:
8284 {
8285 scsi_srp_transport_id_t *srptpd1, *srptpd2;
8286
8287 srptpd1 = (scsi_srp_transport_id_t *)tpd1;
8288 srptpd2 = (scsi_srp_transport_id_t *)tpd2;
8289 if (memcmp(srptpd1->srp_name, srptpd2->srp_name,
8290 sizeof (srptpd1->srp_name)) != 0)
8291 return (B_FALSE);
8292 }
8293 break;
8294
8295 case PROTOCOL_FIBRE_CHANNEL:
8296 {
8297 scsi_fc_transport_id_t *fctpd1, *fctpd2;
8298
8299 fctpd1 = (scsi_fc_transport_id_t *)tpd1;
8300 fctpd2 = (scsi_fc_transport_id_t *)tpd2;
8301 if (memcmp(fctpd1->port_name, fctpd2->port_name,
8302 sizeof (fctpd1->port_name)) != 0)
8303 return (B_FALSE);
8304 }
8305 break;
8306
8307 case PROTOCOL_PARALLEL_SCSI:
8308 case PROTOCOL_SSA:
8309 case PROTOCOL_IEEE_1394:
8310 case PROTOCOL_SAS:
8311 case PROTOCOL_ADT:
8312 case PROTOCOL_ATAPI:
8313 default:
8314 {
8315 stmf_dflt_scsi_tptid_t *dflt1, *dflt2;
8316 uint16_t len;
8317
8318 dflt1 = (stmf_dflt_scsi_tptid_t *)tpd1;
8319 dflt2 = (stmf_dflt_scsi_tptid_t *)tpd2;
8320 len = SCSI_READ16(&dflt1->ident_len);
8321 if ((memcmp(dflt1->ident_len, dflt2->ident_len, 2) != 0) ||
8322 (memcmp(dflt1->ident, dflt2->ident, len) != 0))
8323 return (B_FALSE);
8324 }
8325 break;
8326 }
8327 return (B_TRUE);
8328 }
8329
8330 /*
8331 * Changes devid_desc to corresponding TransportID format
8332 * Returns :- pointer to stmf_remote_port_t
8333 * Note :- Allocates continous memory for stmf_remote_port_t and TransportID,
8334 * This memory need to be freed when this remote_port is no longer
8335 * used.
8336 */
8337 stmf_remote_port_t *
8338 stmf_scsilib_devid_to_remote_port(scsi_devid_desc_t *devid)
8339 {
8340 struct scsi_fc_transport_id *fc_tpd;
8341 struct iscsi_transport_id *iscsi_tpd;
8342 struct scsi_srp_transport_id *srp_tpd;
8343 struct stmf_dflt_scsi_tptid *dflt_tpd;
8344 uint16_t ident_len, sz = 0;
8345 stmf_remote_port_t *rpt = NULL;
8346
8347 ident_len = devid->ident_length;
8348 ASSERT(ident_len);
8349 switch (devid->protocol_id) {
8350 case PROTOCOL_FIBRE_CHANNEL:
8351 sz = sizeof (scsi_fc_transport_id_t);
8352 rpt = stmf_remote_port_alloc(sz);
8353 rpt->rport_tptid->format_code = 0;
8354 rpt->rport_tptid->protocol_id = devid->protocol_id;
8355 fc_tpd = (scsi_fc_transport_id_t *)rpt->rport_tptid;
8356 /*
8357 * convert from "wwn.xxxxxxxxxxxxxxxx" to 8-byte binary
8358 * skip first 4 byte for "wwn."
8359 */
8360 ASSERT(strncmp("wwn.", (char *)devid->ident, 4) == 0);
8361 if ((ident_len < SCSI_TPTID_FC_PORT_NAME_SIZE * 2 + 4) ||
8362 !stmf_base16_str_to_binary((char *)devid->ident + 4,
8363 SCSI_TPTID_FC_PORT_NAME_SIZE, fc_tpd->port_name))
8364 goto devid_to_remote_port_fail;
8365 break;
8366
8367 case PROTOCOL_iSCSI:
8368 sz = ALIGNED_TO_8BYTE_BOUNDARY(sizeof (iscsi_transport_id_t) +
8369 ident_len - 1);
8370 rpt = stmf_remote_port_alloc(sz);
8371 rpt->rport_tptid->format_code = 0;
8372 rpt->rport_tptid->protocol_id = devid->protocol_id;
8373 iscsi_tpd = (iscsi_transport_id_t *)rpt->rport_tptid;
8374 SCSI_WRITE16(iscsi_tpd->add_len, ident_len);
8375 (void) memcpy(iscsi_tpd->iscsi_name, devid->ident, ident_len);
8376 break;
8377
8378 case PROTOCOL_SRP:
8379 sz = sizeof (scsi_srp_transport_id_t);
8380 rpt = stmf_remote_port_alloc(sz);
8381 rpt->rport_tptid->format_code = 0;
8382 rpt->rport_tptid->protocol_id = devid->protocol_id;
8383 srp_tpd = (scsi_srp_transport_id_t *)rpt->rport_tptid;
8384 /*
8385 * convert from "eui.xxxxxxxxxxxxxxx" to 8-byte binary
8386 * skip first 4 byte for "eui."
8387 * Assume 8-byte initiator-extension part of srp_name is NOT
8388 * stored in devid and hence will be set as zero
8389 */
8390 ASSERT(strncmp("eui.", (char *)devid->ident, 4) == 0);
8391 if ((ident_len < (SCSI_TPTID_SRP_PORT_NAME_LEN - 8) * 2 + 4) ||
8392 !stmf_base16_str_to_binary((char *)devid->ident+4,
8393 SCSI_TPTID_SRP_PORT_NAME_LEN, srp_tpd->srp_name))
8394 goto devid_to_remote_port_fail;
8395 break;
8396
8397 case PROTOCOL_PARALLEL_SCSI:
8398 case PROTOCOL_SSA:
8399 case PROTOCOL_IEEE_1394:
8400 case PROTOCOL_SAS:
8401 case PROTOCOL_ADT:
8402 case PROTOCOL_ATAPI:
8403 default :
8404 ident_len = devid->ident_length;
8405 sz = ALIGNED_TO_8BYTE_BOUNDARY(sizeof (stmf_dflt_scsi_tptid_t) +
8406 ident_len - 1);
8407 rpt = stmf_remote_port_alloc(sz);
8408 rpt->rport_tptid->format_code = 0;
8409 rpt->rport_tptid->protocol_id = devid->protocol_id;
8410 dflt_tpd = (stmf_dflt_scsi_tptid_t *)rpt->rport_tptid;
8411 SCSI_WRITE16(dflt_tpd->ident_len, ident_len);
8412 (void) memcpy(dflt_tpd->ident, devid->ident, ident_len);
8413 break;
8414 }
8415 return (rpt);
8416
8417 devid_to_remote_port_fail:
8418 stmf_remote_port_free(rpt);
8419 return (NULL);
8420
8421 }
8422
8423 stmf_remote_port_t *
8424 stmf_remote_port_alloc(uint16_t tptid_sz) {
8425 stmf_remote_port_t *rpt;
8426 rpt = (stmf_remote_port_t *)kmem_zalloc(
8427 sizeof (stmf_remote_port_t) + tptid_sz, KM_SLEEP);
8428 rpt->rport_tptid_sz = tptid_sz;
8429 rpt->rport_tptid = (scsi_transport_id_t *)(rpt + 1);
8430 return (rpt);
8431 }
8432
8433 void
8434 stmf_remote_port_free(stmf_remote_port_t *rpt)
8435 {
8436 /*
8437 * Note: stmf_scsilib_devid_to_remote_port() function allocates
8438 * remote port structures for all transports in the same way, So
8439 * it is safe to deallocate it in a protocol independent manner.
8440 * If any of the allocation method changes, corresponding changes
8441 * need to be made here too.
8442 */
8443 kmem_free(rpt, sizeof (stmf_remote_port_t) + rpt->rport_tptid_sz);
8444 }