1c0586b87SGarrett D'Amore /*
2c0586b87SGarrett D'Amore * This file and its contents are supplied under the terms of the
3c0586b87SGarrett D'Amore * Common Development and Distribution License ("CDDL"), version 1.0.
4c0586b87SGarrett D'Amore * You may only use this file in accordance with the terms of version
5c0586b87SGarrett D'Amore * 1.0 of the CDDL.
6c0586b87SGarrett D'Amore *
7c0586b87SGarrett D'Amore * A full copy of the text of the CDDL should have accompanied this
8c0586b87SGarrett D'Amore * source. A copy of the CDDL is also available via the Internet at
9c0586b87SGarrett D'Amore * http://www.illumos.org/license/CDDL.
10c0586b87SGarrett D'Amore */
11c0586b87SGarrett D'Amore
12c0586b87SGarrett D'Amore /*
13c0586b87SGarrett D'Amore * Copyright 2016 Nexenta Systems, Inc.
14c0586b87SGarrett D'Amore * Copyright 2022 RackTop Systems, Inc.
15c0586b87SGarrett D'Amore */
16c0586b87SGarrett D'Amore
17c0586b87SGarrett D'Amore #include <sys/atomic.h>
18c0586b87SGarrett D'Amore #include <sys/cmn_err.h>
19c0586b87SGarrett D'Amore #include <sys/cpuvar.h>
20c0586b87SGarrett D'Amore #include <sys/ddi.h>
21c0586b87SGarrett D'Amore #include <sys/id32.h>
22c0586b87SGarrett D'Amore #include <sys/kmem.h>
23c0586b87SGarrett D'Amore #include <sys/list.h>
24c0586b87SGarrett D'Amore #include <sys/modctl.h>
25c0586b87SGarrett D'Amore #include <sys/pci.h>
26c0586b87SGarrett D'Amore #include <sys/scsi/scsi.h>
27c0586b87SGarrett D'Amore #include <sys/sunddi.h>
28c0586b87SGarrett D'Amore #include <sys/sysmacros.h>
29c0586b87SGarrett D'Amore #include <sys/types.h>
30c0586b87SGarrett D'Amore #include <sys/note.h>
31c0586b87SGarrett D'Amore
32c0586b87SGarrett D'Amore #include "pvscsi.h"
33c0586b87SGarrett D'Amore #include "pvscsi_var.h"
34c0586b87SGarrett D'Amore
35c0586b87SGarrett D'Amore /* we can support any of the interrupt types */
36c0586b87SGarrett D'Amore int pvscsi_intr_types = \
37c0586b87SGarrett D'Amore DDI_INTR_TYPE_MSIX|DDI_INTR_TYPE_MSI|DDI_INTR_TYPE_FIXED;
38c0586b87SGarrett D'Amore int pvscsi_ring_pages = PVSCSI_DEFAULT_NUM_PAGES_PER_RING;
39c0586b87SGarrett D'Amore int pvscsi_msg_ring_pages = PVSCSI_DEFAULT_NUM_PAGES_MSG_RING;
40c0586b87SGarrett D'Amore static int pvscsi_hz;
41c0586b87SGarrett D'Amore
42c0586b87SGarrett D'Amore static int pvscsi_abort(struct scsi_address *, struct scsi_pkt *);
43c0586b87SGarrett D'Amore static void pvscsi_timeout(void *);
44c0586b87SGarrett D'Amore static void pvscsi_setup_rings(pvscsi_softc_t *);
45c0586b87SGarrett D'Amore static void pvscsi_complete_cmds(pvscsi_softc_t *, pvscsi_cmd_t *);
46c0586b87SGarrett D'Amore static boolean_t pvscsi_cmd_init(pvscsi_softc_t *, pvscsi_cmd_t *, int);
47c0586b87SGarrett D'Amore static void pvscsi_cmd_fini(pvscsi_cmd_t *);
48c0586b87SGarrett D'Amore
49c0586b87SGarrett D'Amore /* HBA DMA attributes */
50c0586b87SGarrett D'Amore static ddi_dma_attr_t pvscsi_dma_attr = {
51c0586b87SGarrett D'Amore .dma_attr_version = DMA_ATTR_V0,
52c0586b87SGarrett D'Amore .dma_attr_addr_lo = 0,
53c0586b87SGarrett D'Amore .dma_attr_addr_hi = 0xFFFFFFFFFFFFFFFFull,
54c0586b87SGarrett D'Amore .dma_attr_count_max = 0xFFFFFFFFFFFFFFFFull,
55c0586b87SGarrett D'Amore .dma_attr_align = PAGE_SIZE,
56c0586b87SGarrett D'Amore .dma_attr_burstsizes = 1,
57c0586b87SGarrett D'Amore .dma_attr_minxfer = 1,
58c0586b87SGarrett D'Amore .dma_attr_maxxfer = 0xFFFFFFFFFFFFFFFFull,
59c0586b87SGarrett D'Amore .dma_attr_seg = 0xFFFFFFFFFFFFFFFFull,
60c0586b87SGarrett D'Amore .dma_attr_sgllen = 1,
61c0586b87SGarrett D'Amore .dma_attr_granular = 1,
62c0586b87SGarrett D'Amore .dma_attr_flags = 0
63c0586b87SGarrett D'Amore };
64c0586b87SGarrett D'Amore
65c0586b87SGarrett D'Amore /* DMA attributes for buffer I/O */
66c0586b87SGarrett D'Amore static ddi_dma_attr_t pvscsi_io_dma_attr = {
67c0586b87SGarrett D'Amore .dma_attr_version = DMA_ATTR_V0,
68c0586b87SGarrett D'Amore .dma_attr_addr_lo = 0,
69c0586b87SGarrett D'Amore .dma_attr_addr_hi = 0xFFFFFFFFFFFFFFFFull,
70c0586b87SGarrett D'Amore .dma_attr_count_max = 0x7FFFFFFFll,
71c0586b87SGarrett D'Amore .dma_attr_align = 1,
72c0586b87SGarrett D'Amore .dma_attr_burstsizes = 1,
73c0586b87SGarrett D'Amore .dma_attr_minxfer = 1,
74c0586b87SGarrett D'Amore .dma_attr_maxxfer = PAGE_SIZE * PVSCSI_MAX_SG_SIZE,
75c0586b87SGarrett D'Amore .dma_attr_seg = 0xFFFFFFFFFFFFFFFFull,
76c0586b87SGarrett D'Amore .dma_attr_sgllen = PVSCSI_MAX_SG_SIZE,
77c0586b87SGarrett D'Amore .dma_attr_granular = 1,
78c0586b87SGarrett D'Amore .dma_attr_flags = 0
79c0586b87SGarrett D'Amore };
80c0586b87SGarrett D'Amore
81c0586b87SGarrett D'Amore /*
82c0586b87SGarrett D'Amore * The structures are always little endian (VMware only runs
83c0586b87SGarrett D'Amore * on little endian CPUs), but we only run on LE processors,
84c0586b87SGarrett D'Amore * and NEVERSWAP avoids needing to use DDI accessor functions.
85c0586b87SGarrett D'Amore * (It would be incredibly bizarre to have a VMware guest running
86c0586b87SGarrett D'Amore * with a different endianness than the hypervisor.)
87c0586b87SGarrett D'Amore */
88c0586b87SGarrett D'Amore static ddi_device_acc_attr_t pvscsi_mmio_attr = {
89c0586b87SGarrett D'Amore .devacc_attr_version = DDI_DEVICE_ATTR_V1,
90c0586b87SGarrett D'Amore .devacc_attr_endian_flags = DDI_NEVERSWAP_ACC,
91c0586b87SGarrett D'Amore .devacc_attr_dataorder = DDI_STRICTORDER_ACC,
92c0586b87SGarrett D'Amore .devacc_attr_access = DDI_DEFAULT_ACC
93c0586b87SGarrett D'Amore };
94c0586b87SGarrett D'Amore
95c0586b87SGarrett D'Amore static ddi_device_acc_attr_t pvscsi_dma_attrs = {
96c0586b87SGarrett D'Amore .devacc_attr_version = DDI_DEVICE_ATTR_V1,
97c0586b87SGarrett D'Amore .devacc_attr_endian_flags = DDI_NEVERSWAP_ACC,
98c0586b87SGarrett D'Amore .devacc_attr_dataorder = DDI_STRICTORDER_ACC,
99c0586b87SGarrett D'Amore .devacc_attr_access = DDI_DEFAULT_ACC,
100c0586b87SGarrett D'Amore };
101c0586b87SGarrett D'Amore
102c0586b87SGarrett D'Amore static void
pvscsi_add_to_queue(pvscsi_softc_t * pvs,pvscsi_cmd_t * cmd)103c0586b87SGarrett D'Amore pvscsi_add_to_queue(pvscsi_softc_t *pvs, pvscsi_cmd_t *cmd)
104c0586b87SGarrett D'Amore {
105c0586b87SGarrett D'Amore pvscsi_cmd_t *r;
106c0586b87SGarrett D'Amore list_t *l;
107c0586b87SGarrett D'Amore
108c0586b87SGarrett D'Amore /*
109c0586b87SGarrett D'Amore * We insert in order of expiration, with the earliest
110c0586b87SGarrett D'Amore * expirations at the front. This logic assumes that most
111c0586b87SGarrett D'Amore * commands will have the same timeout, and is optimized
112c0586b87SGarrett D'Amore * to minimize walking the list. It allows timeouts to
113c0586b87SGarrett D'Amore * run without looking at more than one node that has not
114c0586b87SGarrett D'Amore * yet expired.
115c0586b87SGarrett D'Amore */
116c0586b87SGarrett D'Amore ASSERT(mutex_owned(&pvs->lock));
117c0586b87SGarrett D'Amore
118c0586b87SGarrett D'Amore l = &pvs->cmd_queue;
119c0586b87SGarrett D'Amore for (r = list_tail(l); r != NULL; r = list_prev(l, r)) {
120c0586b87SGarrett D'Amore /* this subtraction is safe if lbolt wraps */
121c0586b87SGarrett D'Amore if (((cmd->start + cmd->timeout) -
122c0586b87SGarrett D'Amore (r->start + r->timeout)) >= 0) {
123c0586b87SGarrett D'Amore list_insert_after(l, r, cmd);
124c0586b87SGarrett D'Amore return;
125c0586b87SGarrett D'Amore }
126c0586b87SGarrett D'Amore }
127c0586b87SGarrett D'Amore
128c0586b87SGarrett D'Amore list_insert_head(l, cmd);
129c0586b87SGarrett D'Amore }
130c0586b87SGarrett D'Amore
131c0586b87SGarrett D'Amore static uint32_t
pvscsi_reg_read(pvscsi_softc_t * pvs,uint32_t offset)132c0586b87SGarrett D'Amore pvscsi_reg_read(pvscsi_softc_t *pvs, uint32_t offset)
133c0586b87SGarrett D'Amore {
134c0586b87SGarrett D'Amore uint32_t ret;
135c0586b87SGarrett D'Amore
136c0586b87SGarrett D'Amore ASSERT((offset & (sizeof (uint32_t) - 1)) == 0);
137c0586b87SGarrett D'Amore
138c0586b87SGarrett D'Amore ret = ddi_get32(pvs->mmio_handle,
139c0586b87SGarrett D'Amore (uint32_t *)(pvs->mmio_base + offset));
140c0586b87SGarrett D'Amore
141c0586b87SGarrett D'Amore return (ret);
142c0586b87SGarrett D'Amore }
143c0586b87SGarrett D'Amore
144c0586b87SGarrett D'Amore static void
pvscsi_reg_write(pvscsi_softc_t * pvs,uint32_t offset,uint32_t value)145c0586b87SGarrett D'Amore pvscsi_reg_write(pvscsi_softc_t *pvs, uint32_t offset, uint32_t value)
146c0586b87SGarrett D'Amore {
147c0586b87SGarrett D'Amore ASSERT((offset & (sizeof (uint32_t) - 1)) == 0);
148c0586b87SGarrett D'Amore
149c0586b87SGarrett D'Amore ddi_put32(pvs->mmio_handle, (uint32_t *)(pvs->mmio_base + offset),
150c0586b87SGarrett D'Amore value);
151c0586b87SGarrett D'Amore }
152c0586b87SGarrett D'Amore
153c0586b87SGarrett D'Amore static void
pvscsi_write_cmd_desc(pvscsi_softc_t * pvs,uint32_t cmd,void * desc,size_t len)154c0586b87SGarrett D'Amore pvscsi_write_cmd_desc(pvscsi_softc_t *pvs, uint32_t cmd, void *desc, size_t len)
155c0586b87SGarrett D'Amore {
156c0586b87SGarrett D'Amore len /= sizeof (uint32_t);
157c0586b87SGarrett D'Amore pvscsi_reg_write(pvs, PVSCSI_REG_OFFSET_COMMAND, cmd);
158c0586b87SGarrett D'Amore ddi_rep_put32(pvs->mmio_handle, (uint32_t *)desc,
159c0586b87SGarrett D'Amore (uint32_t *)(pvs->mmio_base + PVSCSI_REG_OFFSET_COMMAND_DATA),
160c0586b87SGarrett D'Amore len, DDI_DEV_NO_AUTOINCR);
161c0586b87SGarrett D'Amore }
162c0586b87SGarrett D'Amore
163c0586b87SGarrett D'Amore static uint32_t
pvscsi_read_intr_status(pvscsi_softc_t * pvs)164c0586b87SGarrett D'Amore pvscsi_read_intr_status(pvscsi_softc_t *pvs)
165c0586b87SGarrett D'Amore {
166c0586b87SGarrett D'Amore return (pvscsi_reg_read(pvs, PVSCSI_REG_OFFSET_INTR_STATUS));
167c0586b87SGarrett D'Amore }
168c0586b87SGarrett D'Amore
169c0586b87SGarrett D'Amore static void
pvscsi_write_intr_status(pvscsi_softc_t * pvs,uint32_t val)170c0586b87SGarrett D'Amore pvscsi_write_intr_status(pvscsi_softc_t *pvs, uint32_t val)
171c0586b87SGarrett D'Amore {
172c0586b87SGarrett D'Amore pvscsi_reg_write(pvs, PVSCSI_REG_OFFSET_INTR_STATUS, val);
173c0586b87SGarrett D'Amore }
174c0586b87SGarrett D'Amore
175c0586b87SGarrett D'Amore static pvscsi_cmd_t *
pvscsi_reclaim_cmds(pvscsi_softc_t * pvs)176c0586b87SGarrett D'Amore pvscsi_reclaim_cmds(pvscsi_softc_t *pvs)
177c0586b87SGarrett D'Amore {
178c0586b87SGarrett D'Amore pvscsi_cmd_t *head = NULL;
179c0586b87SGarrett D'Amore pvscsi_cmd_t **tail = &head;
180c0586b87SGarrett D'Amore pvscsi_cmd_t *cmd;
181c0586b87SGarrett D'Amore
182c0586b87SGarrett D'Amore ASSERT(mutex_owned(&pvs->lock));
183c0586b87SGarrett D'Amore while ((cmd = list_remove_head(&pvs->cmd_queue)) != NULL) {
184c0586b87SGarrett D'Amore list_remove(&pvs->cmd_queue, cmd);
185c0586b87SGarrett D'Amore *tail = cmd;
186c0586b87SGarrett D'Amore tail = &cmd->next_cmd;
187c0586b87SGarrett D'Amore *tail = NULL;
188c0586b87SGarrett D'Amore cmd->host_status = BTSTAT_BUSRESET;
189c0586b87SGarrett D'Amore }
190c0586b87SGarrett D'Amore return (head);
191c0586b87SGarrett D'Amore }
192c0586b87SGarrett D'Amore
193c0586b87SGarrett D'Amore static void
pvscsi_stop_hba(pvscsi_softc_t * pvs)194c0586b87SGarrett D'Amore pvscsi_stop_hba(pvscsi_softc_t *pvs)
195c0586b87SGarrett D'Amore {
196c0586b87SGarrett D'Amore pvscsi_write_cmd_desc(pvs, PVSCSI_CMD_ADAPTER_RESET, NULL, 0);
197c0586b87SGarrett D'Amore pvscsi_reg_write(pvs, PVSCSI_REG_OFFSET_INTR_MASK, 0);
198c0586b87SGarrett D'Amore /* read interrupt status to flush PCI write buffers */
199c0586b87SGarrett D'Amore (void) pvscsi_read_intr_status(pvs);
200c0586b87SGarrett D'Amore }
201c0586b87SGarrett D'Amore
202c0586b87SGarrett D'Amore static void
pvscsi_start_hba(pvscsi_softc_t * pvs)203c0586b87SGarrett D'Amore pvscsi_start_hba(pvscsi_softc_t *pvs)
204c0586b87SGarrett D'Amore {
205c0586b87SGarrett D'Amore pvscsi_setup_rings(pvs);
206c0586b87SGarrett D'Amore pvscsi_reg_write(pvs, PVSCSI_REG_OFFSET_INTR_MASK,
207c0586b87SGarrett D'Amore PVSCSI_INTR_CMPL_MASK | PVSCSI_INTR_MSG_MASK);
208c0586b87SGarrett D'Amore }
209c0586b87SGarrett D'Amore
210c0586b87SGarrett D'Amore static void
pvscsi_reset_bus(pvscsi_softc_t * pvs)211c0586b87SGarrett D'Amore pvscsi_reset_bus(pvscsi_softc_t *pvs)
212c0586b87SGarrett D'Amore {
213c0586b87SGarrett D'Amore pvscsi_write_cmd_desc(pvs, PVSCSI_CMD_RESET_BUS, NULL, 0);
214c0586b87SGarrett D'Amore }
215c0586b87SGarrett D'Amore
216c0586b87SGarrett D'Amore /*
217c0586b87SGarrett D'Amore * pvscsi_restart_hba resets the HBA, and reconfigures it. It also
218c0586b87SGarrett D'Amore * completes all commands that have not been already completed with
219c0586b87SGarrett D'Amore * a reset.
220c0586b87SGarrett D'Amore */
221c0586b87SGarrett D'Amore static void
pvscsi_restart_hba(pvscsi_softc_t * pvs)222c0586b87SGarrett D'Amore pvscsi_restart_hba(pvscsi_softc_t *pvs)
223c0586b87SGarrett D'Amore {
224c0586b87SGarrett D'Amore pvscsi_cmd_t *cmd;
225c0586b87SGarrett D'Amore
226c0586b87SGarrett D'Amore mutex_enter(&pvs->lock);
227c0586b87SGarrett D'Amore pvscsi_stop_hba(pvs);
228c0586b87SGarrett D'Amore cmd = pvscsi_reclaim_cmds(pvs);
229c0586b87SGarrett D'Amore pvscsi_start_hba(pvs);
230c0586b87SGarrett D'Amore mutex_exit(&pvs->lock);
231c0586b87SGarrett D'Amore
232c0586b87SGarrett D'Amore /* run the completions from the reclaimed commands */
233c0586b87SGarrett D'Amore pvscsi_complete_cmds(pvs, cmd);
234c0586b87SGarrett D'Amore }
235c0586b87SGarrett D'Amore
236c0586b87SGarrett D'Amore static void
pvscsi_submit_nonrw_io(pvscsi_softc_t * pvs)237c0586b87SGarrett D'Amore pvscsi_submit_nonrw_io(pvscsi_softc_t *pvs)
238c0586b87SGarrett D'Amore {
239c0586b87SGarrett D'Amore pvscsi_reg_write(pvs, PVSCSI_REG_OFFSET_KICK_NON_RW_IO, 0);
240c0586b87SGarrett D'Amore }
241c0586b87SGarrett D'Amore
242c0586b87SGarrett D'Amore static void
pvscsi_submit_rw_io(pvscsi_softc_t * pvs)243c0586b87SGarrett D'Amore pvscsi_submit_rw_io(pvscsi_softc_t *pvs)
244c0586b87SGarrett D'Amore {
245c0586b87SGarrett D'Amore pvscsi_reg_write(pvs, PVSCSI_REG_OFFSET_KICK_RW_IO, 0);
246c0586b87SGarrett D'Amore }
247c0586b87SGarrett D'Amore
248c0586b87SGarrett D'Amore static pvscsi_cmd_t *
pvscsi_process_comp_ring(pvscsi_softc_t * pvs)249c0586b87SGarrett D'Amore pvscsi_process_comp_ring(pvscsi_softc_t *pvs)
250c0586b87SGarrett D'Amore {
251c0586b87SGarrett D'Amore pvscsi_cmd_t **pnext_cmd;
252c0586b87SGarrett D'Amore pvscsi_cmd_t *cmd;
253c0586b87SGarrett D'Amore pvscsi_cmd_t *head = NULL;
254c0586b87SGarrett D'Amore struct PVSCSIRingsState *sdesc = RINGS_STATE(pvs);
255c0586b87SGarrett D'Amore uint32_t cmp_ne = sdesc->cmpNumEntriesLog2;
256c0586b87SGarrett D'Amore
257c0586b87SGarrett D'Amore ASSERT(mutex_owned(&pvs->lock));
258c0586b87SGarrett D'Amore
259c0586b87SGarrett D'Amore pnext_cmd = &head;
260c0586b87SGarrett D'Amore
261c0586b87SGarrett D'Amore (void) ddi_dma_sync(pvs->state_buf.dmah, 0, 0, DDI_DMA_SYNC_FORKERNEL);
262c0586b87SGarrett D'Amore
263c0586b87SGarrett D'Amore while (sdesc->cmpConsIdx != sdesc->cmpProdIdx) {
264c0586b87SGarrett D'Amore struct PVSCSIRingCmpDesc *cdesc;
265c0586b87SGarrett D'Amore
266c0586b87SGarrett D'Amore (void) ddi_dma_sync(pvs->cmp_ring_buf.dmah, 0, 0,
267c0586b87SGarrett D'Amore DDI_DMA_SYNC_FORKERNEL);
268c0586b87SGarrett D'Amore
269c0586b87SGarrett D'Amore cdesc = CMP_RING(pvs) + (sdesc->cmpConsIdx & MASK(cmp_ne));
270c0586b87SGarrett D'Amore
271c0586b87SGarrett D'Amore if ((cmd = id32_lookup((uint32_t)cdesc->context)) != NULL) {
272c0586b87SGarrett D'Amore cmd->next_cmd = NULL;
273c0586b87SGarrett D'Amore
274c0586b87SGarrett D'Amore /* Save command status for further processing */
275c0586b87SGarrett D'Amore cmd->host_status = cdesc->hostStatus;
276c0586b87SGarrett D'Amore cmd->scsi_status = cdesc->scsiStatus;
277c0586b87SGarrett D'Amore cmd->transferred = cdesc->dataLen;
278c0586b87SGarrett D'Amore
279c0586b87SGarrett D'Amore *pnext_cmd = cmd;
280c0586b87SGarrett D'Amore pnext_cmd = &cmd->next_cmd;
281c0586b87SGarrett D'Amore
282c0586b87SGarrett D'Amore list_remove(&pvs->cmd_queue, cmd);
283c0586b87SGarrett D'Amore }
284c0586b87SGarrett D'Amore
285c0586b87SGarrett D'Amore sdesc->cmpConsIdx++;
286c0586b87SGarrett D'Amore }
287c0586b87SGarrett D'Amore (void) ddi_dma_sync(pvs->state_buf.dmah, 0, 0, DDI_DMA_SYNC_FORDEV);
288c0586b87SGarrett D'Amore
289c0586b87SGarrett D'Amore return (head);
290c0586b87SGarrett D'Amore }
291c0586b87SGarrett D'Amore
292c0586b87SGarrett D'Amore static pvscsi_msg_t *
pvscsi_process_msg_ring(pvscsi_softc_t * pvs)293c0586b87SGarrett D'Amore pvscsi_process_msg_ring(pvscsi_softc_t *pvs)
294c0586b87SGarrett D'Amore {
295c0586b87SGarrett D'Amore pvscsi_msg_t *msg;
296c0586b87SGarrett D'Amore struct PVSCSIRingsState *sdesc = RINGS_STATE(pvs);
297c0586b87SGarrett D'Amore struct PVSCSIRingMsgDesc *mdesc;
298c0586b87SGarrett D'Amore struct PVSCSIMsgDescDevStatusChanged *desc;
299c0586b87SGarrett D'Amore uint32_t msg_ne = sdesc->msgNumEntriesLog2;
300c0586b87SGarrett D'Amore
301c0586b87SGarrett D'Amore (void) ddi_dma_sync(pvs->state_buf.dmah, 0, 0, DDI_DMA_SYNC_FORKERNEL);
302c0586b87SGarrett D'Amore
303c0586b87SGarrett D'Amore if (sdesc->msgProdIdx == sdesc->msgConsIdx) {
304c0586b87SGarrett D'Amore return (NULL);
305c0586b87SGarrett D'Amore }
306c0586b87SGarrett D'Amore
307c0586b87SGarrett D'Amore (void) ddi_dma_sync(pvs->msg_ring_buf.dmah, 0, 0,
308c0586b87SGarrett D'Amore DDI_DMA_SYNC_FORKERNEL);
309c0586b87SGarrett D'Amore
310c0586b87SGarrett D'Amore mdesc = MSG_RING(pvs) + (sdesc->msgConsIdx & MASK(msg_ne));
311c0586b87SGarrett D'Amore
312c0586b87SGarrett D'Amore switch (mdesc->type) {
313c0586b87SGarrett D'Amore case PVSCSI_MSG_DEV_ADDED:
314c0586b87SGarrett D'Amore case PVSCSI_MSG_DEV_REMOVED:
315c0586b87SGarrett D'Amore desc = (struct PVSCSIMsgDescDevStatusChanged *)mdesc;
316c0586b87SGarrett D'Amore msg = kmem_alloc(sizeof (pvscsi_msg_t), KM_NOSLEEP);
317c0586b87SGarrett D'Amore if (msg == NULL)
318c0586b87SGarrett D'Amore return (NULL);
319c0586b87SGarrett D'Amore msg->pvs = pvs;
320c0586b87SGarrett D'Amore msg->type = mdesc->type;
321c0586b87SGarrett D'Amore msg->target = desc->target;
322c0586b87SGarrett D'Amore msg->lun = desc->lun[1]; /* T10 format */
323c0586b87SGarrett D'Amore break;
324c0586b87SGarrett D'Amore default:
325c0586b87SGarrett D'Amore dev_err(pvs->dip, CE_WARN, "!unknown msg type: %d",
326c0586b87SGarrett D'Amore mdesc->type);
327c0586b87SGarrett D'Amore return (NULL);
328c0586b87SGarrett D'Amore }
329c0586b87SGarrett D'Amore
330c0586b87SGarrett D'Amore sdesc->msgConsIdx++;
331c0586b87SGarrett D'Amore (void) ddi_dma_sync(pvs->state_buf.dmah, 0, 0, DDI_DMA_SYNC_FORDEV);
332c0586b87SGarrett D'Amore return (msg);
333c0586b87SGarrett D'Amore }
334c0586b87SGarrett D'Amore
335c0586b87SGarrett D'Amore static void
pvscsi_handle_msg(void * arg)336c0586b87SGarrett D'Amore pvscsi_handle_msg(void *arg)
337c0586b87SGarrett D'Amore {
338c0586b87SGarrett D'Amore pvscsi_msg_t *msg = arg;
339c0586b87SGarrett D'Amore pvscsi_softc_t *pvs = msg->pvs;
340c0586b87SGarrett D'Amore char addr[8];
341c0586b87SGarrett D'Amore
342c0586b87SGarrett D'Amore (void) snprintf(addr, sizeof (addr), "%x", msg->target);
343c0586b87SGarrett D'Amore
344c0586b87SGarrett D'Amore if (msg->lun == 0) {
345c0586b87SGarrett D'Amore switch (msg->type) {
346c0586b87SGarrett D'Amore case PVSCSI_MSG_DEV_ADDED:
347c0586b87SGarrett D'Amore (void) scsi_hba_tgtmap_tgt_add(pvs->tgtmap,
348c0586b87SGarrett D'Amore SCSI_TGT_SCSI_DEVICE, addr, NULL);
349c0586b87SGarrett D'Amore break;
350c0586b87SGarrett D'Amore case PVSCSI_MSG_DEV_REMOVED:
351c0586b87SGarrett D'Amore (void) scsi_hba_tgtmap_tgt_remove(pvs->tgtmap,
352c0586b87SGarrett D'Amore SCSI_TGT_SCSI_DEVICE, addr);
353c0586b87SGarrett D'Amore break;
354c0586b87SGarrett D'Amore }
355c0586b87SGarrett D'Amore } else {
356c0586b87SGarrett D'Amore scsi_hba_tgtmap_scan_luns(pvs->tgtmap, addr);
357c0586b87SGarrett D'Amore }
358c0586b87SGarrett D'Amore kmem_free(msg, sizeof (pvscsi_msg_t));
359c0586b87SGarrett D'Amore }
360c0586b87SGarrett D'Amore
361c0586b87SGarrett D'Amore static void
pvscsi_abort_cmd(pvscsi_softc_t * pvs,pvscsi_cmd_t * cmd)362c0586b87SGarrett D'Amore pvscsi_abort_cmd(pvscsi_softc_t *pvs, pvscsi_cmd_t *cmd)
363c0586b87SGarrett D'Amore {
364c0586b87SGarrett D'Amore struct PVSCSICmdDescAbortCmd acmd;
365c0586b87SGarrett D'Amore
366c0586b87SGarrett D'Amore bzero(&acmd, sizeof (acmd));
367c0586b87SGarrett D'Amore acmd.target = cmd->target;
368c0586b87SGarrett D'Amore acmd.context = cmd->ctx;
369c0586b87SGarrett D'Amore pvscsi_write_cmd_desc(pvs, PVSCSI_CMD_ABORT_CMD, &acmd, sizeof (acmd));
370c0586b87SGarrett D'Amore }
371c0586b87SGarrett D'Amore
372c0586b87SGarrett D'Amore static void
pvscsi_map_buffers(pvscsi_cmd_t * cmd,struct PVSCSIRingReqDesc * rdesc)373c0586b87SGarrett D'Amore pvscsi_map_buffers(pvscsi_cmd_t *cmd, struct PVSCSIRingReqDesc *rdesc)
374c0586b87SGarrett D'Amore {
375c0586b87SGarrett D'Amore struct scsi_pkt *pkt = cmd->pkt;
376c0586b87SGarrett D'Amore
377c0586b87SGarrett D'Amore rdesc->dataLen = 0;
378c0586b87SGarrett D'Amore rdesc->dataAddr = 0;
379c0586b87SGarrett D'Amore if (pkt == NULL || pkt->pkt_numcookies == 0) {
380c0586b87SGarrett D'Amore return;
381c0586b87SGarrett D'Amore }
382c0586b87SGarrett D'Amore
383c0586b87SGarrett D'Amore pkt->pkt_resid = 0;
384c0586b87SGarrett D'Amore
385c0586b87SGarrett D'Amore if (pkt->pkt_numcookies > 1) {
386c0586b87SGarrett D'Amore size_t len = 0;
387c0586b87SGarrett D'Amore struct PVSCSISGElement *sgl = cmd->sgl;
388c0586b87SGarrett D'Amore
389c0586b87SGarrett D'Amore for (uint_t i = 0; i < pkt->pkt_numcookies; i++) {
390c0586b87SGarrett D'Amore sgl[i].addr = pkt->pkt_cookies[i].dmac_laddress;
391c0586b87SGarrett D'Amore sgl[i].length = pkt->pkt_cookies[i].dmac_size;
392c0586b87SGarrett D'Amore sgl[i].flags = 0;
393c0586b87SGarrett D'Amore len += pkt->pkt_cookies[i].dmac_size;
394c0586b87SGarrett D'Amore }
395c0586b87SGarrett D'Amore rdesc->flags |= PVSCSI_FLAG_CMD_WITH_SG_LIST;
396c0586b87SGarrett D'Amore rdesc->dataAddr = cmd->sgl_pa;
397c0586b87SGarrett D'Amore rdesc->dataLen = len;
398c0586b87SGarrett D'Amore (void) ddi_dma_sync(cmd->sgl_dmah, 0, 0, DDI_DMA_SYNC_FORDEV);
399c0586b87SGarrett D'Amore } else {
400c0586b87SGarrett D'Amore rdesc->flags = 0;
401c0586b87SGarrett D'Amore rdesc->dataAddr = pkt->pkt_cookies[0].dmac_laddress;
402c0586b87SGarrett D'Amore rdesc->dataLen = pkt->pkt_cookies[0].dmac_size;
403c0586b87SGarrett D'Amore }
404c0586b87SGarrett D'Amore pkt->pkt_resid = rdesc->dataLen;
405c0586b87SGarrett D'Amore }
406c0586b87SGarrett D'Amore
407c0586b87SGarrett D'Amore static void
pvscsi_comp_cmd(pvscsi_cmd_t * cmd)408c0586b87SGarrett D'Amore pvscsi_comp_cmd(pvscsi_cmd_t *cmd)
409c0586b87SGarrett D'Amore {
410c0586b87SGarrett D'Amore struct scsi_pkt *pkt = cmd->pkt;
411c0586b87SGarrett D'Amore uint8_t status = cmd->scsi_status;
412c0586b87SGarrett D'Amore
413c0586b87SGarrett D'Amore pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET | STATE_SENT_CMD |
414c0586b87SGarrett D'Amore STATE_GOT_STATUS);
415c0586b87SGarrett D'Amore if (pkt->pkt_numcookies > 0) {
416c0586b87SGarrett D'Amore pkt->pkt_state |= STATE_XFERRED_DATA;
417c0586b87SGarrett D'Amore }
418c0586b87SGarrett D'Amore pkt->pkt_reason = CMD_CMPLT;
419c0586b87SGarrett D'Amore pkt->pkt_resid -= cmd->transferred;
420c0586b87SGarrett D'Amore *(pkt->pkt_scbp) = status;
421c0586b87SGarrett D'Amore
422c0586b87SGarrett D'Amore if (status == STATUS_CHECK) {
423c0586b87SGarrett D'Amore /*
424c0586b87SGarrett D'Amore * Our virtual HBA *always* does ARQ, and it never
425c0586b87SGarrett D'Amore * is more than 20 bytes, so no need to try to handle
426c0586b87SGarrett D'Amore * extended versions of it.
427c0586b87SGarrett D'Amore */
428c0586b87SGarrett D'Amore struct scsi_arq_status *ars = (void *)(pkt->pkt_scbp);
429c0586b87SGarrett D'Amore int len = min(pkt->pkt_scblen, SENSE_LENGTH);
430c0586b87SGarrett D'Amore
431c0586b87SGarrett D'Amore pkt->pkt_state |= STATE_ARQ_DONE;
432c0586b87SGarrett D'Amore ars->sts_rqpkt_resid = 0;
433c0586b87SGarrett D'Amore bcopy(cmd->arq_sense, &ars->sts_sensedata, len);
434c0586b87SGarrett D'Amore ars->sts_rqpkt_reason = CMD_CMPLT;
435c0586b87SGarrett D'Amore *(uint8_t *)&ars->sts_rqpkt_status = STATUS_GOOD;
436c0586b87SGarrett D'Amore ars->sts_rqpkt_state = STATE_GOT_BUS |
437c0586b87SGarrett D'Amore STATE_GOT_TARGET | STATE_SENT_CMD |
438c0586b87SGarrett D'Amore STATE_XFERRED_DATA | STATE_GOT_STATUS;
439c0586b87SGarrett D'Amore }
440c0586b87SGarrett D'Amore }
441c0586b87SGarrett D'Amore
442c0586b87SGarrett D'Amore static void
pvscsi_set_status(pvscsi_softc_t * pvs,pvscsi_cmd_t * cmd)443c0586b87SGarrett D'Amore pvscsi_set_status(pvscsi_softc_t *pvs, pvscsi_cmd_t *cmd)
444c0586b87SGarrett D'Amore {
445c0586b87SGarrett D'Amore struct scsi_pkt *pkt = cmd->pkt;
446c0586b87SGarrett D'Amore uint32_t host_status = cmd->host_status;
447c0586b87SGarrett D'Amore
448c0586b87SGarrett D'Amore switch (host_status) {
449c0586b87SGarrett D'Amore case BTSTAT_SUCCESS:
450c0586b87SGarrett D'Amore case BTSTAT_LINKED_COMMAND_COMPLETED:
451c0586b87SGarrett D'Amore case BTSTAT_LINKED_COMMAND_COMPLETED_WITH_FLAG:
452c0586b87SGarrett D'Amore pvscsi_comp_cmd(cmd);
453c0586b87SGarrett D'Amore break;
454c0586b87SGarrett D'Amore case BTSTAT_DATARUN:
455c0586b87SGarrett D'Amore pkt->pkt_reason = CMD_DATA_OVR;
456c0586b87SGarrett D'Amore pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET |
457c0586b87SGarrett D'Amore STATE_SENT_CMD | STATE_GOT_STATUS |
458c0586b87SGarrett D'Amore STATE_XFERRED_DATA);
459c0586b87SGarrett D'Amore pkt->pkt_resid -= cmd->transferred;
460c0586b87SGarrett D'Amore break;
461c0586b87SGarrett D'Amore case BTSTAT_SELTIMEO:
462c0586b87SGarrett D'Amore pkt->pkt_reason = CMD_DEV_GONE;
463c0586b87SGarrett D'Amore pkt->pkt_state |= STATE_GOT_BUS;
464c0586b87SGarrett D'Amore break;
465c0586b87SGarrett D'Amore case BTSTAT_TAGREJECT:
466c0586b87SGarrett D'Amore pkt->pkt_reason = CMD_TAG_REJECT;
467c0586b87SGarrett D'Amore pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET |
468c0586b87SGarrett D'Amore STATE_SENT_CMD | STATE_GOT_STATUS);
469c0586b87SGarrett D'Amore break;
470c0586b87SGarrett D'Amore case BTSTAT_BADMSG:
471c0586b87SGarrett D'Amore pkt->pkt_reason = CMD_BADMSG;
472c0586b87SGarrett D'Amore pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET |
473c0586b87SGarrett D'Amore STATE_SENT_CMD | STATE_GOT_STATUS);
474c0586b87SGarrett D'Amore break;
475c0586b87SGarrett D'Amore case BTSTAT_SENTRST:
476c0586b87SGarrett D'Amore case BTSTAT_RECVRST:
477c0586b87SGarrett D'Amore pkt->pkt_reason = CMD_RESET;
478c0586b87SGarrett D'Amore pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET |
479c0586b87SGarrett D'Amore STATE_SENT_CMD | STATE_GOT_STATUS);
480c0586b87SGarrett D'Amore pkt->pkt_statistics |= STAT_DEV_RESET;
481c0586b87SGarrett D'Amore pkt->pkt_resid -= cmd->transferred;
482c0586b87SGarrett D'Amore break;
483c0586b87SGarrett D'Amore case BTSTAT_BUSRESET:
484c0586b87SGarrett D'Amore pkt->pkt_reason = CMD_RESET;
485c0586b87SGarrett D'Amore pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET |
486c0586b87SGarrett D'Amore STATE_SENT_CMD | STATE_GOT_STATUS);
487c0586b87SGarrett D'Amore pkt->pkt_statistics |= STAT_BUS_RESET;
488c0586b87SGarrett D'Amore pkt->pkt_resid -= cmd->transferred;
489c0586b87SGarrett D'Amore break;
490c0586b87SGarrett D'Amore case BTSTAT_ABORTQUEUE:
491c0586b87SGarrett D'Amore if (cmd->expired) {
492c0586b87SGarrett D'Amore pkt->pkt_reason = CMD_TIMEOUT;
493c0586b87SGarrett D'Amore pkt->pkt_statistics |= STAT_TIMEOUT;
494c0586b87SGarrett D'Amore } else {
495c0586b87SGarrett D'Amore pkt->pkt_reason = CMD_ABORTED;
496c0586b87SGarrett D'Amore pkt->pkt_statistics |= STAT_ABORTED;
497c0586b87SGarrett D'Amore }
498c0586b87SGarrett D'Amore pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET |
499c0586b87SGarrett D'Amore STATE_SENT_CMD | STATE_GOT_STATUS);
500c0586b87SGarrett D'Amore pkt->pkt_resid -= cmd->transferred;
501c0586b87SGarrett D'Amore break;
502c0586b87SGarrett D'Amore case BTSTAT_HAHARDWARE:
503c0586b87SGarrett D'Amore case BTSTAT_INVPHASE:
504c0586b87SGarrett D'Amore case BTSTAT_HATIMEOUT:
505c0586b87SGarrett D'Amore case BTSTAT_NORESPONSE:
506c0586b87SGarrett D'Amore case BTSTAT_DISCONNECT:
507c0586b87SGarrett D'Amore case BTSTAT_HASOFTWARE:
508c0586b87SGarrett D'Amore case BTSTAT_BUSFREE:
509c0586b87SGarrett D'Amore case BTSTAT_SENSFAILED:
510c0586b87SGarrett D'Amore case BTSTAT_DATA_UNDERRUN:
511c0586b87SGarrett D'Amore pkt->pkt_reason = CMD_TRAN_ERR;
512c0586b87SGarrett D'Amore pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET |
513c0586b87SGarrett D'Amore STATE_SENT_CMD | STATE_GOT_STATUS);
514c0586b87SGarrett D'Amore pkt->pkt_resid -= cmd->transferred;
515c0586b87SGarrett D'Amore break;
516c0586b87SGarrett D'Amore default:
517c0586b87SGarrett D'Amore dev_err(pvs->dip, CE_WARN,
518c0586b87SGarrett D'Amore "!unknown host status code: %d", host_status);
519c0586b87SGarrett D'Amore pkt->pkt_reason = CMD_TRAN_ERR;
520c0586b87SGarrett D'Amore pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET |
521c0586b87SGarrett D'Amore STATE_SENT_CMD | STATE_GOT_STATUS);
522c0586b87SGarrett D'Amore break;
523c0586b87SGarrett D'Amore }
524c0586b87SGarrett D'Amore }
525c0586b87SGarrett D'Amore
526c0586b87SGarrett D'Amore /*
527c0586b87SGarrett D'Amore * pvscsi_complete_cmds processes a linked list of
528c0586b87SGarrett D'Amore * commands that have been completed. This is done
529c0586b87SGarrett D'Amore * without acquiring any locks.
530c0586b87SGarrett D'Amore */
531c0586b87SGarrett D'Amore static void
pvscsi_complete_cmds(pvscsi_softc_t * pvs,pvscsi_cmd_t * cmd)532c0586b87SGarrett D'Amore pvscsi_complete_cmds(pvscsi_softc_t *pvs, pvscsi_cmd_t *cmd)
533c0586b87SGarrett D'Amore {
534c0586b87SGarrett D'Amore struct scsi_pkt *pkt;
535c0586b87SGarrett D'Amore
536c0586b87SGarrett D'Amore while (cmd != NULL) {
537c0586b87SGarrett D'Amore pvscsi_cmd_t *next = cmd->next_cmd;
538c0586b87SGarrett D'Amore
539c0586b87SGarrett D'Amore cmd->next_cmd = NULL;
540c0586b87SGarrett D'Amore
541c0586b87SGarrett D'Amore if (((pkt = cmd->pkt) == NULL) || (cmd->poll)) {
542c0586b87SGarrett D'Amore atomic_or_8(&cmd->done, 1);
543c0586b87SGarrett D'Amore } else {
544c0586b87SGarrett D'Amore pvscsi_set_status(pvs, cmd);
545c0586b87SGarrett D'Amore scsi_hba_pkt_comp(pkt);
546c0586b87SGarrett D'Amore }
547c0586b87SGarrett D'Amore
548c0586b87SGarrett D'Amore cmd = next;
549c0586b87SGarrett D'Amore }
550c0586b87SGarrett D'Amore }
551c0586b87SGarrett D'Amore
552c0586b87SGarrett D'Amore static void
pvscsi_dev_reset(pvscsi_softc_t * pvs,int target,int lun)553c0586b87SGarrett D'Amore pvscsi_dev_reset(pvscsi_softc_t *pvs, int target, int lun)
554c0586b87SGarrett D'Amore {
555c0586b87SGarrett D'Amore struct PVSCSICmdDescResetDevice cmd = { 0 };
556c0586b87SGarrett D'Amore
557c0586b87SGarrett D'Amore cmd.target = target;
558c0586b87SGarrett D'Amore cmd.lun[1] = lun & 0xff;
559c0586b87SGarrett D'Amore pvscsi_write_cmd_desc(pvs, PVSCSI_CMD_RESET_DEVICE, &cmd, sizeof (cmd));
560c0586b87SGarrett D'Amore }
561c0586b87SGarrett D'Amore
562c0586b87SGarrett D'Amore static boolean_t
pvscsi_poll_cmd_until(pvscsi_softc_t * pvs,pvscsi_cmd_t * cmd,clock_t usec)563c0586b87SGarrett D'Amore pvscsi_poll_cmd_until(pvscsi_softc_t *pvs, pvscsi_cmd_t *cmd, clock_t usec)
564c0586b87SGarrett D'Amore {
565c0586b87SGarrett D'Amore while (usec > 0) {
566c0586b87SGarrett D'Amore pvscsi_cmd_t *done;
567c0586b87SGarrett D'Amore if (cmd->done) {
568c0586b87SGarrett D'Amore return (B_TRUE);
569c0586b87SGarrett D'Amore }
570c0586b87SGarrett D'Amore mutex_enter(&pvs->lock);
571c0586b87SGarrett D'Amore done = pvscsi_process_comp_ring(pvs);
572c0586b87SGarrett D'Amore mutex_exit(&pvs->lock);
573c0586b87SGarrett D'Amore
574c0586b87SGarrett D'Amore pvscsi_complete_cmds(pvs, done);
575c0586b87SGarrett D'Amore drv_usecwait(10);
576c0586b87SGarrett D'Amore usec -= 10;
577c0586b87SGarrett D'Amore }
578c0586b87SGarrett D'Amore
579c0586b87SGarrett D'Amore return (B_FALSE);
580c0586b87SGarrett D'Amore }
581c0586b87SGarrett D'Amore
582c0586b87SGarrett D'Amore static void
pvscsi_poll_cmd(pvscsi_softc_t * pvs,pvscsi_cmd_t * cmd)583c0586b87SGarrett D'Amore pvscsi_poll_cmd(pvscsi_softc_t *pvs, pvscsi_cmd_t *cmd)
584c0586b87SGarrett D'Amore {
585c0586b87SGarrett D'Amore if (pvscsi_poll_cmd_until(pvs, cmd, drv_hztousec(cmd->timeout))) {
586c0586b87SGarrett D'Amore return;
587c0586b87SGarrett D'Amore }
588c0586b87SGarrett D'Amore
589c0586b87SGarrett D'Amore /* now we try an abort first */
590c0586b87SGarrett D'Amore pvscsi_abort_cmd(pvs, cmd);
591c0586b87SGarrett D'Amore if (pvscsi_poll_cmd_until(pvs, cmd, 2)) {
592c0586b87SGarrett D'Amore return;
593c0586b87SGarrett D'Amore }
594c0586b87SGarrett D'Amore /* well that failed... try reset */
595c0586b87SGarrett D'Amore pvscsi_dev_reset(pvs, cmd->target, cmd->lun);
596c0586b87SGarrett D'Amore if (pvscsi_poll_cmd_until(pvs, cmd, 2)) {
597c0586b87SGarrett D'Amore return;
598c0586b87SGarrett D'Amore }
599c0586b87SGarrett D'Amore /* still trying... reset the bus */
600c0586b87SGarrett D'Amore pvscsi_reset_bus(pvs);
601c0586b87SGarrett D'Amore if (pvscsi_poll_cmd_until(pvs, cmd, 2)) {
602c0586b87SGarrett D'Amore return;
603c0586b87SGarrett D'Amore }
604c0586b87SGarrett D'Amore /* full up adapter reset -- be brutal */
605c0586b87SGarrett D'Amore pvscsi_restart_hba(pvs);
606c0586b87SGarrett D'Amore }
607c0586b87SGarrett D'Amore
608c0586b87SGarrett D'Amore static void
pvscsi_abort_all(pvscsi_softc_t * pvs,pvscsi_device_t * pd)609c0586b87SGarrett D'Amore pvscsi_abort_all(pvscsi_softc_t *pvs, pvscsi_device_t *pd)
610c0586b87SGarrett D'Amore {
611c0586b87SGarrett D'Amore pvscsi_cmd_t *cmd;
612c0586b87SGarrett D'Amore
613c0586b87SGarrett D'Amore mutex_enter(&pvs->lock);
614c0586b87SGarrett D'Amore list_t *l = &pvs->cmd_queue;
615c0586b87SGarrett D'Amore for (cmd = list_head(l); cmd != NULL; cmd = list_next(l, cmd)) {
616c0586b87SGarrett D'Amore if ((pd->target == cmd->target) && (pd->lun == cmd->lun)) {
617c0586b87SGarrett D'Amore pvscsi_abort_cmd(pvs, cmd);
618c0586b87SGarrett D'Amore }
619c0586b87SGarrett D'Amore }
620c0586b87SGarrett D'Amore mutex_exit(&pvs->lock);
621c0586b87SGarrett D'Amore }
622c0586b87SGarrett D'Amore
623c0586b87SGarrett D'Amore static int
pvscsi_transport_command(pvscsi_softc_t * pvs,pvscsi_cmd_t * cmd)624c0586b87SGarrett D'Amore pvscsi_transport_command(pvscsi_softc_t *pvs, pvscsi_cmd_t *cmd)
625c0586b87SGarrett D'Amore {
626c0586b87SGarrett D'Amore struct PVSCSIRingReqDesc *rdesc;
627c0586b87SGarrett D'Amore struct PVSCSIRingsState *sdesc = RINGS_STATE(pvs);
628c0586b87SGarrett D'Amore uint32_t req_ne = sdesc->reqNumEntriesLog2;
629c0586b87SGarrett D'Amore
630c0586b87SGarrett D'Amore cmd->done = 0;
631c0586b87SGarrett D'Amore cmd->expired = 0;
632c0586b87SGarrett D'Amore
633c0586b87SGarrett D'Amore mutex_enter(&pvs->lock);
634c0586b87SGarrett D'Amore
635c0586b87SGarrett D'Amore if ((sdesc->reqProdIdx - sdesc->cmpConsIdx) >= (1 << req_ne)) {
636c0586b87SGarrett D'Amore mutex_exit(&pvs->lock);
637c0586b87SGarrett D'Amore return (TRAN_BUSY);
638c0586b87SGarrett D'Amore }
639c0586b87SGarrett D'Amore
640c0586b87SGarrett D'Amore rdesc = REQ_RING(pvs) + (sdesc->reqProdIdx & MASK(req_ne));
641c0586b87SGarrett D'Amore
642c0586b87SGarrett D'Amore rdesc->bus = 0;
643c0586b87SGarrett D'Amore rdesc->target = cmd->target;
644c0586b87SGarrett D'Amore bzero(rdesc->lun, sizeof (rdesc->lun));
645c0586b87SGarrett D'Amore /* Matches other implementations; can pvscsi support luns > 255? */
646c0586b87SGarrett D'Amore rdesc->lun[1] = cmd->lun & 0xff;
647c0586b87SGarrett D'Amore
648c0586b87SGarrett D'Amore bzero(cmd->arq_sense, sizeof (cmd->arq_sense));
649c0586b87SGarrett D'Amore rdesc->context = cmd->ctx;
650c0586b87SGarrett D'Amore rdesc->senseLen = sizeof (cmd->arq_sense);
651c0586b87SGarrett D'Amore rdesc->senseAddr = cmd->arq_pa;
652c0586b87SGarrett D'Amore rdesc->tag = cmd->tag;
653c0586b87SGarrett D'Amore rdesc->vcpuHint = CPU->cpu_id;
654c0586b87SGarrett D'Amore rdesc->cdbLen = cmd->cdblen;
655c0586b87SGarrett D'Amore rdesc->flags = cmd->dma_dir;
656c0586b87SGarrett D'Amore bcopy(cmd->cdb, rdesc->cdb, cmd->cdblen);
657c0586b87SGarrett D'Amore pvscsi_map_buffers(cmd, rdesc);
658c0586b87SGarrett D'Amore
659c0586b87SGarrett D'Amore (void) ddi_dma_sync(pvs->req_ring_buf.dmah, 0, 0, DDI_DMA_SYNC_FORDEV);
660c0586b87SGarrett D'Amore
661c0586b87SGarrett D'Amore sdesc->reqProdIdx++;
662c0586b87SGarrett D'Amore (void) ddi_dma_sync(pvs->state_buf.dmah, 0, 0, DDI_DMA_SYNC_FORDEV);
663c0586b87SGarrett D'Amore
664c0586b87SGarrett D'Amore pvscsi_add_to_queue(pvs, cmd);
665c0586b87SGarrett D'Amore
666c0586b87SGarrett D'Amore switch (cmd->cdb[0]) {
667c0586b87SGarrett D'Amore case SCMD_READ:
668c0586b87SGarrett D'Amore case SCMD_WRITE:
669c0586b87SGarrett D'Amore case SCMD_READ_G1:
670c0586b87SGarrett D'Amore case SCMD_WRITE_G1:
671c0586b87SGarrett D'Amore case SCMD_READ_G4:
672c0586b87SGarrett D'Amore case SCMD_WRITE_G4:
673c0586b87SGarrett D'Amore case SCMD_READ_G5:
674c0586b87SGarrett D'Amore case SCMD_WRITE_G5:
675c0586b87SGarrett D'Amore pvscsi_submit_rw_io(pvs);
676c0586b87SGarrett D'Amore break;
677c0586b87SGarrett D'Amore default:
678c0586b87SGarrett D'Amore pvscsi_submit_nonrw_io(pvs);
679c0586b87SGarrett D'Amore break;
680c0586b87SGarrett D'Amore }
681c0586b87SGarrett D'Amore
682c0586b87SGarrett D'Amore if (pvs->timeout == 0) {
683c0586b87SGarrett D'Amore /* drivers above should supply, but give a default */
684c0586b87SGarrett D'Amore pvs->timeout = timeout(pvscsi_timeout, pvs, pvscsi_hz * 8);
685c0586b87SGarrett D'Amore }
686c0586b87SGarrett D'Amore mutex_exit(&pvs->lock);
687c0586b87SGarrett D'Amore
688c0586b87SGarrett D'Amore return (TRAN_ACCEPT);
689c0586b87SGarrett D'Amore }
690c0586b87SGarrett D'Amore
691c0586b87SGarrett D'Amore static int
pvscsi_setup_dma_buffer(pvscsi_softc_t * pvs,size_t length,pvscsi_dma_buf_t * buf)692c0586b87SGarrett D'Amore pvscsi_setup_dma_buffer(pvscsi_softc_t *pvs, size_t length,
693c0586b87SGarrett D'Amore pvscsi_dma_buf_t *buf)
694c0586b87SGarrett D'Amore {
695c0586b87SGarrett D'Amore if ((ddi_dma_alloc_handle(pvs->dip, &pvscsi_dma_attr,
696c0586b87SGarrett D'Amore DDI_DMA_SLEEP, NULL, &buf->dmah)) != DDI_SUCCESS) {
697c0586b87SGarrett D'Amore dev_err(pvs->dip, CE_WARN, "!failed to alloc DMA handle");
698c0586b87SGarrett D'Amore return (DDI_FAILURE);
699c0586b87SGarrett D'Amore }
700c0586b87SGarrett D'Amore
701c0586b87SGarrett D'Amore if ((ddi_dma_mem_alloc(buf->dmah, length, &pvscsi_dma_attrs,
702c0586b87SGarrett D'Amore DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &buf->addr,
703c0586b87SGarrett D'Amore &length, &buf->acch)) != DDI_SUCCESS) {
704c0586b87SGarrett D'Amore dev_err(pvs->dip, CE_WARN, "!failed to alloc DMA memory");
705c0586b87SGarrett D'Amore return (DDI_FAILURE);
706c0586b87SGarrett D'Amore }
707c0586b87SGarrett D'Amore
708c0586b87SGarrett D'Amore if ((ddi_dma_addr_bind_handle(buf->dmah, NULL, buf->addr,
709c0586b87SGarrett D'Amore length, DDI_DMA_CONSISTENT | DDI_DMA_RDWR, DDI_DMA_SLEEP,
710c0586b87SGarrett D'Amore NULL, NULL, NULL)) != DDI_SUCCESS) {
711c0586b87SGarrett D'Amore dev_err(pvs->dip, CE_WARN, "!failed to bind DMA buffer");
712c0586b87SGarrett D'Amore return (DDI_FAILURE);
713c0586b87SGarrett D'Amore }
714c0586b87SGarrett D'Amore
715c0586b87SGarrett D'Amore buf->pa = ddi_dma_cookie_one(buf->dmah)->dmac_laddress;
716c0586b87SGarrett D'Amore
717c0586b87SGarrett D'Amore return (DDI_SUCCESS);
718c0586b87SGarrett D'Amore }
719c0586b87SGarrett D'Amore
720c0586b87SGarrett D'Amore static void
pvscsi_free_dma_buffer(pvscsi_dma_buf_t * buf)721c0586b87SGarrett D'Amore pvscsi_free_dma_buffer(pvscsi_dma_buf_t *buf)
722c0586b87SGarrett D'Amore {
723c0586b87SGarrett D'Amore if (buf->pa != 0) {
724c0586b87SGarrett D'Amore (void) ddi_dma_unbind_handle(buf->dmah);
725c0586b87SGarrett D'Amore }
726c0586b87SGarrett D'Amore if (buf->acch != NULL) {
727c0586b87SGarrett D'Amore ddi_dma_mem_free(&buf->acch);
728c0586b87SGarrett D'Amore }
729c0586b87SGarrett D'Amore if (buf->dmah != NULL) {
730c0586b87SGarrett D'Amore ddi_dma_free_handle(&buf->dmah);
731c0586b87SGarrett D'Amore }
732c0586b87SGarrett D'Amore }
733c0586b87SGarrett D'Amore
734c0586b87SGarrett D'Amore static int
pvscsi_allocate_rings(pvscsi_softc_t * pvs)735c0586b87SGarrett D'Amore pvscsi_allocate_rings(pvscsi_softc_t *pvs)
736c0586b87SGarrett D'Amore {
737c0586b87SGarrett D'Amore /* allocate DMA buffer for rings state */
738c0586b87SGarrett D'Amore if (pvscsi_setup_dma_buffer(pvs, PAGE_SIZE, &pvs->state_buf) !=
739c0586b87SGarrett D'Amore DDI_SUCCESS) {
740c0586b87SGarrett D'Amore return (DDI_FAILURE);
741c0586b87SGarrett D'Amore }
742c0586b87SGarrett D'Amore
743c0586b87SGarrett D'Amore /* allocate DMA buffer for request ring */
744c0586b87SGarrett D'Amore pvs->req_pages = MIN(pvscsi_ring_pages, PVSCSI_MAX_NUM_PAGES_REQ_RING);
745c0586b87SGarrett D'Amore pvs->req_depth = pvs->req_pages * PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE;
746c0586b87SGarrett D'Amore if (pvscsi_setup_dma_buffer(pvs, pvs->req_pages * PAGE_SIZE,
747c0586b87SGarrett D'Amore &pvs->req_ring_buf) != DDI_SUCCESS) {
748c0586b87SGarrett D'Amore return (DDI_FAILURE);
749c0586b87SGarrett D'Amore }
750c0586b87SGarrett D'Amore
751c0586b87SGarrett D'Amore /* allocate completion ring */
752c0586b87SGarrett D'Amore pvs->cmp_pages = MIN(pvscsi_ring_pages, PVSCSI_MAX_NUM_PAGES_CMP_RING);
753c0586b87SGarrett D'Amore if (pvscsi_setup_dma_buffer(pvs, pvs->cmp_pages * PAGE_SIZE,
754c0586b87SGarrett D'Amore &pvs->cmp_ring_buf) != DDI_SUCCESS) {
755c0586b87SGarrett D'Amore return (DDI_FAILURE);
756c0586b87SGarrett D'Amore }
757c0586b87SGarrett D'Amore
758c0586b87SGarrett D'Amore /* allocate message ring */
759c0586b87SGarrett D'Amore pvs->msg_pages = MIN(pvscsi_msg_ring_pages,
760c0586b87SGarrett D'Amore PVSCSI_MAX_NUM_PAGES_MSG_RING);
761c0586b87SGarrett D'Amore if (pvscsi_setup_dma_buffer(pvs, pvs->msg_pages * PAGE_SIZE,
762c0586b87SGarrett D'Amore &pvs->msg_ring_buf) != DDI_SUCCESS) {
763c0586b87SGarrett D'Amore return (DDI_FAILURE);
764c0586b87SGarrett D'Amore }
765c0586b87SGarrett D'Amore
766c0586b87SGarrett D'Amore return (DDI_SUCCESS);
767c0586b87SGarrett D'Amore }
768c0586b87SGarrett D'Amore
769c0586b87SGarrett D'Amore static void
pvscsi_free_rings(pvscsi_softc_t * pvs)770c0586b87SGarrett D'Amore pvscsi_free_rings(pvscsi_softc_t *pvs)
771c0586b87SGarrett D'Amore {
772c0586b87SGarrett D'Amore pvscsi_free_dma_buffer(&pvs->msg_ring_buf);
773c0586b87SGarrett D'Amore pvscsi_free_dma_buffer(&pvs->cmp_ring_buf);
774c0586b87SGarrett D'Amore pvscsi_free_dma_buffer(&pvs->req_ring_buf);
775c0586b87SGarrett D'Amore pvscsi_free_dma_buffer(&pvs->state_buf);
776c0586b87SGarrett D'Amore }
777c0586b87SGarrett D'Amore
778c0586b87SGarrett D'Amore static void
pvscsi_setup_rings(pvscsi_softc_t * pvs)779c0586b87SGarrett D'Amore pvscsi_setup_rings(pvscsi_softc_t *pvs)
780c0586b87SGarrett D'Amore {
781c0586b87SGarrett D'Amore int i;
782c0586b87SGarrett D'Amore struct PVSCSICmdDescSetupMsgRing cmd_msg = { 0 };
783c0586b87SGarrett D'Amore struct PVSCSICmdDescSetupRings cmd = { 0 };
784c0586b87SGarrett D'Amore uint64_t base;
785c0586b87SGarrett D'Amore
786c0586b87SGarrett D'Amore cmd.ringsStatePPN = pvs->state_buf.pa >> PAGE_SHIFT;
787c0586b87SGarrett D'Amore cmd.reqRingNumPages = pvs->req_pages;
788c0586b87SGarrett D'Amore cmd.cmpRingNumPages = pvs->cmp_pages;
789c0586b87SGarrett D'Amore
790c0586b87SGarrett D'Amore /* Setup request ring */
791c0586b87SGarrett D'Amore base = pvs->req_ring_buf.pa;
792c0586b87SGarrett D'Amore for (i = 0; i < pvs->req_pages; i++) {
793c0586b87SGarrett D'Amore cmd.reqRingPPNs[i] = base >> PAGE_SHIFT;
794c0586b87SGarrett D'Amore base += PAGE_SIZE;
795c0586b87SGarrett D'Amore }
796c0586b87SGarrett D'Amore
797c0586b87SGarrett D'Amore /* Setup completion ring */
798c0586b87SGarrett D'Amore base = pvs->cmp_ring_buf.pa;
799c0586b87SGarrett D'Amore for (i = 0; i < pvs->cmp_pages; i++) {
800c0586b87SGarrett D'Amore cmd.cmpRingPPNs[i] = base >> PAGE_SHIFT;
801c0586b87SGarrett D'Amore base += PAGE_SIZE;
802c0586b87SGarrett D'Amore }
803c0586b87SGarrett D'Amore
804c0586b87SGarrett D'Amore bzero(RINGS_STATE(pvs), PAGE_SIZE);
805c0586b87SGarrett D'Amore bzero(REQ_RING(pvs), pvs->req_pages * PAGE_SIZE);
806c0586b87SGarrett D'Amore bzero(CMP_RING(pvs), pvs->cmp_pages * PAGE_SIZE);
807c0586b87SGarrett D'Amore
808c0586b87SGarrett D'Amore /* Issue SETUP command */
809c0586b87SGarrett D'Amore pvscsi_write_cmd_desc(pvs, PVSCSI_CMD_SETUP_RINGS, &cmd, sizeof (cmd));
810c0586b87SGarrett D'Amore
811c0586b87SGarrett D'Amore /* Setup message ring */
812c0586b87SGarrett D'Amore cmd_msg.numPages = pvs->msg_pages;
813c0586b87SGarrett D'Amore base = pvs->msg_ring_buf.pa;
814c0586b87SGarrett D'Amore
815c0586b87SGarrett D'Amore for (i = 0; i < pvs->msg_pages; i++) {
816c0586b87SGarrett D'Amore cmd_msg.ringPPNs[i] = base >> PAGE_SHIFT;
817c0586b87SGarrett D'Amore base += PAGE_SIZE;
818c0586b87SGarrett D'Amore }
819c0586b87SGarrett D'Amore bzero(MSG_RING(pvs), pvs->msg_pages * PAGE_SIZE);
820c0586b87SGarrett D'Amore
821c0586b87SGarrett D'Amore pvscsi_write_cmd_desc(pvs, PVSCSI_CMD_SETUP_MSG_RING, &cmd_msg,
822c0586b87SGarrett D'Amore sizeof (cmd_msg));
823c0586b87SGarrett D'Amore }
824c0586b87SGarrett D'Amore
825c0586b87SGarrett D'Amore static int
pvscsi_setup_io(pvscsi_softc_t * pvs)826c0586b87SGarrett D'Amore pvscsi_setup_io(pvscsi_softc_t *pvs)
827c0586b87SGarrett D'Amore {
828c0586b87SGarrett D'Amore int offset, rcount, rn, type;
829c0586b87SGarrett D'Amore int ret = DDI_FAILURE;
830c0586b87SGarrett D'Amore off_t regsize;
831c0586b87SGarrett D'Amore pci_regspec_t *regs;
832c0586b87SGarrett D'Amore uint_t regs_length;
833c0586b87SGarrett D'Amore
834c0586b87SGarrett D'Amore if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, pvs->dip,
835c0586b87SGarrett D'Amore DDI_PROP_DONTPASS, "reg", (int **)®s,
836c0586b87SGarrett D'Amore ®s_length) != DDI_PROP_SUCCESS) {
837c0586b87SGarrett D'Amore dev_err(pvs->dip, CE_WARN, "!failed to lookup 'reg' property");
838c0586b87SGarrett D'Amore return (DDI_FAILURE);
839c0586b87SGarrett D'Amore }
840c0586b87SGarrett D'Amore
841c0586b87SGarrett D'Amore rcount = regs_length * sizeof (int) / sizeof (pci_regspec_t);
842c0586b87SGarrett D'Amore
843c0586b87SGarrett D'Amore for (offset = PCI_CONF_BASE0; offset <= PCI_CONF_BASE5; offset += 4) {
844c0586b87SGarrett D'Amore for (rn = 0; rn < rcount; ++rn) {
845c0586b87SGarrett D'Amore if (PCI_REG_REG_G(regs[rn].pci_phys_hi) == offset) {
846c0586b87SGarrett D'Amore type = regs[rn].pci_phys_hi & PCI_ADDR_MASK;
847c0586b87SGarrett D'Amore break;
848c0586b87SGarrett D'Amore }
849c0586b87SGarrett D'Amore }
850c0586b87SGarrett D'Amore
851c0586b87SGarrett D'Amore if (rn >= rcount)
852c0586b87SGarrett D'Amore continue;
853c0586b87SGarrett D'Amore
854c0586b87SGarrett D'Amore if (type != PCI_ADDR_IO) {
855c0586b87SGarrett D'Amore if (ddi_dev_regsize(pvs->dip, rn,
856c0586b87SGarrett D'Amore ®size) != DDI_SUCCESS) {
857c0586b87SGarrett D'Amore dev_err(pvs->dip, CE_WARN,
858c0586b87SGarrett D'Amore "!failed to get size of reg %d", rn);
859c0586b87SGarrett D'Amore goto out;
860c0586b87SGarrett D'Amore }
861c0586b87SGarrett D'Amore if (regsize == PVSCSI_MEM_SPACE_SIZE) {
862c0586b87SGarrett D'Amore if (ddi_regs_map_setup(pvs->dip, rn,
863c0586b87SGarrett D'Amore &pvs->mmio_base, 0, 0,
864c0586b87SGarrett D'Amore &pvscsi_mmio_attr,
865c0586b87SGarrett D'Amore &pvs->mmio_handle) != DDI_SUCCESS) {
866c0586b87SGarrett D'Amore dev_err(pvs->dip, CE_WARN,
867c0586b87SGarrett D'Amore "!failed to map MMIO BAR");
868c0586b87SGarrett D'Amore goto out;
869c0586b87SGarrett D'Amore }
870c0586b87SGarrett D'Amore ret = DDI_SUCCESS;
871c0586b87SGarrett D'Amore break;
872c0586b87SGarrett D'Amore }
873c0586b87SGarrett D'Amore }
874c0586b87SGarrett D'Amore }
875c0586b87SGarrett D'Amore
876c0586b87SGarrett D'Amore out:
877c0586b87SGarrett D'Amore ddi_prop_free(regs);
878c0586b87SGarrett D'Amore
879c0586b87SGarrett D'Amore return (ret);
880c0586b87SGarrett D'Amore }
881c0586b87SGarrett D'Amore
882c0586b87SGarrett D'Amore static int
pvscsi_enable_intrs(pvscsi_softc_t * pvs)883c0586b87SGarrett D'Amore pvscsi_enable_intrs(pvscsi_softc_t *pvs)
884c0586b87SGarrett D'Amore {
885c0586b87SGarrett D'Amore int i, rc, intr_caps;
886c0586b87SGarrett D'Amore
887c0586b87SGarrett D'Amore if ((rc = ddi_intr_get_cap(pvs->intr_handles[0], &intr_caps)) !=
888c0586b87SGarrett D'Amore DDI_SUCCESS) {
889c0586b87SGarrett D'Amore dev_err(pvs->dip, CE_WARN, "!failed to get interrupt caps");
890c0586b87SGarrett D'Amore return (DDI_FAILURE);
891c0586b87SGarrett D'Amore }
892c0586b87SGarrett D'Amore
893c0586b87SGarrett D'Amore if ((intr_caps & DDI_INTR_FLAG_BLOCK) != 0) {
894c0586b87SGarrett D'Amore if ((rc = ddi_intr_block_enable(pvs->intr_handles,
895c0586b87SGarrett D'Amore pvs->intr_cnt)) != DDI_SUCCESS) {
896c0586b87SGarrett D'Amore dev_err(pvs->dip, CE_WARN,
897c0586b87SGarrett D'Amore "!failed to enable interrupt block");
898c0586b87SGarrett D'Amore }
899c0586b87SGarrett D'Amore } else {
900c0586b87SGarrett D'Amore for (i = 0; i < pvs->intr_cnt; i++) {
901c0586b87SGarrett D'Amore if ((rc = ddi_intr_enable(pvs->intr_handles[i])) ==
902c0586b87SGarrett D'Amore DDI_SUCCESS)
903c0586b87SGarrett D'Amore continue;
904c0586b87SGarrett D'Amore dev_err(pvs->dip, CE_WARN,
905c0586b87SGarrett D'Amore "!failed to enable interrupt");
906c0586b87SGarrett D'Amore while (--i >= 0)
907c0586b87SGarrett D'Amore (void) ddi_intr_disable(pvs->intr_handles[i]);
908c0586b87SGarrett D'Amore break;
909c0586b87SGarrett D'Amore }
910c0586b87SGarrett D'Amore }
911c0586b87SGarrett D'Amore
912c0586b87SGarrett D'Amore return (rc);
913c0586b87SGarrett D'Amore }
914c0586b87SGarrett D'Amore
915c0586b87SGarrett D'Amore static uint32_t
pvscsi_intr(caddr_t arg1,caddr_t arg2)916c0586b87SGarrett D'Amore pvscsi_intr(caddr_t arg1, caddr_t arg2)
917c0586b87SGarrett D'Amore {
918c0586b87SGarrett D'Amore pvscsi_softc_t *pvs = (pvscsi_softc_t *)arg1;
919c0586b87SGarrett D'Amore uint32_t status;
920c0586b87SGarrett D'Amore pvscsi_cmd_t *cmd;
921c0586b87SGarrett D'Amore pvscsi_msg_t *msg;
922c0586b87SGarrett D'Amore uint32_t rv = DDI_INTR_CLAIMED;
923c0586b87SGarrett D'Amore _NOTE(ARGUNUSED(arg2));
924c0586b87SGarrett D'Amore
925c0586b87SGarrett D'Amore mutex_enter(&pvs->lock);
926c0586b87SGarrett D'Amore status = pvscsi_read_intr_status(pvs);
927c0586b87SGarrett D'Amore if ((status & PVSCSI_INTR_ALL_SUPPORTED) != 0) {
928c0586b87SGarrett D'Amore pvscsi_write_intr_status(pvs, status);
929c0586b87SGarrett D'Amore } else if (pvs->intr_type == DDI_INTR_TYPE_FIXED) {
930c0586b87SGarrett D'Amore rv = DDI_INTR_UNCLAIMED;
931c0586b87SGarrett D'Amore }
932c0586b87SGarrett D'Amore if (pvs->detach) {
933c0586b87SGarrett D'Amore mutex_exit(&pvs->lock);
934c0586b87SGarrett D'Amore return (rv);
935c0586b87SGarrett D'Amore }
936c0586b87SGarrett D'Amore cmd = pvscsi_process_comp_ring(pvs);
937c0586b87SGarrett D'Amore msg = pvscsi_process_msg_ring(pvs);
938c0586b87SGarrett D'Amore
939c0586b87SGarrett D'Amore /*
940c0586b87SGarrett D'Amore * Do this under the lock, so that we won't dispatch
941c0586b87SGarrett D'Amore * if we are detaching
942c0586b87SGarrett D'Amore */
943c0586b87SGarrett D'Amore if (msg != NULL) {
944c0586b87SGarrett D'Amore if (ddi_taskq_dispatch(pvs->tq, pvscsi_handle_msg, msg,
945c0586b87SGarrett D'Amore DDI_NOSLEEP) != DDI_SUCCESS) {
946c0586b87SGarrett D'Amore dev_err(pvs->dip, CE_WARN,
947c0586b87SGarrett D'Amore "!failed to dispatch discovery");
948c0586b87SGarrett D'Amore }
949c0586b87SGarrett D'Amore }
950c0586b87SGarrett D'Amore mutex_exit(&pvs->lock);
951c0586b87SGarrett D'Amore
952c0586b87SGarrett D'Amore pvscsi_complete_cmds(pvs, cmd);
953c0586b87SGarrett D'Amore
954c0586b87SGarrett D'Amore return (rv);
955c0586b87SGarrett D'Amore }
956c0586b87SGarrett D'Amore
957c0586b87SGarrett D'Amore static void
pvscsi_free_intrs(pvscsi_softc_t * pvs)958c0586b87SGarrett D'Amore pvscsi_free_intrs(pvscsi_softc_t *pvs)
959c0586b87SGarrett D'Amore {
960c0586b87SGarrett D'Amore for (int i = 0; i < pvs->intr_cnt; i++) {
961c0586b87SGarrett D'Amore (void) ddi_intr_disable(pvs->intr_handles[i]);
962c0586b87SGarrett D'Amore (void) ddi_intr_remove_handler(pvs->intr_handles[i]);
963c0586b87SGarrett D'Amore (void) ddi_intr_free(pvs->intr_handles[i]);
964c0586b87SGarrett D'Amore }
965c0586b87SGarrett D'Amore pvs->intr_cnt = 0;
966c0586b87SGarrett D'Amore }
967c0586b87SGarrett D'Amore
968c0586b87SGarrett D'Amore static int
pvscsi_register_isr(pvscsi_softc_t * pvs,int type)969c0586b87SGarrett D'Amore pvscsi_register_isr(pvscsi_softc_t *pvs, int type)
970c0586b87SGarrett D'Amore {
971c0586b87SGarrett D'Amore int navail, nactual;
972c0586b87SGarrett D'Amore int i;
973c0586b87SGarrett D'Amore
974c0586b87SGarrett D'Amore if (ddi_intr_get_navail(pvs->dip, type, &navail) != DDI_SUCCESS ||
975c0586b87SGarrett D'Amore navail == 0) {
976c0586b87SGarrett D'Amore dev_err(pvs->dip, CE_WARN,
977c0586b87SGarrett D'Amore "!failed to get number of available interrupts of type %d",
978c0586b87SGarrett D'Amore type);
979c0586b87SGarrett D'Amore return (DDI_FAILURE);
980c0586b87SGarrett D'Amore }
981c0586b87SGarrett D'Amore navail = MIN(navail, PVSCSI_MAX_INTRS);
982c0586b87SGarrett D'Amore
983c0586b87SGarrett D'Amore if (ddi_intr_alloc(pvs->dip, pvs->intr_handles, type, 0, navail,
984c0586b87SGarrett D'Amore &nactual, DDI_INTR_ALLOC_NORMAL) != DDI_SUCCESS || nactual == 0) {
985c0586b87SGarrett D'Amore dev_err(pvs->dip, CE_WARN, "!failed to allocate %d interrupts",
986c0586b87SGarrett D'Amore navail);
987c0586b87SGarrett D'Amore return (DDI_FAILURE);
988c0586b87SGarrett D'Amore }
989c0586b87SGarrett D'Amore
990c0586b87SGarrett D'Amore pvs->intr_cnt = nactual;
991c0586b87SGarrett D'Amore
992c0586b87SGarrett D'Amore if (ddi_intr_get_pri(pvs->intr_handles[0], (uint_t *)&pvs->intr_pri) !=
993c0586b87SGarrett D'Amore DDI_SUCCESS) {
994c0586b87SGarrett D'Amore dev_err(pvs->dip, CE_WARN, "!failed to get interrupt priority");
995c0586b87SGarrett D'Amore pvscsi_free_intrs(pvs);
996c0586b87SGarrett D'Amore return (DDI_FAILURE);
997c0586b87SGarrett D'Amore }
998c0586b87SGarrett D'Amore
999c0586b87SGarrett D'Amore for (i = 0; i < nactual; i++) {
1000c0586b87SGarrett D'Amore if (ddi_intr_add_handler(pvs->intr_handles[i], pvscsi_intr,
1001c0586b87SGarrett D'Amore (caddr_t)pvs, NULL) != DDI_SUCCESS) {
1002c0586b87SGarrett D'Amore dev_err(pvs->dip, CE_WARN,
1003c0586b87SGarrett D'Amore "!failed to add intr handler");
1004c0586b87SGarrett D'Amore pvscsi_free_intrs(pvs);
1005c0586b87SGarrett D'Amore return (DDI_FAILURE);
1006c0586b87SGarrett D'Amore }
1007c0586b87SGarrett D'Amore }
1008c0586b87SGarrett D'Amore
1009c0586b87SGarrett D'Amore pvs->intr_type = type;
1010c0586b87SGarrett D'Amore return (DDI_SUCCESS);
1011c0586b87SGarrett D'Amore }
1012c0586b87SGarrett D'Amore
1013c0586b87SGarrett D'Amore static int
pvscsi_setup_isr(pvscsi_softc_t * pvs)1014c0586b87SGarrett D'Amore pvscsi_setup_isr(pvscsi_softc_t *pvs)
1015c0586b87SGarrett D'Amore {
1016c0586b87SGarrett D'Amore int types;
1017c0586b87SGarrett D'Amore
1018c0586b87SGarrett D'Amore if (ddi_intr_get_supported_types(pvs->dip, &types) != DDI_SUCCESS) {
1019c0586b87SGarrett D'Amore dev_err(pvs->dip, CE_WARN, "!failed to get interrupt types");
1020c0586b87SGarrett D'Amore return (DDI_FAILURE);
1021c0586b87SGarrett D'Amore }
1022c0586b87SGarrett D'Amore
1023c0586b87SGarrett D'Amore types &= pvscsi_intr_types;
1024c0586b87SGarrett D'Amore if (types == 0) {
1025c0586b87SGarrett D'Amore dev_err(pvs->dip, CE_WARN, "!no supported interrupt types");
1026c0586b87SGarrett D'Amore return (DDI_FAILURE);
1027c0586b87SGarrett D'Amore }
1028c0586b87SGarrett D'Amore
1029c0586b87SGarrett D'Amore
1030c0586b87SGarrett D'Amore if (((types & DDI_INTR_TYPE_MSIX) != 0) &&
1031c0586b87SGarrett D'Amore (pvscsi_register_isr(pvs, DDI_INTR_TYPE_MSIX) == DDI_SUCCESS)) {
1032c0586b87SGarrett D'Amore return (DDI_SUCCESS);
1033c0586b87SGarrett D'Amore }
1034c0586b87SGarrett D'Amore if (((types & DDI_INTR_TYPE_MSI) != 0) &&
1035c0586b87SGarrett D'Amore (pvscsi_register_isr(pvs, DDI_INTR_TYPE_MSI) == DDI_SUCCESS)) {
1036c0586b87SGarrett D'Amore return (DDI_SUCCESS);
1037c0586b87SGarrett D'Amore }
1038c0586b87SGarrett D'Amore if (((types & DDI_INTR_TYPE_FIXED) != 0) &&
1039c0586b87SGarrett D'Amore (pvscsi_register_isr(pvs, DDI_INTR_TYPE_FIXED) == DDI_SUCCESS)) {
1040c0586b87SGarrett D'Amore return (DDI_SUCCESS);
1041c0586b87SGarrett D'Amore }
1042c0586b87SGarrett D'Amore
1043c0586b87SGarrett D'Amore dev_err(pvs->dip, CE_WARN, "!failed installing any interrupt handler");
1044c0586b87SGarrett D'Amore return (DDI_FAILURE);
1045c0586b87SGarrett D'Amore }
1046c0586b87SGarrett D'Amore
1047c0586b87SGarrett D'Amore
1048c0586b87SGarrett D'Amore static void
pvscsi_timeout(void * arg)1049c0586b87SGarrett D'Amore pvscsi_timeout(void *arg)
1050c0586b87SGarrett D'Amore {
1051c0586b87SGarrett D'Amore pvscsi_softc_t *pvs;
1052c0586b87SGarrett D'Amore pvscsi_cmd_t *cmd;
1053c0586b87SGarrett D'Amore pvscsi_cmd_t *reclaimed = NULL;
1054c0586b87SGarrett D'Amore list_t *l;
1055c0586b87SGarrett D'Amore clock_t now;
1056c0586b87SGarrett D'Amore
1057c0586b87SGarrett D'Amore pvs = arg;
1058c0586b87SGarrett D'Amore l = &pvs->cmd_queue;
1059c0586b87SGarrett D'Amore now = ddi_get_lbolt();
1060c0586b87SGarrett D'Amore
1061c0586b87SGarrett D'Amore mutex_enter(&pvs->lock);
1062c0586b87SGarrett D'Amore if (pvs->timeout == 0) {
1063c0586b87SGarrett D'Amore mutex_exit(&pvs->lock);
1064c0586b87SGarrett D'Amore return;
1065c0586b87SGarrett D'Amore }
1066c0586b87SGarrett D'Amore
1067c0586b87SGarrett D'Amore for (cmd = list_head(l); cmd != NULL; cmd = list_next(l, cmd)) {
1068c0586b87SGarrett D'Amore clock_t overdue;
1069c0586b87SGarrett D'Amore
1070c0586b87SGarrett D'Amore /* polling takes care of it's own timeouts */
1071c0586b87SGarrett D'Amore if (cmd->poll) {
1072c0586b87SGarrett D'Amore continue;
1073c0586b87SGarrett D'Amore }
1074c0586b87SGarrett D'Amore
1075c0586b87SGarrett D'Amore overdue = now - (cmd->start + cmd->timeout);
1076c0586b87SGarrett D'Amore
1077c0586b87SGarrett D'Amore /*
1078c0586b87SGarrett D'Amore * We keep the list of requests sorted by expiration
1079c0586b87SGarrett D'Amore * time, so we hopefully won't need to walk through
1080c0586b87SGarrett D'Amore * many of these. This check is safe if lbolt wraps.
1081c0586b87SGarrett D'Amore */
1082c0586b87SGarrett D'Amore if (overdue <= 0) {
1083c0586b87SGarrett D'Amore break;
1084c0586b87SGarrett D'Amore }
1085c0586b87SGarrett D'Amore
1086c0586b87SGarrett D'Amore /* first we try aborting */
1087c0586b87SGarrett D'Amore if (!cmd->expired) {
1088c0586b87SGarrett D'Amore atomic_or_8(&cmd->expired, 1);
1089c0586b87SGarrett D'Amore dev_err(pvs->dip, CE_WARN, "!cmd timed out (%lds)",
1090c0586b87SGarrett D'Amore drv_hztousec(cmd->timeout)/1000000);
1091c0586b87SGarrett D'Amore continue;
1092c0586b87SGarrett D'Amore }
1093c0586b87SGarrett D'Amore
1094c0586b87SGarrett D'Amore /* if we're less than 2 seconds overdue, wait for abort */
1095c0586b87SGarrett D'Amore if (overdue <= pvscsi_hz * 2) {
1096c0586b87SGarrett D'Amore continue;
1097c0586b87SGarrett D'Amore }
1098c0586b87SGarrett D'Amore
1099c0586b87SGarrett D'Amore /* next it's a reset of the device */
1100c0586b87SGarrett D'Amore if (overdue <= pvscsi_hz * 8) {
1101c0586b87SGarrett D'Amore pvscsi_dev_reset(pvs, cmd->target, cmd->lun);
1102c0586b87SGarrett D'Amore break;
1103c0586b87SGarrett D'Amore }
1104c0586b87SGarrett D'Amore
1105c0586b87SGarrett D'Amore /* next it's a reset of the bus */
1106c0586b87SGarrett D'Amore if (overdue <= pvscsi_hz * 16) {
1107c0586b87SGarrett D'Amore pvscsi_reset_bus(pvs);
1108c0586b87SGarrett D'Amore break;
1109c0586b87SGarrett D'Amore }
1110c0586b87SGarrett D'Amore
1111c0586b87SGarrett D'Amore /* finally it's a reset of the entire adapter */
1112c0586b87SGarrett D'Amore dev_err(pvs->dip, CE_WARN, "!adapter hung? restarting...");
1113c0586b87SGarrett D'Amore mutex_enter(&pvs->lock);
1114c0586b87SGarrett D'Amore pvscsi_stop_hba(pvs);
1115c0586b87SGarrett D'Amore reclaimed = pvscsi_reclaim_cmds(pvs);
1116c0586b87SGarrett D'Amore pvscsi_start_hba(pvs);
1117c0586b87SGarrett D'Amore mutex_exit(&pvs->lock);
1118c0586b87SGarrett D'Amore break;
1119c0586b87SGarrett D'Amore }
1120c0586b87SGarrett D'Amore
1121c0586b87SGarrett D'Amore /* see if reset or abort completed anything */
1122c0586b87SGarrett D'Amore cmd = pvscsi_process_comp_ring(pvs);
1123c0586b87SGarrett D'Amore
1124c0586b87SGarrett D'Amore /* reschedule us if we still have requests pending */
1125c0586b87SGarrett D'Amore if (!list_is_empty(l)) {
1126c0586b87SGarrett D'Amore pvs->timeout = timeout(pvscsi_timeout, pvs, pvscsi_hz);
1127c0586b87SGarrett D'Amore }
1128c0586b87SGarrett D'Amore
1129c0586b87SGarrett D'Amore mutex_exit(&pvs->lock);
1130c0586b87SGarrett D'Amore
1131c0586b87SGarrett D'Amore /* if we had things that got completed, then do the callbacks */
1132c0586b87SGarrett D'Amore pvscsi_complete_cmds(pvs, reclaimed);
1133c0586b87SGarrett D'Amore pvscsi_complete_cmds(pvs, cmd);
1134c0586b87SGarrett D'Amore }
1135c0586b87SGarrett D'Amore
1136c0586b87SGarrett D'Amore static int
pvscsi_start(struct scsi_address * ap,struct scsi_pkt * pkt)1137c0586b87SGarrett D'Amore pvscsi_start(struct scsi_address *ap, struct scsi_pkt *pkt)
1138c0586b87SGarrett D'Amore {
1139c0586b87SGarrett D'Amore pvscsi_cmd_t *cmd = pkt->pkt_ha_private;
1140c0586b87SGarrett D'Amore struct scsi_device *sd;
1141c0586b87SGarrett D'Amore pvscsi_device_t *pd;
1142c0586b87SGarrett D'Amore pvscsi_softc_t *pvs;
1143c0586b87SGarrett D'Amore int rc;
1144*7a73cc88SGarrett D'Amore boolean_t poll;
1145c0586b87SGarrett D'Amore
1146c0586b87SGarrett D'Amore /* make sure the packet is sane */
1147c0586b87SGarrett D'Amore if ((pkt->pkt_numcookies > PVSCSI_MAX_SG_SIZE) ||
1148c0586b87SGarrett D'Amore ((pkt->pkt_dma_flags & DDI_DMA_RDWR) == DDI_DMA_RDWR) ||
1149c0586b87SGarrett D'Amore (pkt->pkt_cdblen > sizeof (cmd->cdb)) ||
1150c0586b87SGarrett D'Amore ((sd = scsi_address_device(ap)) == NULL) ||
1151c0586b87SGarrett D'Amore ((pd = scsi_device_hba_private_get(sd)) == NULL) ||
1152c0586b87SGarrett D'Amore ((pvs = pd->pvs) == NULL)) {
1153c0586b87SGarrett D'Amore return (TRAN_BADPKT);
1154c0586b87SGarrett D'Amore }
1155c0586b87SGarrett D'Amore
1156c0586b87SGarrett D'Amore ASSERT(cmd->pkt == pkt);
1157c0586b87SGarrett D'Amore
1158*7a73cc88SGarrett D'Amore poll = cmd->poll = ((pkt->pkt_flags & FLAG_NOINTR) != 0);
1159c0586b87SGarrett D'Amore
1160c0586b87SGarrett D'Amore if (pkt->pkt_flags & (FLAG_HTAG|FLAG_HEAD)) {
1161c0586b87SGarrett D'Amore cmd->tag = MSG_HEAD_QTAG;
1162c0586b87SGarrett D'Amore } else if (pkt->pkt_flags & FLAG_OTAG) {
1163c0586b87SGarrett D'Amore cmd->tag = MSG_ORDERED_QTAG;
1164c0586b87SGarrett D'Amore } else { /* also FLAG_STAG */
1165c0586b87SGarrett D'Amore cmd->tag = MSG_SIMPLE_QTAG;
1166c0586b87SGarrett D'Amore }
1167c0586b87SGarrett D'Amore
1168c0586b87SGarrett D'Amore bcopy(pkt->pkt_cdbp, cmd->cdb, pkt->pkt_cdblen);
1169c0586b87SGarrett D'Amore cmd->cdblen = pkt->pkt_cdblen;
1170c0586b87SGarrett D'Amore bzero(&cmd->cmd_scb, sizeof (cmd->cmd_scb));
1171c0586b87SGarrett D'Amore
1172c0586b87SGarrett D'Amore /*
1173c0586b87SGarrett D'Amore * Reinitialize some fields because the packet may
1174c0586b87SGarrett D'Amore * have been resubmitted.
1175c0586b87SGarrett D'Amore */
1176c0586b87SGarrett D'Amore pkt->pkt_reason = CMD_CMPLT;
1177c0586b87SGarrett D'Amore pkt->pkt_state = 0;
1178c0586b87SGarrett D'Amore pkt->pkt_statistics = 0;
1179c0586b87SGarrett D'Amore
1180c0586b87SGarrett D'Amore /* Zero status byte - but only if present */
1181c0586b87SGarrett D'Amore if (pkt->pkt_scblen > 0) {
1182c0586b87SGarrett D'Amore *(pkt->pkt_scbp) = 0;
1183c0586b87SGarrett D'Amore }
1184c0586b87SGarrett D'Amore
1185c0586b87SGarrett D'Amore if (pkt->pkt_numcookies > 0) {
1186c0586b87SGarrett D'Amore if (pkt->pkt_dma_flags & DDI_DMA_READ) {
1187c0586b87SGarrett D'Amore cmd->dma_dir = PVSCSI_FLAG_CMD_DIR_TOHOST;
1188c0586b87SGarrett D'Amore } else if (pkt->pkt_dma_flags & DDI_DMA_WRITE) {
1189c0586b87SGarrett D'Amore cmd->dma_dir = PVSCSI_FLAG_CMD_DIR_TODEVICE;
1190c0586b87SGarrett D'Amore } else {
1191c0586b87SGarrett D'Amore cmd->dma_dir = 0;
1192c0586b87SGarrett D'Amore }
1193c0586b87SGarrett D'Amore }
1194c0586b87SGarrett D'Amore
1195c0586b87SGarrett D'Amore cmd->target = pd->target;
1196c0586b87SGarrett D'Amore cmd->lun = pd->lun;
1197c0586b87SGarrett D'Amore cmd->start = ddi_get_lbolt();
1198c0586b87SGarrett D'Amore cmd->timeout = pkt->pkt_time * pvscsi_hz;
1199c0586b87SGarrett D'Amore
1200c0586b87SGarrett D'Amore rc = pvscsi_transport_command(pvs, cmd);
1201c0586b87SGarrett D'Amore
1202*7a73cc88SGarrett D'Amore if (poll && rc == TRAN_ACCEPT) {
1203c0586b87SGarrett D'Amore pvscsi_poll_cmd(pvs, cmd);
1204c0586b87SGarrett D'Amore pvscsi_set_status(pvs, cmd);
1205c0586b87SGarrett D'Amore }
1206c0586b87SGarrett D'Amore
1207c0586b87SGarrett D'Amore return (rc);
1208c0586b87SGarrett D'Amore }
1209c0586b87SGarrett D'Amore
1210c0586b87SGarrett D'Amore
1211c0586b87SGarrett D'Amore static int
pvscsi_parse_ua(const char * ua,int * target,int * lun)1212c0586b87SGarrett D'Amore pvscsi_parse_ua(const char *ua, int *target, int *lun)
1213c0586b87SGarrett D'Amore {
1214c0586b87SGarrett D'Amore char *end;
1215c0586b87SGarrett D'Amore long num;
1216c0586b87SGarrett D'Amore if (((ddi_strtol(ua, &end, 16, &num)) != 0) ||
1217c0586b87SGarrett D'Amore ((*end != ',') && (*end != 0))) {
1218c0586b87SGarrett D'Amore return (DDI_FAILURE);
1219c0586b87SGarrett D'Amore }
1220c0586b87SGarrett D'Amore *target = (int)num;
1221c0586b87SGarrett D'Amore if (*end == 0) {
1222c0586b87SGarrett D'Amore *lun = 0;
1223c0586b87SGarrett D'Amore return (DDI_SUCCESS);
1224c0586b87SGarrett D'Amore }
1225c0586b87SGarrett D'Amore end++;
1226c0586b87SGarrett D'Amore if ((ddi_strtol(end, &end, 16, &num) != 0) || (*end != 0)) {
1227c0586b87SGarrett D'Amore return (DDI_FAILURE);
1228c0586b87SGarrett D'Amore }
1229c0586b87SGarrett D'Amore *lun = (int)num;
1230c0586b87SGarrett D'Amore return (DDI_SUCCESS);
1231c0586b87SGarrett D'Amore }
1232c0586b87SGarrett D'Amore
1233c0586b87SGarrett D'Amore static uint32_t
pvscsi_max_targets(pvscsi_softc_t * pvs)1234c0586b87SGarrett D'Amore pvscsi_max_targets(pvscsi_softc_t *pvs)
1235c0586b87SGarrett D'Amore {
1236c0586b87SGarrett D'Amore pvscsi_dma_buf_t db;
1237c0586b87SGarrett D'Amore struct PVSCSIConfigPageController cpc;
1238c0586b87SGarrett D'Amore struct PVSCSICmdDescConfigCmd cmd;
1239c0586b87SGarrett D'Amore
1240c0586b87SGarrett D'Amore bzero(&db, sizeof (db));
1241c0586b87SGarrett D'Amore
1242c0586b87SGarrett D'Amore /* NB: config pages fit in a single page */
1243c0586b87SGarrett D'Amore if (pvscsi_setup_dma_buffer(pvs, PAGE_SIZE, &db) != DDI_SUCCESS) {
1244c0586b87SGarrett D'Amore dev_err(pvs->dip, CE_WARN,
1245c0586b87SGarrett D'Amore "!failed to setup config page DMA");
1246c0586b87SGarrett D'Amore return (PVSCSI_MAXTGTS);
1247c0586b87SGarrett D'Amore }
1248c0586b87SGarrett D'Amore
1249c0586b87SGarrett D'Amore bzero(&cmd, sizeof (cmd));
1250c0586b87SGarrett D'Amore cmd.configPageAddress = PVSCSI_CONFIG_CONTROLLER_ADDRESS;
1251c0586b87SGarrett D'Amore cmd.configPageAddress <<= 32;
1252c0586b87SGarrett D'Amore cmd.configPageNum = PVSCSI_CONFIG_PAGE_CONTROLLER;
1253c0586b87SGarrett D'Amore cmd.cmpAddr = db.pa;
1254c0586b87SGarrett D'Amore
1255c0586b87SGarrett D'Amore pvscsi_write_cmd_desc(pvs, PVSCSI_CMD_CONFIG, &cmd, sizeof (cmd));
1256c0586b87SGarrett D'Amore (void) ddi_dma_sync(db.dmah, 0, 0, DDI_DMA_SYNC_FORKERNEL);
1257c0586b87SGarrett D'Amore bcopy(db.addr, &cpc, sizeof (cpc));
1258c0586b87SGarrett D'Amore pvscsi_free_dma_buffer(&db);
1259c0586b87SGarrett D'Amore
1260c0586b87SGarrett D'Amore
1261c0586b87SGarrett D'Amore if ((cpc.header.scsiStatus == STATUS_GOOD) &&
1262c0586b87SGarrett D'Amore (cpc.header.hostStatus == BTSTAT_SUCCESS) &&
1263c0586b87SGarrett D'Amore (cpc.numPhys > 0)) {
1264c0586b87SGarrett D'Amore return (cpc.numPhys);
1265c0586b87SGarrett D'Amore }
1266c0586b87SGarrett D'Amore
1267c0586b87SGarrett D'Amore dev_err(pvs->dip, CE_WARN, "!failed to determine max targets");
1268c0586b87SGarrett D'Amore return (PVSCSI_MAXTGTS);
1269c0586b87SGarrett D'Amore }
1270c0586b87SGarrett D'Amore
1271c0586b87SGarrett D'Amore static boolean_t
pvscsi_probe_target(pvscsi_softc_t * pvs,int target)1272c0586b87SGarrett D'Amore pvscsi_probe_target(pvscsi_softc_t *pvs, int target)
1273c0586b87SGarrett D'Amore {
1274c0586b87SGarrett D'Amore pvscsi_cmd_t cmd;
1275c0586b87SGarrett D'Amore
1276c0586b87SGarrett D'Amore if (!pvscsi_cmd_init(pvs, &cmd, KM_SLEEP)) {
1277c0586b87SGarrett D'Amore pvscsi_cmd_fini(&cmd);
1278c0586b87SGarrett D'Amore return (B_FALSE);
1279c0586b87SGarrett D'Amore }
1280c0586b87SGarrett D'Amore /* NB: CDB 0 is a TUR which is perfect for our needs */
1281c0586b87SGarrett D'Amore bzero(cmd.cdb, sizeof (cmd.cdb));
1282c0586b87SGarrett D'Amore cmd.poll = B_TRUE;
1283c0586b87SGarrett D'Amore cmd.dma_dir = 0;
1284c0586b87SGarrett D'Amore cmd.target = target;
1285c0586b87SGarrett D'Amore cmd.lun = 0;
1286c0586b87SGarrett D'Amore cmd.start = ddi_get_lbolt();
1287c0586b87SGarrett D'Amore cmd.timeout = pvscsi_hz;
1288c0586b87SGarrett D'Amore
1289c0586b87SGarrett D'Amore if (pvscsi_transport_command(pvs, &cmd) != TRAN_ACCEPT) {
1290c0586b87SGarrett D'Amore pvscsi_cmd_fini(&cmd);
1291c0586b87SGarrett D'Amore return (B_FALSE);
1292c0586b87SGarrett D'Amore }
1293c0586b87SGarrett D'Amore pvscsi_poll_cmd(pvs, &cmd);
1294c0586b87SGarrett D'Amore
1295c0586b87SGarrett D'Amore switch (cmd.host_status) {
1296c0586b87SGarrett D'Amore case BTSTAT_SUCCESS:
1297c0586b87SGarrett D'Amore case BTSTAT_LINKED_COMMAND_COMPLETED:
1298c0586b87SGarrett D'Amore case BTSTAT_LINKED_COMMAND_COMPLETED_WITH_FLAG:
1299c0586b87SGarrett D'Amore /* We don't care about the actual SCSI status */
1300c0586b87SGarrett D'Amore pvscsi_cmd_fini(&cmd);
1301c0586b87SGarrett D'Amore return (B_TRUE);
1302c0586b87SGarrett D'Amore }
1303c0586b87SGarrett D'Amore
1304c0586b87SGarrett D'Amore pvscsi_cmd_fini(&cmd);
1305c0586b87SGarrett D'Amore return (B_FALSE);
1306c0586b87SGarrett D'Amore }
1307c0586b87SGarrett D'Amore
1308c0586b87SGarrett D'Amore static int
pvscsi_tgt_init(dev_info_t * dip,dev_info_t * child,scsi_hba_tran_t * tran,struct scsi_device * sd)1309c0586b87SGarrett D'Amore pvscsi_tgt_init(dev_info_t *dip, dev_info_t *child, scsi_hba_tran_t *tran,
1310c0586b87SGarrett D'Amore struct scsi_device *sd)
1311c0586b87SGarrett D'Amore {
1312c0586b87SGarrett D'Amore /*
1313c0586b87SGarrett D'Amore * Assumption: the HBA framework only asks us to have a single
1314c0586b87SGarrett D'Amore * target initialized per address at any given time.
1315c0586b87SGarrett D'Amore */
1316c0586b87SGarrett D'Amore pvscsi_device_t *pd;
1317c0586b87SGarrett D'Amore pvscsi_softc_t *pvs;
1318c0586b87SGarrett D'Amore const char *ua;
1319c0586b87SGarrett D'Amore
1320c0586b87SGarrett D'Amore if (((scsi_hba_iport_unit_address(dip)) == NULL) ||
1321c0586b87SGarrett D'Amore ((pvs = tran->tran_hba_private) == NULL) ||
1322c0586b87SGarrett D'Amore ((ua = scsi_device_unit_address(sd)) == NULL)) {
1323c0586b87SGarrett D'Amore return (DDI_FAILURE);
1324c0586b87SGarrett D'Amore }
1325c0586b87SGarrett D'Amore
1326c0586b87SGarrett D'Amore /* parse the unit address */
1327c0586b87SGarrett D'Amore pd = kmem_zalloc(sizeof (*pd), KM_SLEEP);
1328c0586b87SGarrett D'Amore if (pvscsi_parse_ua(ua, &pd->target, &pd->lun) != DDI_SUCCESS) {
1329c0586b87SGarrett D'Amore kmem_free(pd, sizeof (*pd));
1330c0586b87SGarrett D'Amore return (DDI_FAILURE);
1331c0586b87SGarrett D'Amore }
1332c0586b87SGarrett D'Amore pd->pvs = pvs;
1333c0586b87SGarrett D'Amore scsi_device_hba_private_set(sd, pd);
1334c0586b87SGarrett D'Amore
1335c0586b87SGarrett D'Amore mutex_enter(&pvs->lock);
1336c0586b87SGarrett D'Amore list_insert_tail(&pvs->devices, pd);
1337c0586b87SGarrett D'Amore mutex_exit(&pvs->lock);
1338c0586b87SGarrett D'Amore return (DDI_SUCCESS);
1339c0586b87SGarrett D'Amore }
1340c0586b87SGarrett D'Amore
1341c0586b87SGarrett D'Amore static void
pvscsi_tgt_free(dev_info_t * dip,dev_info_t * child,scsi_hba_tran_t * tran,struct scsi_device * sd)1342c0586b87SGarrett D'Amore pvscsi_tgt_free(dev_info_t *dip, dev_info_t *child, scsi_hba_tran_t *tran,
1343c0586b87SGarrett D'Amore struct scsi_device *sd)
1344c0586b87SGarrett D'Amore {
1345c0586b87SGarrett D'Amore pvscsi_device_t *pd;
1346c0586b87SGarrett D'Amore pvscsi_softc_t *pvs;
1347c0586b87SGarrett D'Amore
1348c0586b87SGarrett D'Amore if (((scsi_hba_iport_unit_address(dip)) == NULL) ||
1349c0586b87SGarrett D'Amore ((pvs = tran->tran_hba_private) == NULL) ||
1350c0586b87SGarrett D'Amore ((pd = scsi_device_hba_private_get(sd)) == NULL)) {
1351c0586b87SGarrett D'Amore return;
1352c0586b87SGarrett D'Amore }
1353c0586b87SGarrett D'Amore scsi_device_hba_private_set(sd, NULL);
1354c0586b87SGarrett D'Amore mutex_enter(&pvs->lock);
1355c0586b87SGarrett D'Amore list_remove(&pvs->devices, pd);
1356c0586b87SGarrett D'Amore mutex_exit(&pvs->lock);
1357c0586b87SGarrett D'Amore
1358c0586b87SGarrett D'Amore kmem_free(pd, sizeof (*pd));
1359c0586b87SGarrett D'Amore }
1360c0586b87SGarrett D'Amore
1361c0586b87SGarrett D'Amore static int
pvscsi_reset(struct scsi_address * ap,int level)1362c0586b87SGarrett D'Amore pvscsi_reset(struct scsi_address *ap, int level)
1363c0586b87SGarrett D'Amore {
1364c0586b87SGarrett D'Amore struct scsi_device *sd;
1365c0586b87SGarrett D'Amore pvscsi_device_t *pd;
1366c0586b87SGarrett D'Amore pvscsi_softc_t *pvs;
1367c0586b87SGarrett D'Amore pvscsi_cmd_t *cmd;
1368c0586b87SGarrett D'Amore
1369c0586b87SGarrett D'Amore if (((sd = scsi_address_device(ap)) == NULL) ||
1370c0586b87SGarrett D'Amore ((pd = scsi_device_hba_private_get(sd)) == NULL) ||
1371c0586b87SGarrett D'Amore ((pvs = pd->pvs) == NULL)) {
1372c0586b87SGarrett D'Amore return (0);
1373c0586b87SGarrett D'Amore }
1374c0586b87SGarrett D'Amore switch (level) {
1375c0586b87SGarrett D'Amore case RESET_ALL:
1376c0586b87SGarrett D'Amore case RESET_BUS:
1377c0586b87SGarrett D'Amore pvscsi_reset_bus(pvs);
1378c0586b87SGarrett D'Amore break;
1379c0586b87SGarrett D'Amore case RESET_TARGET:
1380c0586b87SGarrett D'Amore /* reset both the lun and lun 0 */
1381c0586b87SGarrett D'Amore pvscsi_dev_reset(pvs, pd->target, pd->lun);
1382c0586b87SGarrett D'Amore pvscsi_dev_reset(pvs, pd->target, 0);
1383c0586b87SGarrett D'Amore break;
1384c0586b87SGarrett D'Amore case RESET_LUN:
1385c0586b87SGarrett D'Amore pvscsi_dev_reset(pvs, pd->target, pd->lun);
1386c0586b87SGarrett D'Amore break;
1387c0586b87SGarrett D'Amore default:
1388c0586b87SGarrett D'Amore return (0);
1389c0586b87SGarrett D'Amore }
1390c0586b87SGarrett D'Amore
1391c0586b87SGarrett D'Amore /* reset may have caused some completions */
1392c0586b87SGarrett D'Amore mutex_enter(&pvs->lock);
1393c0586b87SGarrett D'Amore cmd = pvscsi_process_comp_ring(pvs);
1394c0586b87SGarrett D'Amore mutex_exit(&pvs->lock);
1395c0586b87SGarrett D'Amore
1396c0586b87SGarrett D'Amore pvscsi_complete_cmds(pvs, cmd);
1397c0586b87SGarrett D'Amore return (1);
1398c0586b87SGarrett D'Amore }
1399c0586b87SGarrett D'Amore
1400c0586b87SGarrett D'Amore static int
pvscsi_abort(struct scsi_address * ap,struct scsi_pkt * pkt)1401c0586b87SGarrett D'Amore pvscsi_abort(struct scsi_address *ap, struct scsi_pkt *pkt)
1402c0586b87SGarrett D'Amore {
1403c0586b87SGarrett D'Amore struct scsi_device *sd;
1404c0586b87SGarrett D'Amore pvscsi_device_t *pd;
1405c0586b87SGarrett D'Amore pvscsi_softc_t *pvs;
1406c0586b87SGarrett D'Amore pvscsi_cmd_t *cmd;
1407c0586b87SGarrett D'Amore
1408c0586b87SGarrett D'Amore if (pkt != NULL) {
1409c0586b87SGarrett D'Amore /* abort single command */
1410c0586b87SGarrett D'Amore cmd = pkt->pkt_ha_private;
1411c0586b87SGarrett D'Amore pvs = cmd->pvs;
1412c0586b87SGarrett D'Amore pvscsi_abort_cmd(pvs, cmd);
1413c0586b87SGarrett D'Amore } else if ((ap != NULL) &&
1414c0586b87SGarrett D'Amore ((sd = scsi_address_device(ap)) != NULL) &&
1415c0586b87SGarrett D'Amore ((pd = scsi_device_hba_private_get(sd)) != NULL) &&
1416c0586b87SGarrett D'Amore ((pvs = pd->pvs) != NULL)) {
1417c0586b87SGarrett D'Amore /* abort all commands on the bus */
1418c0586b87SGarrett D'Amore pvscsi_abort_all(pvs, pd);
1419c0586b87SGarrett D'Amore } else {
1420c0586b87SGarrett D'Amore return (0);
1421c0586b87SGarrett D'Amore }
1422c0586b87SGarrett D'Amore
1423c0586b87SGarrett D'Amore /* abort may have caused some completions */
1424c0586b87SGarrett D'Amore mutex_enter(&pvs->lock);
1425c0586b87SGarrett D'Amore cmd = pvscsi_process_comp_ring(pvs);
1426c0586b87SGarrett D'Amore mutex_exit(&pvs->lock);
1427c0586b87SGarrett D'Amore
1428c0586b87SGarrett D'Amore pvscsi_complete_cmds(pvs, cmd);
1429c0586b87SGarrett D'Amore
1430c0586b87SGarrett D'Amore return (1);
1431c0586b87SGarrett D'Amore }
1432c0586b87SGarrett D'Amore
1433c0586b87SGarrett D'Amore static int
pvscsi_getcap(struct scsi_address * ap,char * cap,int whom)1434c0586b87SGarrett D'Amore pvscsi_getcap(struct scsi_address *ap, char *cap, int whom)
1435c0586b87SGarrett D'Amore {
1436c0586b87SGarrett D'Amore _NOTE(ARGUNUSED(ap));
1437c0586b87SGarrett D'Amore _NOTE(ARGUNUSED(whom));
1438c0586b87SGarrett D'Amore
1439c0586b87SGarrett D'Amore if (cap == NULL) {
1440c0586b87SGarrett D'Amore return (-1);
1441c0586b87SGarrett D'Amore }
1442c0586b87SGarrett D'Amore
1443c0586b87SGarrett D'Amore switch (scsi_hba_lookup_capstr(cap)) {
1444c0586b87SGarrett D'Amore case SCSI_CAP_ARQ:
1445c0586b87SGarrett D'Amore case SCSI_CAP_UNTAGGED_QING:
1446c0586b87SGarrett D'Amore case SCSI_CAP_TAGGED_QING:
1447c0586b87SGarrett D'Amore return (1);
1448c0586b87SGarrett D'Amore default:
1449c0586b87SGarrett D'Amore return (-1);
1450c0586b87SGarrett D'Amore }
1451c0586b87SGarrett D'Amore }
1452c0586b87SGarrett D'Amore
1453c0586b87SGarrett D'Amore static int
pvscsi_setcap(struct scsi_address * ap,char * cap,int value,int whom)1454c0586b87SGarrett D'Amore pvscsi_setcap(struct scsi_address *ap, char *cap, int value, int whom)
1455c0586b87SGarrett D'Amore {
1456c0586b87SGarrett D'Amore _NOTE(ARGUNUSED(ap));
1457c0586b87SGarrett D'Amore _NOTE(ARGUNUSED(value));
1458c0586b87SGarrett D'Amore _NOTE(ARGUNUSED(whom));
1459c0586b87SGarrett D'Amore
1460c0586b87SGarrett D'Amore if (cap == NULL) {
1461c0586b87SGarrett D'Amore return (-1);
1462c0586b87SGarrett D'Amore }
1463c0586b87SGarrett D'Amore
1464c0586b87SGarrett D'Amore switch (scsi_hba_lookup_capstr(cap)) {
1465c0586b87SGarrett D'Amore case SCSI_CAP_ARQ:
1466c0586b87SGarrett D'Amore case SCSI_CAP_UNTAGGED_QING:
1467c0586b87SGarrett D'Amore case SCSI_CAP_TAGGED_QING:
1468c0586b87SGarrett D'Amore return (0); /* not changeable */
1469c0586b87SGarrett D'Amore default:
1470c0586b87SGarrett D'Amore return (-1);
1471c0586b87SGarrett D'Amore }
1472c0586b87SGarrett D'Amore }
1473c0586b87SGarrett D'Amore
1474c0586b87SGarrett D'Amore static void
pvscsi_cmd_fini(pvscsi_cmd_t * cmd)1475c0586b87SGarrett D'Amore pvscsi_cmd_fini(pvscsi_cmd_t *cmd)
1476c0586b87SGarrett D'Amore {
1477c0586b87SGarrett D'Amore if (cmd->arq_pa != 0) {
1478c0586b87SGarrett D'Amore (void) ddi_dma_unbind_handle(cmd->arq_dmah);
1479c0586b87SGarrett D'Amore cmd->arq_dmah = NULL;
1480c0586b87SGarrett D'Amore }
1481c0586b87SGarrett D'Amore if (cmd->arq_dmah != NULL) {
1482c0586b87SGarrett D'Amore ddi_dma_free_handle(&cmd->arq_dmah);
1483c0586b87SGarrett D'Amore cmd->arq_dmah = NULL;
1484c0586b87SGarrett D'Amore }
1485c0586b87SGarrett D'Amore if (cmd->sgl_pa != 0) {
1486c0586b87SGarrett D'Amore (void) ddi_dma_unbind_handle(cmd->sgl_dmah);
1487c0586b87SGarrett D'Amore cmd->sgl_pa = 0;
1488c0586b87SGarrett D'Amore }
1489c0586b87SGarrett D'Amore if (cmd->sgl_acch != NULL) {
1490c0586b87SGarrett D'Amore ddi_dma_mem_free(&cmd->sgl_acch);
1491c0586b87SGarrett D'Amore cmd->sgl_acch = NULL;
1492c0586b87SGarrett D'Amore cmd->sgl = NULL;
1493c0586b87SGarrett D'Amore }
1494c0586b87SGarrett D'Amore if (cmd->sgl_dmah != NULL) {
1495c0586b87SGarrett D'Amore ddi_dma_free_handle(&cmd->sgl_dmah);
1496c0586b87SGarrett D'Amore cmd->sgl_dmah = NULL;
1497c0586b87SGarrett D'Amore }
1498c0586b87SGarrett D'Amore if (cmd->ctx != 0) {
1499c0586b87SGarrett D'Amore id32_free(cmd->ctx);
1500c0586b87SGarrett D'Amore cmd->ctx = 0;
1501c0586b87SGarrett D'Amore }
1502c0586b87SGarrett D'Amore }
1503c0586b87SGarrett D'Amore
1504c0586b87SGarrett D'Amore static void
pvscsi_pkt_dtor(struct scsi_pkt * pkt,scsi_hba_tran_t * tran)1505c0586b87SGarrett D'Amore pvscsi_pkt_dtor(struct scsi_pkt *pkt, scsi_hba_tran_t *tran)
1506c0586b87SGarrett D'Amore {
1507c0586b87SGarrett D'Amore pvscsi_cmd_t *cmd = pkt->pkt_ha_private;
1508c0586b87SGarrett D'Amore pvscsi_cmd_fini(cmd);
1509c0586b87SGarrett D'Amore }
1510c0586b87SGarrett D'Amore
1511c0586b87SGarrett D'Amore static boolean_t
pvscsi_cmd_init(pvscsi_softc_t * pvs,pvscsi_cmd_t * cmd,int sleep)1512c0586b87SGarrett D'Amore pvscsi_cmd_init(pvscsi_softc_t *pvs, pvscsi_cmd_t *cmd, int sleep)
1513c0586b87SGarrett D'Amore {
1514c0586b87SGarrett D'Amore int (*cb)(caddr_t);
1515c0586b87SGarrett D'Amore size_t len;
1516c0586b87SGarrett D'Amore caddr_t kaddr;
1517c0586b87SGarrett D'Amore
1518c0586b87SGarrett D'Amore cb = sleep == KM_SLEEP ? DDI_DMA_SLEEP : DDI_DMA_DONTWAIT;
1519c0586b87SGarrett D'Amore
1520c0586b87SGarrett D'Amore bzero(cmd, sizeof (*cmd));
1521c0586b87SGarrett D'Amore cmd->ctx = id32_alloc(cmd, sleep);
1522c0586b87SGarrett D'Amore if (cmd->ctx == 0) {
1523c0586b87SGarrett D'Amore dev_err(pvs->dip, CE_WARN,
1524c0586b87SGarrett D'Amore "!failed to allocate 32-bit context id");
1525c0586b87SGarrett D'Amore return (B_FALSE);
1526c0586b87SGarrett D'Amore }
1527c0586b87SGarrett D'Amore
1528c0586b87SGarrett D'Amore /* allocate DMA resources for scatter/gather list */
1529c0586b87SGarrett D'Amore if (ddi_dma_alloc_handle(pvs->dip, &pvscsi_dma_attr, cb, NULL,
1530c0586b87SGarrett D'Amore &cmd->sgl_dmah) != DDI_SUCCESS) {
1531c0586b87SGarrett D'Amore dev_err(pvs->dip, CE_WARN,
1532c0586b87SGarrett D'Amore "!failed to allocate DMA handle for SG list");
1533c0586b87SGarrett D'Amore return (B_FALSE);
1534c0586b87SGarrett D'Amore }
1535c0586b87SGarrett D'Amore if (ddi_dma_mem_alloc(cmd->sgl_dmah, PAGE_SIZE, &pvscsi_dma_attrs,
1536c0586b87SGarrett D'Amore DDI_DMA_CONSISTENT, cb, NULL, &kaddr, &len, &cmd->sgl_acch) !=
1537c0586b87SGarrett D'Amore DDI_SUCCESS) {
1538c0586b87SGarrett D'Amore dev_err(pvs->dip, CE_WARN,
1539c0586b87SGarrett D'Amore "!failed to allocate DMA memory for SG list");
1540c0586b87SGarrett D'Amore return (B_FALSE);
1541c0586b87SGarrett D'Amore }
1542c0586b87SGarrett D'Amore cmd->sgl = (void *)kaddr;
1543c0586b87SGarrett D'Amore if (ddi_dma_addr_bind_handle(cmd->sgl_dmah, NULL, kaddr,
1544c0586b87SGarrett D'Amore PAGE_SIZE, DDI_DMA_WRITE | DDI_DMA_CONSISTENT, cb, NULL,
1545c0586b87SGarrett D'Amore NULL, NULL) != DDI_DMA_MAPPED) {
1546c0586b87SGarrett D'Amore dev_err(pvs->dip, CE_WARN, "!failed to bind SGL list");
1547c0586b87SGarrett D'Amore return (B_FALSE);
1548c0586b87SGarrett D'Amore }
1549c0586b87SGarrett D'Amore cmd->sgl_pa = ddi_dma_cookie_one(cmd->sgl_dmah)->dmac_laddress;
1550c0586b87SGarrett D'Amore
1551c0586b87SGarrett D'Amore /* allocate DMA resource for auto-sense-request */
1552c0586b87SGarrett D'Amore if (ddi_dma_alloc_handle(pvs->dip, &pvscsi_dma_attr,
1553c0586b87SGarrett D'Amore cb, NULL, &cmd->arq_dmah) != DDI_SUCCESS) {
1554c0586b87SGarrett D'Amore dev_err(pvs->dip, CE_WARN,
1555c0586b87SGarrett D'Amore "!failed to allocate DMA handle for ARQ buffer");
1556c0586b87SGarrett D'Amore return (B_FALSE);
1557c0586b87SGarrett D'Amore }
1558c0586b87SGarrett D'Amore
1559c0586b87SGarrett D'Amore if (ddi_dma_addr_bind_handle(cmd->arq_dmah, NULL,
1560c0586b87SGarrett D'Amore (void *)cmd->arq_sense, SENSE_LENGTH,
1561c0586b87SGarrett D'Amore DDI_DMA_READ | DDI_DMA_CONSISTENT, cb, NULL,
1562c0586b87SGarrett D'Amore NULL, NULL) != DDI_DMA_MAPPED) {
1563c0586b87SGarrett D'Amore dev_err(pvs->dip, CE_WARN, "!failed to bind ARQ buffer");
1564c0586b87SGarrett D'Amore return (B_FALSE);
1565c0586b87SGarrett D'Amore }
1566c0586b87SGarrett D'Amore cmd->arq_pa = ddi_dma_cookie_one(cmd->arq_dmah)->dmac_laddress;
1567c0586b87SGarrett D'Amore return (B_TRUE);
1568c0586b87SGarrett D'Amore }
1569c0586b87SGarrett D'Amore
1570c0586b87SGarrett D'Amore static int
pvscsi_pkt_ctor(struct scsi_pkt * pkt,scsi_hba_tran_t * tran,int sleep)1571c0586b87SGarrett D'Amore pvscsi_pkt_ctor(struct scsi_pkt *pkt, scsi_hba_tran_t *tran, int sleep)
1572c0586b87SGarrett D'Amore {
1573c0586b87SGarrett D'Amore pvscsi_cmd_t *cmd = pkt->pkt_ha_private;
1574c0586b87SGarrett D'Amore pvscsi_softc_t *pvs = tran->tran_hba_private;
1575c0586b87SGarrett D'Amore
1576c0586b87SGarrett D'Amore if (!pvscsi_cmd_init(pvs, cmd, sleep)) {
1577c0586b87SGarrett D'Amore pvscsi_pkt_dtor(pkt, tran);
1578c0586b87SGarrett D'Amore return (-1);
1579c0586b87SGarrett D'Amore }
1580c0586b87SGarrett D'Amore cmd->pkt = pkt;
1581c0586b87SGarrett D'Amore return (0);
1582c0586b87SGarrett D'Amore }
1583c0586b87SGarrett D'Amore
1584c0586b87SGarrett D'Amore static void
pvscsi_teardown_pkt(struct scsi_pkt * pkt)1585c0586b87SGarrett D'Amore pvscsi_teardown_pkt(struct scsi_pkt *pkt)
1586c0586b87SGarrett D'Amore {
1587c0586b87SGarrett D'Amore _NOTE(ARGUNUSED(pkt));
1588c0586b87SGarrett D'Amore /* nothing to do */
1589c0586b87SGarrett D'Amore }
1590c0586b87SGarrett D'Amore
1591c0586b87SGarrett D'Amore static int
pvscsi_setup_pkt(struct scsi_pkt * pkt,int (* cb)(caddr_t),caddr_t arg)1592c0586b87SGarrett D'Amore pvscsi_setup_pkt(struct scsi_pkt *pkt, int (*cb)(caddr_t), caddr_t arg)
1593c0586b87SGarrett D'Amore {
1594c0586b87SGarrett D'Amore /* all work is done in start */
1595c0586b87SGarrett D'Amore return (0);
1596c0586b87SGarrett D'Amore }
1597c0586b87SGarrett D'Amore
1598c0586b87SGarrett D'Amore static int
pvscsi_hba_setup(pvscsi_softc_t * pvs)1599c0586b87SGarrett D'Amore pvscsi_hba_setup(pvscsi_softc_t *pvs)
1600c0586b87SGarrett D'Amore {
1601c0586b87SGarrett D'Amore scsi_hba_tran_t *tran;
1602c0586b87SGarrett D'Amore
1603c0586b87SGarrett D'Amore tran = scsi_hba_tran_alloc(pvs->dip, SCSI_HBA_CANSLEEP);
1604c0586b87SGarrett D'Amore ASSERT(tran != NULL);
1605c0586b87SGarrett D'Amore
1606c0586b87SGarrett D'Amore tran->tran_hba_private = pvs;
1607c0586b87SGarrett D'Amore tran->tran_start = pvscsi_start;
1608c0586b87SGarrett D'Amore tran->tran_reset = pvscsi_reset;
1609c0586b87SGarrett D'Amore tran->tran_abort = pvscsi_abort;
1610c0586b87SGarrett D'Amore tran->tran_getcap = pvscsi_getcap;
1611c0586b87SGarrett D'Amore tran->tran_setcap = pvscsi_setcap;
1612c0586b87SGarrett D'Amore tran->tran_pkt_constructor = pvscsi_pkt_ctor;
1613c0586b87SGarrett D'Amore tran->tran_pkt_destructor = pvscsi_pkt_dtor;
1614c0586b87SGarrett D'Amore tran->tran_setup_pkt = pvscsi_setup_pkt;
1615c0586b87SGarrett D'Amore tran->tran_teardown_pkt = pvscsi_teardown_pkt;
1616c0586b87SGarrett D'Amore tran->tran_tgt_init = pvscsi_tgt_init;
1617c0586b87SGarrett D'Amore tran->tran_tgt_free = pvscsi_tgt_free;
1618c0586b87SGarrett D'Amore tran->tran_hba_len = sizeof (pvscsi_cmd_t);
1619c0586b87SGarrett D'Amore
1620c0586b87SGarrett D'Amore tran->tran_interconnect_type = INTERCONNECT_PARALLEL;
1621c0586b87SGarrett D'Amore
1622c0586b87SGarrett D'Amore if (scsi_hba_attach_setup(pvs->dip, &pvscsi_io_dma_attr, tran,
1623c0586b87SGarrett D'Amore SCSI_HBA_HBA | SCSI_HBA_TRAN_CDB | SCSI_HBA_TRAN_SCB |
1624c0586b87SGarrett D'Amore SCSI_HBA_ADDR_COMPLEX) !=
1625c0586b87SGarrett D'Amore DDI_SUCCESS) {
1626c0586b87SGarrett D'Amore scsi_hba_tran_free(tran);
1627c0586b87SGarrett D'Amore dev_err(pvs->dip, CE_WARN, "!failed to attach HBA");
1628c0586b87SGarrett D'Amore return (DDI_FAILURE);
1629c0586b87SGarrett D'Amore }
1630c0586b87SGarrett D'Amore
1631c0586b87SGarrett D'Amore pvs->tran = tran;
1632c0586b87SGarrett D'Amore return (DDI_SUCCESS);
1633c0586b87SGarrett D'Amore }
1634c0586b87SGarrett D'Amore
1635c0586b87SGarrett D'Amore static void
pvscsi_teardown(pvscsi_softc_t * pvs)1636c0586b87SGarrett D'Amore pvscsi_teardown(pvscsi_softc_t *pvs)
1637c0586b87SGarrett D'Amore {
1638c0586b87SGarrett D'Amore timeout_id_t tid;
1639c0586b87SGarrett D'Amore
1640c0586b87SGarrett D'Amore pvscsi_stop_hba(pvs);
1641c0586b87SGarrett D'Amore
1642c0586b87SGarrett D'Amore if (pvs->tq != NULL) {
1643c0586b87SGarrett D'Amore ddi_taskq_destroy(pvs->tq);
1644c0586b87SGarrett D'Amore }
1645c0586b87SGarrett D'Amore mutex_enter(&pvs->lock);
1646c0586b87SGarrett D'Amore tid = pvs->timeout;
1647c0586b87SGarrett D'Amore pvs->timeout = 0;
1648c0586b87SGarrett D'Amore mutex_exit(&pvs->lock);
1649c0586b87SGarrett D'Amore
1650c0586b87SGarrett D'Amore if (tid != 0) {
1651c0586b87SGarrett D'Amore (void) untimeout(tid);
1652c0586b87SGarrett D'Amore }
1653c0586b87SGarrett D'Amore
1654c0586b87SGarrett D'Amore pvscsi_free_intrs(pvs);
1655c0586b87SGarrett D'Amore pvscsi_free_rings(pvs);
1656c0586b87SGarrett D'Amore
1657c0586b87SGarrett D'Amore if (pvs->mmio_handle != NULL) {
1658c0586b87SGarrett D'Amore ddi_regs_map_free(&pvs->mmio_handle);
1659c0586b87SGarrett D'Amore }
1660c0586b87SGarrett D'Amore
1661c0586b87SGarrett D'Amore if (pvs->tran != NULL) {
1662c0586b87SGarrett D'Amore scsi_hba_tran_free(pvs->tran);
1663c0586b87SGarrett D'Amore }
1664c0586b87SGarrett D'Amore mutex_destroy(&pvs->lock);
1665c0586b87SGarrett D'Amore list_destroy(&pvs->cmd_queue);
1666c0586b87SGarrett D'Amore list_destroy(&pvs->devices);
1667c0586b87SGarrett D'Amore
1668c0586b87SGarrett D'Amore kmem_free(pvs, sizeof (*pvs));
1669c0586b87SGarrett D'Amore }
1670c0586b87SGarrett D'Amore
1671c0586b87SGarrett D'Amore static int
pvscsi_iport_attach(dev_info_t * dip)1672c0586b87SGarrett D'Amore pvscsi_iport_attach(dev_info_t *dip)
1673c0586b87SGarrett D'Amore {
1674c0586b87SGarrett D'Amore scsi_hba_tran_t *tran;
1675c0586b87SGarrett D'Amore dev_info_t *parent;
1676c0586b87SGarrett D'Amore pvscsi_softc_t *pvs;
1677c0586b87SGarrett D'Amore char *ua;
1678c0586b87SGarrett D'Amore uint32_t max_targets;
1679c0586b87SGarrett D'Amore
1680c0586b87SGarrett D'Amore if (((parent = ddi_get_parent(dip)) == NULL) ||
1681c0586b87SGarrett D'Amore ((tran = ddi_get_driver_private(parent)) == NULL) ||
1682c0586b87SGarrett D'Amore ((pvs = tran->tran_hba_private) == NULL) ||
1683c0586b87SGarrett D'Amore ((ua = scsi_hba_iport_unit_address(dip)) == NULL) ||
1684c0586b87SGarrett D'Amore (strcmp(ua, "iport0") != 0)) {
1685c0586b87SGarrett D'Amore return (DDI_FAILURE);
1686c0586b87SGarrett D'Amore }
1687c0586b87SGarrett D'Amore
1688c0586b87SGarrett D'Amore /* store our softc on the iport private tran */
1689c0586b87SGarrett D'Amore tran = ddi_get_driver_private(dip);
1690c0586b87SGarrett D'Amore tran->tran_hba_private = pvs;
1691c0586b87SGarrett D'Amore
1692c0586b87SGarrett D'Amore /* setup the target map - allow 100ms for settle / sync times */
1693c0586b87SGarrett D'Amore if (scsi_hba_tgtmap_create(dip, SCSI_TM_PERADDR, 100000,
1694c0586b87SGarrett D'Amore 100000, pvs, NULL, NULL, &pvs->tgtmap) != DDI_SUCCESS) {
1695c0586b87SGarrett D'Amore dev_err(pvs->dip, CE_WARN, "!failed to create target map");
1696c0586b87SGarrett D'Amore return (DDI_FAILURE);
1697c0586b87SGarrett D'Amore }
1698c0586b87SGarrett D'Amore
1699c0586b87SGarrett D'Amore /* reset hardware and setup the rings */
1700c0586b87SGarrett D'Amore mutex_enter(&pvs->lock);
1701c0586b87SGarrett D'Amore pvs->detach = B_FALSE; /* in case of reattach */
1702c0586b87SGarrett D'Amore pvscsi_start_hba(pvs);
1703c0586b87SGarrett D'Amore
1704c0586b87SGarrett D'Amore max_targets = pvs->max_targets = pvscsi_max_targets(pvs);
1705c0586b87SGarrett D'Amore mutex_exit(&pvs->lock);
1706c0586b87SGarrett D'Amore
1707c0586b87SGarrett D'Amore for (uint32_t i = 0; i < max_targets; i++) {
1708c0586b87SGarrett D'Amore char addr[8];
1709c0586b87SGarrett D'Amore if (pvscsi_probe_target(pvs, i)) {
1710c0586b87SGarrett D'Amore (void) snprintf(addr, sizeof (addr), "%x", i);
1711c0586b87SGarrett D'Amore (void) scsi_hba_tgtmap_tgt_add(pvs->tgtmap,
1712c0586b87SGarrett D'Amore SCSI_TGT_SCSI_DEVICE, addr, NULL);
1713c0586b87SGarrett D'Amore }
1714c0586b87SGarrett D'Amore }
1715c0586b87SGarrett D'Amore
1716c0586b87SGarrett D'Amore return (DDI_SUCCESS);
1717c0586b87SGarrett D'Amore }
1718c0586b87SGarrett D'Amore
1719c0586b87SGarrett D'Amore static int
pvscsi_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)1720c0586b87SGarrett D'Amore pvscsi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
1721c0586b87SGarrett D'Amore {
1722c0586b87SGarrett D'Amore pvscsi_softc_t *pvs;
1723c0586b87SGarrett D'Amore
1724c0586b87SGarrett D'Amore if (cmd != DDI_ATTACH) {
1725c0586b87SGarrett D'Amore return (DDI_FAILURE);
1726c0586b87SGarrett D'Amore }
1727c0586b87SGarrett D'Amore
1728c0586b87SGarrett D'Amore if (scsi_hba_iport_unit_address(dip) != NULL) {
1729c0586b87SGarrett D'Amore return (pvscsi_iport_attach(dip));
1730c0586b87SGarrett D'Amore }
1731c0586b87SGarrett D'Amore
1732c0586b87SGarrett D'Amore pvs = kmem_zalloc(sizeof (*pvs), KM_SLEEP);
1733c0586b87SGarrett D'Amore
1734c0586b87SGarrett D'Amore /* Setup HBA instance */
1735c0586b87SGarrett D'Amore pvs->dip = dip;
1736c0586b87SGarrett D'Amore
1737c0586b87SGarrett D'Amore /*
1738c0586b87SGarrett D'Amore * mutex initialization - note that we always run below
1739c0586b87SGarrett D'Amore * lock level, so we can get by without interrupt priorities
1740c0586b87SGarrett D'Amore */
1741c0586b87SGarrett D'Amore mutex_init(&pvs->lock, NULL, MUTEX_DRIVER, NULL);
1742c0586b87SGarrett D'Amore list_create(&pvs->cmd_queue, sizeof (pvscsi_cmd_t),
1743c0586b87SGarrett D'Amore offsetof(pvscsi_cmd_t, queue_node));
1744c0586b87SGarrett D'Amore list_create(&pvs->devices, sizeof (pvscsi_device_t),
1745c0586b87SGarrett D'Amore offsetof(pvscsi_device_t, node));
1746c0586b87SGarrett D'Amore
1747c0586b87SGarrett D'Amore if ((pvscsi_setup_io(pvs)) != DDI_SUCCESS) {
1748c0586b87SGarrett D'Amore dev_err(pvs->dip, CE_WARN, "!failed to setup I/O region");
1749c0586b87SGarrett D'Amore pvscsi_teardown(pvs);
1750c0586b87SGarrett D'Amore return (DDI_FAILURE);
1751c0586b87SGarrett D'Amore }
1752c0586b87SGarrett D'Amore
1753c0586b87SGarrett D'Amore pvscsi_stop_hba(pvs);
1754c0586b87SGarrett D'Amore
1755c0586b87SGarrett D'Amore if ((pvscsi_allocate_rings(pvs)) != DDI_SUCCESS) {
1756c0586b87SGarrett D'Amore dev_err(pvs->dip, CE_WARN, "!failed to allocate DMA rings");
1757c0586b87SGarrett D'Amore pvscsi_teardown(pvs);
1758c0586b87SGarrett D'Amore return (DDI_FAILURE);
1759c0586b87SGarrett D'Amore }
1760c0586b87SGarrett D'Amore
1761c0586b87SGarrett D'Amore if (pvscsi_setup_isr(pvs) != DDI_SUCCESS) {
1762c0586b87SGarrett D'Amore dev_err(pvs->dip, CE_WARN, "!failed to setup ISR");
1763c0586b87SGarrett D'Amore pvscsi_teardown(pvs);
1764c0586b87SGarrett D'Amore return (DDI_FAILURE);
1765c0586b87SGarrett D'Amore }
1766c0586b87SGarrett D'Amore
1767c0586b87SGarrett D'Amore /* enable interrupts */
1768c0586b87SGarrett D'Amore if (pvscsi_enable_intrs(pvs) != DDI_SUCCESS) {
1769c0586b87SGarrett D'Amore dev_err(pvs->dip, CE_WARN, "!failed to enable interrupts");
1770c0586b87SGarrett D'Amore pvscsi_teardown(pvs);
1771c0586b87SGarrett D'Amore return (DDI_FAILURE);
1772c0586b87SGarrett D'Amore }
1773c0586b87SGarrett D'Amore
1774c0586b87SGarrett D'Amore pvs->tq = ddi_taskq_create(dip, "iport", 1, TASKQ_DEFAULTPRI, 0);
1775c0586b87SGarrett D'Amore if (pvs->tq == NULL) {
1776c0586b87SGarrett D'Amore dev_err(pvs->dip, CE_WARN, "!failed creating tq");
1777c0586b87SGarrett D'Amore pvscsi_teardown(pvs);
1778c0586b87SGarrett D'Amore return (DDI_FAILURE);
1779c0586b87SGarrett D'Amore }
1780c0586b87SGarrett D'Amore if (pvscsi_hba_setup(pvs) != DDI_SUCCESS) {
1781c0586b87SGarrett D'Amore dev_err(pvs->dip, CE_WARN, "!failed to setup HBA");
1782c0586b87SGarrett D'Amore pvscsi_teardown(pvs);
1783c0586b87SGarrett D'Amore return (DDI_FAILURE);
1784c0586b87SGarrett D'Amore }
1785c0586b87SGarrett D'Amore
1786c0586b87SGarrett D'Amore if (scsi_hba_iport_register(dip, "iport0") != 0) {
1787c0586b87SGarrett D'Amore dev_err(pvs->dip, CE_WARN, "failed to register iport");
1788c0586b87SGarrett D'Amore /* detach cannot fail since we didn't setup the iport */
1789c0586b87SGarrett D'Amore (void) scsi_hba_detach(dip);
1790c0586b87SGarrett D'Amore pvscsi_teardown(pvs);
1791c0586b87SGarrett D'Amore return (DDI_FAILURE);
1792c0586b87SGarrett D'Amore }
1793c0586b87SGarrett D'Amore
1794c0586b87SGarrett D'Amore return (DDI_SUCCESS);
1795c0586b87SGarrett D'Amore }
1796c0586b87SGarrett D'Amore
1797c0586b87SGarrett D'Amore static int
pvscsi_iport_detach(dev_info_t * dip)1798c0586b87SGarrett D'Amore pvscsi_iport_detach(dev_info_t *dip)
1799c0586b87SGarrett D'Amore {
1800c0586b87SGarrett D'Amore pvscsi_softc_t *pvs;
1801c0586b87SGarrett D'Amore scsi_hba_tran_t *tran;
1802c0586b87SGarrett D'Amore const char *ua;
1803c0586b87SGarrett D'Amore pvscsi_cmd_t *reclaimed;
1804c0586b87SGarrett D'Amore
1805c0586b87SGarrett D'Amore if (((ua = scsi_hba_iport_unit_address(dip)) == NULL) ||
1806c0586b87SGarrett D'Amore (strcmp(ua, "iport0") != 0) ||
1807c0586b87SGarrett D'Amore ((tran = ddi_get_driver_private(dip)) == NULL) ||
1808c0586b87SGarrett D'Amore ((pvs = tran->tran_hba_private) == NULL)) {
1809c0586b87SGarrett D'Amore return (DDI_FAILURE);
1810c0586b87SGarrett D'Amore }
1811c0586b87SGarrett D'Amore
1812c0586b87SGarrett D'Amore /* stop the HBA */
1813c0586b87SGarrett D'Amore mutex_enter(&pvs->lock);
1814c0586b87SGarrett D'Amore pvs->detach = B_TRUE;
1815c0586b87SGarrett D'Amore pvscsi_stop_hba(pvs);
1816c0586b87SGarrett D'Amore mutex_exit(&pvs->lock);
1817c0586b87SGarrett D'Amore
1818c0586b87SGarrett D'Amore /* drain the taskq - nothing else will post to it */
1819c0586b87SGarrett D'Amore ddi_taskq_wait(pvs->tq);
1820c0586b87SGarrett D'Amore
1821c0586b87SGarrett D'Amore /* reset the HBA */
1822c0586b87SGarrett D'Amore mutex_enter(&pvs->lock);
1823c0586b87SGarrett D'Amore reclaimed = pvscsi_reclaim_cmds(pvs);
1824c0586b87SGarrett D'Amore mutex_exit(&pvs->lock);
1825c0586b87SGarrett D'Amore
1826c0586b87SGarrett D'Amore /*
1827c0586b87SGarrett D'Amore * If we had any commands, complete them so we can
1828c0586b87SGarrett D'Amore * reclaim the resources. There really should not be any.
1829c0586b87SGarrett D'Amore */
1830c0586b87SGarrett D'Amore pvscsi_complete_cmds(pvs, reclaimed);
1831c0586b87SGarrett D'Amore
1832c0586b87SGarrett D'Amore scsi_hba_tgtmap_destroy(pvs->tgtmap);
1833c0586b87SGarrett D'Amore pvs->tgtmap = NULL;
1834c0586b87SGarrett D'Amore
1835c0586b87SGarrett D'Amore return (DDI_SUCCESS);
1836c0586b87SGarrett D'Amore }
1837c0586b87SGarrett D'Amore
1838c0586b87SGarrett D'Amore static int
pvscsi_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)1839c0586b87SGarrett D'Amore pvscsi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
1840c0586b87SGarrett D'Amore {
1841c0586b87SGarrett D'Amore pvscsi_softc_t *pvs;
1842c0586b87SGarrett D'Amore scsi_hba_tran_t *tran;
1843c0586b87SGarrett D'Amore
1844c0586b87SGarrett D'Amore if (cmd != DDI_DETACH) {
1845c0586b87SGarrett D'Amore return (DDI_FAILURE);
1846c0586b87SGarrett D'Amore }
1847c0586b87SGarrett D'Amore
1848c0586b87SGarrett D'Amore if (scsi_hba_iport_unit_address(dip) != NULL) {
1849c0586b87SGarrett D'Amore return (pvscsi_iport_detach(dip));
1850c0586b87SGarrett D'Amore }
1851c0586b87SGarrett D'Amore
1852c0586b87SGarrett D'Amore if (((tran = ddi_get_driver_private(dip)) == NULL) ||
1853c0586b87SGarrett D'Amore ((pvs = tran->tran_hba_private) == NULL)) {
1854c0586b87SGarrett D'Amore /* this can only mean we aren't attached yet */
1855c0586b87SGarrett D'Amore return (DDI_SUCCESS);
1856c0586b87SGarrett D'Amore }
1857c0586b87SGarrett D'Amore if (scsi_hba_detach(dip) != DDI_SUCCESS) {
1858c0586b87SGarrett D'Amore return (DDI_FAILURE);
1859c0586b87SGarrett D'Amore }
1860c0586b87SGarrett D'Amore
1861c0586b87SGarrett D'Amore pvscsi_teardown(pvs);
1862c0586b87SGarrett D'Amore
1863c0586b87SGarrett D'Amore return (DDI_SUCCESS);
1864c0586b87SGarrett D'Amore }
1865c0586b87SGarrett D'Amore
1866c0586b87SGarrett D'Amore static int
pvscsi_quiesce(dev_info_t * dip)1867c0586b87SGarrett D'Amore pvscsi_quiesce(dev_info_t *dip)
1868c0586b87SGarrett D'Amore {
1869c0586b87SGarrett D'Amore scsi_hba_tran_t *tran;
1870c0586b87SGarrett D'Amore pvscsi_softc_t *pvs;
1871c0586b87SGarrett D'Amore
1872c0586b87SGarrett D'Amore if (((tran = ddi_get_driver_private(dip)) == NULL) ||
1873c0586b87SGarrett D'Amore ((pvs = tran->tran_hba_private) == NULL)) {
1874c0586b87SGarrett D'Amore return (DDI_SUCCESS);
1875c0586b87SGarrett D'Amore }
1876c0586b87SGarrett D'Amore
1877c0586b87SGarrett D'Amore pvscsi_stop_hba(pvs);
1878c0586b87SGarrett D'Amore
1879c0586b87SGarrett D'Amore return (DDI_SUCCESS);
1880c0586b87SGarrett D'Amore }
1881c0586b87SGarrett D'Amore
1882c0586b87SGarrett D'Amore static struct dev_ops pvscsi_ops = {
1883c0586b87SGarrett D'Amore .devo_rev = DEVO_REV,
1884c0586b87SGarrett D'Amore .devo_refcnt = 0,
1885c0586b87SGarrett D'Amore .devo_getinfo = nodev,
1886c0586b87SGarrett D'Amore .devo_identify = nulldev,
1887c0586b87SGarrett D'Amore .devo_probe = nulldev,
1888c0586b87SGarrett D'Amore .devo_attach = pvscsi_attach,
1889c0586b87SGarrett D'Amore .devo_detach = pvscsi_detach,
1890c0586b87SGarrett D'Amore .devo_reset = nodev,
1891c0586b87SGarrett D'Amore .devo_cb_ops = NULL,
1892c0586b87SGarrett D'Amore .devo_bus_ops = NULL,
1893c0586b87SGarrett D'Amore .devo_power = NULL,
1894c0586b87SGarrett D'Amore .devo_quiesce = pvscsi_quiesce
1895c0586b87SGarrett D'Amore };
1896c0586b87SGarrett D'Amore
1897c0586b87SGarrett D'Amore #define PVSCSI_IDENT "VMware PVSCSI"
1898c0586b87SGarrett D'Amore
1899c0586b87SGarrett D'Amore static struct modldrv modldrv = {
1900c0586b87SGarrett D'Amore &mod_driverops,
1901c0586b87SGarrett D'Amore PVSCSI_IDENT,
1902c0586b87SGarrett D'Amore &pvscsi_ops,
1903c0586b87SGarrett D'Amore };
1904c0586b87SGarrett D'Amore
1905c0586b87SGarrett D'Amore static struct modlinkage modlinkage = {
1906c0586b87SGarrett D'Amore MODREV_1,
1907c0586b87SGarrett D'Amore &modldrv,
1908c0586b87SGarrett D'Amore NULL
1909c0586b87SGarrett D'Amore };
1910c0586b87SGarrett D'Amore
1911c0586b87SGarrett D'Amore int
_init(void)1912c0586b87SGarrett D'Amore _init(void)
1913c0586b87SGarrett D'Amore {
1914c0586b87SGarrett D'Amore int ret;
1915c0586b87SGarrett D'Amore
1916c0586b87SGarrett D'Amore /* get HZ - DDI compliant */
1917c0586b87SGarrett D'Amore pvscsi_hz = drv_usectohz(1000000);
1918c0586b87SGarrett D'Amore
1919c0586b87SGarrett D'Amore if ((ret = scsi_hba_init(&modlinkage)) != 0) {
1920c0586b87SGarrett D'Amore cmn_err(CE_WARN, "!scsi_hba_init() failed");
1921c0586b87SGarrett D'Amore return (ret);
1922c0586b87SGarrett D'Amore }
1923c0586b87SGarrett D'Amore
1924c0586b87SGarrett D'Amore if ((ret = mod_install(&modlinkage)) != 0) {
1925c0586b87SGarrett D'Amore cmn_err(CE_WARN, "!mod_install() failed");
1926c0586b87SGarrett D'Amore scsi_hba_fini(&modlinkage);
1927c0586b87SGarrett D'Amore }
1928c0586b87SGarrett D'Amore
1929c0586b87SGarrett D'Amore return (ret);
1930c0586b87SGarrett D'Amore }
1931c0586b87SGarrett D'Amore
1932c0586b87SGarrett D'Amore int
_info(struct modinfo * modinfop)1933c0586b87SGarrett D'Amore _info(struct modinfo *modinfop)
1934c0586b87SGarrett D'Amore {
1935c0586b87SGarrett D'Amore return (mod_info(&modlinkage, modinfop));
1936c0586b87SGarrett D'Amore }
1937c0586b87SGarrett D'Amore
1938c0586b87SGarrett D'Amore int
_fini(void)1939c0586b87SGarrett D'Amore _fini(void)
1940c0586b87SGarrett D'Amore {
1941c0586b87SGarrett D'Amore int ret;
1942c0586b87SGarrett D'Amore
1943c0586b87SGarrett D'Amore if ((ret = mod_remove(&modlinkage)) == 0) {
1944c0586b87SGarrett D'Amore scsi_hba_fini(&modlinkage);
1945c0586b87SGarrett D'Amore }
1946c0586b87SGarrett D'Amore
1947c0586b87SGarrett D'Amore return (ret);
1948c0586b87SGarrett D'Amore }
1949