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;
923