1fcf3ce44SJohn Forte /*
2fcf3ce44SJohn Forte  * CDDL HEADER START
3fcf3ce44SJohn Forte  *
4fcf3ce44SJohn Forte  * The contents of this file are subject to the terms of the
5fcf3ce44SJohn Forte  * Common Development and Distribution License (the "License").
6fcf3ce44SJohn Forte  * You may not use this file except in compliance with the License.
7fcf3ce44SJohn Forte  *
8fcf3ce44SJohn Forte  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fcf3ce44SJohn Forte  * or http://www.opensolaris.org/os/licensing.
10fcf3ce44SJohn Forte  * See the License for the specific language governing permissions
11fcf3ce44SJohn Forte  * and limitations under the License.
12fcf3ce44SJohn Forte  *
13fcf3ce44SJohn Forte  * When distributing Covered Code, include this CDDL HEADER in each
14fcf3ce44SJohn Forte  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fcf3ce44SJohn Forte  * If applicable, add the following below this CDDL HEADER, with the
16fcf3ce44SJohn Forte  * fields enclosed by brackets "[]" replaced with your own identifying
17fcf3ce44SJohn Forte  * information: Portions Copyright [yyyy] [name of copyright owner]
18fcf3ce44SJohn Forte  *
19fcf3ce44SJohn Forte  * CDDL HEADER END
20fcf3ce44SJohn Forte  */
21fcf3ce44SJohn Forte /*
22fcf3ce44SJohn Forte  * Copyright 2000 by Cisco Systems, Inc.  All rights reserved.
23904e51f6SJack Meng  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24*61dfa509SRick McNeal  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
257284664aSJoshua M. Clulow  * Copyright 2019 Joshua M. Clulow <josh@sysmgr.org>
26fcf3ce44SJohn Forte  *
27fcf3ce44SJohn Forte  * iSCSI Software Initiator
28fcf3ce44SJohn Forte  */
29fcf3ce44SJohn Forte 
30fcf3ce44SJohn Forte /*
31fcf3ce44SJohn Forte  * Framework interface routines for iSCSI
32fcf3ce44SJohn Forte  */
33fcf3ce44SJohn Forte 
3430e7468fSPeter Dunlap #include "iscsi.h"				/* main header */
3530e7468fSPeter Dunlap #include <sys/iscsi_protocol.h>	/* protocol structs */
3630e7468fSPeter Dunlap #include <sys/scsi/adapters/iscsi_if.h>		/* ioctl interfaces */
37fcf3ce44SJohn Forte #include "iscsi_targetparam.h"
38fcf3ce44SJohn Forte #include "persistent.h"
39fcf3ce44SJohn Forte #include <sys/scsi/adapters/iscsi_door.h>
40fcf3ce44SJohn Forte #include <sys/dlpi.h>
41fcf3ce44SJohn Forte #include <sys/utsname.h>
42fcf3ce44SJohn Forte #include "isns_client.h"
43fcf3ce44SJohn Forte #include "isns_protocol.h"
446cefaae1SJack Meng #include <sys/bootprops.h>
454246c8e9SJack Meng #include <sys/types.h>
464246c8e9SJack Meng #include <sys/bootconf.h>
47fcf3ce44SJohn Forte 
48fcf3ce44SJohn Forte #define	ISCSI_NAME_VERSION	"iSCSI Initiator v-1.55"
49fcf3ce44SJohn Forte 
50fcf3ce44SJohn Forte #define	MAX_GET_NAME_SIZE	1024
51fcf3ce44SJohn Forte #define	MAX_NAME_PROP_SIZE	256
52fcf3ce44SJohn Forte #define	UNDEFINED		-1
53aff4bce5Syi zhang - Sun Microsystems - Beijing China #define	ISCSI_DISC_DELAY	2	/* seconds */
54fcf3ce44SJohn Forte 
55fcf3ce44SJohn Forte /*
56fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
57fcf3ce44SJohn Forte  * | iscsi globals                                                      |
58fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
59fcf3ce44SJohn Forte  */
60fcf3ce44SJohn Forte void		*iscsi_state;
61fcf3ce44SJohn Forte kmutex_t	iscsi_oid_mutex;
62fcf3ce44SJohn Forte uint32_t	iscsi_oid;
63fcf3ce44SJohn Forte int		iscsi_nop_delay		= ISCSI_DEFAULT_NOP_DELAY;
64fcf3ce44SJohn Forte int		iscsi_rx_window		= ISCSI_DEFAULT_RX_WINDOW;
65fcf3ce44SJohn Forte int		iscsi_rx_max_window	= ISCSI_DEFAULT_RX_MAX_WINDOW;
6630e7468fSPeter Dunlap boolean_t	iscsi_logging		= B_FALSE;
67fcf3ce44SJohn Forte 
686cefaae1SJack Meng extern ib_boot_prop_t	*iscsiboot_prop;
694246c8e9SJack Meng extern int		modrootloaded;
704246c8e9SJack Meng extern struct bootobj	rootfs;
716cefaae1SJack Meng 
72fcf3ce44SJohn Forte /*
73fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
74fcf3ce44SJohn Forte  * | iscsi.c prototypes							|
75fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
76fcf3ce44SJohn Forte  */
77fcf3ce44SJohn Forte static int iscsi_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd,
78fcf3ce44SJohn Forte     void *arg, void **result);
79fcf3ce44SJohn Forte static int iscsi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
80fcf3ce44SJohn Forte static int iscsi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
81fcf3ce44SJohn Forte 
82fcf3ce44SJohn Forte /* scsi_tran prototypes */
83fcf3ce44SJohn Forte static int iscsi_tran_lun_init(dev_info_t *hba_dip, dev_info_t *lun_dip,
84fcf3ce44SJohn Forte     scsi_hba_tran_t *hba_tran, struct scsi_device *sd);
85fcf3ce44SJohn Forte static int iscsi_tran_lun_probe(struct scsi_device *sd, int (*callback) ());
86fcf3ce44SJohn Forte static struct scsi_pkt *iscsi_tran_init_pkt(struct scsi_address *ap,
87fcf3ce44SJohn Forte     struct scsi_pkt *pkt, struct buf *bp, int cmdlen, int statuslen,
88fcf3ce44SJohn Forte     int tgtlen, int flags, int (*callback) (), caddr_t arg);
89fcf3ce44SJohn Forte static void iscsi_tran_lun_free(dev_info_t *hba_dip, dev_info_t *lun_dip,
90fcf3ce44SJohn Forte     scsi_hba_tran_t *hba_tran, struct scsi_device *sd);
91fcf3ce44SJohn Forte static int iscsi_tran_start(struct scsi_address *ap, struct scsi_pkt *pkt);
92fcf3ce44SJohn Forte static int iscsi_tran_abort(struct scsi_address *ap, struct scsi_pkt *pkt);
93fcf3ce44SJohn Forte static int iscsi_tran_reset(struct scsi_address *ap, int level);
94fcf3ce44SJohn Forte static int iscsi_tran_getcap(struct scsi_address *ap, char *cap, int whom);
95fcf3ce44SJohn Forte static int iscsi_tran_setcap(struct scsi_address *ap, char *cap,
96fcf3ce44SJohn Forte     int value, int whom);
97fcf3ce44SJohn Forte static void iscsi_tran_destroy_pkt(struct scsi_address *ap,
98fcf3ce44SJohn Forte     struct scsi_pkt *pkt);
99fcf3ce44SJohn Forte static void iscsi_tran_dmafree(struct scsi_address *ap,
100fcf3ce44SJohn Forte     struct scsi_pkt *pkt);
101fcf3ce44SJohn Forte static void iscsi_tran_sync_pkt(struct scsi_address *ap,
102fcf3ce44SJohn Forte     struct scsi_pkt *pkt);
103fcf3ce44SJohn Forte static void iscsi_tran_sync_pkt(struct scsi_address *ap,
104fcf3ce44SJohn Forte     struct scsi_pkt *pkt);
105fcf3ce44SJohn Forte static int iscsi_tran_reset_notify(struct scsi_address *ap, int flag,
106fcf3ce44SJohn Forte     void (*callback) (caddr_t), caddr_t arg);
107fcf3ce44SJohn Forte static int iscsi_tran_bus_config(dev_info_t *parent, uint_t flags,
108fcf3ce44SJohn Forte     ddi_bus_config_op_t op, void *arg, dev_info_t **childp);
109fcf3ce44SJohn Forte static int iscsi_tran_bus_unconfig(dev_info_t *parent, uint_t flags,
110fcf3ce44SJohn Forte     ddi_bus_config_op_t op, void *arg);
111fcf3ce44SJohn Forte static int iscsi_tran_get_name(struct scsi_device *sd, char *name, int len);
112fcf3ce44SJohn Forte static int iscsi_tran_get_bus_addr(struct scsi_device *sd, char *name, int len);
113fcf3ce44SJohn Forte 
114fcf3ce44SJohn Forte /* bus_ops prototypes */
115fcf3ce44SJohn Forte /* LINTED E_STATIC_UNUSED */
116fcf3ce44SJohn Forte static ddi_intrspec_t iscsi_get_intrspec(dev_info_t *dip, dev_info_t *rdip,
117fcf3ce44SJohn Forte     uint_t inumber);
118fcf3ce44SJohn Forte /* LINTED E_STATIC_UNUSED */
119fcf3ce44SJohn Forte static int iscsi_add_intrspec(dev_info_t *dip, dev_info_t *rdip,
120fcf3ce44SJohn Forte     ddi_intrspec_t intrspec, ddi_iblock_cookie_t *iblock_cookiep,
121fcf3ce44SJohn Forte     ddi_idevice_cookie_t *idevice_cookiep, uint_t (*int_handler)(caddr_t
122fcf3ce44SJohn Forte     int_handler_arg), caddr_t int_handler_arg, int kind);
123fcf3ce44SJohn Forte /* LINTED E_STATIC_UNUSED */
124fcf3ce44SJohn Forte static void iscsi_remove_intrspec(dev_info_t *dip, dev_info_t *rdip,
125fcf3ce44SJohn Forte     ddi_intrspec_t intrspec, ddi_iblock_cookie_t iblock_cookie);
126fcf3ce44SJohn Forte /* LINTED E_STATIC_UNUSED */
127fcf3ce44SJohn Forte static int iscsi_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop,
128fcf3ce44SJohn Forte     void *arg, void *result);
129fcf3ce44SJohn Forte 
130fcf3ce44SJohn Forte /* cb_ops prototypes */
131fcf3ce44SJohn Forte static int iscsi_open(dev_t *devp, int flags, int otyp, cred_t *credp);
132fcf3ce44SJohn Forte static int iscsi_close(dev_t dev, int flag, int otyp, cred_t *credp);
1334246c8e9SJack Meng static int iscsi_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
134fcf3ce44SJohn Forte     cred_t *credp, int *rvalp);
135fcf3ce44SJohn Forte 
136fcf3ce44SJohn Forte int iscsi_get_persisted_param(uchar_t *name,
137fcf3ce44SJohn Forte     iscsi_param_get_t *ipgp,
138fcf3ce44SJohn Forte     iscsi_login_params_t *params);
139fcf3ce44SJohn Forte static void iscsi_override_target_default(iscsi_hba_t *ihp,
140fcf3ce44SJohn Forte     iscsi_param_get_t *ipg);
141fcf3ce44SJohn Forte 
142fcf3ce44SJohn Forte /* scsi_tran helpers */
143fcf3ce44SJohn Forte static int iscsi_virt_lun_init(dev_info_t *hba_dip, dev_info_t *lun_dip,
144fcf3ce44SJohn Forte     scsi_hba_tran_t *hba_tran, struct scsi_device *sd);
145fcf3ce44SJohn Forte static int iscsi_phys_lun_init(dev_info_t *hba_dip, dev_info_t *lun_dip,
146fcf3ce44SJohn Forte     scsi_hba_tran_t *hba_tran, struct scsi_device *sd);
147fcf3ce44SJohn Forte static int iscsi_i_commoncap(struct scsi_address *ap, char *cap,
148fcf3ce44SJohn Forte     int val, int lunonly, int doset);
149fcf3ce44SJohn Forte static void iscsi_get_name_to_iqn(char *name, int name_max_len);
150fcf3ce44SJohn Forte static void iscsi_get_name_from_iqn(char *name, int name_max_len);
1516cefaae1SJack Meng static boolean_t iscsi_cmp_boot_sess_oid(iscsi_hba_t *ihp, uint32_t oid);
152fcf3ce44SJohn Forte 
1534246c8e9SJack Meng /* iscsi initiator service helpers */
1544246c8e9SJack Meng static boolean_t iscsi_enter_service_zone(iscsi_hba_t *ihp, uint32_t status);
1554246c8e9SJack Meng static void iscsi_exit_service_zone(iscsi_hba_t *ihp, uint32_t status);
1564246c8e9SJack Meng static void iscsi_check_miniroot(iscsi_hba_t *ihp);
157aff4bce5Syi zhang - Sun Microsystems - Beijing China static void iscsi_get_tunable_default(iscsi_tunable_object_t *param);
158aff4bce5Syi zhang - Sun Microsystems - Beijing China static int iscsi_get_persisted_tunable_param(uchar_t *name,
159aff4bce5Syi zhang - Sun Microsystems - Beijing China     iscsi_tunable_object_t *tpsg);
160aff4bce5Syi zhang - Sun Microsystems - Beijing China static void iscsi_set_default_tunable_params(iscsi_tunable_params_t *params);
1614246c8e9SJack Meng 
162fcf3ce44SJohn Forte /* struct helpers prototypes */
163fcf3ce44SJohn Forte 
164fcf3ce44SJohn Forte /*
165fcf3ce44SJohn Forte  * At this point this driver doesn't need this structure because nothing
166fcf3ce44SJohn Forte  * is done during the open, close or ioctl. Code put in place because
167fcf3ce44SJohn Forte  * some admin related work might be done in the ioctl routine.
168fcf3ce44SJohn Forte  */
169fcf3ce44SJohn Forte static struct cb_ops iscsi_cb_ops = {
170fcf3ce44SJohn Forte 	iscsi_open,			/* open */
171fcf3ce44SJohn Forte 	iscsi_close,			/* close */
172fcf3ce44SJohn Forte 	nodev,				/* strategy */
173fcf3ce44SJohn Forte 	nodev,				/* print */
174fcf3ce44SJohn Forte 	nodev,				/* dump */
175fcf3ce44SJohn Forte 	nodev,				/* read */
176fcf3ce44SJohn Forte 	nodev,				/* write */
177fcf3ce44SJohn Forte 	iscsi_ioctl,			/* ioctl */
178fcf3ce44SJohn Forte 	nodev,				/* devmap */
179fcf3ce44SJohn Forte 	nodev,				/* mmap */
180fcf3ce44SJohn Forte 	nodev,				/* segmap */
181fcf3ce44SJohn Forte 	nochpoll,			/* poll */
182fcf3ce44SJohn Forte 	ddi_prop_op,			/* prop_op */
183fcf3ce44SJohn Forte 	NULL,				/* streamtab */
184fcf3ce44SJohn Forte 	D_NEW | D_MP | D_HOTPLUG,	/* flags */
185fcf3ce44SJohn Forte 	CB_REV,				/* cb_rev */
186fcf3ce44SJohn Forte 	nodev,				/* aread */
187fcf3ce44SJohn Forte 	nodev,				/* awrite */
188fcf3ce44SJohn Forte };
189fcf3ce44SJohn Forte 
190fcf3ce44SJohn Forte static struct dev_ops iscsi_dev_ops = {
191fcf3ce44SJohn Forte 	DEVO_REV,		/* devo_rev */
192fcf3ce44SJohn Forte 	0,			/* refcnt */
193fcf3ce44SJohn Forte 	iscsi_getinfo,		/* getinfo */
194fcf3ce44SJohn Forte 	nulldev,		/* identify */
195fcf3ce44SJohn Forte 	nulldev,		/* probe */
196fcf3ce44SJohn Forte 	iscsi_attach,		/* attach */
197fcf3ce44SJohn Forte 	iscsi_detach,		/* detach */
198fcf3ce44SJohn Forte 	nodev,			/* reset */
199fcf3ce44SJohn Forte 	&iscsi_cb_ops,		/* driver operations */
200fcf3ce44SJohn Forte 	NULL,			/* bus ops */
201fcf3ce44SJohn Forte 	NULL,			/* power management */
202edd20d23Syi zhang - Sun Microsystems - Beijing China 	ddi_quiesce_not_needed,	/* quiesce */
203fcf3ce44SJohn Forte };
204fcf3ce44SJohn Forte 
205fcf3ce44SJohn Forte static struct modldrv modldrv = {
206fcf3ce44SJohn Forte 	&mod_driverops,		/* drv_modops */
207fcf3ce44SJohn Forte 	ISCSI_NAME_VERSION,	/* drv_linkinfo */
208fcf3ce44SJohn Forte 	&iscsi_dev_ops		/* drv_dev_ops */
209fcf3ce44SJohn Forte };
210fcf3ce44SJohn Forte 
211fcf3ce44SJohn Forte static struct modlinkage modlinkage = {
212fcf3ce44SJohn Forte 	MODREV_1,		/* ml_rev */
213fcf3ce44SJohn Forte 	&modldrv,		/* ml_linkage[] */
214fcf3ce44SJohn Forte 	NULL			/* NULL termination */
215fcf3ce44SJohn Forte };
216fcf3ce44SJohn Forte 
217fcf3ce44SJohn Forte /*
218fcf3ce44SJohn Forte  * This structure is bogus. scsi_hba_attach_setup() requires, as in the kernel
219fcf3ce44SJohn Forte  * will panic if you don't pass this in to the routine, this information.
220fcf3ce44SJohn Forte  * Need to determine what the actual impact to the system is by providing
221fcf3ce44SJohn Forte  * this information if any. Since dma allocation is done in pkt_init it may
222fcf3ce44SJohn Forte  * not have any impact. These values are straight from the Writing Device
223fcf3ce44SJohn Forte  * Driver manual.
224fcf3ce44SJohn Forte  */
225fcf3ce44SJohn Forte static ddi_dma_attr_t iscsi_dma_attr = {
226fcf3ce44SJohn Forte 	DMA_ATTR_V0,	/* ddi_dma_attr version */
227fcf3ce44SJohn Forte 	0,		/* low address */
228fcf3ce44SJohn Forte 	0xffffffff,	/* high address */
229fcf3ce44SJohn Forte 	0x00ffffff,	/* counter upper bound */
230fcf3ce44SJohn Forte 	1,		/* alignment requirements */
231fcf3ce44SJohn Forte 	0x3f,		/* burst sizes */
232fcf3ce44SJohn Forte 	1,		/* minimum DMA access */
233fcf3ce44SJohn Forte 	0xffffffff,	/* maximum DMA access */
234fcf3ce44SJohn Forte 	(1 << 24) - 1,	/* segment boundary restrictions */
235fcf3ce44SJohn Forte 	1,		/* scater/gather list length */
236fcf3ce44SJohn Forte 	512,		/* device granularity */
237fcf3ce44SJohn Forte 	0		/* DMA flags */
238fcf3ce44SJohn Forte };
239fcf3ce44SJohn Forte 
240fcf3ce44SJohn Forte /*
241fcf3ce44SJohn Forte  * _init - General driver init entry
242fcf3ce44SJohn Forte  */
243fcf3ce44SJohn Forte int
_init(void)244fcf3ce44SJohn Forte _init(void)
245fcf3ce44SJohn Forte {
246fcf3ce44SJohn Forte 	int rval = 0;
247fcf3ce44SJohn Forte 
248fcf3ce44SJohn Forte 	iscsi_net_init();
249fcf3ce44SJohn Forte 
250fcf3ce44SJohn Forte 	mutex_init(&iscsi_oid_mutex, NULL, MUTEX_DRIVER, NULL);
251fcf3ce44SJohn Forte 	iscsi_oid = ISCSI_INITIATOR_OID;
252fcf3ce44SJohn Forte 
253fcf3ce44SJohn Forte 	/*
254fcf3ce44SJohn Forte 	 * Set up the soft state structures. If this driver is actually
255fcf3ce44SJohn Forte 	 * being attached to the system then we'll have at least one
256fcf3ce44SJohn Forte 	 * HBA/NIC used.
257fcf3ce44SJohn Forte 	 */
258fcf3ce44SJohn Forte 	rval = ddi_soft_state_init(&iscsi_state,
259fcf3ce44SJohn Forte 	    sizeof (iscsi_hba_t), 1);
260fcf3ce44SJohn Forte 	if (rval != 0) {
261fcf3ce44SJohn Forte 		iscsi_net_fini();
262fcf3ce44SJohn Forte 		goto init_done;
263fcf3ce44SJohn Forte 	}
264fcf3ce44SJohn Forte 
265fcf3ce44SJohn Forte 	rval = scsi_hba_init(&modlinkage);
266fcf3ce44SJohn Forte 	if (rval != 0) {
267fcf3ce44SJohn Forte 		ddi_soft_state_fini(&iscsi_state);
268fcf3ce44SJohn Forte 		iscsi_net_fini();
269fcf3ce44SJohn Forte 		goto init_done;
270fcf3ce44SJohn Forte 	}
271fcf3ce44SJohn Forte 
272fcf3ce44SJohn Forte 	rval = mod_install(&modlinkage);
273fcf3ce44SJohn Forte 	if (rval != 0) {
274fcf3ce44SJohn Forte 		ddi_soft_state_fini(&iscsi_state);
275fcf3ce44SJohn Forte 		scsi_hba_fini(&modlinkage);
276fcf3ce44SJohn Forte 		iscsi_net_fini();
277fcf3ce44SJohn Forte 		goto init_done;
278fcf3ce44SJohn Forte 	}
279fcf3ce44SJohn Forte 	(void) iscsi_door_ini();
280fcf3ce44SJohn Forte 
281fcf3ce44SJohn Forte init_done:
282fcf3ce44SJohn Forte 	return (rval);
283fcf3ce44SJohn Forte }
284fcf3ce44SJohn Forte 
285fcf3ce44SJohn Forte /*
286fcf3ce44SJohn Forte  * _fini - General driver destructor entry
287fcf3ce44SJohn Forte  */
288fcf3ce44SJohn Forte int
_fini(void)289fcf3ce44SJohn Forte _fini(void)
290fcf3ce44SJohn Forte {
291fcf3ce44SJohn Forte 	int rval = 0;
292fcf3ce44SJohn Forte 
293fcf3ce44SJohn Forte 	rval = mod_remove(&modlinkage);
294fcf3ce44SJohn Forte 	if (rval == 0) {
295fcf3ce44SJohn Forte 		scsi_hba_fini(&modlinkage);
296fcf3ce44SJohn Forte 		ddi_soft_state_fini(&iscsi_state);
297fcf3ce44SJohn Forte 		mutex_destroy(&iscsi_oid_mutex);
298fcf3ce44SJohn Forte 		(void) iscsi_door_term();
299fcf3ce44SJohn Forte 		iscsi_net_fini();
300fcf3ce44SJohn Forte 	}
301fcf3ce44SJohn Forte 	return (rval);
302fcf3ce44SJohn Forte }
303fcf3ce44SJohn Forte 
304fcf3ce44SJohn Forte /*
305fcf3ce44SJohn Forte  * _info - General driver info entry
306fcf3ce44SJohn Forte  */
307fcf3ce44SJohn Forte int
_info(struct modinfo * mp)308fcf3ce44SJohn Forte _info(struct modinfo *mp)
309fcf3ce44SJohn Forte {
310fcf3ce44SJohn Forte 	int rval = 0;
311fcf3ce44SJohn Forte 
312fcf3ce44SJohn Forte 	rval = mod_info(&modlinkage, mp);
313fcf3ce44SJohn Forte 
314fcf3ce44SJohn Forte 	return (rval);
315fcf3ce44SJohn Forte }
316fcf3ce44SJohn Forte 
317fcf3ce44SJohn Forte 
318fcf3ce44SJohn Forte /*
319fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
320fcf3ce44SJohn Forte  * | Start of dev_ops routines					  |
321fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
322fcf3ce44SJohn Forte  */
323fcf3ce44SJohn Forte 
324fcf3ce44SJohn Forte /*
325fcf3ce44SJohn Forte  * iscsi_getinfo - returns general driver information
326fcf3ce44SJohn Forte  */
327fcf3ce44SJohn Forte /* ARGSUSED */
328fcf3ce44SJohn Forte static int
iscsi_getinfo(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)329fcf3ce44SJohn Forte iscsi_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd,
330fcf3ce44SJohn Forte     void *arg, void **result)
331fcf3ce44SJohn Forte {
332fcf3ce44SJohn Forte 	int		rval		= DDI_SUCCESS;
333fcf3ce44SJohn Forte 	int		instance	= getminor((dev_t)arg);
334fcf3ce44SJohn Forte 	iscsi_hba_t	*ip;
335fcf3ce44SJohn Forte 
336fcf3ce44SJohn Forte 	switch (infocmd) {
337fcf3ce44SJohn Forte 	case DDI_INFO_DEVT2DEVINFO:
338fcf3ce44SJohn Forte 		if ((ip = ddi_get_soft_state(iscsi_state, instance)) == NULL) {
339fcf3ce44SJohn Forte 			return (DDI_FAILURE);
340fcf3ce44SJohn Forte 		}
341fcf3ce44SJohn Forte 		*result = ip->hba_dip;
342fcf3ce44SJohn Forte 		if (ip->hba_dip == NULL)
343fcf3ce44SJohn Forte 			rval = DDI_FAILURE;
344fcf3ce44SJohn Forte 		else
345fcf3ce44SJohn Forte 			rval = DDI_SUCCESS;
346fcf3ce44SJohn Forte 		break;
347fcf3ce44SJohn Forte 
348fcf3ce44SJohn Forte 	case DDI_INFO_DEVT2INSTANCE:
349fcf3ce44SJohn Forte 		*result = (void *)(uintptr_t)instance;
350fcf3ce44SJohn Forte 		rval = DDI_SUCCESS;
351fcf3ce44SJohn Forte 		break;
352fcf3ce44SJohn Forte 
353fcf3ce44SJohn Forte 	default:
354fcf3ce44SJohn Forte 		rval = DDI_FAILURE;
355fcf3ce44SJohn Forte 		break;
356fcf3ce44SJohn Forte 	}
357fcf3ce44SJohn Forte 	return (rval);
358fcf3ce44SJohn Forte }
359fcf3ce44SJohn Forte 
360fcf3ce44SJohn Forte 
361fcf3ce44SJohn Forte /*
362fcf3ce44SJohn Forte  * iscsi_attach -- Attach instance of an iSCSI HBA.  We
363fcf3ce44SJohn Forte  * will attempt to create our HBA and register it with
364fcf3ce44SJohn Forte  * scsi_vhci.  If it's not possible to create the HBA
365fcf3ce44SJohn Forte  * or register with vhci we will fail the attach.
366fcf3ce44SJohn Forte  */
367fcf3ce44SJohn Forte static int
iscsi_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)368fcf3ce44SJohn Forte iscsi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
369fcf3ce44SJohn Forte {
370fcf3ce44SJohn Forte 	int			instance	= ddi_get_instance(dip);
371fcf3ce44SJohn Forte 	iscsi_hba_t		*ihp		= NULL;
372fcf3ce44SJohn Forte 	scsi_hba_tran_t		*tran		= NULL;
373fcf3ce44SJohn Forte 	char			init_port_name[MAX_NAME_PROP_SIZE];
374fcf3ce44SJohn Forte 
3757284664aSJoshua M. Clulow 	if (cmd == DDI_RESUME) {
3767284664aSJoshua M. Clulow 		return (DDI_SUCCESS);
3777284664aSJoshua M. Clulow 	} else if (cmd != DDI_ATTACH) {
3787284664aSJoshua M. Clulow 		return (DDI_FAILURE);
3797284664aSJoshua M. Clulow 	}
380fcf3ce44SJohn Forte 
3817284664aSJoshua M. Clulow 	if (!modrootloaded && iscsiboot_prop == NULL) {
3827284664aSJoshua M. Clulow 		/*
3837284664aSJoshua M. Clulow 		 * The root file system has not yet been mounted, and we're not
3847284664aSJoshua M. Clulow 		 * trying to boot from an iSCSI device.  Fail to attach now so
3857284664aSJoshua M. Clulow 		 * that we can retry after root has been mounted.
3867284664aSJoshua M. Clulow 		 */
3877284664aSJoshua M. Clulow 		return (DDI_FAILURE);
3887284664aSJoshua M. Clulow 	}
389fcf3ce44SJohn Forte 
3907284664aSJoshua M. Clulow 	/* create iSCSI HBA devctl device node */
3917284664aSJoshua M. Clulow 	if (ddi_create_minor_node(dip, ISCSI_DEVCTL, S_IFCHR, 0,
3927284664aSJoshua M. Clulow 	    DDI_PSEUDO, 0) != DDI_SUCCESS) {
3937284664aSJoshua M. Clulow 		goto iscsi_attach_failed3;
3947284664aSJoshua M. Clulow 	}
395fcf3ce44SJohn Forte 
3967284664aSJoshua M. Clulow 	/* allocate HBA soft state */
3977284664aSJoshua M. Clulow 	if (ddi_soft_state_zalloc(iscsi_state, instance) !=
3987284664aSJoshua M. Clulow 	    DDI_SUCCESS) {
3997284664aSJoshua M. Clulow 		ddi_remove_minor_node(dip, NULL);
4007284664aSJoshua M. Clulow 		goto iscsi_attach_failed3;
4017284664aSJoshua M. Clulow 	}
40230e7468fSPeter Dunlap 
4037284664aSJoshua M. Clulow 	/* get reference to soft state */
4047284664aSJoshua M. Clulow 	if ((ihp = (iscsi_hba_t *)ddi_get_soft_state(
4057284664aSJoshua M. Clulow 	    iscsi_state, instance)) == NULL) {
4067284664aSJoshua M. Clulow 		ddi_remove_minor_node(dip, NULL);
4077284664aSJoshua M. Clulow 		ddi_soft_state_free(iscsi_state, instance);
4087284664aSJoshua M. Clulow 		goto iscsi_attach_failed3;
4097284664aSJoshua M. Clulow 	}
4104246c8e9SJack Meng 
4117284664aSJoshua M. Clulow 	/* init HBA mutex used to protect discovery events */
4127284664aSJoshua M. Clulow 	mutex_init(&ihp->hba_discovery_events_mutex, NULL,
4137284664aSJoshua M. Clulow 	    MUTEX_DRIVER, NULL);
414fcf3ce44SJohn Forte 
4157284664aSJoshua M. Clulow 	VERIFY0(ldi_ident_from_dip(dip, &ihp->hba_li));
416fcf3ce44SJohn Forte 
4177284664aSJoshua M. Clulow 	/* init HBA mutex used to protect service status */
4187284664aSJoshua M. Clulow 	mutex_init(&ihp->hba_service_lock, NULL,
4197284664aSJoshua M. Clulow 	    MUTEX_DRIVER, NULL);
4207284664aSJoshua M. Clulow 	cv_init(&ihp->hba_service_cv, NULL, CV_DRIVER, NULL);
421fcf3ce44SJohn Forte 
4227284664aSJoshua M. Clulow 	/*
4237284664aSJoshua M. Clulow 	 * init SendTargets semaphore that is used to allow
4247284664aSJoshua M. Clulow 	 * only one operation at a time
4257284664aSJoshua M. Clulow 	 */
4267284664aSJoshua M. Clulow 	sema_init(&ihp->hba_sendtgts_semaphore, 1, NULL,
4277284664aSJoshua M. Clulow 	    SEMA_DRIVER, NULL);
428fcf3ce44SJohn Forte 
4297284664aSJoshua M. Clulow 	ihp->hba_sess_list = NULL;
4307284664aSJoshua M. Clulow 	rw_init(&ihp->hba_sess_list_rwlock, NULL,
4317284664aSJoshua M. Clulow 	    RW_DRIVER, NULL);
432fcf3ce44SJohn Forte 
4337284664aSJoshua M. Clulow 	/* allocate scsi_hba_tran */
4347284664aSJoshua M. Clulow 	if ((tran = scsi_hba_tran_alloc(dip, SCSI_HBA_CANSLEEP))
4357284664aSJoshua M. Clulow 	    == NULL) {
4367284664aSJoshua M. Clulow 		ddi_remove_minor_node(dip, NULL);
4377284664aSJoshua M. Clulow 		goto iscsi_attach_failed2;
4387284664aSJoshua M. Clulow 	}
439fcf3ce44SJohn Forte 
4407284664aSJoshua M. Clulow 	/* soft state setup */
4417284664aSJoshua M. Clulow 	ihp->hba_sig	= ISCSI_SIG_HBA;
4427284664aSJoshua M. Clulow 	ihp->hba_tran	= tran;
4437284664aSJoshua M. Clulow 	ihp->hba_dip	= dip;
4447284664aSJoshua M. Clulow 	if (iscsiboot_prop == NULL) {
4457284664aSJoshua M. Clulow 		ihp->hba_service_status =
4467284664aSJoshua M. Clulow 		    ISCSI_SERVICE_DISABLED;
4477284664aSJoshua M. Clulow 		ihp->hba_service_status_overwrite = B_FALSE;
4487284664aSJoshua M. Clulow 	} else {
4497284664aSJoshua M. Clulow 		ihp->hba_service_status =
4507284664aSJoshua M. Clulow 		    ISCSI_SERVICE_ENABLED;
4517284664aSJoshua M. Clulow 		ihp->hba_service_status_overwrite = B_TRUE;
4527284664aSJoshua M. Clulow 	}
4537284664aSJoshua M. Clulow 	ihp->hba_service_client_count = 0;
4547284664aSJoshua M. Clulow 
4557284664aSJoshua M. Clulow 	mutex_enter(&iscsi_oid_mutex);
4567284664aSJoshua M. Clulow 	ihp->hba_oid		  = iscsi_oid++;
4577284664aSJoshua M. Clulow 	mutex_exit(&iscsi_oid_mutex);
4587284664aSJoshua M. Clulow 
4597284664aSJoshua M. Clulow 	ihp->hba_name[0]	  = '\0';
4607284664aSJoshua M. Clulow 	ihp->hba_name_length	  = 0;
4617284664aSJoshua M. Clulow 	ihp->hba_alias_length	  = 0;
4627284664aSJoshua M. Clulow 	ihp->hba_alias[0]	  = '\0';
4637284664aSJoshua M. Clulow 
4647284664aSJoshua M. Clulow 	iscsi_net->tweaks.rcvbuf = ddi_prop_get_int(
4657284664aSJoshua M. Clulow 	    DDI_DEV_T_ANY, ihp->hba_dip, 0, "so-rcvbuf",
4667284664aSJoshua M. Clulow 	    ISCSI_SOCKET_RCVBUF_SIZE);
4677284664aSJoshua M. Clulow 
4687284664aSJoshua M. Clulow 	iscsi_net->tweaks.sndbuf = ddi_prop_get_int(
4697284664aSJoshua M. Clulow 	    DDI_DEV_T_ANY, ihp->hba_dip, 0, "so-sndbuf",
4707284664aSJoshua M. Clulow 	    ISCSI_SOCKET_SNDBUF_SIZE);
4717284664aSJoshua M. Clulow 
4727284664aSJoshua M. Clulow 	iscsi_net->tweaks.nodelay = ddi_prop_get_int(
4737284664aSJoshua M. Clulow 	    DDI_DEV_T_ANY, ihp->hba_dip, 0, "tcp-nodelay",
4747284664aSJoshua M. Clulow 	    ISCSI_TCP_NODELAY_DEFAULT);
4757284664aSJoshua M. Clulow 
4767284664aSJoshua M. Clulow 	iscsi_net->tweaks.conn_notify_threshold =
4777284664aSJoshua M. Clulow 	    ddi_prop_get_int(DDI_DEV_T_ANY,
4787284664aSJoshua M. Clulow 	    ihp->hba_dip, 0, "tcp-conn-notify-threshold",
4797284664aSJoshua M. Clulow 	    ISCSI_TCP_CNOTIFY_THRESHOLD_DEFAULT);
4807284664aSJoshua M. Clulow 
4817284664aSJoshua M. Clulow 	iscsi_net->tweaks.conn_abort_threshold =
4827284664aSJoshua M. Clulow 	    ddi_prop_get_int(DDI_DEV_T_ANY, ihp->hba_dip,
4837284664aSJoshua M. Clulow 	    0, "tcp-conn-abort-threshold",
4847284664aSJoshua M. Clulow 	    ISCSI_TCP_CABORT_THRESHOLD_DEFAULT);
4857284664aSJoshua M. Clulow 
4867284664aSJoshua M. Clulow 	iscsi_net->tweaks.abort_threshold = ddi_prop_get_int(
4877284664aSJoshua M. Clulow 	    DDI_DEV_T_ANY, ihp->hba_dip, 0,
4887284664aSJoshua M. Clulow 	    "tcp-abort-threshold",
4897284664aSJoshua M. Clulow 	    ISCSI_TCP_ABORT_THRESHOLD_DEFAULT);
4907284664aSJoshua M. Clulow 
4917284664aSJoshua M. Clulow 	ihp->hba_config_storm_delay = ddi_prop_get_int(
4927284664aSJoshua M. Clulow 	    DDI_DEV_T_ANY, ihp->hba_dip, 0,
4937284664aSJoshua M. Clulow 	    "config-storm-delay",
4947284664aSJoshua M. Clulow 	    ISCSI_CONFIG_STORM_DELAY_DEFAULT);
4957284664aSJoshua M. Clulow 
4967284664aSJoshua M. Clulow 	(void) ddi_prop_update_int(DDI_DEV_T_NONE, ihp->hba_dip,
4977284664aSJoshua M. Clulow 	    "so-rcvbuf", iscsi_net->tweaks.rcvbuf);
4987284664aSJoshua M. Clulow 
4997284664aSJoshua M. Clulow 	(void) ddi_prop_update_int(DDI_DEV_T_NONE, ihp->hba_dip,
5007284664aSJoshua M. Clulow 	    "so-sndbuf", iscsi_net->tweaks.sndbuf);
5017284664aSJoshua M. Clulow 
5027284664aSJoshua M. Clulow 	(void) ddi_prop_update_int(DDI_DEV_T_NONE, ihp->hba_dip,
5037284664aSJoshua M. Clulow 	    "tcp-nodelay", iscsi_net->tweaks.nodelay);
5047284664aSJoshua M. Clulow 
5057284664aSJoshua M. Clulow 	(void) ddi_prop_update_int(DDI_DEV_T_NONE, ihp->hba_dip,
5067284664aSJoshua M. Clulow 	    "tcp-conn-notify-threshold",
5077284664aSJoshua M. Clulow 	    iscsi_net->tweaks.conn_notify_threshold);
5087284664aSJoshua M. Clulow 
5097284664aSJoshua M. Clulow 	(void) ddi_prop_update_int(DDI_DEV_T_NONE, ihp->hba_dip,
5107284664aSJoshua M. Clulow 	    "tcp-conn-abort-threshold",
5117284664aSJoshua M. Clulow 	    iscsi_net->tweaks.conn_abort_threshold);
5127284664aSJoshua M. Clulow 
5137284664aSJoshua M. Clulow 	(void) ddi_prop_update_int(DDI_DEV_T_NONE, ihp->hba_dip,
5147284664aSJoshua M. Clulow 	    "tcp-abort-threshold",
5157284664aSJoshua M. Clulow 	    iscsi_net->tweaks.abort_threshold);
5167284664aSJoshua M. Clulow 
5177284664aSJoshua M. Clulow 	(void) ddi_prop_update_int(DDI_DEV_T_NONE, ihp->hba_dip,
5187284664aSJoshua M. Clulow 	    "config-storm-delay",
5197284664aSJoshua M. Clulow 	    ihp->hba_config_storm_delay);
5207284664aSJoshua M. Clulow 
5217284664aSJoshua M. Clulow 	/* setup hba defaults */
5227284664aSJoshua M. Clulow 	iscsi_set_default_login_params(&ihp->hba_params);
5237284664aSJoshua M. Clulow 	iscsi_set_default_tunable_params(
5247284664aSJoshua M. Clulow 	    &ihp->hba_tunable_params);
5257284664aSJoshua M. Clulow 
5267284664aSJoshua M. Clulow 	/* setup minimal initiator params */
5277284664aSJoshua M. Clulow 	iscsid_set_default_initiator_node_settings(ihp, B_TRUE);
5287284664aSJoshua M. Clulow 
5297284664aSJoshua M. Clulow 	/* hba set up */
5307284664aSJoshua M. Clulow 	tran->tran_hba_private  = ihp;
5317284664aSJoshua M. Clulow 	tran->tran_tgt_private  = NULL;
5327284664aSJoshua M. Clulow 	tran->tran_tgt_init	= iscsi_tran_lun_init;
5337284664aSJoshua M. Clulow 	tran->tran_tgt_probe	= iscsi_tran_lun_probe;
5347284664aSJoshua M. Clulow 	tran->tran_tgt_free	= iscsi_tran_lun_free;
5357284664aSJoshua M. Clulow 	tran->tran_start	= iscsi_tran_start;
5367284664aSJoshua M. Clulow 	tran->tran_abort	= iscsi_tran_abort;
5377284664aSJoshua M. Clulow 	tran->tran_reset	= iscsi_tran_reset;
5387284664aSJoshua M. Clulow 	tran->tran_getcap	= iscsi_tran_getcap;
5397284664aSJoshua M. Clulow 	tran->tran_setcap	= iscsi_tran_setcap;
5407284664aSJoshua M. Clulow 	tran->tran_init_pkt	= iscsi_tran_init_pkt;
5417284664aSJoshua M. Clulow 	tran->tran_destroy_pkt	= iscsi_tran_destroy_pkt;
5427284664aSJoshua M. Clulow 	tran->tran_dmafree	= iscsi_tran_dmafree;
5437284664aSJoshua M. Clulow 	tran->tran_sync_pkt	= iscsi_tran_sync_pkt;
5447284664aSJoshua M. Clulow 	tran->tran_reset_notify	= iscsi_tran_reset_notify;
5457284664aSJoshua M. Clulow 	tran->tran_bus_config	= iscsi_tran_bus_config;
5467284664aSJoshua M. Clulow 	tran->tran_bus_unconfig	= iscsi_tran_bus_unconfig;
5477284664aSJoshua M. Clulow 
5487284664aSJoshua M. Clulow 	tran->tran_get_name	= iscsi_tran_get_name;
5497284664aSJoshua M. Clulow 	tran->tran_get_bus_addr	= iscsi_tran_get_bus_addr;
5507284664aSJoshua M. Clulow 	tran->tran_interconnect_type = INTERCONNECT_ISCSI;
5517284664aSJoshua M. Clulow 
5527284664aSJoshua M. Clulow 	/* register scsi hba with scsa */
5537284664aSJoshua M. Clulow 	if (scsi_hba_attach_setup(dip, &iscsi_dma_attr,
5547284664aSJoshua M. Clulow 	    tran, SCSI_HBA_TRAN_CLONE) != DDI_SUCCESS) {
5557284664aSJoshua M. Clulow 		goto iscsi_attach_failed1;
5567284664aSJoshua M. Clulow 	}
557fcf3ce44SJohn Forte 
5587284664aSJoshua M. Clulow 	/* register scsi hba with mdi (MPxIO/vhci) */
5597284664aSJoshua M. Clulow 	if (mdi_phci_register(MDI_HCI_CLASS_SCSI, dip, 0) !=
5607284664aSJoshua M. Clulow 	    MDI_SUCCESS) {
5617284664aSJoshua M. Clulow 		ihp->hba_mpxio_enabled = B_FALSE;
5627284664aSJoshua M. Clulow 	} else {
5637284664aSJoshua M. Clulow 		ihp->hba_mpxio_enabled = B_TRUE;
5647284664aSJoshua M. Clulow 	}
565fcf3ce44SJohn Forte 
5667284664aSJoshua M. Clulow 	(void) iscsi_hba_kstat_init(ihp);
567fcf3ce44SJohn Forte 
5687284664aSJoshua M. Clulow 	/* Initialize targetparam list */
5697284664aSJoshua M. Clulow 	iscsi_targetparam_init();
570fcf3ce44SJohn Forte 
5717284664aSJoshua M. Clulow 	/* Initialize ISID */
5727284664aSJoshua M. Clulow 	ihp->hba_isid[0] = ISCSI_SUN_ISID_0;
5737284664aSJoshua M. Clulow 	ihp->hba_isid[1] = ISCSI_SUN_ISID_1;
5747284664aSJoshua M. Clulow 	ihp->hba_isid[2] = ISCSI_SUN_ISID_2;
5757284664aSJoshua M. Clulow 	ihp->hba_isid[3] = ISCSI_SUN_ISID_3;
5767284664aSJoshua M. Clulow 	ihp->hba_isid[4] = ISCSI_SUN_ISID_4;
5777284664aSJoshua M. Clulow 	ihp->hba_isid[5] = ISCSI_SUN_ISID_5;
578fcf3ce44SJohn Forte 
5797284664aSJoshua M. Clulow 	/* Setup iSNS transport services and client */
5807284664aSJoshua M. Clulow 	isns_client_init();
581fcf3ce44SJohn Forte 
5827284664aSJoshua M. Clulow 	/*
5837284664aSJoshua M. Clulow 	 * initialize persistent store,
5847284664aSJoshua M. Clulow 	 * or boot target info in case of iscsi boot
5857284664aSJoshua M. Clulow 	 */
5867284664aSJoshua M. Clulow 	ihp->hba_persistent_loaded = B_FALSE;
5877284664aSJoshua M. Clulow 	if (iscsid_init(ihp) == B_FALSE) {
5887284664aSJoshua M. Clulow 		goto iscsi_attach_failed0;
5897284664aSJoshua M. Clulow 	}
590fcf3ce44SJohn Forte 
5917284664aSJoshua M. Clulow 	/* Setup init_port_name for MPAPI */
5927284664aSJoshua M. Clulow 	(void) snprintf(init_port_name, MAX_NAME_PROP_SIZE,
5937284664aSJoshua M. Clulow 	    "%s,%02x%02x%02x%02x%02x%02x",
5947284664aSJoshua M. Clulow 	    (char *)ihp->hba_name, ihp->hba_isid[0],
5957284664aSJoshua M. Clulow 	    ihp->hba_isid[1], ihp->hba_isid[2],
5967284664aSJoshua M. Clulow 	    ihp->hba_isid[3], ihp->hba_isid[4],
5977284664aSJoshua M. Clulow 	    ihp->hba_isid[5]);
598fcf3ce44SJohn Forte 
5997284664aSJoshua M. Clulow 	if (ddi_prop_update_string(DDI_DEV_T_NONE, dip,
6007284664aSJoshua M. Clulow 	    SCSI_ADDR_PROP_INITIATOR_PORT, init_port_name) !=
6017284664aSJoshua M. Clulow 	    DDI_PROP_SUCCESS) {
6027284664aSJoshua M. Clulow 		cmn_err(CE_WARN, "iscsi_attach: Creating "
6037284664aSJoshua M. Clulow 		    SCSI_ADDR_PROP_INITIATOR_PORT
6047284664aSJoshua M. Clulow 		    " property on iSCSI "
6057284664aSJoshua M. Clulow 		    "HBA(%s) with dip(%d) Failed",
6067284664aSJoshua M. Clulow 		    (char *)ihp->hba_name,
6077284664aSJoshua M. Clulow 		    ddi_get_instance(dip));
608fcf3ce44SJohn Forte 	}
609fcf3ce44SJohn Forte 
6107284664aSJoshua M. Clulow 	ddi_report_dev(dip);
6117284664aSJoshua M. Clulow 	return (DDI_SUCCESS);
612fcf3ce44SJohn Forte 
6137284664aSJoshua M. Clulow iscsi_attach_failed0:
6147284664aSJoshua M. Clulow 	isns_client_cleanup();
6157284664aSJoshua M. Clulow 	if (ihp->stats.ks) {
6167284664aSJoshua M. Clulow 		(void) iscsi_hba_kstat_term(ihp);
6177284664aSJoshua M. Clulow 	}
6187284664aSJoshua M. Clulow 	if (ihp->hba_mpxio_enabled == B_TRUE) {
6197284664aSJoshua M. Clulow 		(void) mdi_phci_unregister(dip, 0);
6207284664aSJoshua M. Clulow 	}
6217284664aSJoshua M. Clulow 	(void) scsi_hba_detach(ihp->hba_dip);
6227284664aSJoshua M. Clulow iscsi_attach_failed1:
6237284664aSJoshua M. Clulow 	ddi_remove_minor_node(dip, NULL);
6247284664aSJoshua M. Clulow 	ddi_prop_remove_all(ihp->hba_dip);
6257284664aSJoshua M. Clulow 	scsi_hba_tran_free(tran);
6267284664aSJoshua M. Clulow iscsi_attach_failed2:
6277284664aSJoshua M. Clulow 	cv_destroy(&ihp->hba_service_cv);
6287284664aSJoshua M. Clulow 	mutex_destroy(&ihp->hba_service_lock);
6297284664aSJoshua M. Clulow 	mutex_destroy(&ihp->hba_discovery_events_mutex);
6307284664aSJoshua M. Clulow 	sema_destroy(&ihp->hba_sendtgts_semaphore);
6317284664aSJoshua M. Clulow 	rw_destroy(&ihp->hba_sess_list_rwlock);
6327284664aSJoshua M. Clulow 	ddi_soft_state_free(iscsi_state, instance);
6337284664aSJoshua M. Clulow iscsi_attach_failed3:
6347284664aSJoshua M. Clulow 	cmn_err(CE_WARN, "iscsi driver unable to attach "
6357284664aSJoshua M. Clulow 	    "hba instance %d", instance);
6367284664aSJoshua M. Clulow 	return (DDI_FAILURE);
637fcf3ce44SJohn Forte }
638fcf3ce44SJohn Forte 
639fcf3ce44SJohn Forte /*
640fcf3ce44SJohn Forte  * iscsi_detach - called on unload of hba instance
641fcf3ce44SJohn Forte  */
642fcf3ce44SJohn Forte static int
iscsi_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)643fcf3ce44SJohn Forte iscsi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
644fcf3ce44SJohn Forte {
645fcf3ce44SJohn Forte 	int			rval		= DDI_SUCCESS;
646fcf3ce44SJohn Forte 	scsi_hba_tran_t		*tran		= NULL;
647fcf3ce44SJohn Forte 	iscsi_hba_t		*ihp		= NULL;
648fcf3ce44SJohn Forte 	iscsi_hba_t		*ihp_check	= NULL;
649fcf3ce44SJohn Forte 	int			instance;
650fcf3ce44SJohn Forte 	char			*init_node_name;
651fcf3ce44SJohn Forte 
652fcf3ce44SJohn Forte 	instance = ddi_get_instance(dip);
653fcf3ce44SJohn Forte 
654fcf3ce44SJohn Forte 	switch (cmd) {
655fcf3ce44SJohn Forte 	case DDI_DETACH:
656fcf3ce44SJohn Forte 		if (!(tran = (scsi_hba_tran_t *)ddi_get_driver_private(dip))) {
657fcf3ce44SJohn Forte 			rval = DDI_SUCCESS;
658fcf3ce44SJohn Forte 			break;
659fcf3ce44SJohn Forte 		}
660fcf3ce44SJohn Forte 
661fcf3ce44SJohn Forte 		if ((ihp = (iscsi_hba_t *)tran->tran_hba_private) == NULL) {
662fcf3ce44SJohn Forte 			rval =  DDI_FAILURE;
663fcf3ce44SJohn Forte 			break;
664fcf3ce44SJohn Forte 		}
665fcf3ce44SJohn Forte 
666fcf3ce44SJohn Forte 		/*
667fcf3ce44SJohn Forte 		 * Validate that what is stored by the DDI framework is still
668fcf3ce44SJohn Forte 		 * the same state structure referenced by the SCSI framework
669fcf3ce44SJohn Forte 		 */
670fcf3ce44SJohn Forte 		ihp_check = ddi_get_soft_state(iscsi_state, instance);
671fcf3ce44SJohn Forte 		if (ihp_check != ihp) {
672fcf3ce44SJohn Forte 			rval = DDI_FAILURE;
673fcf3ce44SJohn Forte 			break;
674fcf3ce44SJohn Forte 		}
675fcf3ce44SJohn Forte 
676fcf3ce44SJohn Forte 		/* If a session exists we can't safely detach */
677fcf3ce44SJohn Forte 		rw_enter(&ihp->hba_sess_list_rwlock, RW_READER);
678fcf3ce44SJohn Forte 		if (ihp->hba_sess_list != NULL) {
679fcf3ce44SJohn Forte 			rw_exit(&ihp->hba_sess_list_rwlock);
680fcf3ce44SJohn Forte 			rval = DDI_FAILURE;
681fcf3ce44SJohn Forte 			break;
682fcf3ce44SJohn Forte 		}
683fcf3ce44SJohn Forte 		rw_exit(&ihp->hba_sess_list_rwlock);
684fcf3ce44SJohn Forte 
685fcf3ce44SJohn Forte 		/* Disable all discovery services */
686fcf3ce44SJohn Forte 		if (iscsid_disable_discovery(ihp,
687fcf3ce44SJohn Forte 		    ISCSI_ALL_DISCOVERY_METHODS) == B_FALSE) {
688fcf3ce44SJohn Forte 			/* Disable failed.  Fail detach */
689fcf3ce44SJohn Forte 			rval = DDI_FAILURE;
690fcf3ce44SJohn Forte 			break;
691fcf3ce44SJohn Forte 		}
692fcf3ce44SJohn Forte 
693fcf3ce44SJohn Forte 		/* Deregister from iSNS server(s). */
694fcf3ce44SJohn Forte 		init_node_name = kmem_zalloc(ISCSI_MAX_NAME_LEN, KM_SLEEP);
695fcf3ce44SJohn Forte 		if (persistent_initiator_name_get(init_node_name,
696fcf3ce44SJohn Forte 		    ISCSI_MAX_NAME_LEN) == B_TRUE) {
697fcf3ce44SJohn Forte 			if (strlen(init_node_name) > 0) {
698fcf3ce44SJohn Forte 				(void) isns_dereg(ihp->hba_isid,
699fcf3ce44SJohn Forte 				    (uint8_t *)init_node_name);
700fcf3ce44SJohn Forte 			}
701fcf3ce44SJohn Forte 		}
702fcf3ce44SJohn Forte 		kmem_free(init_node_name, ISCSI_MAX_NAME_LEN);
703fcf3ce44SJohn Forte 		init_node_name = NULL;
704fcf3ce44SJohn Forte 
705fcf3ce44SJohn Forte 		/* Cleanup iSNS Client */
706fcf3ce44SJohn Forte 		isns_client_cleanup();
707fcf3ce44SJohn Forte 
708fcf3ce44SJohn Forte 		iscsi_targetparam_cleanup();
709fcf3ce44SJohn Forte 
710fcf3ce44SJohn Forte 		/* Cleanup iscsid resources */
711fcf3ce44SJohn Forte 		iscsid_fini();
712fcf3ce44SJohn Forte 
713fcf3ce44SJohn Forte 		if (rval != DDI_SUCCESS) {
714fcf3ce44SJohn Forte 			break;
715fcf3ce44SJohn Forte 		}
716fcf3ce44SJohn Forte 		/* kstat hba. destroy */
717fcf3ce44SJohn Forte 		KSTAT_DEC_HBA_CNTR_SESS(ihp);
718fcf3ce44SJohn Forte 
719fcf3ce44SJohn Forte 		if (ihp->hba_mpxio_enabled == B_TRUE) {
720fcf3ce44SJohn Forte 			(void) mdi_phci_unregister(dip, 0);
721fcf3ce44SJohn Forte 		}
722fcf3ce44SJohn Forte 		ddi_remove_minor_node(dip, NULL);
723fcf3ce44SJohn Forte 
724fcf3ce44SJohn Forte 		ddi_prop_remove_all(ihp->hba_dip);
72530e7468fSPeter Dunlap 
72630e7468fSPeter Dunlap 		ldi_ident_release(ihp->hba_li);
72730e7468fSPeter Dunlap 
7284246c8e9SJack Meng 		cv_destroy(&ihp->hba_service_cv);
7294246c8e9SJack Meng 		mutex_destroy(&ihp->hba_service_lock);
730fcf3ce44SJohn Forte 		mutex_destroy(&ihp->hba_discovery_events_mutex);
731fcf3ce44SJohn Forte 		rw_destroy(&ihp->hba_sess_list_rwlock);
732fcf3ce44SJohn Forte 		(void) iscsi_hba_kstat_term(ihp);
733fcf3ce44SJohn Forte 
734fcf3ce44SJohn Forte 		(void) scsi_hba_detach(dip);
735fcf3ce44SJohn Forte 		if (tran != NULL) {
736fcf3ce44SJohn Forte 			scsi_hba_tran_free(tran);
737fcf3ce44SJohn Forte 		}
738fcf3ce44SJohn Forte 		ddi_soft_state_free(iscsi_state, instance);
739fcf3ce44SJohn Forte 		break;
740fcf3ce44SJohn Forte 	default:
741fcf3ce44SJohn Forte 		break;
742fcf3ce44SJohn Forte 	}
743fcf3ce44SJohn Forte 
744fcf3ce44SJohn Forte 	if (rval != DDI_SUCCESS) {
745fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "iscsi driver unable to "
746fcf3ce44SJohn Forte 		    "detach hba instance %d", instance);
747fcf3ce44SJohn Forte 	}
748fcf3ce44SJohn Forte 
749fcf3ce44SJohn Forte 	return (rval);
750fcf3ce44SJohn Forte }
751fcf3ce44SJohn Forte 
752fcf3ce44SJohn Forte /*
753fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
754fcf3ce44SJohn Forte  * | End of dev_ops routines						|
755fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
756fcf3ce44SJohn Forte  */
757fcf3ce44SJohn Forte 
758fcf3ce44SJohn Forte /*
759fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
760fcf3ce44SJohn Forte  * | scsi_tran(9E) routines						|
761fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
762fcf3ce44SJohn Forte  */
763fcf3ce44SJohn Forte 
764fcf3ce44SJohn Forte /*
765fcf3ce44SJohn Forte  * iscsi_tran_lun_init - Find target device based on SCSI device
766fcf3ce44SJohn Forte  * Based on the information given (SCSI device, target dev_info) find
767fcf3ce44SJohn Forte  * the target iSCSI device and put a pointer to that information in
768fcf3ce44SJohn Forte  * the scsi_hba_tran_t structure.
769fcf3ce44SJohn Forte  */
770fcf3ce44SJohn Forte static int
iscsi_tran_lun_init(dev_info_t * hba_dip,dev_info_t * lun_dip,scsi_hba_tran_t * hba_tran,struct scsi_device * sd)771fcf3ce44SJohn Forte iscsi_tran_lun_init(dev_info_t *hba_dip, dev_info_t *lun_dip,
772fcf3ce44SJohn Forte     scsi_hba_tran_t *hba_tran, struct scsi_device *sd)
773fcf3ce44SJohn Forte {
774fcf3ce44SJohn Forte 	int		rval	= 0;
775fcf3ce44SJohn Forte 	int		type	= 0;
776fcf3ce44SJohn Forte 
777fcf3ce44SJohn Forte 	ASSERT(hba_tran->tran_hba_private != NULL);
778fcf3ce44SJohn Forte 
779fcf3ce44SJohn Forte 	/*
780fcf3ce44SJohn Forte 	 * Child node is getting initialized.  Look at the mpxio component
781fcf3ce44SJohn Forte 	 * type on the child device to see if this device is mpxio managed
782fcf3ce44SJohn Forte 	 * or not.
783fcf3ce44SJohn Forte 	 */
784fcf3ce44SJohn Forte 	type = mdi_get_component_type(lun_dip);
785fcf3ce44SJohn Forte 	if (type != MDI_COMPONENT_CLIENT) {
786fcf3ce44SJohn Forte 		rval = iscsi_phys_lun_init(hba_dip, lun_dip, hba_tran, sd);
787fcf3ce44SJohn Forte 	} else {
788fcf3ce44SJohn Forte 		rval = iscsi_virt_lun_init(hba_dip, lun_dip, hba_tran, sd);
789fcf3ce44SJohn Forte 	}
790fcf3ce44SJohn Forte 
791fcf3ce44SJohn Forte 	return (rval);
792fcf3ce44SJohn Forte }
793fcf3ce44SJohn Forte 
794fcf3ce44SJohn Forte /*
795fcf3ce44SJohn Forte  * iscsi_tran_lun_probe - This function didn't need to be implemented.
796fcf3ce44SJohn Forte  * We could have left NULL in the tran table.  Since this isn't a
797fcf3ce44SJohn Forte  * performance path this seems safe.  We are just wrappering the
798fcf3ce44SJohn Forte  * function so we can see the call go through if we have debugging
799fcf3ce44SJohn Forte  * enabled.
800fcf3ce44SJohn Forte  */
801fcf3ce44SJohn Forte static int
iscsi_tran_lun_probe(struct scsi_device * sd,int (* callback)())802fcf3ce44SJohn Forte iscsi_tran_lun_probe(struct scsi_device *sd, int (*callback) ())
803fcf3ce44SJohn Forte {
804fcf3ce44SJohn Forte 	int rval = 0;
805fcf3ce44SJohn Forte 
806fcf3ce44SJohn Forte 	rval = scsi_hba_probe(sd, callback);
807fcf3ce44SJohn Forte 
808fcf3ce44SJohn Forte 	return (rval);
809fcf3ce44SJohn Forte }
810fcf3ce44SJohn Forte 
811fcf3ce44SJohn Forte /*
812fcf3ce44SJohn Forte  * iscsi_init_pkt - Allocate SCSI packet and fill in required info.
813fcf3ce44SJohn Forte  */
814fcf3ce44SJohn Forte /* ARGSUSED */
815fcf3ce44SJohn Forte static struct scsi_pkt *
iscsi_tran_init_pkt(struct scsi_address * ap,struct scsi_pkt * pkt,struct buf * bp,int cmdlen,int statuslen,int tgtlen,int flags,int (* callback)(),caddr_t arg)816fcf3ce44SJohn Forte iscsi_tran_init_pkt(struct scsi_address *ap, struct scsi_pkt *pkt,
817fcf3ce44SJohn Forte     struct buf *bp, int cmdlen, int statuslen, int tgtlen, int flags,
818fcf3ce44SJohn Forte     int (*callback) (), caddr_t arg)
819fcf3ce44SJohn Forte {
820fcf3ce44SJohn Forte 	iscsi_lun_t *ilp;
821fcf3ce44SJohn Forte 	iscsi_cmd_t *icmdp;
822fcf3ce44SJohn Forte 
823fcf3ce44SJohn Forte 	ASSERT(ap != NULL);
824fcf3ce44SJohn Forte 	ASSERT(callback == NULL_FUNC || callback == SLEEP_FUNC);
825fcf3ce44SJohn Forte 
826fcf3ce44SJohn Forte 	/*
827fcf3ce44SJohn Forte 	 * The software stack doesn't have DMA which means the iSCSI
828fcf3ce44SJohn Forte 	 * protocol layer will be doing a bcopy from bp to outgoing
829fcf3ce44SJohn Forte 	 * streams buffers. Make sure that the buffer is mapped in
830fcf3ce44SJohn Forte 	 * so that the copy won't panic the system.
831fcf3ce44SJohn Forte 	 */
8325e5f9182SJack Meng 	if (bp && (bp->b_bcount != 0) &&
8335e5f9182SJack Meng 	    bp_mapin_common(bp, (callback == NULL_FUNC) ?
834fcf3ce44SJohn Forte 	    VM_NOSLEEP : VM_SLEEP) == NULL) {
835fcf3ce44SJohn Forte 		return (NULL);
836fcf3ce44SJohn Forte 	}
837fcf3ce44SJohn Forte 
838fcf3ce44SJohn Forte 	ilp = (iscsi_lun_t *)ap->a_hba_tran->tran_tgt_private;
839fcf3ce44SJohn Forte 	ASSERT(ilp != NULL);
840fcf3ce44SJohn Forte 
841fcf3ce44SJohn Forte 	if (pkt == NULL) {
842fcf3ce44SJohn Forte 		pkt = scsi_hba_pkt_alloc(ilp->lun_sess->sess_hba->hba_dip,
843fcf3ce44SJohn Forte 		    ap, cmdlen, statuslen, tgtlen, sizeof (iscsi_cmd_t),
844fcf3ce44SJohn Forte 		    callback, arg);
845fcf3ce44SJohn Forte 		if (pkt == NULL) {
846fcf3ce44SJohn Forte 			return (NULL);
847fcf3ce44SJohn Forte 		}
848fcf3ce44SJohn Forte 		icmdp = (iscsi_cmd_t *)pkt->pkt_ha_private;
849fcf3ce44SJohn Forte 		icmdp->cmd_sig			= ISCSI_SIG_CMD;
850fcf3ce44SJohn Forte 		icmdp->cmd_state		= ISCSI_CMD_STATE_FREE;
851fcf3ce44SJohn Forte 		icmdp->cmd_lun			= ilp;
852*61dfa509SRick McNeal 		iscsi_lun_hold(ilp);
853fcf3ce44SJohn Forte 		icmdp->cmd_type			= ISCSI_CMD_TYPE_SCSI;
854fcf3ce44SJohn Forte 		/* add the report lun addressing type on to the lun */
855fcf3ce44SJohn Forte 		icmdp->cmd_un.scsi.lun		= ilp->lun_addr_type << 14;
856fcf3ce44SJohn Forte 		icmdp->cmd_un.scsi.lun		= icmdp->cmd_un.scsi.lun |
857fcf3ce44SJohn Forte 		    ilp->lun_num;
858fcf3ce44SJohn Forte 		icmdp->cmd_un.scsi.pkt		= pkt;
859fcf3ce44SJohn Forte 		icmdp->cmd_un.scsi.bp		= bp;
860fcf3ce44SJohn Forte 		icmdp->cmd_un.scsi.cmdlen	= cmdlen;
861fcf3ce44SJohn Forte 		icmdp->cmd_un.scsi.statuslen	= statuslen;
862fcf3ce44SJohn Forte 		icmdp->cmd_crc_error_seen	= B_FALSE;
863d233de7eSJack Meng 		icmdp->cmd_misc_flags		= 0;
864b4243054SSheng-Liang Eric Zhang 		if (flags & PKT_XARQ) {
865b4243054SSheng-Liang Eric Zhang 			icmdp->cmd_misc_flags |= ISCSI_CMD_MISCFLAG_XARQ;
866b4243054SSheng-Liang Eric Zhang 		}
867b4243054SSheng-Liang Eric Zhang 
86830e7468fSPeter Dunlap 
86930e7468fSPeter Dunlap 		idm_sm_audit_init(&icmdp->cmd_state_audit);
87030e7468fSPeter Dunlap 
871fcf3ce44SJohn Forte 		mutex_init(&icmdp->cmd_mutex, NULL, MUTEX_DRIVER, NULL);
872fcf3ce44SJohn Forte 		cv_init(&icmdp->cmd_completion, NULL, CV_DRIVER, NULL);
873fcf3ce44SJohn Forte 
874fcf3ce44SJohn Forte 		pkt->pkt_address		= *ap;
875fcf3ce44SJohn Forte 		pkt->pkt_comp			= (void (*)())NULL;
876fcf3ce44SJohn Forte 		pkt->pkt_flags			= 0;
877fcf3ce44SJohn Forte 		pkt->pkt_time			= 0;
878fcf3ce44SJohn Forte 		pkt->pkt_resid			= 0;
879fcf3ce44SJohn Forte 		pkt->pkt_statistics		= 0;
880fcf3ce44SJohn Forte 		pkt->pkt_reason			= 0;
881fcf3ce44SJohn Forte 	}
882fcf3ce44SJohn Forte 	return (pkt);
883fcf3ce44SJohn Forte }
884fcf3ce44SJohn Forte 
885fcf3ce44SJohn Forte /*
886fcf3ce44SJohn Forte  * iscsi_tran_lun_free - Free a SCSI LUN
887fcf3ce44SJohn Forte  */
888fcf3ce44SJohn Forte static void
iscsi_tran_lun_free(dev_info_t * hba_dip,dev_info_t * lun_dip,scsi_hba_tran_t * hba_tran,struct scsi_device * sd)889fcf3ce44SJohn Forte iscsi_tran_lun_free(dev_info_t *hba_dip, dev_info_t *lun_dip,
890fcf3ce44SJohn Forte     scsi_hba_tran_t *hba_tran, struct scsi_device *sd)
891fcf3ce44SJohn Forte {
892fcf3ce44SJohn Forte 	iscsi_lun_t *ilp = NULL;
893fcf3ce44SJohn Forte 
894fcf3ce44SJohn Forte 	ASSERT(hba_dip != NULL);
895fcf3ce44SJohn Forte 	ASSERT(lun_dip != NULL);
896fcf3ce44SJohn Forte 	ASSERT(hba_tran != NULL);
897fcf3ce44SJohn Forte 	ASSERT(sd != NULL);
898fcf3ce44SJohn Forte 	ilp = (iscsi_lun_t *)hba_tran->tran_tgt_private;
899fcf3ce44SJohn Forte 	ASSERT(ilp != NULL);
900fcf3ce44SJohn Forte 
901fcf3ce44SJohn Forte 	(void) mdi_prop_remove(ilp->lun_pip, NULL);
902fcf3ce44SJohn Forte }
903fcf3ce44SJohn Forte 
904fcf3ce44SJohn Forte /*
905fcf3ce44SJohn Forte  * iscsi_start -- Start a SCSI transaction based on the packet
906fcf3ce44SJohn Forte  * This will attempt to add the icmdp to the pending queue
907fcf3ce44SJohn Forte  * for the connection and kick the queue.  If the enqueue
908fcf3ce44SJohn Forte  * fails that means the queue is full.
909fcf3ce44SJohn Forte  */
910fcf3ce44SJohn Forte static int
iscsi_tran_start(struct scsi_address * ap,struct scsi_pkt * pkt)911fcf3ce44SJohn Forte iscsi_tran_start(struct scsi_address *ap, struct scsi_pkt *pkt)
912fcf3ce44SJohn Forte {
913fcf3ce44SJohn Forte 	iscsi_lun_t	*ilp		= NULL;
914fcf3ce44SJohn Forte 	iscsi_sess_t	*isp		= NULL;
915fcf3ce44SJohn Forte 	iscsi_cmd_t	*icmdp		= NULL;
916fcf3ce44SJohn Forte 	uint_t		flags;
917fcf3ce44SJohn Forte 
918fcf3ce44SJohn Forte 	ASSERT(ap != NULL);
919fcf3ce44SJohn Forte 	ASSERT(pkt != NULL);
920fcf3ce44SJohn Forte 	ilp = (iscsi_lun_t *)ap->a_hba_tran->tran_tgt_private;
921fcf3ce44SJohn Forte 	isp = (iscsi_sess_t *)ilp->lun_sess;
922fcf3ce44SJohn Forte 	icmdp = (iscsi_cmd_t *)pkt->pkt_ha_private;