1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 /*
26  * Copyright 2019 Nexenta Systems, Inc.  All rights reserved.
27  * Copyright (c) 2013 by Delphix. All rights reserved.
28  * Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
29  */
30 
31 #include <sys/conf.h>
32 #include <sys/file.h>
33 #include <sys/ddi.h>
34 #include <sys/sunddi.h>
35 #include <sys/modctl.h>
36 #include <sys/scsi/scsi.h>
37 #include <sys/scsi/generic/persist.h>
38 #include <sys/scsi/impl/scsi_reset_notify.h>
39 #include <sys/disp.h>
40 #include <sys/byteorder.h>
41 #include <sys/atomic.h>
42 #include <sys/ethernet.h>
43 #include <sys/sdt.h>
44 #include <sys/nvpair.h>
45 #include <sys/zone.h>
46 #include <sys/id_space.h>
47 
48 #include <sys/stmf.h>
49 #include <sys/lpif.h>
50 #include <sys/portif.h>
51 #include <sys/stmf_ioctl.h>
52 #include <sys/pppt_ic_if.h>
53 
54 #include "stmf_impl.h"
55 #include "lun_map.h"
56 #include "stmf_state.h"
57 #include "stmf_stats.h"
58 
59 /*
60  * Lock order:
61  * stmf_state_lock --> ilport_lock/iss_lockp --> ilu_task_lock
62  */
63 
64 static uint64_t stmf_session_counter = 0;
65 static uint16_t stmf_rtpid_counter = 0;
66 /* start messages at 1 */
67 static uint64_t stmf_proxy_msg_id = 1;
68 #define	MSG_ID_TM_BIT	0x8000000000000000
69 #define	ALIGNED_TO_8BYTE_BOUNDARY(i)	(((i) + 7) & ~7)
70 
71 /*
72  * When stmf_io_deadman_enabled is set to B_TRUE, we check that finishing up
73  * I/O operations on an offlining LU doesn't take longer than stmf_io_deadman
74  * seconds. If it does, we trigger a panic to inform the user of hung I/O
75  * blocking us for too long.
76  */
77 boolean_t stmf_io_deadman_enabled = B_TRUE;
78 int stmf_io_deadman = 1000;			/* seconds */
79 
80 struct stmf_svc_clocks;
81 
82 static int stmf_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
83 static int stmf_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
84 static int stmf_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
85 	void **result);
86 static int stmf_open(dev_t *devp, int flag, int otype, cred_t *credp);
87 static int stmf_close(dev_t dev, int flag, int otype, cred_t *credp);
88 static int stmf_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
89 	cred_t *credp, int *rval);
90 static int stmf_get_stmf_state(stmf_state_desc_t *std);
91 static int stmf_set_stmf_state(stmf_state_desc_t *std);
92 static void stmf_abort_task_offline(scsi_task_t *task, int offline_lu,
93     char *info);
94 static int stmf_set_alua_state(stmf_alua_state_desc_t *alua_state);
95 static void stmf_get_alua_state(stmf_alua_state_desc_t *alua_state);
96 
97 static void stmf_task_audit(stmf_i_scsi_task_t *itask,
98     task_audit_event_t te, uint32_t cmd_or_iof, stmf_data_buf_t *dbuf);
99 
100 static boolean_t stmf_base16_str_to_binary(char *c, int dplen, uint8_t *dp);
101 static char stmf_ctoi(char c);
102 stmf_xfer_data_t *stmf_prepare_tpgs_data(uint8_t ilu_alua);
103 void stmf_svc_init();
104 stmf_status_t stmf_svc_fini();
105 void stmf_svc(void *arg);
106 static void stmf_wait_ilu_tasks_finish(stmf_i_lu_t *ilu);
107 void stmf_svc_queue(int cmd, void *obj, stmf_state_change_info_t *info);
108 static void stmf_svc_kill_obj_requests(void *obj);
109 static void stmf_svc_timeout(struct stmf_svc_clocks *);
110 void stmf_check_freetask();
111 void stmf_abort_target_reset(scsi_task_t *task);
112 stmf_status_t stmf_lun_reset_poll(stmf_lu_t *lu, struct scsi_task *task,
113 							int target_reset);
114 void stmf_target_reset_poll(struct scsi_task *task);
115 void stmf_handle_lun_reset(scsi_task_t *task);
116 void stmf_handle_target_reset(scsi_task_t *task);
117 void stmf_xd_to_dbuf(stmf_data_buf_t *dbuf, int set_rel_off);
118 int stmf_load_ppd_ioctl(stmf_ppioctl_data_t *ppi, uint64_t *ppi_token,
119     uint32_t *err_ret);
120 int stmf_delete_ppd_ioctl(stmf_ppioctl_data_t *ppi);
121 int stmf_get_ppd_ioctl(stmf_ppioctl_data_t *ppi, stmf_ppioctl_data_t *ppi_out,
122     uint32_t *err_ret);
123 void stmf_delete_ppd(stmf_pp_data_t *ppd);
124 void stmf_delete_all_ppds();
125 void stmf_trace_clear();
126 void stmf_worker_init();
127 stmf_status_t stmf_worker_fini();
128 void stmf_worker_task(void *arg);
129 static void stmf_task_lu_free(scsi_task_t *task, stmf_i_scsi_session_t *iss);
130 static stmf_status_t stmf_ic_lu_reg(stmf_ic_reg_dereg_lun_msg_t *msg,
131     uint32_t type);
132 static stmf_status_t stmf_ic_lu_dereg(stmf_ic_reg_dereg_lun_msg_t *msg);
133 static stmf_status_t stmf_ic_rx_scsi_status(stmf_ic_scsi_status_msg_t *msg);
134 static stmf_status_t stmf_ic_rx_status(stmf_ic_status_msg_t *msg);
135 static stmf_status_t stmf_ic_rx_scsi_data(stmf_ic_scsi_data_msg_t *msg);
136 void stmf_task_lu_killall(stmf_lu_t *lu, scsi_task_t *tm_task, stmf_status_t s);
137 
138 /* pppt modhandle */
139 ddi_modhandle_t pppt_mod;
140 
141 /* pppt modload imported functions */
142 stmf_ic_reg_port_msg_alloc_func_t ic_reg_port_msg_alloc;
143 stmf_ic_dereg_port_msg_alloc_func_t ic_dereg_port_msg_alloc;
144 stmf_ic_reg_lun_msg_alloc_func_t ic_reg_lun_msg_alloc;
145 stmf_ic_dereg_lun_msg_alloc_func_t ic_dereg_lun_msg_alloc;
146 stmf_ic_lun_active_msg_alloc_func_t ic_lun_active_msg_alloc;
147 stmf_ic_scsi_cmd_msg_alloc_func_t ic_scsi_cmd_msg_alloc;
148 stmf_ic_scsi_data_xfer_done_msg_alloc_func_t ic_scsi_data_xfer_done_msg_alloc;
149 stmf_ic_session_create_msg_alloc_func_t ic_session_reg_msg_alloc;
150 stmf_ic_session_destroy_msg_alloc_func_t ic_session_dereg_msg_alloc;
151 stmf_ic_tx_msg_func_t ic_tx_msg;
152 stmf_ic_msg_free_func_t ic_msg_free;
153 
154 static void stmf_itl_task_start(stmf_i_scsi_task_t *itask);
155 static void stmf_itl_lu_new_task(stmf_i_scsi_task_t *itask);
156 static void stmf_itl_task_done(stmf_i_scsi_task_t *itask);
157 
158 static void stmf_lport_xfer_start(stmf_i_scsi_task_t *itask,
159     stmf_data_buf_t *dbuf);
160 static void stmf_lport_xfer_done(stmf_i_scsi_task_t *itask,
161     stmf_data_buf_t *dbuf);
162 
163 static void stmf_update_kstat_lu_q(scsi_task_t *, void());
164 static void stmf_update_kstat_lport_q(scsi_task_t *, void());
165 static void stmf_update_kstat_lu_io(scsi_task_t *, stmf_data_buf_t *);
166 static void stmf_update_kstat_lport_io(scsi_task_t *, stmf_data_buf_t *);
167 static hrtime_t stmf_update_rport_timestamps(hrtime_t *start_tstamp,
168     hrtime_t *done_tstamp, stmf_i_scsi_task_t *itask);
169 
170 static int stmf_irport_compare(const void *void_irport1,
171     const void *void_irport2);
172 static void stmf_create_kstat_rport(stmf_i_remote_port_t *irport);
173 static void stmf_destroy_kstat_rport(stmf_i_remote_port_t *irport);
174 static int stmf_kstat_rport_update(kstat_t *ksp, int rw);
175 static stmf_i_remote_port_t *stmf_irport_create(scsi_devid_desc_t *rport_devid);
176 static void stmf_irport_destroy(stmf_i_remote_port_t *irport);
177 static stmf_i_remote_port_t *stmf_irport_register(
178     scsi_devid_desc_t *rport_devid);
179 static stmf_i_remote_port_t *stmf_irport_lookup_locked(
180     scsi_devid_desc_t *rport_devid);
181 static void stmf_irport_deregister(stmf_i_remote_port_t *irport);
182 
183 extern struct mod_ops mod_driverops;
184 
185 /* =====[ Tunables ]===== */
186 /* Internal tracing */
187 volatile int	stmf_trace_on = 0;
188 volatile int	stmf_trace_buf_size = (1 * 1024 * 1024);
189 /*
190  * The reason default task timeout is 75 is because we want the
191  * host to timeout 1st and mostly host timeout is 60 seconds.
192  */
193 volatile int	stmf_default_task_timeout = 75;
194 /*
195  * Setting this to one means, you are responsible for config load and keeping
196  * things in sync with persistent database.
197  */
198 volatile int	stmf_allow_modunload = 0;
199 
200 volatile int stmf_nworkers = 512;
201 
202 /* === [ Debugging and fault injection ] === */
203 #ifdef	DEBUG
204 volatile int stmf_drop_task_counter = 0;
205 volatile int stmf_drop_buf_counter = 0;
206 
207 #endif
208 
209 stmf_state_t		stmf_state;
210 static stmf_lu_t	*dlun0;
211 
212 static uint8_t stmf_first_zero[] =
213 	{ 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 0xff };
214 static uint8_t stmf_first_one[] =
215 	{ 0xff, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 };
216 
217 static kmutex_t	trace_buf_lock;
218 static int	trace_buf_size;
219 static int	trace_buf_curndx;
220 caddr_t	stmf_trace_buf;
221 
222 static enum {
223 	STMF_WORKERS_DISABLED = 0,
224 	STMF_WORKERS_ENABLING,
225 	STMF_WORKERS_ENABLED
226 } stmf_workers_state = STMF_WORKERS_DISABLED;
227 static kmutex_t	stmf_worker_sel_mx;
228 volatile uint32_t stmf_nworkers_cur = 0; /* # of workers currently running */
229 static int stmf_worker_sel_counter = 0;
230 static uint32_t stmf_cur_ntasks = 0;
231 static clock_t stmf_wm_next = 0;
232 static int stmf_nworkers_accepting_cmds;
233 static stmf_worker_t *stmf_workers = NULL;
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
_init(void)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 	mutex_init(&stmf_worker_sel_mx, NULL, MUTEX_ADAPTIVE, 0);
300 	bzero(&stmf_state, sizeof (stmf_state_t));
301 	/* STMF service is off by default */
302 	stmf_state.stmf_service_running = 0;
303 	/* default lu/lport states are online */
304 	stmf_state.stmf_default_lu_state = STMF_STATE_ONLINE;
305 	stmf_state.stmf_default_lport_state = STMF_STATE_ONLINE;
306 	mutex_init(&stmf_state.stmf_lock, NULL, MUTEX_DRIVER, NULL);
307 	cv_init(&stmf_state.stmf_cv, NULL, CV_DRIVER, NULL);
308 	stmf_session_counter = (uint64_t)ddi_get_lbolt();
309 	avl_create(&stmf_state.stmf_irportlist,
310 	    stmf_irport_compare, sizeof (stmf_i_remote_port_t),
311 	    offsetof(stmf_i_remote_port_t, irport_ln));
312 	stmf_state.stmf_ilport_inst_space =
313 	    id_space_create("lport-instances", 0, MAX_ILPORT);
314 	stmf_state.stmf_irport_inst_space =
315 	    id_space_create("rport-instances", 0, MAX_IRPORT);
316 	stmf_view_init();
317 	stmf_svc_init();
318 	stmf_dlun_init();
319 	return (ret);
320 }
321 
322 int
_fini(void)323 _fini(void)
324 {
325 	int ret;
326 	stmf_i_remote_port_t	*irport;
327 	void			*avl_dest_cookie = NULL;
328 
329 	if (stmf_state.stmf_service_running)
330 		return (EBUSY);
331 	if ((!stmf_allow_modunload) &&
332 	    (stmf_state.stmf_config_state != STMF_CONFIG_NONE)) {
333 		return (EBUSY);
334 	}
335 	if (stmf_state.stmf_nlps || stmf_state.stmf_npps) {
336 		return (EBUSY);
337 	}
338 	if (stmf_dlun_fini() != STMF_SUCCESS)
339 		return (EBUSY);
340 	if (stmf_worker_fini() != STMF_SUCCESS) {
341 		stmf_dlun_init();
342 		return (EBUSY);
343 	}
344 	if (stmf_svc_fini() != STMF_SUCCESS) {
345 		stmf_dlun_init();
346 		stmf_worker_init();
347 		return (EBUSY);
348 	}
349 
350 	ret = mod_remove(&modlinkage);
351 	if (ret) {
352 		stmf_svc_init();
353 		stmf_dlun_init();
354 		stmf_worker_init();
355 		return (ret);
356 	}
357 
358 	stmf_view_clear_config();
359 
360 	while ((irport = avl_destroy_nodes(&stmf_state.stmf_irportlist,
361 	    &avl_dest_cookie)) != NULL)
362 		stmf_irport_destroy(irport);
363 	avl_destroy(&stmf_state.stmf_irportlist);
364 	id_space_destroy(stmf_state.stmf_ilport_inst_space);
365 	id_space_destroy(stmf_state.stmf_irport_inst_space);
366 
367 	kmem_free(stmf_trace_buf, stmf_trace_buf_size);
368 	mutex_destroy(&trace_buf_lock);
369 	mutex_destroy(&stmf_state.stmf_lock);
370 	mutex_destroy(&stmf_worker_sel_mx);
371 	cv_destroy(&stmf_state.stmf_cv);
372 	return (ret);
373 }
374 
375 int
_info(struct modinfo * modinfop)376 _info(struct modinfo *modinfop)
377 {
378 	return (mod_info(&modlinkage, modinfop));
379 }
380 
381 /* ARGSUSED */
382 static int
stmf_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** result)383 stmf_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
384 {
385 	switch (cmd) {
386 	case DDI_INFO_DEVT2DEVINFO:
387 		*result = stmf_state.stmf_dip;
388 		break;
389 	case DDI_INFO_DEVT2INSTANCE:
390 		*result =
391 		    (void *)(uintptr_t)ddi_get_instance(stmf_state.stmf_dip);
392 		break;
393 	default:
394 		return (DDI_FAILURE);
395 	}
396 
397 	return (DDI_SUCCESS);
398 }
399 
400 static int
stmf_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)401 stmf_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
402 {
403 	switch (cmd) {
404 	case DDI_ATTACH:
405 		stmf_state.stmf_dip = dip;
406 
407 		if (ddi_create_minor_node(dip, "admin", S_IFCHR, 0,
408 		    DDI_NT_STMF, 0) != DDI_SUCCESS) {
409 			break;
410 		}
411 		ddi_report_dev(dip);
412 		return (DDI_SUCCESS);
413 	}
414 
415 	return (DDI_FAILURE);
416 }
417 
418 static int
stmf_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)419 stmf_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
420 {
421 	switch (cmd) {
422 	case DDI_DETACH:
423 		ddi_remove_minor_node(dip, 0);
424 		return (DDI_SUCCESS);
425 	}
426 
427 	return (DDI_FAILURE);
428 }
429 
430 /* ARGSUSED */
431 static int
stmf_open(dev_t * devp,int flag,int otype,cred_t * credp)432 stmf_open(dev_t *devp, int flag, int otype, cred_t *credp)
433 {
434 	mutex_enter(&stmf_state.stmf_lock);
435 	if (stmf_state.stmf_exclusive_open) {
436 		mutex_exit(&stmf_state.stmf_lock);
437 		return (EBUSY);
438 	}
439 	if (flag & FEXCL) {
440 		if (stmf_state.stmf_opened) {
441 			mutex_exit(&stmf_state.stmf_lock);
442 			return (EBUSY);
443 		}
444 		stmf_state.stmf_exclusive_open = 1;
445 	}
446 	stmf_state.stmf_opened = 1;
447 	mutex_exit(&stmf_state.stmf_lock);
448 	return (0);
449 }
450 
451 /* ARGSUSED */
452 static int
stmf_close(dev_t dev,int flag,int otype,cred_t * credp)453 stmf_close(dev_t dev, int flag, int otype, cred_t *credp)
454 {
455 	mutex_enter(&stmf_state.stmf_lock);
456 	stmf_state.stmf_opened = 0;
457 	if (stmf_state.stmf_exclusive_open &&
458 	    (stmf_state.stmf_config_state != STMF_CONFIG_INIT_DONE)) {
459 		stmf_state.stmf_config_state = STMF_CONFIG_NONE;
460 		stmf_delete_all_ppds();
461 		stmf_view_clear_config();
462 		stmf_view_init();
463 	}
464 	stmf_state.stmf_exclusive_open = 0;
465 	mutex_exit(&stmf_state.stmf_lock);
466 	return (0);
467 }
468 
469 int
stmf_copyin_iocdata(intptr_t data,int mode,stmf_iocdata_t ** iocd,void ** ibuf,void ** obuf)470 stmf_copyin_iocdata(intptr_t data, int mode, stmf_iocdata_t **iocd,
471     void **ibuf, void **obuf)
472 {
473 	int ret;
474 
475 	*ibuf = NULL;
476 	*obuf = NULL;
477 	*iocd = kmem_zalloc(sizeof (stmf_iocdata_t), KM_SLEEP);
478 
479 	ret = ddi_copyin((void *)data, *iocd, sizeof (stmf_iocdata_t), mode);
480 	if (ret)
481 		return (EFAULT);
482 	if ((*iocd)->stmf_version != STMF_VERSION_1) {
483 		ret = EINVAL;
484 		goto copyin_iocdata_done;
485 	}
486 	if ((*iocd)->stmf_ibuf_size) {
487 		*ibuf = kmem_zalloc((*iocd)->stmf_ibuf_size, KM_SLEEP);
488 		ret = ddi_copyin((void *)((unsigned long)(*iocd)->stmf_ibuf),
489 		    *ibuf, (*iocd)->stmf_ibuf_size, mode);
490 	}
491 	if ((*iocd)->stmf_obuf_size)
492 		*obuf = kmem_zalloc((*iocd)->stmf_obuf_size, KM_SLEEP);
493 
494 	if (ret == 0)
495 		return (0);
496 	ret = EFAULT;
497 copyin_iocdata_done:;
498 	if (*obuf) {
499 		kmem_free(*obuf, (*iocd)->stmf_obuf_size);
500 		*obuf = NULL;
501 	}
502 	if (*ibuf) {
503 		kmem_free(*ibuf, (*iocd)->stmf_ibuf_size);
504 		*ibuf = NULL;
505 	}
506 	kmem_free(*iocd, sizeof (stmf_iocdata_t));
507 	return (ret);
508 }
509 
510 int
stmf_copyout_iocdata(intptr_t data,int mode,stmf_iocdata_t * iocd,void * obuf)511 stmf_copyout_iocdata(intptr_t data, int mode, stmf_iocdata_t *iocd, void *obuf)
512 {
513 	int ret;
514 
515 	if (iocd->stmf_obuf_size) {
516 		ret = ddi_copyout(obuf, (void *)(unsigned long)iocd->stmf_obuf,
517 		    iocd->stmf_obuf_size, mode);
518 		if (ret)
519 			return (EFAULT);
520 	}
521 	ret = ddi_copyout(iocd, (void *)data, sizeof (stmf_iocdata_t), mode);
522 	if (ret)
523 		return (EFAULT);
524 	return (0);
525 }
526 
527 /* ARGSUSED */
528 static int
stmf_ioctl(dev_t dev,int cmd,intptr_t data,int mode,cred_t * credp,int * rval)529 stmf_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
530     cred_t *credp, int *rval)
531 {
532 	stmf_iocdata_t *iocd;
533 	void *ibuf = NULL, *obuf = NULL;
534 	slist_lu_t *luid_list;
535 	slist_target_port_t *lportid_list;
536 	stmf_i_lu_t *ilu;
537 	stmf_i_local_port_t *ilport;
538 	stmf_i_scsi_session_t *iss;
539 	slist_scsi_session_t *iss_list;
540 	sioc_lu_props_t *lup;
541 	sioc_target_port_props_t *lportp;
542 	stmf_ppioctl_data_t *ppi, *ppi_out = NULL;
543 	uint64_t *ppi_token = NULL;
544 	uint8_t *p_id, *id;
545 	stmf_state_desc_t *std;
546 	stmf_status_t ctl_ret;
547 	stmf_state_change_info_t ssi;
548 	int ret = 0;
549 	uint32_t n;
550 	int i;
551 	stmf_group_op_data_t *grp_entry;
552 	stmf_group_name_t *grpname;
553 	stmf_view_op_entry_t *ve;
554 	stmf_id_type_t idtype;
555 	stmf_id_data_t *id_entry;
556 	stmf_id_list_t	*id_list;
557 	stmf_view_entry_t *view_entry;
558 	stmf_set_props_t *stmf_set_props;
559 	uint32_t	veid;
560 	if ((cmd & 0xff000000) != STMF_IOCTL) {
561 		return (ENOTTY);
562 	}
563 
564 	if (drv_priv(credp) != 0) {
565 		return (EPERM);
566 	}
567 
568 	ret = stmf_copyin_iocdata(data, mode, &iocd, &ibuf, &obuf);
569 	if (ret)
570 		return (ret);
571 	iocd->stmf_error = 0;
572 
573 	switch (cmd) {
574 	case STMF_IOCTL_LU_LIST:
575 		/* retrieves both registered/unregistered */
576 		mutex_enter(&stmf_state.stmf_lock);
577 		id_list = &stmf_state.stmf_luid_list;
578 		n = min(id_list->id_count,
579 		    (iocd->stmf_obuf_size)/sizeof (slist_lu_t));
580 		iocd->stmf_obuf_max_nentries = id_list->id_count;
581 		luid_list = (slist_lu_t *)obuf;
582 		id_entry = id_list->idl_head;
583 		for (i = 0; i < n; i++) {
584 			bcopy(id_entry->id_data, luid_list[i].lu_guid, 16);
585 			id_entry = id_entry->id_next;
586 		}
587 
588 		n = iocd->stmf_obuf_size/sizeof (slist_lu_t);
589 		for (ilu = stmf_state.stmf_ilulist; ilu; ilu = ilu->ilu_next) {
590 			id = (uint8_t *)ilu->ilu_lu->lu_id;
591 			if (stmf_lookup_id(id_list, 16, id + 4) == NULL) {
592 				iocd->stmf_obuf_max_nentries++;
593 				if (i < n) {
594 					bcopy(id + 4, luid_list[i].lu_guid,
595 					    sizeof (slist_lu_t));
596 					i++;
597 				}
598 			}
599 		}
600 		iocd->stmf_obuf_nentries = i;
601 		mutex_exit(&stmf_state.stmf_lock);
602 		break;
603 
604 	case STMF_IOCTL_REG_LU_LIST:
605 		mutex_enter(&stmf_state.stmf_lock);
606 		iocd->stmf_obuf_max_nentries = stmf_state.stmf_nlus;
607 		n = min(stmf_state.stmf_nlus,
608 		    (iocd->stmf_obuf_size)/sizeof (slist_lu_t));
609 		iocd->stmf_obuf_nentries = n;
610 		ilu = stmf_state.stmf_ilulist;
611 		luid_list = (slist_lu_t *)obuf;
612 		for (i = 0; i < n; i++) {
613 			uint8_t *id;
614 			id = (uint8_t *)ilu->ilu_lu->lu_id;
615 			bcopy(id + 4, luid_list[i].lu_guid, 16);
616 			ilu = ilu->ilu_next;
617 		}
618 		mutex_exit(&stmf_state.stmf_lock);
619 		break;
620 
621 	case STMF_IOCTL_VE_LU_LIST:
622 		mutex_enter(&stmf_state.stmf_lock);
623 		id_list = &stmf_state.stmf_luid_list;
624 		n = min(id_list->id_count,
625 		    (iocd->stmf_obuf_size)/sizeof (slist_lu_t));
626 		iocd->stmf_obuf_max_nentries = id_list->id_count;
627 		iocd->stmf_obuf_nentries = n;
628 		luid_list = (slist_lu_t *)obuf;
629 		id_entry = id_list->idl_head;
630 		for (i = 0; i < n; i++) {
631 			bcopy(id_entry->id_data, luid_list[i].lu_guid, 16);
632 			id_entry = id_entry->id_next;
633 		}
634 		mutex_exit(&stmf_state.stmf_lock);
635 		break;
636 
637 	case STMF_IOCTL_TARGET_PORT_LIST:
638 		mutex_enter(&stmf_state.stmf_lock);
639 		iocd->stmf_obuf_max_nentries = stmf_state.stmf_nlports;
640 		n = min(stmf_state.stmf_nlports,
641 		    (iocd->stmf_obuf_size)/sizeof (slist_target_port_t));
642 		iocd->stmf_obuf_nentries = n;
643 		ilport = stmf_state.stmf_ilportlist;
644 		lportid_list = (slist_target_port_t *)obuf;
645 		for (i = 0; i < n; i++) {
646 			uint8_t *id;
647 			id = (uint8_t *)ilport->ilport_lport->lport_id;
648 			bcopy(id, lportid_list[i].target, id[3] + 4);
649 			ilport = ilport->ilport_next;
650 		}
651 		mutex_exit(&stmf_state.stmf_lock);
652 		break;
653 
654 	case STMF_IOCTL_SESSION_LIST:
655 		p_id = (uint8_t *)ibuf;
656 		if ((p_id == NULL) || (iocd->stmf_ibuf_size < 4) ||
657 		    (iocd->stmf_ibuf_size < (p_id[3] + 4))) {
658 			ret = EINVAL;
659 			break;
660 		}
661 		mutex_enter(&stmf_state.stmf_lock);
662 		for (ilport = stmf_state.stmf_ilportlist; ilport; ilport =
663 		    ilport->ilport_next) {
664 			uint8_t *id;
665 			id = (uint8_t *)ilport->ilport_lport->lport_id;
666 			if ((p_id[3] == id[3]) &&
667 			    (bcmp(p_id + 4, id + 4, id[3]) == 0)) {
668 				break;
669 			}
670 		}
671 		if (ilport == NULL) {
672 			mutex_exit(&stmf_state.stmf_lock);
673 			ret = ENOENT;
674 			break;
675 		}
676 		iocd->stmf_obuf_max_nentries = ilport->ilport_nsessions;
677 		n = min(ilport->ilport_nsessions,
678 		    (iocd->stmf_obuf_size)/sizeof (slist_scsi_session_t));
679 		iocd->stmf_obuf_nentries = n;
680 		iss = ilport->ilport_ss_list;
681 		iss_list = (slist_scsi_session_t *)obuf;
682 		for (i = 0; i < n; i++) {
683 			uint8_t *id;
684 			id = (uint8_t *)iss->iss_ss->ss_rport_id;
685 			bcopy(id, iss_list[i].initiator, id[3] + 4);
686 			iss_list[i].creation_time = (uint32_t)
687 			    iss->iss_creation_time;
688 			if (iss->iss_ss->ss_rport_alias) {
689 				(void) strncpy(iss_list[i].alias,
690 				    iss->iss_ss->ss_rport_alias, 255);
691 				iss_list[i].alias[255] = '\0';
692 			} else {
693 				iss_list[i].alias[0] = '\0';
694 			}
695 			iss = iss->iss_next;
696 		}
697 		mutex_exit(&stmf_state.stmf_lock);
698 		break;
699 
700 	case STMF_IOCTL_GET_LU_PROPERTIES:
701 		p_id = (uint8_t *)ibuf;
702 		if ((iocd->stmf_ibuf_size < 16) ||
703 		    (iocd->stmf_obuf_size < sizeof (sioc_lu_props_t)) ||
704 		    (p_id[0] == 0)) {
705 			ret = EINVAL;
706 			break;
707 		}
708 		mutex_enter(&stmf_state.stmf_lock);
709 		for (ilu = stmf_state.stmf_ilulist; ilu; ilu = ilu->ilu_next) {
710 			if (bcmp(p_id, ilu->ilu_lu->lu_id->ident, 16) == 0)
711 				break;
712 		}
713 		if (ilu == NULL) {
714 			mutex_exit(&stmf_state.stmf_lock);
715 			ret = ENOENT;
716 			break;
717 		}
718 		lup = (sioc_lu_props_t *)obuf;
719 		bcopy(ilu->ilu_lu->lu_id->ident, lup->lu_guid, 16);
720 		lup->lu_state = ilu->ilu_state & 0x0f;
721 		lup->lu_present = 1; /* XXX */
722 		(void) strncpy(lup->lu_provider_name,
723 		    ilu->ilu_lu->lu_lp->lp_name, 255);
724 		lup->lu_provider_name[254] = '\0';
725 		if (ilu->ilu_lu->lu_alias) {
726 			(void) strncpy(lup->lu_alias,
727 			    ilu->ilu_lu->lu_alias, 255);
728 			lup->lu_alias[255] = '\0';
729 		} else {
730 			lup->lu_alias[0] = '\0';
731 		}
732 		mutex_exit(&stmf_state.stmf_lock);
733 		break;
734 
735 	case STMF_IOCTL_GET_TARGET_PORT_PROPERTIES:
736 		p_id = (uint8_t *)ibuf;
737 		if ((p_id == NULL) ||
738 		    (iocd->stmf_ibuf_size < (p_id[3] + 4)) ||
739 		    (iocd->stmf_obuf_size <
740 		    sizeof (sioc_target_port_props_t))) {
741 			ret = EINVAL;
742 			break;
743 		}
744 		mutex_enter(&stmf_state.stmf_lock);
745 		for (ilport = stmf_state.stmf_ilportlist; ilport;
746 		    ilport = ilport->ilport_next) {
747 			uint8_t *id;
748 			id = (uint8_t *)ilport->ilport_lport->lport_id;
749 			if ((p_id[3] == id[3]) &&
750 			    (bcmp(p_id+4, id+4, id[3]) == 0))
751 				break;
752 		}
753 		if (ilport == NULL) {
754 			mutex_exit(&stmf_state.stmf_lock);
755 			ret = ENOENT;
756 			break;
757 		}
758 		lportp = (sioc_target_port_props_t *)obuf;
759 		bcopy(ilport->ilport_lport->lport_id, lportp->tgt_id,
760 		    ilport->ilport_lport->lport_id->ident_length + 4);
761 		lportp->tgt_state = ilport->ilport_state & 0x0f;
762 		lportp->tgt_present = 1; /* XXX */
763 		(void) strncpy(lportp->tgt_provider_name,
764 		    ilport->ilport_lport->lport_pp->pp_name, 255);
765 		lportp->tgt_provider_name[254] = '\0';
766 		if (ilport->ilport_lport->lport_alias) {
767 			(void) strncpy(lportp->tgt_alias,
768 			    ilport->ilport_lport->lport_alias, 255);
769 			lportp->tgt_alias[255] = '\0';
770 		} else {
771 			lportp->tgt_alias[0] = '\0';
772 		}
773 		mutex_exit(&stmf_state.stmf_lock);
774 		break;
775 
776 	case STMF_IOCTL_SET_STMF_STATE:
777 		if ((ibuf == NULL) ||
778 		    (iocd->stmf_ibuf_size < sizeof (stmf_state_desc_t))) {
779 			ret = EINVAL;
780 			break;
781 		}
782 		ret = stmf_set_stmf_state((stmf_state_desc_t *)ibuf);
783 		break;
784 
785 	case STMF_IOCTL_GET_STMF_STATE:
786 		if ((obuf == NULL) ||
787 		    (iocd->stmf_obuf_size < sizeof (stmf_state_desc_t))) {
788 			ret = EINVAL;
789 			break;
790 		}
791 		ret = stmf_get_stmf_state((stmf_state_desc_t *)obuf);
792 		break;
793 
794 	case STMF_IOCTL_SET_ALUA_STATE:
795 		if ((ibuf == NULL) ||
796 		    (iocd->stmf_ibuf_size < sizeof (stmf_alua_state_desc_t))) {
797 			ret = EINVAL;
798 			break;
799 		}
800 		ret = stmf_set_alua_state((stmf_alua_state_desc_t *)ibuf);
801 		break;
802 
803 	case STMF_IOCTL_GET_ALUA_STATE:
804 		if ((obuf == NULL) ||
805 		    (iocd->stmf_obuf_size < sizeof (stmf_alua_state_desc_t))) {
806 			ret = EINVAL;
807 			break;
808 		}
809 		stmf_get_alua_state((stmf_alua_state_desc_t *)obuf);
810 		break;
811 
812 	case STMF_IOCTL_SET_LU_STATE:
813 		ssi.st_rflags = STMF_RFLAG_USER_REQUEST;
814 		ssi.st_additional_info = NULL;
815 		std = (stmf_state_desc_t *)ibuf;
816 		if ((ibuf == NULL) ||
817 		    (iocd->stmf_ibuf_size < sizeof (stmf_state_desc_t))) {
818 			ret = EINVAL;
819 			break;
820 		}
821 		p_id = std->ident;
822 		mutex_enter(&stmf_state.stmf_lock);
823 		if (stmf_state.stmf_inventory_locked) {
824 			mutex_exit(&stmf_state.stmf_lock);
825 			ret = EBUSY;
826 			break;
827 		}
828 		for (ilu = stmf_state.stmf_ilulist; ilu; ilu = ilu->ilu_next) {
829 			if (bcmp(p_id, ilu->ilu_lu->lu_id->ident, 16) == 0)
830 				break;
831 		}
832 		if (ilu == NULL) {
833 			mutex_exit(&stmf_state.stmf_lock);
834 			ret = ENOENT;
835 			break;
836 		}
837 		stmf_state.stmf_inventory_locked = 1;
838 		mutex_exit(&stmf_state.stmf_lock);
839 		cmd = (std->state == STMF_STATE_ONLINE) ? STMF_CMD_LU_ONLINE :
840 		    STMF_CMD_LU_OFFLINE;
841 		ctl_ret = stmf_ctl(cmd, (void *)ilu->ilu_lu, &ssi);
842 		if (ctl_ret == STMF_ALREADY)
843 			ret = 0;
844 		else if (ctl_ret == STMF_BUSY)
845 			ret = EBUSY;
846 		else if (ctl_ret != STMF_SUCCESS)
847 			ret = EIO;
848 		mutex_enter(&stmf_state.stmf_lock);
849 		stmf_state.stmf_inventory_locked = 0;
850 		mutex_exit(&stmf_state.stmf_lock);
851 		break;
852 
853 	case STMF_IOCTL_SET_STMF_PROPS:
854 		if ((ibuf == NULL) ||
855 		    (iocd->stmf_ibuf_size < sizeof (stmf_set_props_t))) {
856 			ret = EINVAL;
857 			break;
858 		}
859 		stmf_set_props = (stmf_set_props_t *)ibuf;
860 		mutex_enter(&stmf_state.stmf_lock);
861 		if ((stmf_set_props->default_lu_state_value ==
862 		    STMF_STATE_OFFLINE) ||
863 		    (stmf_set_props->default_lu_state_value ==
864 		    STMF_STATE_ONLINE)) {
865 			stmf_state.stmf_default_lu_state =
866 			    stmf_set_props->default_lu_state_value;
867 		}
868 		if ((stmf_set_props->default_target_state_value ==
869 		    STMF_STATE_OFFLINE) ||
870 		    (stmf_set_props->default_target_state_value ==
871 		    STMF_STATE_ONLINE)) {
872 			stmf_state.stmf_default_lport_state =
873 			    stmf_set_props->default_target_state_value;
874 		}
875 
876 		mutex_exit(&stmf_state.stmf_lock);
877 		break;
878 
879 	case STMF_IOCTL_SET_TARGET_PORT_STATE:
880 		ssi.st_rflags = STMF_RFLAG_USER_REQUEST;
881 		ssi.st_additional_info = NULL;
882 		std = (stmf_state_desc_t *)ibuf;
883 		if ((ibuf == NULL) ||
884 		    (iocd->stmf_ibuf_size < sizeof (stmf_state_desc_t))) {
885 			ret = EINVAL;
886 			break;
887 		}
888 		p_id = std->ident;
889 		mutex_enter(&stmf_state.stmf_lock);
890 		if (stmf_state.stmf_inventory_locked) {
891 			mutex_exit(&stmf_state.stmf_lock);
892 			ret = EBUSY;
893 			break;
894 		}
895 		for (ilport = stmf_state.stmf_ilportlist; ilport;
896 		    ilport = ilport->ilport_next) {
897 			uint8_t *id;
898 			id = (uint8_t *)ilport->ilport_lport->lport_id;
899 			if ((id[3] == p_id[3]) &&
900 			    (bcmp(id+4, p_id+4, id[3]) == 0)) {
901 				break;
902 			}
903 		}
904 		if (ilport == NULL) {
905 			mutex_exit(&stmf_state.stmf_lock);
906 			ret = ENOENT;
907 			break;
908 		}
909 		stmf_state.stmf_inventory_locked = 1;
910 		mutex_exit(&stmf_state.stmf_lock);
911 		cmd = (std->state == STMF_STATE_ONLINE) ?
912 		    STMF_CMD_LPORT_ONLINE : STMF_CMD_LPORT_OFFLINE;
913 		ctl_ret = stmf_ctl(cmd, (void *)ilport->ilport_lport, &ssi);
914 		if (ctl_ret == STMF_ALREADY)
915 			ret = 0;
916 		else if (ctl_ret == STMF_BUSY)
917 			ret = EBUSY;
918 		else if (ctl_ret != STMF_SUCCESS)
919 			ret = EIO;
920 		mutex_enter(&stmf_state.stmf_lock);
921 		stmf_state.stmf_inventory_locked = 0;
922 		mutex_exit(&stmf_state.stmf_lock);
923 		break;
924 
925 	case STMF_IOCTL_ADD_HG_ENTRY:
926 		idtype = STMF_ID_TYPE_HOST;
927 		/* FALLTHROUGH */
928 	case STMF_IOCTL_ADD_TG_ENTRY:
929 		if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) {
930 			ret = EACCES;
931 			iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT;
932 			break;
933 		}
934 		if (cmd == STMF_IOCTL_ADD_TG_ENTRY) {
935 			idtype = STMF_ID_TYPE_TARGET;
936 		}
937 		grp_entry = (stmf_group_op_data_t *)ibuf;
938 		if ((ibuf == NULL) ||
939 		    (iocd->stmf_ibuf_size < sizeof (stmf_group_op_data_t))) {
940 			ret = EINVAL;
941 			break;
942 		}
943 		if (grp_entry->group.name[0] == '*') {
944 			ret = EINVAL;
945 			break; /* not allowed */
946 		}
947 		mutex_enter(&stmf_state.stmf_lock);
948 		ret = stmf_add_group_member(grp_entry->group.name,
949 		    grp_entry->group.name_size,
950 		    grp_entry->ident + 4,
951 		    grp_entry->ident[3],
952 		    idtype,
953 		    &iocd->stmf_error);
954 		mutex_exit(&stmf_state.stmf_lock);
955 		break;
956 	case STMF_IOCTL_REMOVE_HG_ENTRY:
957 		idtype = STMF_ID_TYPE_HOST;
958 		/* FALLTHROUGH */
959 	case STMF_IOCTL_REMOVE_TG_ENTRY:
960 		if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) {
961 			ret = EACCES;
962 			iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT;
963 			break;
964 		}
965 		if (cmd == STMF_IOCTL_REMOVE_TG_ENTRY) {
966 			idtype = STMF_ID_TYPE_TARGET;
967 		}
968 		grp_entry = (stmf_group_op_data_t *)ibuf;
969 		if ((ibuf == NULL) ||
970 		    (iocd->stmf_ibuf_size < sizeof (stmf_group_op_data_t))) {
971 			ret = EINVAL;
972 			break;
973 		}
974 		if (grp_entry->group.name[0] == '*') {
975 			ret = EINVAL;
976 			break; /* not allowed */
977 		}
978 		mutex_enter(&stmf_state.stmf_lock);
979 		ret = stmf_remove_group_member(grp_entry->group.name,
980 		    grp_entry->group.name_size,
981 		    grp_entry->ident + 4,
982 		    grp_entry->ident[3],
983 		    idtype,
984 		    &iocd->stmf_error);
985 		mutex_exit(&stmf_state.stmf_lock);
986 		break;
987 	case STMF_IOCTL_CREATE_HOST_GROUP:
988 		idtype = STMF_ID_TYPE_HOST_GROUP;
989 		/* FALLTHROUGH */
990 	case STMF_IOCTL_CREATE_TARGET_GROUP:
991 		if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) {
992 			ret = EACCES;
993 			iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT;
994 			break;
995 		}
996 		grpname = (stmf_group_name_t *)ibuf;
997 
998 		if (cmd == STMF_IOCTL_CREATE_TARGET_GROUP)
999 			idtype = STMF_ID_TYPE_TARGET_GROUP;
1000 		if ((ibuf == NULL) ||
1001 		    (iocd->stmf_ibuf_size < sizeof (stmf_group_name_t))) {
1002 			ret = EINVAL;
1003 			break;
1004 		}
1005 		if (grpname->name[0] == '*') {
1006 			ret = EINVAL;
1007 			break; /* not allowed */
1008 		}
1009 		mutex_enter(&stmf_state.stmf_lock);
1010 		ret = stmf_add_group(grpname->name,
1011 		    grpname->name_size, idtype, &iocd->stmf_error);
1012 		mutex_exit(&stmf_state.stmf_lock);
1013 		break;
1014 	case STMF_IOCTL_REMOVE_HOST_GROUP:
1015 		idtype = STMF_ID_TYPE_HOST_GROUP;
1016 		/* FALLTHROUGH */
1017 	case STMF_IOCTL_REMOVE_TARGET_GROUP:
1018 		if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) {
1019 			ret = EACCES;
1020 			iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT;
1021 			break;
1022 		}
1023 		grpname = (stmf_group_name_t *)ibuf;
1024 		if (cmd == STMF_IOCTL_REMOVE_TARGET_GROUP)
1025 			idtype = STMF_ID_TYPE_TARGET_GROUP;
1026 		if ((ibuf == NULL) ||
1027 		    (iocd->stmf_ibuf_size < sizeof (stmf_group_name_t))) {
1028 			ret = EINVAL;
1029 			break;
1030 		}
1031 		if (grpname->name[0] == '*') {
1032 			ret = EINVAL;
1033 			break; /* not allowed */
1034 		}
1035 		mutex_enter(&stmf_state.stmf_lock);
1036 		ret = stmf_remove_group(grpname->name,
1037 		    grpname->name_size, idtype, &iocd->stmf_error);
1038 		mutex_exit(&stmf_state.stmf_lock);
1039 		break;
1040 	case STMF_IOCTL_VALIDATE_VIEW:
1041 	case STMF_IOCTL_ADD_VIEW_ENTRY:
1042 		if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) {
1043 			ret = EACCES;
1044 			iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT;
1045 			break;
1046 		}
1047 		ve = (stmf_view_op_entry_t *)ibuf;
1048 		if ((ibuf == NULL) ||
1049 		    (iocd->stmf_ibuf_size < sizeof (stmf_view_op_entry_t))) {
1050 			ret = EINVAL;
1051 			break;
1052 		}
1053 		if (!ve->ve_lu_number_valid)
1054 			ve->ve_lu_nbr[2] = 0xFF;
1055 		if (ve->ve_all_hosts) {
1056 			ve->ve_host_group.name[0] = '*';
1057 			ve->ve_host_group.name_size = 1;
1058 		}
1059 		if (ve->ve_all_targets) {
1060 			ve->ve_target_group.name[0] = '*';
1061 			ve->ve_target_group.name_size = 1;
1062 		}
1063 		if (ve->ve_ndx_valid)
1064 			veid = ve->ve_ndx;
1065 		else
1066 			veid = 0xffffffff;
1067 		mutex_enter(&stmf_state.stmf_lock);
1068 		if (cmd == STMF_IOCTL_ADD_VIEW_ENTRY) {
1069 			ret = stmf_add_ve(ve->ve_host_group.name,
1070 			    ve->ve_host_group.name_size,
1071 			    ve->ve_target_group.name,
1072 			    ve->ve_target_group.name_size,
1073 			    ve->ve_guid,
1074 			    &veid,
1075 			    ve->ve_lu_nbr,
1076 			    &iocd->stmf_error);
1077 		} else {  /* STMF_IOCTL_VALIDATE_VIEW */
1078 			ret = stmf_validate_lun_ve(ve->ve_host_group.name,
1079 			    ve->ve_host_group.name_size,
1080 			    ve->ve_target_group.name,
1081 			    ve->ve_target_group.name_size,
1082 			    ve->ve_lu_nbr,
1083 			    &iocd->stmf_error);
1084 		}
1085 		mutex_exit(&stmf_state.stmf_lock);
1086 		if (ret == 0 &&
1087 		    (!ve->ve_ndx_valid || !ve->ve_lu_number_valid) &&
1088 		    iocd->stmf_obuf_size >= sizeof (stmf_view_op_entry_t)) {
1089 			stmf_view_op_entry_t *ve_ret =
1090 			    (stmf_view_op_entry_t *)obuf;
1091 			iocd->stmf_obuf_nentries = 1;
1092 			iocd->stmf_obuf_max_nentries = 1;
1093 			if (!ve->ve_ndx_valid) {
1094 				ve_ret->ve_ndx = veid;
1095 				ve_ret->ve_ndx_valid = 1;
1096 			}
1097 			if (!ve->ve_lu_number_valid) {
1098 				ve_ret->ve_lu_number_valid = 1;
1099 				bcopy(ve->ve_lu_nbr, ve_ret->ve_lu_nbr, 8);
1100 			}
1101 		}
1102 		break;
1103 	case STMF_IOCTL_REMOVE_VIEW_ENTRY:
1104 		if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) {
1105 			ret = EACCES;
1106 			iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT;
1107 			break;
1108 		}
1109 		ve = (stmf_view_op_entry_t *)ibuf;
1110 		if ((ibuf == NULL) ||
1111 		    (iocd->stmf_ibuf_size < sizeof (stmf_view_op_entry_t))) {
1112 			ret = EINVAL;
1113 			break;
1114 		}
1115 		if (!ve->ve_ndx_valid) {
1116 			ret = EINVAL;
1117 			break;
1118 		}
1119 		mutex_enter(&stmf_state.stmf_lock);
1120 		ret = stmf_remove_ve_by_id(ve->ve_guid, ve->ve_ndx,
1121 		    &iocd->stmf_error);
1122 		mutex_exit(&stmf_state.stmf_lock);
1123 		break;
1124 	case STMF_IOCTL_GET_HG_LIST:
1125 		id_list = &stmf_state.stmf_hg_list;
1126 		/* FALLTHROUGH */
1127 	case STMF_IOCTL_GET_TG_LIST:
1128 		if (cmd == STMF_IOCTL_GET_TG_LIST)
1129 			id_list = &stmf_state.stmf_tg_list;
1130 		mutex_enter(&stmf_state.stmf_lock);
1131 		iocd->stmf_obuf_max_nentries = id_list->id_count;
1132 		n = min(id_list->id_count,
1133 		    (iocd->stmf_obuf_size)/sizeof (stmf_group_name_t));
1134 		iocd->stmf_obuf_nentries = n;
1135 		id_entry = id_list->idl_head;
1136 		grpname = (stmf_group_name_t *)obuf;
1137 		for (i = 0; i < n; i++) {
1138 			if (id_entry->id_data[0] == '*') {
1139 				if (iocd->stmf_obuf_nentries > 0) {
1140 					iocd->stmf_obuf_nentries--;
1141 				}
1142 				id_entry = id_entry->id_next;
1143 				continue;
1144 			}
1145 			grpname->name_size = id_entry->id_data_size;
1146 			bcopy(id_entry->id_data, grpname->name,
1147 			    id_entry->id_data_size);
1148 			grpname++;
1149 			id_entry = id_entry->id_next;
1150 		}
1151 		mutex_exit(&stmf_state.stmf_lock);
1152 		break;
1153 	case STMF_IOCTL_GET_HG_ENTRIES:
1154 		id_list = &stmf_state.stmf_hg_list;
1155 		/* FALLTHROUGH */
1156 	case STMF_IOCTL_GET_TG_ENTRIES:
1157 		grpname = (stmf_group_name_t *)ibuf;
1158 		if ((ibuf == NULL) ||
1159 		    (iocd->stmf_ibuf_size < sizeof (stmf_group_name_t))) {
1160 			ret = EINVAL;
1161 			break;
1162 		}
1163 		if (cmd == STMF_IOCTL_GET_TG_ENTRIES) {
1164 			id_list = &stmf_state.stmf_tg_list;
1165 		}
1166 		mutex_enter(&stmf_state.stmf_lock);
1167 		id_entry = stmf_lookup_id(id_list, grpname->name_size,
1168 		    grpname->name);
1169 		if (!id_entry)
1170 			ret = ENODEV;
1171 		else {
1172 			stmf_ge_ident_t *grp_entry;
1173 			id_list = (stmf_id_list_t *)id_entry->id_impl_specific;
1174 			iocd->stmf_obuf_max_nentries = id_list->id_count;
1175 			n = min(id_list->id_count,
1176 			    iocd->stmf_obuf_size/sizeof (stmf_ge_ident_t));
1177 			iocd->stmf_obuf_nentries = n;
1178 			id_entry = id_list->idl_head;
1179 			grp_entry = (stmf_ge_ident_t *)obuf;
1180 			for (i = 0; i < n; i++) {
1181 				bcopy(id_entry->id_data, grp_entry->ident,
1182 				    id_entry->id_data_size);
1183 				grp_entry->ident_size = id_entry->id_data_size;
1184 				id_entry = id_entry->id_next;
1185 				grp_entry++;
1186 			}
1187 		}
1188 		mutex_exit(&stmf_state.stmf_lock);
1189 		break;
1190 
1191 	case STMF_IOCTL_GET_VE_LIST:
1192 		n = iocd->stmf_obuf_size/sizeof (stmf_view_op_entry_t);
1193 		mutex_enter(&stmf_state.stmf_lock);
1194 		ve = (stmf_view_op_entry_t *)obuf;
1195 		for (id_entry = stmf_state.stmf_luid_list.idl_head;
1196 		    id_entry; id_entry = id_entry->id_next) {
1197 			for (view_entry = (stmf_view_entry_t *)
1198 			    id_entry->id_impl_specific; view_entry;
1199 			    view_entry = view_entry->ve_next) {
1200 				iocd->stmf_obuf_max_nentries++;
1201 				if (iocd->stmf_obuf_nentries >= n)
1202 					continue;
1203 				ve->ve_ndx_valid = 1;
1204 				ve->ve_ndx = view_entry->ve_id;
1205 				ve->ve_lu_number_valid = 1;
1206 				bcopy(view_entry->ve_lun, ve->ve_lu_nbr, 8);
1207 				bcopy(view_entry->ve_luid->id_data, ve->ve_guid,
1208 				    view_entry->ve_luid->id_data_size);
1209 				if (view_entry->ve_hg->id_data[0] == '*') {
1210 					ve->ve_all_hosts = 1;
1211 				} else {
1212 					bcopy(view_entry->ve_hg->id_data,
1213 					    ve->ve_host_group.name,
1214 					    view_entry->ve_hg->id_data_size);
1215 					ve->ve_host_group.name_size =
1216 					    view_entry->ve_hg->id_data_size;
1217 				}
1218 
1219 				if (view_entry->ve_tg->id_data[0] == '*') {
1220 					ve->ve_all_targets = 1;
1221 				} else {
1222 					bcopy(view_entry->ve_tg->id_data,
1223 					    ve->ve_target_group.name,
1224 					    view_entry->ve_tg->id_data_size);
1225 					ve->ve_target_group.name_size =
1226 					    view_entry->ve_tg->id_data_size;
1227 				}
1228 				ve++;
1229 				iocd->stmf_obuf_nentries++;
1230 			}
1231 		}
1232 		mutex_exit(&stmf_state.stmf_lock);
1233 		break;
1234 
1235 	case STMF_IOCTL_LU_VE_LIST:
1236 		p_id = (uint8_t *)ibuf;
1237 		if ((iocd->stmf_ibuf_size != 16) ||
1238 		    (iocd->stmf_obuf_size < sizeof (stmf_view_op_entry_t))) {
1239 			ret = EINVAL;
1240 			break;
1241 		}
1242 
1243 		n = iocd->stmf_obuf_size/sizeof (stmf_view_op_entry_t);
1244 		mutex_enter(&stmf_state.stmf_lock);
1245 		ve = (stmf_view_op_entry_t *)obuf;
1246 		for (id_entry = stmf_state.stmf_luid_list.idl_head;
1247 		    id_entry; id_entry = id_entry->id_next) {
1248 			if (bcmp(id_entry->id_data, p_id, 16) != 0)
1249 				continue;
1250 			for (view_entry = (stmf_view_entry_t *)
1251 			    id_entry->id_impl_specific; view_entry;
1252 			    view_entry = view_entry->ve_next) {
1253 				iocd->stmf_obuf_max_nentries++;
1254 				if (iocd->stmf_obuf_nentries >= n)
1255 					continue;
1256 				ve->ve_ndx_valid = 1;
1257 				ve->ve_ndx = view_entry->ve_id;
1258 				ve->ve_lu_number_valid = 1;
1259 				bcopy(view_entry->ve_lun, ve->ve_lu_nbr, 8);
1260 				bcopy(view_entry->ve_luid->id_data, ve->ve_guid,
1261 				    view_entry->ve_luid->id_data_size);
1262 				if (view_entry->ve_hg->id_data[0] == '*') {
1263 					ve->ve_all_hosts = 1;
1264 				} else {
1265 					bcopy(view_entry->ve_hg->id_data,
1266 					    ve->ve_host_group.name,
1267 					    view_entry->ve_hg->id_data_size);
1268 					ve->ve_host_group.name_size =
1269 					    view_entry->ve_hg->id_data_size;
1270 				}
1271 
1272 				if (view_entry->ve_tg->id_data[0] == '*') {
1273 					ve->ve_all_targets = 1;
1274 				} else {
1275 					bcopy(view_entry->ve_tg->id_data,
1276 					    ve->ve_target_group.name,
1277 					    view_entry->ve_tg->id_data_size);
1278 					ve->ve_target_group.name_size =
1279 					    view_entry->ve_tg->id_data_size;
1280 				}
1281 				ve++;
1282 				iocd->stmf_obuf_nentries++;
1283 			}
1284 			break;
1285 		}
1286 		mutex_exit(&stmf_state.stmf_lock);
1287 		break;
1288 
1289 	case STMF_IOCTL_LOAD_PP_DATA:
1290 		if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) {
1291 			ret = EACCES;
1292 			iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT;
1293 			break;
1294 		}
1295 		ppi = (stmf_ppioctl_data_t *)ibuf;
1296 		if ((ppi == NULL) ||
1297 		    (iocd->stmf_ibuf_size < sizeof (stmf_ppioctl_data_t))) {
1298 			ret = EINVAL;
1299 			break;
1300 		}
1301 		/* returned token */
1302 		ppi_token = (uint64_t *)obuf;
1303 		if ((ppi_token == NULL) ||
1304 		    (iocd->stmf_obuf_size < sizeof (uint64_t))) {
1305 			ret = EINVAL;
1306 			break;
1307 		}
1308 		ret = stmf_load_ppd_ioctl(ppi, ppi_token, &iocd->stmf_error);
1309 		break;
1310 
1311 	case STMF_IOCTL_GET_PP_DATA:
1312 		if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) {
1313 			ret = EACCES;
1314 			iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT;
1315 			break;
1316 		}
1317 		ppi = (stmf_ppioctl_data_t *)ibuf;
1318 		if (ppi == NULL ||
1319 		    (iocd->stmf_ibuf_size < sizeof (stmf_ppioctl_data_t))) {
1320 			ret = EINVAL;
1321 			break;
1322 		}
1323 		ppi_out = (stmf_ppioctl_data_t *)obuf;
1324 		if ((ppi_out == NULL) ||
1325 		    (iocd->stmf_obuf_size < sizeof (stmf_ppioctl_data_t))) {
1326 			ret = EINVAL;
1327 			break;
1328 		}
1329 		ret = stmf_get_ppd_ioctl(ppi, ppi_out, &iocd->stmf_error);
1330 		break;
1331 
1332 	case STMF_IOCTL_CLEAR_PP_DATA:
1333 		if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) {
1334 			ret = EACCES;
1335 			iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT;
1336 			break;
1337 		}
1338 		ppi = (stmf_ppioctl_data_t *)ibuf;
1339 		if ((ppi == NULL) ||
1340 		    (iocd->stmf_ibuf_size < sizeof (stmf_ppioctl_data_t))) {
1341 			ret = EINVAL;
1342 			break;
1343 		}
1344 		ret = stmf_delete_ppd_ioctl(ppi);
1345 		break;
1346 
1347 	case STMF_IOCTL_CLEAR_TRACE:
1348 		stmf_trace_clear();
1349 		break;
1350 
1351 	case STMF_IOCTL_ADD_TRACE:
1352 		if (iocd->stmf_ibuf_size && ibuf) {
1353 			((uint8_t *)ibuf)[iocd->stmf_ibuf_size - 1] = '\0';
1354 			stmf_trace("\nstradm", "%s\n", ibuf);
1355 		}
1356 		break;
1357 
1358 	case STMF_IOCTL_GET_TRACE_POSITION:
1359 		if (obuf && (iocd->stmf_obuf_size > 3)) {
1360 			mutex_enter(&trace_buf_lock);
1361 			*((int *)obuf) = trace_buf_curndx;
1362 			mutex_exit(&trace_buf_lock);
1363 		} else {
1364 			ret = EINVAL;
1365 		}
1366 		break;
1367 
1368 	case STMF_IOCTL_GET_TRACE:
1369 		if ((iocd->stmf_obuf_size == 0) || (iocd->stmf_ibuf_size < 4)) {
1370 			ret = EINVAL;
1371 			break;
1372 		}
1373 		i = *((int *)ibuf);
1374 		if ((i > trace_buf_size) || ((i + iocd->stmf_obuf_size) >
1375 		    trace_buf_size)) {
1376 			ret = EINVAL;
1377 			break;
1378 		}
1379 		mutex_enter(&trace_buf_lock);
1380 		bcopy(stmf_trace_buf + i, obuf, iocd->stmf_obuf_size);
1381 		mutex_exit(&trace_buf_lock);
1382 		break;
1383 
1384 	default:
1385 		ret = ENOTTY;
1386 	}
1387 
1388 	if (ret == 0) {
1389 		ret = stmf_copyout_iocdata(data, mode, iocd, obuf);
1390 	} else if (iocd->stmf_error) {
1391 		(void) stmf_copyout_iocdata(data, mode, iocd, obuf);
1392 	}
1393 	if (obuf) {
1394 		kmem_free(obuf, iocd->stmf_obuf_size);
1395 		obuf = NULL;
1396 	}
1397 	if (ibuf) {
1398 		kmem_free(ibuf, iocd->stmf_ibuf_size);
1399 		ibuf = NULL;
1400 	}
1401 	kmem_free(iocd, sizeof (stmf_iocdata_t));
1402 	return (ret);
1403 }
1404 
1405 static int
stmf_get_service_state()1406 stmf_get_service_state()
1407 {
1408 	stmf_i_local_port_t *ilport;
1409 	stmf_i_lu_t *ilu;
1410 	int online = 0;
1411 	int offline = 0;
1412 	int onlining = 0;
1413 	int offlining = 0;
1414 
1415 	ASSERT(mutex_owned(&stmf_state.stmf_lock));
1416 	for (ilport = stmf_state.stmf_ilportlist; ilport != NULL;
1417 	    ilport = ilport->ilport_next) {
1418 		if (ilport->ilport_state == STMF_STATE_OFFLINE)
1419 			offline++;
1420 		else if (ilport->ilport_state == STMF_STATE_ONLINE)
1421 			online++;
1422 		else if (ilport->ilport_state == STMF_STATE_ONLINING)
1423 			onlining++;
1424 		else if (ilport->ilport_state == STMF_STATE_OFFLINING)
1425 			offlining++;
1426 	}
1427 
1428 	for (ilu = stmf_state.stmf_ilulist; ilu != NULL;
1429 	    ilu = ilu->ilu_next) {
1430 		if (ilu->ilu_state == STMF_STATE_OFFLINE)
1431 			offline++;
1432 		else if (ilu->ilu_state == STMF_STATE_ONLINE)
1433 			online++;
1434 		else if (ilu->ilu_state == STMF_STATE_ONLINING)
1435 			onlining++;
1436 		else if (ilu->ilu_state == STMF_STATE_OFFLINING)
1437 			offlining++;
1438 	}
1439 
1440 	if (stmf_state.stmf_service_running) {
1441 		if (onlining)
1442 			return (STMF_STATE_ONLINING);
1443 		else
1444 			return (STMF_STATE_ONLINE);
1445 	}
1446 
1447 	if (offlining) {
1448 		return (STMF_STATE_OFFLINING);
1449 	}
1450 
1451 	return (STMF_STATE_OFFLINE);
1452 }
1453 
1454 static int
stmf_set_stmf_state(stmf_state_desc_t * std)1455 stmf_set_stmf_state(stmf_state_desc_t *std)
1456 {
1457 	stmf_i_local_port_t *ilport;
1458 	stmf_i_lu_t *ilu;
1459 	stmf_state_change_info_t ssi;
1460 	int svc_state;
1461 
1462 	ssi.st_rflags = STMF_RFLAG_USER_REQUEST;
1463 	ssi.st_additional_info = NULL;
1464 
1465 	mutex_enter(&stmf_state.stmf_lock);
1466 	if (!stmf_state.stmf_exclusive_open) {
1467 		mutex_exit(&stmf_state.stmf_lock);
1468 		return (EACCES);
1469 	}
1470 
1471 	if (stmf_state.stmf_inventory_locked) {
1472 		mutex_exit(&stmf_state.stmf_lock);
1473 		return (EBUSY);
1474 	}
1475 
1476 	if ((std->state != STMF_STATE_ONLINE) &&
1477 	    (std->state != STMF_STATE_OFFLINE)) {
1478 		mutex_exit(&stmf_state.stmf_lock);
1479 		return (EINVAL);
1480 	}
1481 
1482 	svc_state = stmf_get_service_state();
1483 	if ((svc_state == STMF_STATE_OFFLINING) ||
1484 	    (svc_state == STMF_STATE_ONLINING)) {
1485 		mutex_exit(&stmf_state.stmf_lock);
1486 		return (EBUSY);
1487 	}
1488 
1489 	if (svc_state == STMF_STATE_OFFLINE) {
1490 		if (std->config_state == STMF_CONFIG_INIT) {
1491 			if (std->state != STMF_STATE_OFFLINE) {
1492 				mutex_exit(&stmf_state.stmf_lock);
1493 				return (EINVAL);
1494 			}
1495 			stmf_state.stmf_config_state = STMF_CONFIG_INIT;
1496 			stmf_delete_all_ppds();
1497 			stmf_view_clear_config();
1498 			stmf_view_init();
1499 			mutex_exit(&stmf_state.stmf_lock);
1500 			return (0);
1501 		}
1502 		if ((stmf_state.stmf_config_state == STMF_CONFIG_INIT) ||
1503 		    (stmf_state.stmf_config_state == STMF_CONFIG_NONE)) {
1504 			if (std->config_state != STMF_CONFIG_INIT_DONE) {
1505 				mutex_exit(&stmf_state.stmf_lock);
1506 				return (EINVAL);
1507 			}
1508 			stmf_state.stmf_config_state = STMF_CONFIG_INIT_DONE;
1509 		}
1510 		if (std->state == STMF_STATE_OFFLINE) {
1511 			mutex_exit(&stmf_state.stmf_lock);
1512 			return (0);
1513 		}
1514 		if (stmf_state.stmf_config_state == STMF_CONFIG_INIT) {
1515 			mutex_exit(&stmf_state.stmf_lock);
1516 			return (EINVAL);
1517 		}
1518 		stmf_state.stmf_inventory_locked = 1;
1519 		stmf_state.stmf_service_running = 1;
1520 		mutex_exit(&stmf_state.stmf_lock);
1521 
1522 		for (ilport = stmf_state.stmf_ilportlist; ilport != NULL;
1523 		    ilport = ilport->ilport_next) {
1524 			if (stmf_state.stmf_default_lport_state !=
1525 			    STMF_STATE_ONLINE)
1526 				continue;
1527 			(void) stmf_ctl(STMF_CMD_LPORT_ONLINE,
1528 			    ilport->ilport_lport, &ssi);
1529 		}
1530 
1531 		for (ilu = stmf_state.stmf_ilulist; ilu != NULL;
1532 		    ilu = ilu->ilu_next) {
1533 			if (stmf_state.stmf_default_lu_state !=
1534 			    STMF_STATE_ONLINE)
1535 				continue;
1536 			(void) stmf_ctl(STMF_CMD_LU_ONLINE, ilu->ilu_lu, &ssi);
1537 		}
1538 		mutex_enter(&stmf_state.stmf_lock);
1539 		stmf_state.stmf_inventory_locked = 0;
1540 		mutex_exit(&stmf_state.stmf_lock);
1541 		return (0);
1542 	}
1543 
1544 	/* svc_state is STMF_STATE_ONLINE here */
1545 	if ((std->state != STMF_STATE_OFFLINE) ||
1546 	    (std->config_state == STMF_CONFIG_INIT)) {
1547 		mutex_exit(&stmf_state.stmf_lock);
1548 		return (EACCES);
1549 	}
1550 
1551 	stmf_state.stmf_inventory_locked = 1;
1552 	stmf_state.stmf_service_running = 0;
1553 
1554 	mutex_exit(&stmf_state.stmf_lock);
1555 	for (ilport = stmf_state.stmf_ilportlist; ilport != NULL;
1556 	    ilport = ilport->ilport_next) {
1557 		if (ilport->ilport_state != STMF_STATE_ONLINE)
1558 			continue;
1559 		(void) stmf_ctl(STMF_CMD_LPORT_OFFLINE,
1560 		    ilport->ilport_lport, &ssi);
1561 	}
1562 
1563 	for (ilu = stmf_state.stmf_ilulist; ilu != NULL;
1564 	    ilu = ilu->ilu_next) {
1565 		if (ilu->ilu_state != STMF_STATE_ONLINE)
1566 			continue;
1567 		(void) stmf_ctl(STMF_CMD_LU_OFFLINE, ilu->ilu_lu, &ssi);
1568 	}
1569 	mutex_enter(&stmf_state.stmf_lock);
1570 	stmf_state.stmf_inventory_locked = 0;
1571 	mutex_exit(&stmf_state.stmf_lock);
1572 	return (0);
1573 }
1574 
1575 static int
stmf_get_stmf_state(stmf_state_desc_t * std)1576 stmf_get_stmf_state(stmf_state_desc_t *std)
1577 {
1578 	mutex_enter(&stmf_state.stmf_lock);
1579 	std->state = stmf_get_service_state();
1580 	std->config_state = stmf_state.stmf_config_state;
1581 	mutex_exit(&stmf_state.stmf_lock);
1582 
1583 	return (0);
1584 }
1585 
1586 /*
1587  * handles registration message from pppt for a logical unit
1588  */
1589 stmf_status_t
stmf_ic_lu_reg(stmf_ic_reg_dereg_lun_msg_t * msg,uint32_t type)1590 stmf_ic_lu_reg(stmf_ic_reg_dereg_lun_msg_t *msg, uint32_t type)
1591 {
1592 	stmf_i_lu_provider_t	*ilp;
1593 	stmf_lu_provider_t	*lp;
1594 	mutex_enter(&stmf_state.stmf_lock);
1595 	for (ilp = stmf_state.stmf_ilplist; ilp != NULL; ilp = ilp->ilp_next) {
1596 		if (strcmp(msg->icrl_lu_provider_name,
1597 		    ilp->ilp_lp->lp_name) == 0) {
1598 			lp = ilp->ilp_lp;
1599 			mutex_exit(&stmf_state.stmf_lock);
1600 			lp->lp_proxy_msg(msg->icrl_lun_id, msg->icrl_cb_arg,
1601 			    msg->icrl_cb_arg_len, type);
1602 			return (STMF_SUCCESS);
1603 		}
1604 	}
1605 	mutex_exit(&stmf_state.stmf_lock);
1606 	return (STMF_SUCCESS);
1607 }
1608 
1609 /*
1610  * handles de-registration message from pppt for a logical unit
1611  */
1612 stmf_status_t
stmf_ic_lu_dereg(stmf_ic_reg_dereg_lun_msg_t * msg)1613 stmf_ic_lu_dereg(stmf_ic_reg_dereg_lun_msg_t *msg)
1614 {
1615 	stmf_i_lu_provider_t	*ilp;
1616 	stmf_lu_provider_t	*lp;
1617 	mutex_enter(&stmf_state.stmf_lock);
1618 	for (ilp = stmf_state.stmf_ilplist; ilp != NULL; ilp = ilp->ilp_next) {
1619 		if (strcmp(msg->icrl_lu_provider_name,
1620 		    ilp->ilp_lp->lp_name) == 0) {
1621 			lp = ilp->ilp_lp;
1622 			mutex_exit(&stmf_state.stmf_lock);
1623 			lp->lp_proxy_msg(msg->icrl_lun_id, NULL, 0,
1624 			    STMF_MSG_LU_DEREGISTER);
1625 			return (STMF_SUCCESS);
1626 		}
1627 	}
1628 	mutex_exit(&stmf_state.stmf_lock);
1629 	return (STMF_SUCCESS);
1630 }
1631 
1632 /*
1633  * helper function to find a task that matches a task_msgid
1634  */
1635 scsi_task_t *
find_task_from_msgid(uint8_t * lu_id,stmf_ic_msgid_t task_msgid)1636 find_task_from_msgid(uint8_t *lu_id, stmf_ic_msgid_t task_msgid)
1637 {
1638 	stmf_i_lu_t *ilu;
1639 	stmf_i_scsi_task_t *itask;
1640 
1641 	mutex_enter(&stmf_state.stmf_lock);
1642 	for (ilu = stmf_state.stmf_ilulist; ilu != NULL; ilu = ilu->ilu_next) {
1643 		if (bcmp(lu_id, ilu->ilu_lu->lu_id->ident, 16) == 0) {
1644 			break;
1645 		}
1646 	}
1647 
1648 	if (ilu == NULL) {
1649 		mutex_exit(&stmf_state.stmf_lock);
1650 		return (NULL);
1651 	}
1652 
1653 	mutex_enter(&ilu->ilu_task_lock);
1654 	for (itask = ilu->ilu_tasks; itask != NULL;
1655 	    itask = itask->itask_lu_next) {
1656 		mutex_enter(&itask->itask_mutex);
1657 		if (itask->itask_flags & (ITASK_IN_FREE_LIST |
1658 		    ITASK_BEING_ABORTED)) {
1659 			mutex_exit(&itask->itask_mutex);
1660 			continue;
1661 		}
1662 		mutex_exit(&itask->itask_mutex);
1663 		if (itask->itask_proxy_msg_id == task_msgid) {
1664 			break;
1665 		}
1666 	}
1667 	mutex_exit(&ilu->ilu_task_lock);
1668 	mutex_exit(&stmf_state.stmf_lock);
1669 
1670 	if (itask != NULL) {
1671 		return (itask->itask_task);
1672 	} else {
1673 		/* task not found. Likely already aborted. */
1674 		return (NULL);
1675 	}
1676 }
1677 
1678 /*
1679  * message received from pppt/ic
1680  */
1681 stmf_status_t
stmf_msg_rx(stmf_ic_msg_t * msg)1682 stmf_msg_rx(stmf_ic_msg_t *msg)
1683 {
1684 	mutex_enter(&stmf_state.stmf_lock);
1685 	if (stmf_state.stmf_alua_state != 1) {
1686 		mutex_exit(&stmf_state.stmf_lock);
1687 		cmn_err(CE_WARN, "stmf alua state is disabled");
1688 		ic_msg_free(msg);
1689 		return (STMF_FAILURE);
1690 	}
1691 	mutex_exit(&stmf_state.stmf_lock);
1692 
1693 	switch (msg->icm_msg_type) {
1694 		case STMF_ICM_REGISTER_LUN:
1695 			(void) stmf_ic_lu_reg(
1696 			    (stmf_ic_reg_dereg_lun_msg_t *)msg->icm_msg,
1697 			    STMF_MSG_LU_REGISTER);
1698 			break;
1699 		case STMF_ICM_LUN_ACTIVE:
1700 			(void) stmf_ic_lu_reg(
1701 			    (stmf_ic_reg_dereg_lun_msg_t *)msg->icm_msg,
1702 			    STMF_MSG_LU_ACTIVE);
1703 			break;
1704 		case STMF_ICM_DEREGISTER_LUN:
1705 			(void) stmf_ic_lu_dereg(
1706 			    (stmf_ic_reg_dereg_lun_msg_t *)msg->icm_msg);
1707 			break;
1708 		case STMF_ICM_SCSI_DATA:
1709 			(void) stmf_ic_rx_scsi_data(
1710 			    (stmf_ic_scsi_data_msg_t *)msg->icm_msg);
1711 			break;
1712 		case STMF_ICM_SCSI_STATUS:
1713 			(void) stmf_ic_rx_scsi_status(
1714 			    (stmf_ic_scsi_status_msg_t *)msg->icm_msg);
1715 			break;
1716 		case STMF_ICM_STATUS:
1717 			(void) stmf_ic_rx_status(
1718 			    (stmf_ic_status_msg_t *)msg->icm_msg);
1719 			break;
1720 		default:
1721 			cmn_err(CE_WARN, "unknown message received %d",
1722 			    msg->icm_msg_type);
1723 			ic_msg_free(msg);
1724 			return (STMF_FAILURE);
1725 	}
1726 	ic_msg_free(msg);
1727 	return (STMF_SUCCESS);
1728 }
1729 
1730 stmf_status_t
stmf_ic_rx_status(stmf_ic_status_msg_t * msg)1731 stmf_ic_rx_status(stmf_ic_status_msg_t *msg)
1732 {
1733 	stmf_i_local_port_t *ilport;
1734 
1735 	if (msg->ics_msg_type != STMF_ICM_REGISTER_PROXY_PORT) {
1736 		/* for now, ignore other message status */
1737 		return (STMF_SUCCESS);
1738 	}
1739 
1740 	if (msg->ics_status != STMF_SUCCESS) {
1741 		return (STMF_SUCCESS);
1742 	}
1743 
1744 	mutex_enter(&stmf_state.stmf_lock);
1745 	for (ilport = stmf_state.stmf_ilportlist; ilport != NULL;
1746 	    ilport = ilport->ilport_next) {
1747 		if (msg->ics_msgid == ilport->ilport_reg_msgid) {
1748 			ilport->ilport_proxy_registered = 1;
1749 			break;
1750 		}
1751 	}
1752 	mutex_exit(&stmf_state.stmf_lock);
1753 	return (STMF_SUCCESS);
1754 }
1755 
1756 /*
1757  * handles scsi status message from pppt
1758  */
1759 stmf_status_t
stmf_ic_rx_scsi_status(stmf_ic_scsi_status_msg_t * msg)1760 stmf_ic_rx_scsi_status(stmf_ic_scsi_status_msg_t *msg)
1761 {
1762 	scsi_task_t *task;
1763 
1764 	/* is this a task management command */
1765 	if (msg->icss_task_msgid & MSG_ID_TM_BIT) {
1766 		return (STMF_SUCCESS);
1767 	}
1768 
1769 	task = find_task_from_msgid(msg->icss_lun_id, msg->icss_task_msgid);
1770 
1771 	if (task == NULL) {
1772 		return (STMF_SUCCESS);
1773 	}
1774 
1775 	task->task_scsi_status = msg->icss_status;
1776 	task->task_sense_data = msg->icss_sense;
1777 	task->task_sense_length = msg->icss_sense_len;
1778 	(void) stmf_send_scsi_status(task, STMF_IOF_LU_DONE);
1779 
1780 	return (STMF_SUCCESS);
1781 }
1782 
1783 /*
1784  * handles scsi data message from pppt
1785  */
1786 stmf_status_t
stmf_ic_rx_scsi_data(stmf_ic_scsi_data_msg_t * msg)1787 stmf_ic_rx_scsi_data(stmf_ic_scsi_data_msg_t *msg)
1788 {
1789 	stmf_i_scsi_task_t *itask;
1790 	scsi_task_t *task;
1791 	stmf_xfer_data_t *xd = NULL;
1792 	stmf_data_buf_t *dbuf;
1793 	uint32_t sz, minsz, xd_sz, asz;
1794 
1795 	/* is this a task management command */
1796 	if (msg->icsd_task_msgid & MSG_ID_TM_BIT) {
1797 		return (STMF_SUCCESS);
1798 	}
1799 
1800 	task = find_task_from_msgid(msg->icsd_lun_id, msg->icsd_task_msgid);
1801 	if (task == NULL) {
1802 		stmf_ic_msg_t *ic_xfer_done_msg = NULL;
1803 		static uint64_t data_msg_id;
1804 		stmf_status_t ic_ret = STMF_FAILURE;
1805 		mutex_enter(&stmf_state.stmf_lock);
1806 		data_msg_id = stmf_proxy_msg_id++;
1807 		mutex_exit(&stmf_state.stmf_lock);
1808 		/*
1809 		 * send xfer done status to pppt
1810 		 * for now, set the session id to 0 as we cannot
1811 		 * ascertain it since we cannot find the task
1812 		 */
1813 		ic_xfer_done_msg = ic_scsi_data_xfer_done_msg_alloc(
1814 		    msg->icsd_task_msgid, 0, STMF_FAILURE, data_msg_id);
1815 		if (ic_xfer_done_msg) {
1816 			ic_ret = ic_tx_msg(ic_xfer_done_msg);
1817 			if (ic_ret != STMF_IC_MSG_SUCCESS) {
1818 				cmn_err(CE_WARN, "unable to xmit proxy msg");
1819 			}
1820 		}
1821 		return (STMF_FAILURE);
1822 	}
1823 
1824 	itask = (stmf_i_scsi_task_t *)task->task_stmf_private;
1825 	dbuf = itask->itask_proxy_dbuf;
1826 
1827 	task->task_cmd_xfer_length += msg->icsd_data_len;
1828 
1829 	if (task->task_additional_flags &
1830 	    TASK_AF_NO_EXPECTED_XFER_LENGTH) {
1831 		task->task_expected_xfer_length =
1832 		    task->task_cmd_xfer_length;
1833 	}
1834 
1835 	sz = min(task->task_expected_xfer_length,
1836 	    task->task_cmd_xfer_length);
1837 
1838 	xd_sz = msg->icsd_data_len;
1839 	asz = xd_sz + sizeof (*xd) - 4;
1840 	xd = (stmf_xfer_data_t *)kmem_zalloc(asz, KM_NOSLEEP);
1841 
1842 	if (xd == NULL) {
1843 		stmf_abort(STMF_QUEUE_TASK_ABORT, task,
1844 		    STMF_ALLOC_FAILURE, NULL);
1845 		return (STMF_FAILURE);
1846 	}
1847 
1848 	xd->alloc_size = asz;
1849 	xd->size_left = xd_sz;
1850 	bcopy(msg->icsd_data, xd->buf, xd_sz);
1851 
1852 	sz = min(sz, xd->size_left);
1853 	xd->size_left = sz;
1854 	minsz = min(512, sz);
1855 
1856 	if (dbuf == NULL)
1857 		dbuf = stmf_alloc_dbuf(task, sz, &minsz, 0);
1858 	if (dbuf == NULL) {
1859 		kmem_free(xd, xd->alloc_size);
1860 		stmf_abort(STMF_QUEUE_TASK_ABORT, task,
1861 		    STMF_ALLOC_FAILURE, NULL);
1862 		return (STMF_FAILURE);
1863 	}
1864 	dbuf->db_lu_private = xd;
1865 	dbuf->db_relative_offset = task->task_nbytes_transferred;
1866 	stmf_xd_to_dbuf(dbuf, 0);
1867 
1868 	dbuf->db_flags = DB_DIRECTION_TO_RPORT;
1869 	(void) stmf_xfer_data(task, dbuf, 0);
1870 	return (STMF_SUCCESS);
1871 }
1872 
1873 stmf_status_t
stmf_proxy_scsi_cmd(scsi_task_t * task,stmf_data_buf_t * dbuf)1874 stmf_proxy_scsi_cmd(scsi_task_t *task, stmf_data_buf_t *dbuf)
1875 {
1876 	stmf_i_scsi_task_t *itask =
1877 	    (stmf_i_scsi_task_t *)task->task_stmf_private;
1878 	stmf_i_local_port_t *ilport =
1879 	    (stmf_i_local_port_t *)task->task_lport->lport_stmf_private;
1880 	stmf_ic_msg_t *ic_cmd_msg;
1881 	stmf_ic_msg_status_t ic_ret;
1882 	stmf_status_t ret = STMF_FAILURE;
1883 
1884 	if (stmf_state.stmf_alua_state != 1) {
1885 		cmn_err(CE_WARN, "stmf alua state is disabled");
1886 		return (STMF_FAILURE);
1887 	}
1888 
1889 	if (ilport->ilport_proxy_registered == 0) {
1890 		return (STMF_FAILURE);
1891 	}
1892 
1893 	mutex_enter(&stmf_state.stmf_lock);
1894 	itask->itask_proxy_msg_id = stmf_proxy_msg_id++;
1895 	mutex_exit(&stmf_state.stmf_lock);
1896 	itask->itask_proxy_dbuf = dbuf;
1897 
1898 	/*
1899 	 * stmf will now take over the task handling for this task
1900 	 * but it still needs to be treated differently from other
1901 	 * default handled tasks, hence the ITASK_PROXY_TASK.
1902 	 * If this is a task management function, we're really just
1903 	 * duping the command to the peer. Set the TM bit so that
1904 	 * we can recognize this on return since we won't be completing
1905 	 * the proxied task in that case.
1906 	 */
1907 	mutex_enter(&itask->itask_mutex);
1908 	if (task->task_mgmt_function) {
1909 		itask->itask_proxy_msg_id |= MSG_ID_TM_BIT;
1910 	} else {
1911 		if (itask->itask_flags & ITASK_BEING_ABORTED) {
1912 			mutex_exit(&itask->itask_mutex);
1913 			return (STMF_FAILURE);
1914 		}
1915 		itask->itask_flags |= ITASK_DEFAULT_HANDLING | ITASK_PROXY_TASK;
1916 	}
1917 	if (dbuf) {
1918 		ic_cmd_msg = ic_scsi_cmd_msg_alloc(itask->itask_proxy_msg_id,
1919 		    task, dbuf->db_data_size, dbuf->db_sglist[0].seg_addr,
1920 		    itask->itask_proxy_msg_id);
1921 	} else {
1922 		ic_cmd_msg = ic_scsi_cmd_msg_alloc(itask->itask_proxy_msg_id,
1923 		    task, 0, NULL, itask->itask_proxy_msg_id);
1924 	}
1925 	mutex_exit(&itask->itask_mutex);
1926 	if (ic_cmd_msg) {
1927 		ic_ret = ic_tx_msg(ic_cmd_msg);
1928 		if (ic_ret == STMF_IC_MSG_SUCCESS) {
1929 			ret = STMF_SUCCESS;
1930 		}
1931 	}
1932 	return (ret);
1933 }
1934 
1935 
1936 stmf_status_t
pppt_modload()1937 pppt_modload()
1938 {
1939 	int error;
1940 
1941 	if (pppt_mod == NULL && ((pppt_mod =
1942 	    ddi_modopen("drv/pppt", KRTLD_MODE_FIRST, &error)) == NULL)) {
1943 		cmn_err(CE_WARN, "Unable to load pppt");
1944 		return (STMF_FAILURE);
1945 	}
1946 
1947 	if (ic_reg_port_msg_alloc == NULL && ((ic_reg_port_msg_alloc =
1948 	    (stmf_ic_reg_port_msg_alloc_func_t)
1949 	    ddi_modsym(pppt_mod, "stmf_ic_reg_port_msg_alloc",
1950 	    &error)) == NULL)) {
1951 		cmn_err(CE_WARN,
1952 		    "Unable to find symbol - stmf_ic_reg_port_msg_alloc");
1953 		return (STMF_FAILURE);
1954 	}
1955 
1956 
1957 	if (ic_dereg_port_msg_alloc == NULL && ((ic_dereg_port_msg_alloc =
1958 	    (stmf_ic_dereg_port_msg_alloc_func_t)
1959 	    ddi_modsym(pppt_mod, "stmf_ic_dereg_port_msg_alloc",
1960 	    &error)) == NULL)) {
1961 		cmn_err(CE_WARN,
1962 		    "Unable to find symbol - stmf_ic_dereg_port_msg_alloc");
1963 		return (STMF_FAILURE);
1964 	}
1965 
1966 	if (ic_reg_lun_msg_alloc == NULL && ((ic_reg_lun_msg_alloc =
1967 	    (stmf_ic_reg_lun_msg_alloc_func_t)
1968 	    ddi_modsym(pppt_mod, "stmf_ic_reg_lun_msg_alloc",
1969 	    &error)) == NULL)) {
1970 		cmn_err(CE_WARN,
1971 		    "Unable to find symbol - stmf_ic_reg_lun_msg_alloc");
1972 		return (STMF_FAILURE);
1973 	}
1974 
1975 	if (ic_lun_active_msg_alloc == NULL && ((ic_lun_active_msg_alloc =
1976 	    (stmf_ic_lun_active_msg_alloc_func_t)
1977 	    ddi_modsym(pppt_mod, "stmf_ic_lun_active_msg_alloc",
1978 	    &error)) == NULL)) {
1979 		cmn_err(CE_WARN,
1980 		    "Unable to find symbol - stmf_ic_lun_active_msg_alloc");
1981 		return (STMF_FAILURE);
1982 	}
1983 
1984 	if (ic_dereg_lun_msg_alloc == NULL && ((ic_dereg_lun_msg_alloc =
1985 	    (stmf_ic_dereg_lun_msg_alloc_func_t)
1986 	    ddi_modsym(pppt_mod, "stmf_ic_dereg_lun_msg_alloc",
1987 	    &error)) == NULL)) {
1988 		cmn_err(CE_WARN,
1989 		    "Unable to find symbol - stmf_ic_dereg_lun_msg_alloc");
1990 		return (STMF_FAILURE);
1991 	}
1992 
1993 	if (ic_scsi_cmd_msg_alloc == NULL && ((ic_scsi_cmd_msg_alloc =
1994 	    (stmf_ic_scsi_cmd_msg_alloc_func_t)
1995 	    ddi_modsym(pppt_mod, "stmf_ic_scsi_cmd_msg_alloc",
1996 	    &error)) == NULL)) {
1997 		cmn_err(CE_WARN,
1998 		    "Unable to find symbol - stmf_ic_scsi_cmd_msg_alloc");
1999 		return (STMF_FAILURE);
2000 	}
2001 
2002 	if (ic_scsi_data_xfer_done_msg_alloc == NULL &&
2003 	    ((ic_scsi_data_xfer_done_msg_alloc =
2004 	    (stmf_ic_scsi_data_xfer_done_msg_alloc_func_t)
2005 	    ddi_modsym(pppt_mod, "stmf_ic_scsi_data_xfer_done_msg_alloc",
2006 	    &error)) == NULL)) {
2007 		cmn_err(CE_WARN,
2008 		    "Unable to find symbol -"
2009 		    "stmf_ic_scsi_data_xfer_done_msg_alloc");
2010 		return (STMF_FAILURE);
2011 	}
2012 
2013 	if (ic_session_reg_msg_alloc == NULL &&
2014 	    ((ic_session_reg_msg_alloc =
2015 	    (stmf_ic_session_create_msg_alloc_func_t)
2016 	    ddi_modsym(pppt_mod, "stmf_ic_session_create_msg_alloc",
2017 	    &error)) == NULL)) {
2018 		cmn_err(CE_WARN,
2019 		    "Unable to find symbol -"
2020 		    "stmf_ic_session_create_msg_alloc");
2021 		return (STMF_FAILURE);
2022 	}
2023 
2024 	if (ic_session_dereg_msg_alloc == NULL &&
2025 	    ((ic_session_dereg_msg_alloc =
2026 	    (stmf_ic_session_destroy_msg_alloc_func_t)
2027 	    ddi_modsym(pppt_mod, "stmf_ic_session_destroy_msg_alloc",
2028 	    &error)) == NULL)) {
2029 		cmn_err(CE_WARN,
2030 		    "Unable to find symbol -"
2031 		    "stmf_ic_session_destroy_msg_alloc");
2032 		return (STMF_FAILURE);
2033 	}
2034 
2035 	if (ic_tx_msg == NULL && ((ic_tx_msg =
2036 	    (stmf_ic_tx_msg_func_t)ddi_modsym(pppt_mod, "stmf_ic_tx_msg",
2037 	    &error)) == NULL)) {
2038 		cmn_err(CE_WARN, "Unable to find symbol - stmf_ic_tx_msg");
2039 		return (STMF_FAILURE);
2040 	}
2041 
2042 	if (ic_msg_free == NULL && ((ic_msg_free =
2043 	    (stmf_ic_msg_free_func_t)ddi_modsym(pppt_mod, "stmf_ic_msg_free",
2044 	    &error)) == NULL)) {
2045 		cmn_err(CE_WARN, "Unable to find symbol - stmf_ic_msg_free");
2046 		return (STMF_FAILURE);
2047 	}
2048 	return (STMF_SUCCESS);
2049 }
2050 
2051 static void
stmf_get_alua_state(stmf_alua_state_desc_t * alua_state)2052 stmf_get_alua_state(stmf_alua_state_desc_t *alua_state)
2053 {
2054 	mutex_enter(&stmf_state.stmf_lock);
2055 	alua_state->alua_node = stmf_state.stmf_alua_node;
2056 	alua_state->alua_state = stmf_state.stmf_alua_state;
2057 	mutex_exit(&stmf_state.stmf_lock);
2058 }
2059 
2060 
2061 static int
stmf_set_alua_state(stmf_alua_state_desc_t * alua_state)2062 stmf_set_alua_state(stmf_alua_state_desc_t *alua_state)
2063 {
2064 	stmf_i_local_port_t *ilport;
2065 	stmf_i_lu_t *ilu;
2066 	stmf_lu_t *lu;
2067 	stmf_ic_msg_status_t ic_ret;
2068 	stmf_ic_msg_t *ic_reg_lun, *ic_reg_port;
2069 	stmf_local_port_t *lport;
2070 	int ret = 0;
2071 
2072 	if (alua_state->alua_state > 1 || alua_state->alua_node > 1) {
2073 		return (EINVAL);
2074 	}
2075 
2076 	mutex_enter(&stmf_state.stmf_lock);
2077 	if (alua_state->alua_state == 1) {
2078 		if (pppt_modload() == STMF_FAILURE) {
2079 			ret = EIO;
2080 			goto err;
2081 		}
2082 		if (alua_state->alua_node != 0) {
2083 			/* reset existing rtpids to new base */
2084 			stmf_rtpid_counter = 255;
2085 		}
2086 		stmf_state.stmf_alua_node = alua_state->alua_node;
2087 		stmf_state.stmf_alua_state = 1;
2088 		/* register existing local ports with ppp */
2089 		for (ilport = stmf_state.stmf_ilportlist; ilport != NULL;
2090 		    ilport = ilport->ilport_next) {
2091 			/* skip standby ports and non-alua participants */
2092 			if (ilport->ilport_standby == 1 ||
2093 			    ilport->ilport_alua == 0) {
2094 				continue;
2095 			}
2096 			if (alua_state->alua_node != 0) {
2097 				ilport->ilport_rtpid =
2098 				    atomic_inc_16_nv(&stmf_rtpid_counter);
2099 			}
2100 			lport = ilport->ilport_lport;
2101 			ic_reg_port = ic_reg_port_msg_alloc(
2102 			    lport->lport_id, ilport->ilport_rtpid,
2103 			    0, NULL, stmf_proxy_msg_id);
2104 			if (ic_reg_port) {
2105 				ic_ret = ic_tx_msg(ic_reg_port);
2106 				if (ic_ret == STMF_IC_MSG_SUCCESS) {
2107 					ilport->ilport_reg_msgid =
2108 					    stmf_proxy_msg_id++;
2109 				} else {
2110 					cmn_err(CE_WARN,
2111 					    "error on port registration "
2112 					    "port - %s",
2113 					    ilport->ilport_kstat_tgt_name);
2114 				}
2115 			}
2116 		}
2117 		/* register existing logical units */
2118 		for (ilu = stmf_state.stmf_ilulist; ilu != NULL;
2119 		    ilu = ilu->ilu_next) {
2120 			if (ilu->ilu_access != STMF_LU_ACTIVE) {
2121 				continue;
2122 			}
2123 			/* register with proxy module */
2124 			lu = ilu->ilu_lu;
2125 			if (lu->lu_lp && lu->lu_lp->lp_lpif_rev == LPIF_REV_2 &&
2126 			    lu->lu_lp->lp_alua_support) {
2127 				ilu->ilu_alua = 1;
2128 				/* allocate the register message */
2129 				ic_reg_lun = ic_reg_lun_msg_alloc(
2130 				    lu->lu_id->ident, lu->lu_lp->lp_name,
2131 				    lu->lu_proxy_reg_arg_len,
2132 				    (uint8_t *)lu->lu_proxy_reg_arg,
2133 				    stmf_proxy_msg_id);
2134 				/* send the message */
2135 				if (ic_reg_lun) {
2136 					ic_ret = ic_tx_msg(ic_reg_lun);
2137 					if (ic_ret == STMF_IC_MSG_SUCCESS) {
2138 						stmf_proxy_msg_id++;
2139 					}
2140 				}
2141 			}
2142 		}
2143 	} else {
2144 		stmf_state.stmf_alua_state = 0;
2145 	}
2146 
2147 err:
2148 	mutex_exit(&stmf_state.stmf_lock);
2149 	return (ret);
2150 }
2151 
2152 
2153 typedef struct {
2154 	void	*bp;	/* back pointer from internal struct to main struct */
2155 	int	alloc_size;
2156 } __istmf_t;
2157 
2158 typedef struct {
2159 	__istmf_t	*fp;	/* Framework private */
2160 	void		*cp;	/* Caller private */
2161 	void		*ss;	/* struct specific */
2162 } __stmf_t;
2163 
2164 static struct {
2165 	int shared;
2166 	int fw_private;
2167 } stmf_sizes[] = { { 0, 0 },
2168 	{ GET_STRUCT_SIZE(stmf_lu_provider_t),
2169 		GET_STRUCT_SIZE(stmf_i_lu_provider_t) },
2170 	{ GET_STRUCT_SIZE(stmf_port_provider_t),
2171 		GET_STRUCT_SIZE(stmf_i_port_provider_t) },
2172 	{ GET_STRUCT_SIZE(stmf_local_port_t),
2173 		GET_STRUCT_SIZE(stmf_i_local_port_t) },
2174 	{ GET_STRUCT_SIZE(stmf_lu_t),
2175 		GET_STRUCT_SIZE(stmf_i_lu_t) },
2176 	{ GET_STRUCT_SIZE(stmf_scsi_session_t),
2177 		GET_STRUCT_SIZE(stmf_i_scsi_session_t) },
2178 	{ GET_STRUCT_SIZE(scsi_task_t),
2179 		GET_STRUCT_SIZE(stmf_i_scsi_task_t) },
2180 	{ GET_STRUCT_SIZE(stmf_data_buf_t),
2181 		GET_STRUCT_SIZE(__istmf_t) },
2182 	{ GET_STRUCT_SIZE(stmf_dbuf_store_t),
2183 		GET_STRUCT_SIZE(__istmf_t) }
2184 
2185 };
2186 
2187 void *
stmf_alloc(stmf_struct_id_t struct_id,int additional_size,int flags)2188 stmf_alloc(stmf_struct_id_t struct_id, int additional_size, int flags)
2189 {
2190 	int stmf_size;
2191 	int kmem_flag;
2192 	__stmf_t *sh;
2193 
2194 	if ((struct_id == 0) || (struct_id >= STMF_MAX_STRUCT_IDS))
2195 		return (NULL);
2196 
2197 	if ((curthread->t_flag & T_INTR_THREAD) || (flags & AF_FORCE_NOSLEEP)) {
2198 		kmem_flag = KM_NOSLEEP;
2199 	} else {
2200 		kmem_flag = KM_SLEEP;
2201 	}
2202 
2203 	additional_size = (additional_size + 7) & (~7);
2204 	stmf_size = stmf_sizes[struct_id].shared +
2205 	    stmf_sizes[struct_id].fw_private + additional_size;
2206 
2207 	if (flags & AF_DONTZERO)
2208 		sh = (__stmf_t *)kmem_alloc(stmf_size, kmem_flag);
2209 	else
2210 		sh = (__stmf_t *)kmem_zalloc(stmf_size, kmem_flag);
2211 
2212 	if (sh == NULL)
2213 		return (NULL);
2214 
2215 	/*
2216 	 * In principle, the implementation inside stmf_alloc should not
2217 	 * be changed anyway. But the original order of framework private
2218 	 * data and caller private data does not support sglist in the caller
2219 	 * private data.
2220 	 * To work around this, the memory segments of framework private
2221 	 * data and caller private data are re-ordered here.
2222 	 * A better solution is to provide a specific interface to allocate
2223 	 * the sglist, then we will not need this workaround any more.
2224 	 * But before the new interface is available, the memory segment
2225 	 * ordering should be kept as is.
2226 	 */
2227 	sh->cp = GET_BYTE_OFFSET(sh, stmf_sizes[struct_id].shared);
2228 	sh->fp = (__istmf_t *)GET_BYTE_OFFSET(sh,
2229 	    stmf_sizes[struct_id].shared + additional_size);
2230 
2231 	sh->fp->bp = sh;
2232 	/* Just store the total size instead of storing additional size */
2233 	sh->fp->alloc_size = stmf_size;
2234 
2235 	return (sh);
2236 }
2237 
2238 void
stmf_free(void * ptr)2239 stmf_free(void *ptr)
2240 {
2241 	__stmf_t *sh = (__stmf_t *)ptr;
2242 
2243 	/*
2244 	 * So far we dont need any struct specific processing. If such
2245 	 * a need ever arises, then store the struct id in the framework
2246 	 * private section and get it here as sh->fp->struct_id.
2247 	 */
2248 	kmem_free(ptr, sh->fp->alloc_size);
2249 }
2250 
2251 /*
2252  * Given a pointer to stmf_lu_t, verifies if this lu is registered with the
2253  * framework and returns a pointer to framework private data for the lu.
2254  * Returns NULL if the lu was not found.
2255  */
2256 stmf_i_lu_t *
stmf_lookup_lu(stmf_lu_t * lu)2257 stmf_lookup_lu(stmf_lu_t *lu)
2258 {
2259 	stmf_i_lu_t *ilu;
2260 	ASSERT(mutex_owned(&stmf_state.stmf_lock));
2261 
2262 	for (ilu = stmf_state.stmf_ilulist; ilu != NULL; ilu = ilu->ilu_next) {
2263 		if (ilu->ilu_lu == lu)
2264 			return (ilu);
2265 	}
2266 	return (NULL);
2267 }
2268 
2269 /*
2270  * Given a pointer to stmf_local_port_t, verifies if this lport is registered
2271  * with the framework and returns a pointer to framework private data for
2272  * the lport.
2273  * Returns NULL if the lport was not found.
2274  */
2275 stmf_i_local_port_t *
stmf_lookup_lport(stmf_local_port_t * lport)2276 stmf_lookup_lport(stmf_local_port_t *lport)
2277 {
2278 	stmf_i_local_port_t *ilport;
2279 	ASSERT(mutex_owned(&stmf_state.stmf_lock));
2280 
2281 	for (ilport = stmf_state.stmf_ilportlist; ilport != NULL;
2282 	    ilport = ilport->ilport_next) {
2283 		if (ilport->ilport_lport == lport)
2284 			return (ilport);
2285 	}
2286 	return (NULL);
2287 }
2288 
2289 stmf_status_t
stmf_register_lu_provider(stmf_lu_provider_t * lp)2290 stmf_register_lu_provider(stmf_lu_provider_t *lp)
2291 {
2292 	stmf_i_lu_provider_t *ilp = (stmf_i_lu_provider_t *)lp->lp_stmf_private;
2293 	stmf_pp_data_t *ppd;
2294 	uint32_t cb_flags;
2295 
2296 	if (lp->lp_lpif_rev != LPIF_REV_1 && lp->lp_lpif_rev != LPIF_REV_2)
2297 		return (STMF_FAILURE);
2298 
2299 	mutex_enter(&stmf_state.stmf_lock);
2300 	ilp->ilp_next = stmf_state.stmf_ilplist;
2301 	stmf_state.stmf_ilplist = ilp;
2302 	stmf_state.stmf_nlps++;
2303 
2304 	/* See if we need to do a callback */
2305 	for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = ppd->ppd_next) {
2306 		if (strcmp(ppd->ppd_name, lp->lp_name) == 0) {
2307 			break;
2308 		}
2309 	}
2310 	if ((ppd == NULL) || (ppd->ppd_nv == NULL)) {
2311 		goto rlp_bail_out;
2312 	}
2313 	ilp->ilp_ppd = ppd;
2314 	ppd->ppd_provider = ilp;
2315 	if (lp->lp_cb == NULL)
2316 		goto rlp_bail_out;
2317 	ilp->ilp_cb_in_progress = 1;
2318 	cb_flags = STMF_PCB_PREG_COMPLETE;
2319 	if (stmf_state.stmf_config_state == STMF_CONFIG_INIT)
2320 		cb_flags |= STMF_PCB_STMF_ONLINING;
2321 	mutex_exit(&stmf_state.stmf_lock);
2322 	lp->lp_cb(lp, STMF_PROVIDER_DATA_UPDATED, ppd->ppd_nv, cb_flags);
2323 	mutex_enter(&stmf_state.stmf_lock);
2324 	ilp->ilp_cb_in_progress = 0;
2325 
2326 rlp_bail_out:
2327 	mutex_exit(&stmf_state.stmf_lock);
2328 
2329 	return (STMF_SUCCESS);
2330 }
2331 
2332 stmf_status_t
stmf_deregister_lu_provider(stmf_lu_provider_t * lp)2333 stmf_deregister_lu_provider(stmf_lu_provider_t *lp)
2334 {
2335 	stmf_i_lu_provider_t	**ppilp;
2336 	stmf_i_lu_provider_t *ilp = (stmf_i_lu_provider_t *)lp->lp_stmf_private;
2337 
2338 	mutex_enter(&stmf_state.stmf_lock);
2339 	if (ilp->ilp_nlus || ilp->ilp_cb_in_progress) {
2340 		mutex_exit(&stmf_state.stmf_lock);
2341 		return (STMF_BUSY);
2342 	}
2343 	for (ppilp = &stmf_state.stmf_ilplist; *ppilp != NULL;
2344 	    ppilp = &((*ppilp)->ilp_next)) {
2345 		if (*ppilp == ilp) {
2346 			*ppilp = ilp->ilp_next;
2347 			stmf_state.stmf_nlps--;
2348 			if (ilp->ilp_ppd) {
2349 				ilp->ilp_ppd->ppd_provider = NULL;
2350 				ilp->ilp_ppd = NULL;
2351 			}
2352 			mutex_exit(&stmf_state.stmf_lock);
2353 			return (STMF_SUCCESS);
2354 		}
2355 	}
2356 	mutex_exit(&stmf_state.stmf_lock);
2357 	return (STMF_NOT_FOUND);
2358 }
2359 
2360 stmf_status_t
stmf_register_port_provider(stmf_port_provider_t * pp)2361 stmf_register_port_provider(stmf_port_provider_t *pp)
2362 {
2363 	stmf_i_port_provider_t *ipp =
2364 	    (stmf_i_port_provider_t *)pp->pp_stmf_private;
2365 	stmf_pp_data_t *ppd;
2366 	uint32_t cb_flags;
2367 
2368 	if (pp->pp_portif_rev != PORTIF_REV_1)
2369 		return (STMF_FAILURE);
2370 
2371 	mutex_enter(&stmf_state.stmf_lock);
2372 	ipp->ipp_next = stmf_state.stmf_ipplist;
2373 	stmf_state.stmf_ipplist = ipp;
2374 	stmf_state.stmf_npps++;
2375 	/* See if we need to do a callback */
2376 	for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = ppd->ppd_next) {
2377 		if (strcmp(ppd->ppd_name, pp->pp_name) == 0) {
2378 			break;
2379 		}
2380 	}
2381 	if ((ppd == NULL) || (ppd->ppd_nv == NULL)) {
2382 		goto rpp_bail_out;
2383 	}
2384 	ipp->ipp_ppd = ppd;
2385 	ppd->ppd_provider = ipp;
2386 	if (pp->pp_cb == NULL)
2387 		goto rpp_bail_out;
2388 	ipp->ipp_cb_in_progress = 1;
2389 	cb_flags = STMF_PCB_PREG_COMPLETE;
2390 	if (stmf_state.stmf_config_state == STMF_CONFIG_INIT)
2391 		cb_flags |= STMF_PCB_STMF_ONLINING;
2392 	mutex_exit(&stmf_state.stmf_lock);
2393 	pp->pp_cb(pp, STMF_PROVIDER_DATA_UPDATED, ppd->ppd_nv, cb_flags);
2394 	mutex_enter(&stmf_state.stmf_lock);
2395 	ipp->ipp_cb_in_progress = 0;
2396 
2397 rpp_bail_out:
2398 	mutex_exit(&stmf_state.stmf_lock);
2399 
2400 	return (STMF_SUCCESS);
2401 }
2402 
2403 stmf_status_t
stmf_deregister_port_provider(stmf_port_provider_t * pp)2404 stmf_deregister_port_provider(stmf_port_provider_t *pp)
2405 {
2406 	stmf_i_port_provider_t *ipp =
2407 	    (stmf_i_port_provider_t *)pp->pp_stmf_private;
2408 	stmf_i_port_provider_t **ppipp;
2409 
2410 	mutex_enter(&stmf_state.stmf_lock);
2411 	if (ipp->ipp_npps || ipp->ipp_cb_in_progress) {
2412 		mutex_exit(&stmf_state.stmf_lock);
2413 		return (STMF_BUSY);
2414 	}
2415 	for (ppipp = &stmf_state.stmf_ipplist; *ppipp != NULL;
2416 	    ppipp = &((*ppipp)->ipp_next)) {
2417 		if (*ppipp == ipp) {
2418 			*ppipp = ipp->ipp_next;
2419 			stmf_state.stmf_npps--;
2420 			if (ipp->ipp_ppd) {
2421 				ipp->ipp_ppd->ppd_provider = NULL;
2422 				ipp->ipp_ppd = NULL;
2423 			}
2424 			mutex_exit(&stmf_state.stmf_lock);
2425 			return (STMF_SUCCESS);
2426 		}
2427 	}
2428 	mutex_exit(&stmf_state.stmf_lock);
2429 	return (STMF_NOT_FOUND);
2430 }
2431 
2432 int
stmf_load_ppd_ioctl(stmf_ppioctl_data_t * ppi,uint64_t * ppi_token,uint32_t * err_ret)2433 stmf_load_ppd_ioctl(stmf_ppioctl_data_t *ppi, uint64_t *ppi_token,
2434     uint32_t *err_ret)
2435 {
2436 	stmf_i_port_provider_t		*ipp;
2437 	stmf_i_lu_provider_t		*ilp;
2438 	stmf_pp_data_t			*ppd;
2439 	nvlist_t			*nv;
2440 	int				s;
2441 	int				ret;
2442 
2443 	*err_ret = 0;
2444 
2445 	if ((ppi->ppi_lu_provider + ppi->ppi_port_provider) != 1) {
2446 		return (EINVAL);
2447 	}
2448 
2449 	mutex_enter(&stmf_state.stmf_lock);
2450 	for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = ppd->ppd_next) {
2451 		if (ppi->ppi_lu_provider) {
2452 			if (!ppd->ppd_lu_provider)
2453 				continue;
2454 		} else if (ppi->ppi_port_provider) {
2455 			if (!ppd->ppd_port_provider)
2456 				continue;
2457 		}
2458 		if (strncmp(ppi->ppi_name, ppd->ppd_name, 254) == 0)
2459 			break;
2460 	}
2461 
2462 	if (ppd == NULL) {
2463 		/* New provider */
2464 		s = strlen(ppi->ppi_name);
2465 		if (s > 254) {
2466 			mutex_exit(&stmf_state.stmf_lock);
2467 			return (EINVAL);
2468 		}
2469 		s += sizeof (stmf_pp_data_t) - 7;
2470 
2471 		ppd = kmem_zalloc(s, KM_NOSLEEP);
2472 		if (ppd == NULL) {
2473 			mutex_exit(&stmf_state.stmf_lock);
2474 			return (ENOMEM);
2475 		}
2476 		ppd->ppd_alloc_size = s;
2477 		(void) strcpy(ppd->ppd_name, ppi->ppi_name);
2478 
2479 		/* See if this provider already exists */
2480 		if (ppi->ppi_lu_provider) {
2481 			ppd->ppd_lu_provider = 1;
2482 			for (ilp = stmf_state.stmf_ilplist; ilp != NULL;
2483 			    ilp = ilp->ilp_next) {
2484 				if (strcmp(ppi->ppi_name,
2485 				    ilp->ilp_lp->lp_name) == 0) {
2486 					ppd->ppd_provider = ilp;
2487 					ilp->ilp_ppd = ppd;
2488 					break;
2489 				}
2490 			}
2491 		} else {
2492 			ppd->ppd_port_provider = 1;
2493 			for (ipp = stmf_state.stmf_ipplist; ipp != NULL;
2494 			    ipp = ipp->ipp_next) {
2495 				if (strcmp(ppi->ppi_name,
2496 				    ipp->ipp_pp->pp_name) == 0) {
2497 					ppd->ppd_provider = ipp;
2498 					ipp->ipp_ppd = ppd;
2499 					break;
2500 				}
2501 			}
2502 		}
2503 
2504 		/* Link this ppd in */
2505 		ppd->ppd_next = stmf_state.stmf_ppdlist;
2506 		stmf_state.stmf_ppdlist = ppd;
2507 	}
2508 
2509 	/*
2510 	 * User is requesting that the token be checked.
2511 	 * If there was another set after the user's get
2512 	 * it's an error
2513 	 */
2514 	if (ppi->ppi_token_valid) {
2515 		if (ppi->ppi_token != ppd->ppd_token) {
2516 			*err_ret = STMF_IOCERR_PPD_UPDATED;
2517 			mutex_exit(&stmf_state.stmf_lock);
2518 			return (EINVAL);
2519 		}
2520 	}
2521 
2522 	if ((ret = nvlist_unpack((char *)ppi->ppi_data,
2523 	    (size_t)ppi->ppi_data_size, &nv, KM_NOSLEEP)) != 0) {
2524 		mutex_exit(&stmf_state.stmf_lock);
2525 		return (ret);
2526 	}
2527 
2528 	/* Free any existing lists and add this one to the ppd */
2529 	if (ppd->ppd_nv)
2530 		nvlist_free(ppd->ppd_nv);
2531 	ppd->ppd_nv = nv;
2532 
2533 	/* set the token for writes */
2534 	ppd->ppd_token++;
2535 	/* return token to caller */
2536 	if (ppi_token) {
2537 		*ppi_token = ppd->ppd_token;
2538 	}
2539 
2540 	/* If there is a provider registered, do the notifications */
2541 	if (ppd->ppd_provider) {
2542 		uint32_t cb_flags = 0;
2543 
2544 		if (stmf_state.stmf_config_state == STMF_CONFIG_INIT)
2545 			cb_flags |= STMF_PCB_STMF_ONLINING;
2546 		if (ppi->ppi_lu_provider) {
2547 			ilp = (stmf_i_lu_provider_t *)ppd->ppd_provider;
2548 			if (ilp->ilp_lp->lp_cb == NULL)
2549 				goto bail_out;
2550 			ilp->ilp_cb_in_progress = 1;
2551 			mutex_exit(&stmf_state.stmf_lock);
2552 			ilp->ilp_lp->lp_cb(ilp->ilp_lp,
2553 			    STMF_PROVIDER_DATA_UPDATED, ppd->ppd_nv, cb_flags);
2554 			mutex_enter(&stmf_state.stmf_lock);
2555 			ilp->ilp_cb_in_progress = 0;
2556 		} else {
2557 			ipp = (stmf_i_port_provider_t *)ppd->ppd_provider;
2558 			if (ipp->ipp_pp->pp_cb == NULL)
2559 				goto bail_out;
2560 			ipp->ipp_cb_in_progress = 1;
2561 			mutex_exit(&stmf_state.stmf_lock);
2562 			ipp->ipp_pp->pp_cb(ipp->ipp_pp,
2563 			    STMF_PROVIDER_DATA_UPDATED, ppd->ppd_nv, cb_flags);
2564 			mutex_enter(&stmf_state.stmf_lock);
2565 			ipp->ipp_cb_in_progress = 0;
2566 		}
2567 	}
2568 
2569 bail_out:
2570 	mutex_exit(&stmf_state.stmf_lock);
2571 
2572 	return (0);
2573 }
2574 
2575 void
stmf_delete_ppd(stmf_pp_data_t * ppd)2576 stmf_delete_ppd(stmf_pp_data_t *ppd)
2577 {
2578 	stmf_pp_data_t **pppd;
2579 
2580 	ASSERT(mutex_owned(&stmf_state.stmf_lock));
2581 	if (ppd->ppd_provider) {
2582 		if (ppd->ppd_lu_provider) {
2583 			((stmf_i_lu_provider_t *)
2584 			    ppd->ppd_provider)->ilp_ppd = NULL;
2585 		} else {
2586 			((stmf_i_port_provider_t *)
2587 			    ppd->ppd_provider)->ipp_ppd = NULL;
2588 		}
2589 		ppd->ppd_provider = NULL;
2590 	}
2591 
2592 	for (pppd = &stmf_state.stmf_ppdlist; *pppd != NULL;
2593 	    pppd = &((*pppd)->ppd_next)) {
2594 		if (*pppd == ppd)
2595 			break;
2596 	}
2597 
2598 	if (*pppd == NULL)
2599 		return;
2600 
2601 	*pppd = ppd->ppd_next;
2602 	if (ppd->ppd_nv)
2603 		nvlist_free(ppd->ppd_nv);
2604 
2605 	kmem_free(ppd, ppd->ppd_alloc_size);
2606 }
2607 
2608 int
stmf_delete_ppd_ioctl(stmf_ppioctl_data_t * ppi)2609 stmf_delete_ppd_ioctl(stmf_ppioctl_data_t *ppi)
2610 {
2611 	stmf_pp_data_t *ppd;
2612 	int ret = ENOENT;
2613 
2614 	if ((ppi->ppi_lu_provider + ppi->ppi_port_provider) != 1) {
2615 		return (EINVAL);
2616 	}
2617 
2618 	mutex_enter(&stmf_state.stmf_lock);
2619 
2620 	for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = ppd->ppd_next) {
2621 		if (ppi->ppi_lu_provider) {
2622 			if (!ppd->ppd_lu_provider)
2623 				continue;
2624 		} else if (ppi->ppi_port_provider) {
2625 			if (!ppd->ppd_port_provider)
2626 				continue;
2627 		}
2628 		if (strncmp(ppi->ppi_name, ppd->ppd_name, 254) == 0)
2629 			break;
2630 	}
2631 
2632 	if (ppd) {
2633 		ret = 0;
2634 		stmf_delete_ppd(ppd);
2635 	}
2636 	mutex_exit(&stmf_state.stmf_lock);
2637 
2638 	return (ret);
2639 }
2640 
2641 int
stmf_get_ppd_ioctl(stmf_ppioctl_data_t * ppi,stmf_ppioctl_data_t * ppi_out,uint32_t * err_ret)2642 stmf_get_ppd_ioctl(stmf_ppioctl_data_t *ppi, stmf_ppioctl_data_t *ppi_out,
2643     uint32_t *err_ret)
2644 {
2645 	stmf_pp_data_t *ppd;
2646 	size_t req_size;
2647 	int ret = ENOENT;
2648 	char *bufp = (char *)ppi_out->ppi_data;
2649 
2650 	if ((ppi->ppi_lu_provider + ppi->ppi_port_provider) != 1) {
2651 		return (EINVAL);
2652 	}
2653 
2654 	mutex_enter(&stmf_state.stmf_lock);
2655 
2656 	for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = ppd->ppd_next) {
2657 		if (ppi->ppi_lu_provider) {
2658 			if (!ppd->ppd_lu_provider)
2659 				continue;
2660 		} else if (ppi->ppi_port_provider) {
2661 			if (!ppd->ppd_port_provider)
2662 				continue;
2663 		}
2664 		if (strncmp(ppi->ppi_name, ppd->ppd_name, 254) == 0)
2665 			break;
2666 	}
2667 
2668 	if (ppd && ppd->ppd_nv) {
2669 		ppi_out->ppi_token = ppd->ppd_token;
2670 		if ((ret = nvlist_size(ppd->ppd_nv, &req_size,
2671 		    NV_ENCODE_XDR)) != 0) {
2672 			goto done;
2673 		}
2674 		ppi_out->ppi_data_size = req_size;
2675 		if (req_size > ppi->ppi_data_size) {
2676 			*err_ret = STMF_IOCERR_INSUFFICIENT_BUF;
2677 			ret = EINVAL;
2678 			goto done;
2679 		}
2680 
2681 		if ((ret = nvlist_pack(ppd->ppd_nv, &bufp, &req_size,
2682 		    NV_ENCODE_XDR, 0)) != 0) {
2683 			goto done;
2684 		}
2685 		ret = 0;
2686 	}
2687 
2688 done:
2689 	mutex_exit(&stmf_state.stmf_lock);
2690 
2691 	return (ret);
2692 }
2693 
2694 void
stmf_delete_all_ppds()2695 stmf_delete_all_ppds()
2696 {
2697 	stmf_pp_data_t *ppd, *nppd;
2698 
2699 	ASSERT(mutex_owned(&stmf_state.stmf_lock));
2700 	for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = nppd) {
2701 		nppd = ppd->ppd_next;
2702 		stmf_delete_ppd(ppd);
2703 	}
2704 }
2705 
2706 /*
2707  * 16 is the max string length of a protocol_ident, increase
2708  * the size if needed.
2709  */
2710 #define	STMF_KSTAT_LU_SZ	(STMF_GUID_INPUT + 1 + 256)
2711 #define	STMF_KSTAT_TGT_SZ	(256 * 2 + 16)
2712 #define	STMF_KSTAT_RPORT_DATAMAX	(sizeof (stmf_kstat_rport_info_t) / \
2713 					    sizeof (kstat_named_t))
2714 
2715 /*
2716  * This array matches the Protocol Identifier in stmf_ioctl.h
2717  */
2718 #define	MAX_PROTO_STR_LEN	32
2719 
2720 char *protocol_ident[PROTOCOL_ANY] = {
2721 	"Fibre Channel",
2722 	"Parallel SCSI",
2723 	"SSA",
2724 	"IEEE_1394",
2725 	"SRP",
2726 	"iSCSI",
2727 	"SAS",
2728 	"ADT",
2729 	"ATAPI",
2730 	"UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN"
2731 };
2732 
2733 /*
2734  * Update the lun wait/run queue count
2735  */
2736 static void
stmf_update_kstat_lu_q(scsi_task_t * task,void func ())2737 stmf_update_kstat_lu_q(scsi_task_t *task, void func())
2738 {
2739 	stmf_i_lu_t		*ilu;
2740 	kstat_io_t		*kip;
2741 
2742 	if (task->task_lu == dlun0)
2743 		return;
2744 	ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private;
2745 	if (ilu != NULL && ilu->ilu_kstat_io != NULL) {
2746 		kip = KSTAT_IO_PTR(ilu->ilu_kstat_io);
2747 		if (kip != NULL) {
2748 			func(kip);
2749 		}
2750 	}
2751 }
2752 
2753 /*
2754  * Update the target(lport) wait/run queue count
2755  */
2756 static void
stmf_update_kstat_lport_q(scsi_task_t * task,void func ())2757 stmf_update_kstat_lport_q(scsi_task_t *task, void func())
2758 {
2759 	stmf_i_local_port_t	*ilp;
2760 	kstat_io_t		*kip;
2761 
2762 	ilp = (stmf_i_local_port_t *)task->task_lport->lport_stmf_private;
2763 	if (ilp != NULL && ilp->ilport_kstat_io != NULL) {
2764 		kip = KSTAT_IO_PTR(ilp->ilport_kstat_io);
2765 		if (kip != NULL) {
2766 			mutex_enter(ilp->ilport_kstat_io->ks_lock);
2767 			func(kip);
2768 			mutex_exit(ilp->ilport_kstat_io->ks_lock);
2769 		}
2770 	}
2771 }
2772 
2773 static void
stmf_update_kstat_lport_io(scsi_task_t * task,stmf_data_buf_t * dbuf)2774 stmf_update_kstat_lport_io(scsi_task_t *task, stmf_data_buf_t *dbuf)
2775 {
2776 	stmf_i_local_port_t	*ilp;
2777 	kstat_io_t		*kip;
2778 
2779 	ilp = (stmf_i_local_port_t *)task->task_lport->lport_stmf_private;
2780 	if (ilp != NULL && ilp->ilport_kstat_io != NULL) {
2781 		kip = KSTAT_IO_PTR(ilp->ilport_kstat_io);
2782 		if (kip != NULL) {
2783 			mutex_enter(ilp->ilport_kstat_io->ks_lock);
2784 			STMF_UPDATE_KSTAT_IO(kip, dbuf);
2785 			mutex_exit(ilp->ilport_kstat_io->ks_lock);
2786 		}
2787 	}
2788 }
2789 
2790 static void
stmf_update_kstat_rport_io(scsi_task_t * task,stmf_data_buf_t * dbuf)2791 stmf_update_kstat_rport_io(scsi_task_t *task, stmf_data_buf_t *dbuf)
2792 {
2793 	stmf_i_scsi_session_t	*iss;
2794 	stmf_i_remote_port_t	*irport;
2795 	kstat_io_t		*kip;
2796 
2797 	iss = task->task_session->ss_stmf_private;
2798 	irport = iss->iss_irport;
2799 	if (irport->irport_kstat_io != NULL) {
2800 		kip = KSTAT_IO_PTR(irport->irport_kstat_io);
2801 		mutex_enter(irport->irport_kstat_io->ks_lock);
2802 		STMF_UPDATE_KSTAT_IO(kip, dbuf);
2803 		mutex_exit(irport->irport_kstat_io->ks_lock);
2804 	}
2805 }
2806 
2807 static void
stmf_update_kstat_rport_estat(scsi_task_t * task)2808 stmf_update_kstat_rport_estat(scsi_task_t *task)
2809 {
2810 	stmf_i_scsi_task_t		*itask;
2811 	stmf_i_scsi_session_t		*iss;
2812 	stmf_i_remote_port_t		*irport;
2813 	stmf_kstat_rport_estat_t	*ks_estat;
2814 	hrtime_t			lat = 0;
2815 	uint32_t			n = 0;
2816 
2817 	itask = task->task_stmf_private;
2818 	iss = task->task_session->ss_stmf_private;
2819 	irport = iss->iss_irport;
2820 
2821 	if (irport->irport_kstat_estat == NULL)
2822 		return;
2823 
2824 	ks_estat = (stmf_kstat_rport_estat_t *)KSTAT_NAMED_PTR(
2825 	    irport->irport_kstat_estat);
2826 
2827 	mutex_enter(irport->irport_kstat_estat->ks_lock);
2828 
2829 	if (task->task_flags & TF_READ_DATA)
2830 		n = atomic_dec_32_nv(&irport->irport_nread_tasks);
2831 	else if (task->task_flags & TF_WRITE_DATA)
2832 		n = atomic_dec_32_nv(&irport->irport_nwrite_tasks);
2833 
2834 	if (itask->itask_read_xfer > 0) {
2835 		ks_estat->i_nread_tasks.value.ui64++;
2836 		lat = stmf_update_rport_timestamps(
2837 		    &irport->irport_rdstart_timestamp,
2838 		    &irport->irport_rddone_timestamp, itask);
2839 		if (n == 0)
2840 			ks_estat->i_rport_read_latency.value.ui64 += lat;
2841 	} else if ((itask->itask_write_xfer > 0) ||
2842 	    (task->task_flags & TF_INITIAL_BURST)) {
2843 		ks_estat->i_nwrite_tasks.value.ui64++;
2844 		lat = stmf_update_rport_timestamps(
2845 		    &irport->irport_wrstart_timestamp,
2846 		    &irport->irport_wrdone_timestamp, itask);
2847 		if (n == 0)
2848 			ks_estat->i_rport_write_latency.value.ui64 += lat;
2849 	}
2850 
2851 	if (n == 0) {
2852 		if (task->task_flags & TF_READ_DATA) {
2853 			irport->irport_rdstart_timestamp = LLONG_MAX;
2854 			irport->irport_rddone_timestamp = 0;
2855 		} else if (task->task_flags & TF_WRITE_DATA) {
2856 			irport->irport_wrstart_timestamp = LLONG_MAX;
2857 			irport->irport_wrdone_timestamp = 0;
2858 		}
2859 	}
2860 
2861 	mutex_exit(irport->irport_kstat_estat->ks_lock);
2862 }
2863 
2864 static hrtime_t
stmf_update_rport_timestamps(hrtime_t * start_tstamp,hrtime_t * done_tstamp,stmf_i_scsi_task_t * itask)2865 stmf_update_rport_timestamps(hrtime_t *start_tstamp, hrtime_t *done_tstamp,
2866     stmf_i_scsi_task_t *itask)
2867 {
2868 	*start_tstamp = MIN(*start_tstamp, itask->itask_start_timestamp);
2869 	if ((*done_tstamp == 0) &&
2870 	    (itask->itask_xfer_done_timestamp == 0)) {
2871 		*done_tstamp = *start_tstamp;
2872 	} else {
2873 		*done_tstamp = MAX(*done_tstamp,
2874 		    itask->itask_xfer_done_timestamp);
2875 	}
2876 
2877 	return (*done_tstamp - *start_tstamp);
2878 }
2879 
2880 static void
stmf_update_kstat_lu_io(scsi_task_t * task,stmf_data_buf_t * dbuf)2881 stmf_update_kstat_lu_io(scsi_task_t *task, stmf_data_buf_t *dbuf)
2882 {
2883 	stmf_i_lu_t		*ilu;
2884 	kstat_io_t		*kip;
2885 
2886 	ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private;
2887 	if (ilu != NULL && ilu->ilu_kstat_io != NULL) {
2888 		kip = KSTAT_IO_PTR(ilu->ilu_kstat_io);
2889 		if (kip != NULL) {
2890 			mutex_enter(ilu->ilu_kstat_io->ks_lock);
2891 			STMF_UPDATE_KSTAT_IO(kip, dbuf);
2892 			mutex_exit(ilu->ilu_kstat_io->ks_lock);
2893 		}
2894 	}
2895 }
2896 
2897 static void
stmf_create_kstat_lu(stmf_i_lu_t * ilu)2898 stmf_create_kstat_lu(stmf_i_lu_t *ilu)
2899 {
2900 	char				ks_nm[KSTAT_STRLEN];
2901 	stmf_kstat_lu_info_t		*ks_lu;
2902 
2903 	/* create kstat lun info */
2904 	ks_lu = (stmf_kstat_lu_info_t *)kmem_zalloc(STMF_KSTAT_LU_SZ,
2905 	    KM_NOSLEEP);
2906 	if (ks_lu == NULL) {
2907 		cmn_err(CE_WARN, "STMF: kmem_zalloc failed");
2908 		return;
2909 	}
2910 
2911 	bzero(ks_nm, sizeof (ks_nm));
2912 	(void) sprintf(ks_nm, "stmf_lu_%"PRIxPTR"", (uintptr_t)ilu);
2913 	if ((ilu->ilu_kstat_info = kstat_create(STMF_MODULE_NAME, 0,
2914 	    ks_nm, "misc", KSTAT_TYPE_NAMED,
2915 	    sizeof (stmf_kstat_lu_info_t) / sizeof (kstat_named_t),
2916 	    KSTAT_FLAG_VIRTUAL)) == NULL) {
2917 		kmem_free(ks_lu, STMF_KSTAT_LU_SZ);
2918 		cmn_err(CE_WARN, "STMF: kstat_create lu failed");
2919 		return;
2920 	}
2921 
2922 	ilu->ilu_kstat_info->ks_data_size = STMF_KSTAT_LU_SZ;
2923 	ilu->ilu_kstat_info->ks_data = ks_lu;
2924 
2925 	kstat_named_init(&ks_lu->i_lun_guid, "lun-guid",
2926 	    KSTAT_DATA_STRING);
2927 	kstat_named_init(&ks_lu->i_lun_alias, "lun-alias",
2928 	    KSTAT_DATA_STRING);
2929 
2930 	/* convert guid to hex string */
2931 	int		i;
2932 	uint8_t		*p = ilu->ilu_lu->lu_id->ident;
2933 	bzero(ilu->ilu_ascii_hex_guid, sizeof (ilu->ilu_ascii_hex_guid));
2934 	for (i = 0; i < STMF_GUID_INPUT / 2; i++) {
2935 		(void) sprintf(&ilu->ilu_ascii_hex_guid[i * 2], "%02x", p[i]);
2936 	}
2937 	kstat_named_setstr(&ks_lu->i_lun_guid,
2938 	    (const char *)ilu->ilu_ascii_hex_guid);
2939 	kstat_named_setstr(&ks_lu->i_lun_alias,
2940 	    (const char *)ilu->ilu_lu->lu_alias);
2941 	kstat_install(ilu->ilu_kstat_info);
2942 
2943 	/* create kstat lun io */
2944 	bzero(ks_nm, sizeof (ks_nm));
2945 	(void) sprintf(ks_nm, "stmf_lu_io_%"PRIxPTR"", (uintptr_t)ilu);
2946 	if ((ilu->ilu_kstat_io = kstat_create(STMF_MODULE_NAME, 0,
2947 	    ks_nm, "io", KSTAT_TYPE_IO, 1, 0)) == NULL) {
2948 		cmn_err(CE_WARN, "STMF: kstat_create lu_io failed");
2949 		return;
2950 	}
2951 	mutex_init(&ilu->ilu_kstat_lock, NULL, MUTEX_DRIVER, 0);
2952 	ilu->ilu_kstat_io->ks_lock = &ilu->ilu_kstat_lock;
2953 	kstat_install(ilu->ilu_kstat_io);
2954 }
2955 
2956 static void
stmf_create_kstat_lport(stmf_i_local_port_t * ilport)2957 stmf_create_kstat_lport(stmf_i_local_port_t *ilport)
2958 {
2959 	char				ks_nm[KSTAT_STRLEN];
2960 	stmf_kstat_tgt_info_t		*ks_tgt;
2961 	int				id, len;
2962 
2963 	/* create kstat lport info */
2964 	ks_tgt = (stmf_kstat_tgt_info_t *)kmem_zalloc(STMF_KSTAT_TGT_SZ,
2965 	    KM_NOSLEEP);
2966 	if (ks_tgt == NULL) {
2967 		cmn_err(CE_WARN, "STMF: kmem_zalloc failed");
2968 		return;
2969 	}
2970 
2971 	bzero(ks_nm, sizeof (ks_nm));
2972 	(void) sprintf(ks_nm, "stmf_tgt_%"PRIxPTR"", (uintptr_t)ilport);
2973 	if ((ilport->ilport_kstat_info = kstat_create(STMF_MODULE_NAME,
2974 	    0, ks_nm, "misc", KSTAT_TYPE_NAMED,
2975 	    sizeof (stmf_kstat_tgt_info_t) / sizeof (kstat_named_t),
2976 	    KSTAT_FLAG_VIRTUAL)) == NULL) {
2977 		kmem_free(ks_tgt, STMF_KSTAT_TGT_SZ);
2978 		cmn_err(CE_WARN, "STMF: kstat_create target failed");
2979 		return;
2980 	}
2981 
2982 	ilport->ilport_kstat_info->ks_data_size = STMF_KSTAT_TGT_SZ;
2983 	ilport->ilport_kstat_info->ks_data = ks_tgt;
2984 
2985 	kstat_named_init(&ks_tgt->i_tgt_name, "target-name",
2986 	    KSTAT_DATA_STRING);
2987 	kstat_named_init(&ks_tgt->i_tgt_alias, "target-alias",
2988 	    KSTAT_DATA_STRING);
2989 	kstat_named_init(&ks_tgt->i_protocol, "protocol",
2990 	    KSTAT_DATA_STRING);
2991 
2992 	/* ident might not be null terminated */
2993 	len = ilport->ilport_lport->lport_id->ident_length;
2994 	bcopy(ilport->ilport_lport->lport_id->ident,
2995 	    ilport->ilport_kstat_tgt_name, len);
2996 	ilport->ilport_kstat_tgt_name[len + 1] = '\0';
2997 	kstat_named_setstr(&ks_tgt->i_tgt_name,
2998 	    (const char *)ilport->ilport_kstat_tgt_name);
2999 	kstat_named_setstr(&ks_tgt->i_tgt_alias,
3000 	    (const char *)ilport->ilport_lport->lport_alias);
3001 	/* protocol */
3002 	if ((id = ilport->ilport_lport->lport_id->protocol_id) > PROTOCOL_ANY) {
3003 		cmn_err(CE_WARN, "STMF: protocol_id out of bound");
3004 		id = PROTOCOL_ANY;
3005 	}
3006 	kstat_named_setstr(&ks_tgt->i_protocol, protocol_ident[id]);
3007 	kstat_install(ilport->ilport_kstat_info);
3008 
3009 	/* create kstat lport io */
3010 	bzero(ks_nm, sizeof (ks_nm));
3011 	(void) sprintf(ks_nm, "stmf_tgt_io_%"PRIxPTR"", (uintptr_t)ilport);
3012 	if ((ilport->ilport_kstat_io = kstat_create(STMF_MODULE_NAME, 0,
3013 	    ks_nm, "io", KSTAT_TYPE_IO, 1, 0)) == NULL) {
3014 		cmn_err(CE_WARN, "STMF: kstat_create target_io failed");
3015 		return;
3016 	}
3017 	mutex_init(&ilport->ilport_kstat_lock, NULL,