1f52228b8SJoe Beteta /*
2f52228b8SJoe Beteta *
3f52228b8SJoe Beteta * skd.c: Solaris 11/10 Driver for sTec, Inc. S112x PCIe SSD card
4f52228b8SJoe Beteta *
5f52228b8SJoe Beteta * Solaris driver is based on the Linux driver authored by:
6f52228b8SJoe Beteta *
7f52228b8SJoe Beteta * Authors/Alphabetical: Dragan Stancevic <dstancevic@stec-inc.com>
8f52228b8SJoe Beteta * Gordon Waidhofer <gwaidhofer@stec-inc.com>
9f52228b8SJoe Beteta * John Hamilton <jhamilton@stec-inc.com>
10f52228b8SJoe Beteta */
11f52228b8SJoe Beteta
12f52228b8SJoe Beteta /*
13f52228b8SJoe Beteta * This file and its contents are supplied under the terms of the
14f52228b8SJoe Beteta * Common Development and Distribution License ("CDDL"), version 1.0.
15f52228b8SJoe Beteta * You may only use this file in accordance with the terms of version
16f52228b8SJoe Beteta * 1.0 of the CDDL.
17f52228b8SJoe Beteta *
18f52228b8SJoe Beteta * A full copy of the text of the CDDL should have accompanied this
19f52228b8SJoe Beteta * source. A copy of the CDDL is also available via the Internet at
20f52228b8SJoe Beteta * http://www.illumos.org/license/CDDL.
21f52228b8SJoe Beteta */
22f52228b8SJoe Beteta
23f52228b8SJoe Beteta /*
24f52228b8SJoe Beteta * Copyright 2013 STEC, Inc. All rights reserved.
25510a6847SHans Rosenfeld * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
26f52228b8SJoe Beteta */
27f52228b8SJoe Beteta
28f52228b8SJoe Beteta #include <sys/types.h>
29f52228b8SJoe Beteta #include <sys/stream.h>
30f52228b8SJoe Beteta #include <sys/cmn_err.h>
31f52228b8SJoe Beteta #include <sys/kmem.h>
32f52228b8SJoe Beteta #include <sys/file.h>
33f52228b8SJoe Beteta #include <sys/buf.h>
34f52228b8SJoe Beteta #include <sys/uio.h>
35f52228b8SJoe Beteta #include <sys/cred.h>
36f52228b8SJoe Beteta #include <sys/modctl.h>
37f52228b8SJoe Beteta #include <sys/debug.h>
38f52228b8SJoe Beteta #include <sys/modctl.h>
39f52228b8SJoe Beteta #include <sys/list.h>
40f52228b8SJoe Beteta #include <sys/sysmacros.h>
41f52228b8SJoe Beteta #include <sys/errno.h>
42f52228b8SJoe Beteta #include <sys/pcie.h>
43f52228b8SJoe Beteta #include <sys/pci.h>
44f52228b8SJoe Beteta #include <sys/ddi.h>
45f52228b8SJoe Beteta #include <sys/dditypes.h>
46f52228b8SJoe Beteta #include <sys/sunddi.h>
47f52228b8SJoe Beteta #include <sys/atomic.h>
48f52228b8SJoe Beteta #include <sys/mutex.h>
49f52228b8SJoe Beteta #include <sys/param.h>
50f52228b8SJoe Beteta #include <sys/devops.h>
51f52228b8SJoe Beteta #include <sys/blkdev.h>
52f52228b8SJoe Beteta #include <sys/queue.h>
53*bef9e21aSHans Rosenfeld #include <sys/scsi/impl/inquiry.h>
54f52228b8SJoe Beteta
55f52228b8SJoe Beteta #include "skd_s1120.h"
56f52228b8SJoe Beteta #include "skd.h"
57f52228b8SJoe Beteta
58f52228b8SJoe Beteta int skd_dbg_level = 0;
59f52228b8SJoe Beteta
60f52228b8SJoe Beteta void *skd_state = NULL;
61f52228b8SJoe Beteta int skd_disable_msi = 0;
62f52228b8SJoe Beteta int skd_disable_msix = 0;
63f52228b8SJoe Beteta
64f52228b8SJoe Beteta /* Initialized in _init() and tunable, see _init(). */
65f52228b8SJoe Beteta clock_t skd_timer_ticks;
66f52228b8SJoe Beteta
67f52228b8SJoe Beteta /* I/O DMA attributes structures. */
68f52228b8SJoe Beteta static ddi_dma_attr_t skd_64bit_io_dma_attr = {
69f52228b8SJoe Beteta DMA_ATTR_V0, /* dma_attr_version */
70f52228b8SJoe Beteta SKD_DMA_LOW_ADDRESS, /* low DMA address range */
71f52228b8SJoe Beteta SKD_DMA_HIGH_64BIT_ADDRESS, /* high DMA address range */
72f52228b8SJoe Beteta SKD_DMA_XFER_COUNTER, /* DMA counter register */
73f52228b8SJoe Beteta SKD_DMA_ADDRESS_ALIGNMENT, /* DMA address alignment */
74f52228b8SJoe Beteta SKD_DMA_BURSTSIZES, /* DMA burstsizes */
75f52228b8SJoe Beteta SKD_DMA_MIN_XFER_SIZE, /* min effective DMA size */
76f52228b8SJoe Beteta SKD_DMA_MAX_XFER_SIZE, /* max DMA xfer size */
77f52228b8SJoe Beteta SKD_DMA_SEGMENT_BOUNDARY, /* segment boundary */
78f52228b8SJoe Beteta SKD_DMA_SG_LIST_LENGTH, /* s/g list length */
79f52228b8SJoe Beteta SKD_DMA_GRANULARITY, /* granularity of device */
80f52228b8SJoe Beteta SKD_DMA_XFER_FLAGS /* DMA transfer flags */
81f52228b8SJoe Beteta };
82f52228b8SJoe Beteta
83f52228b8SJoe Beteta int skd_isr_type = -1;
84f52228b8SJoe Beteta
85f52228b8SJoe Beteta #define SKD_MAX_QUEUE_DEPTH 255
86f52228b8SJoe Beteta #define SKD_MAX_QUEUE_DEPTH_DEFAULT 64
87f52228b8SJoe Beteta int skd_max_queue_depth = SKD_MAX_QUEUE_DEPTH_DEFAULT;
88f52228b8SJoe Beteta
89f52228b8SJoe Beteta #define SKD_MAX_REQ_PER_MSG 14
90f52228b8SJoe Beteta #define SKD_MAX_REQ_PER_MSG_DEFAULT 1
91f52228b8SJoe Beteta int skd_max_req_per_msg = SKD_MAX_REQ_PER_MSG_DEFAULT;
92f52228b8SJoe Beteta
93f52228b8SJoe Beteta #define SKD_MAX_N_SG_PER_REQ 4096
94f52228b8SJoe Beteta int skd_sgs_per_request = SKD_N_SG_PER_REQ_DEFAULT;
95f52228b8SJoe Beteta
96f52228b8SJoe Beteta static int skd_sys_quiesce_dev(dev_info_t *);
97f52228b8SJoe Beteta static int skd_quiesce_dev(skd_device_t *);
98f52228b8SJoe Beteta static int skd_list_skmsg(skd_device_t *, int);
99f52228b8SJoe Beteta static int skd_list_skreq(skd_device_t *, int);
100f52228b8SJoe Beteta static int skd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
101f52228b8SJoe Beteta static int skd_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
102f52228b8SJoe Beteta static int skd_format_internal_skspcl(struct skd_device *skdev);
103f52228b8SJoe Beteta static void skd_start(skd_device_t *);
104f52228b8SJoe Beteta static void skd_destroy_mutex(skd_device_t *skdev);
105f52228b8SJoe Beteta static void skd_enable_interrupts(struct skd_device *);
106f52228b8SJoe Beteta static void skd_request_fn_not_online(skd_device_t *skdev);
107f52228b8SJoe Beteta static void skd_send_internal_skspcl(struct skd_device *,
108f52228b8SJoe Beteta struct skd_special_context *, uint8_t);
109f52228b8SJoe Beteta static void skd_queue(skd_device_t *, skd_buf_private_t *);
110f52228b8SJoe Beteta static void *skd_alloc_dma_mem(skd_device_t *, dma_mem_t *, uint8_t);
111f52228b8SJoe Beteta static void skd_release_intr(skd_device_t *skdev);
112f52228b8SJoe Beteta static void skd_isr_fwstate(struct skd_device *skdev);
113f52228b8SJoe Beteta static void skd_isr_msg_from_dev(struct skd_device *skdev);
114f52228b8SJoe Beteta static void skd_soft_reset(struct skd_device *skdev);
115f52228b8SJoe Beteta static void skd_refresh_device_data(struct skd_device *skdev);
116f52228b8SJoe Beteta static void skd_update_props(skd_device_t *, dev_info_t *);
117f52228b8SJoe Beteta static void skd_end_request_abnormal(struct skd_device *, skd_buf_private_t *,
118f52228b8SJoe Beteta int, int);
119f52228b8SJoe Beteta static char *skd_pci_info(struct skd_device *skdev, char *str, size_t len);
120f52228b8SJoe Beteta
121f52228b8SJoe Beteta static skd_buf_private_t *skd_get_queued_pbuf(skd_device_t *);
122f52228b8SJoe Beteta
123f52228b8SJoe Beteta static void skd_bd_driveinfo(void *arg, bd_drive_t *drive);
124f52228b8SJoe Beteta static int skd_bd_mediainfo(void *arg, bd_media_t *media);
125f52228b8SJoe Beteta static int skd_bd_read(void *arg, bd_xfer_t *xfer);
126f52228b8SJoe Beteta static int skd_bd_write(void *arg, bd_xfer_t *xfer);
127f52228b8SJoe Beteta static int skd_devid_init(void *arg, dev_info_t *, ddi_devid_t *);
128f52228b8SJoe Beteta
129f52228b8SJoe Beteta
130f52228b8SJoe Beteta static bd_ops_t skd_bd_ops = {
131f52228b8SJoe Beteta BD_OPS_VERSION_0,
132f52228b8SJoe Beteta skd_bd_driveinfo,
133f52228b8SJoe Beteta skd_bd_mediainfo,
134f52228b8SJoe Beteta skd_devid_init,
135f52228b8SJoe Beteta NULL, /* sync_cache */
136f52228b8SJoe Beteta skd_bd_read,
137f52228b8SJoe Beteta skd_bd_write,
138f52228b8SJoe Beteta };
139f52228b8SJoe Beteta
140f52228b8SJoe Beteta static ddi_device_acc_attr_t dev_acc_attr = {
141f52228b8SJoe Beteta DDI_DEVICE_ATTR_V0,
142f52228b8SJoe Beteta DDI_STRUCTURE_LE_ACC,
143f52228b8SJoe Beteta DDI_STRICTORDER_ACC
144f52228b8SJoe Beteta };
145f52228b8SJoe Beteta
146f52228b8SJoe Beteta /*
147f52228b8SJoe Beteta * Solaris module loading/unloading structures
148f52228b8SJoe Beteta */
149f52228b8SJoe Beteta struct dev_ops skd_dev_ops = {
150f52228b8SJoe Beteta DEVO_REV, /* devo_rev */
151f52228b8SJoe Beteta 0, /* refcnt */
152f52228b8SJoe Beteta ddi_no_info, /* getinfo */
153f52228b8SJoe Beteta nulldev, /* identify */
154f52228b8SJoe Beteta nulldev, /* probe */
155f52228b8SJoe Beteta skd_attach, /* attach */
156f52228b8SJoe Beteta skd_detach, /* detach */
157f52228b8SJoe Beteta nodev, /* reset */
158f52228b8SJoe Beteta NULL, /* char/block ops */
159f52228b8SJoe Beteta NULL, /* bus operations */
160f52228b8SJoe Beteta NULL, /* power management */
161f52228b8SJoe Beteta skd_sys_quiesce_dev /* quiesce */
162f52228b8SJoe Beteta };
163f52228b8SJoe Beteta
164f52228b8SJoe Beteta static struct modldrv modldrv = {
165f52228b8SJoe Beteta &mod_driverops, /* type of module: driver */
166f52228b8SJoe Beteta "sTec skd v" DRV_VER_COMPL, /* name of module */
167f52228b8SJoe Beteta &skd_dev_ops /* driver dev_ops */
168f52228b8SJoe Beteta };
169f52228b8SJoe Beteta
170f52228b8SJoe Beteta static struct modlinkage modlinkage = {
171f52228b8SJoe Beteta MODREV_1,
172f52228b8SJoe Beteta &modldrv,
173f52228b8SJoe Beteta NULL
174f52228b8SJoe Beteta };
175f52228b8SJoe Beteta
176f52228b8SJoe Beteta /*
177f52228b8SJoe Beteta * sTec-required wrapper for debug printing.
178f52228b8SJoe Beteta */
179f52228b8SJoe Beteta /*PRINTFLIKE2*/
180f52228b8SJoe Beteta static inline void
Dcmn_err(int lvl,const char * fmt,...)181f52228b8SJoe Beteta Dcmn_err(int lvl, const char *fmt, ...)
182f52228b8SJoe Beteta {
183f52228b8SJoe Beteta va_list ap;
184f52228b8SJoe Beteta
185f52228b8SJoe Beteta if (skd_dbg_level == 0)
186f52228b8SJoe Beteta return;
187f52228b8SJoe Beteta
188f52228b8SJoe Beteta va_start(ap, fmt);
189f52228b8SJoe Beteta vcmn_err(lvl, fmt, ap);
190f52228b8SJoe Beteta va_end(ap);
191f52228b8SJoe Beteta }
192f52228b8SJoe Beteta
193f52228b8SJoe Beteta /*
194f52228b8SJoe Beteta * Solaris module loading/unloading routines
195f52228b8SJoe Beteta */
196f52228b8SJoe Beteta
197f52228b8SJoe Beteta /*
198f52228b8SJoe Beteta *
199f52228b8SJoe Beteta * Name: _init, performs initial installation
200f52228b8SJoe Beteta *
201f52228b8SJoe Beteta * Inputs: None.
202f52228b8SJoe Beteta *
203f52228b8SJoe Beteta * Returns: Returns the value returned by the ddi_softstate_init function
204f52228b8SJoe Beteta * on a failure to create the device state structure or the result
205f52228b8SJoe Beteta * of the module install routines.
206f52228b8SJoe Beteta *
207f52228b8SJoe Beteta */
208f52228b8SJoe Beteta int
_init(void)209f52228b8SJoe Beteta _init(void)
210f52228b8SJoe Beteta {
211f52228b8SJoe Beteta int rval = 0;
212f52228b8SJoe Beteta int tgts = 0;
213f52228b8SJoe Beteta
214f52228b8SJoe Beteta tgts |= 0x02;
215f52228b8SJoe Beteta tgts |= 0x08; /* In #ifdef NEXENTA block from original sTec drop. */
216f52228b8SJoe Beteta
217f52228b8SJoe Beteta /*
218f52228b8SJoe Beteta * drv_usectohz() is a function, so can't initialize it at
219f52228b8SJoe Beteta * instantiation.
220f52228b8SJoe Beteta */
221f52228b8SJoe Beteta skd_timer_ticks = drv_usectohz(1000000);
222f52228b8SJoe Beteta
223f52228b8SJoe Beteta Dcmn_err(CE_NOTE,
224f52228b8SJoe Beteta "<# Installing skd Driver dbg-lvl=%d %s %x>",
225f52228b8SJoe Beteta skd_dbg_level, DRV_BUILD_ID, tgts);
226f52228b8SJoe Beteta
227f52228b8SJoe Beteta rval = ddi_soft_state_init(&skd_state, sizeof (skd_device_t), 0);
228f52228b8SJoe Beteta if (rval != DDI_SUCCESS)
229f52228b8SJoe Beteta return (rval);
230f52228b8SJoe Beteta
231f52228b8SJoe Beteta bd_mod_init(&skd_dev_ops);
232f52228b8SJoe Beteta
233f52228b8SJoe Beteta rval = mod_install(&modlinkage);
234f52228b8SJoe Beteta if (rval != DDI_SUCCESS) {
235f52228b8SJoe Beteta ddi_soft_state_fini(&skd_state);
236f52228b8SJoe Beteta bd_mod_fini(&skd_dev_ops);
237f52228b8SJoe Beteta }
238f52228b8SJoe Beteta
239f52228b8SJoe Beteta return (rval);
240f52228b8SJoe Beteta }
241f52228b8SJoe Beteta
242f52228b8SJoe Beteta /*
243f52228b8SJoe Beteta *
244f52228b8SJoe Beteta * Name: _info, returns information about loadable module.
245f52228b8SJoe Beteta *
246f52228b8SJoe Beteta * Inputs: modinfo, pointer to module information structure.
247f52228b8SJoe Beteta *
248f52228b8SJoe Beteta * Returns: Value returned by mod_info().
249f52228b8SJoe Beteta *
250f52228b8SJoe Beteta */
251f52228b8SJoe Beteta int
_info(struct modinfo * modinfop)252f52228b8SJoe Beteta _info(struct modinfo *modinfop)
253f52228b8SJoe Beteta {
254f52228b8SJoe Beteta return (mod_info(&modlinkage, modinfop));
255f52228b8SJoe Beteta }
256f52228b8SJoe Beteta
257f52228b8SJoe Beteta /*
258f52228b8SJoe Beteta * _fini Prepares a module for unloading. It is called when the system
259f52228b8SJoe Beteta * wants to unload a module. If the module determines that it can
260f52228b8SJoe Beteta * be unloaded, then _fini() returns the value returned by
261f52228b8SJoe Beteta * mod_remove(). Upon successful return from _fini() no other
262f52228b8SJoe Beteta * routine in the module will be called before _init() is called.
263f52228b8SJoe Beteta *
264f52228b8SJoe Beteta * Inputs: None.
265f52228b8SJoe Beteta *
266f52228b8SJoe Beteta * Returns: DDI_SUCCESS or DDI_FAILURE.
267f52228b8SJoe Beteta *
268f52228b8SJoe Beteta */
269f52228b8SJoe Beteta int
_fini(void)270f52228b8SJoe Beteta _fini(void)
271f52228b8SJoe Beteta {
272f52228b8SJoe Beteta int rval;
273f52228b8SJoe Beteta
274f52228b8SJoe Beteta rval = mod_remove(&modlinkage);
275f52228b8SJoe Beteta if (rval == DDI_SUCCESS) {
276f52228b8SJoe Beteta ddi_soft_state_fini(&skd_state);
277f52228b8SJoe Beteta bd_mod_fini(&skd_dev_ops);
278f52228b8SJoe Beteta }
279f52228b8SJoe Beteta
280f52228b8SJoe Beteta return (rval);
281f52228b8SJoe Beteta }
282f52228b8SJoe Beteta
283f52228b8SJoe Beteta /*
284f52228b8SJoe Beteta * Solaris Register read/write routines
285f52228b8SJoe Beteta */
286f52228b8SJoe Beteta
287f52228b8SJoe Beteta /*
288f52228b8SJoe Beteta *
289f52228b8SJoe Beteta * Name: skd_reg_write64, writes a 64-bit value to specified address
290f52228b8SJoe Beteta *
291f52228b8SJoe Beteta * Inputs: skdev - device state structure.
292f52228b8SJoe Beteta * val - 64-bit value to be written.
293f52228b8SJoe Beteta * offset - offset from PCI base address.
294f52228b8SJoe Beteta *
295f52228b8SJoe Beteta * Returns: Nothing.
296f52228b8SJoe Beteta *
297f52228b8SJoe Beteta */
298f52228b8SJoe Beteta /*
299f52228b8SJoe Beteta * Local vars are to keep lint silent. Any compiler worth its weight will
300f52228b8SJoe Beteta * optimize it all right out...
301f52228b8SJoe Beteta */
302f52228b8SJoe Beteta static inline void
skd_reg_write64(struct skd_device * skdev,uint64_t val,uint32_t offset)303f52228b8SJoe Beteta skd_reg_write64(struct skd_device *skdev, uint64_t val, uint32_t offset)
304f52228b8SJoe Beteta {
305f52228b8SJoe Beteta uint64_t *addr;
306f52228b8SJoe Beteta
307f52228b8SJoe Beteta ASSERT((offset & 0x7) == 0);
308f52228b8SJoe Beteta /* LINTED */
309f52228b8SJoe Beteta addr = (uint64_t *)(skdev->dev_iobase + offset);
310f52228b8SJoe Beteta ddi_put64(skdev->dev_handle, addr, val);
311f52228b8SJoe Beteta }
312f52228b8SJoe Beteta
313f52228b8SJoe Beteta /*
314f52228b8SJoe Beteta *
315f52228b8SJoe Beteta * Name: skd_reg_read32, reads a 32-bit value to specified address
316f52228b8SJoe Beteta *
317f52228b8SJoe Beteta * Inputs: skdev - device state structure.
318f52228b8SJoe Beteta * offset - offset from PCI base address.
319f52228b8SJoe Beteta *
320f52228b8SJoe Beteta * Returns: val, 32-bit value read from specified PCI address.
321f52228b8SJoe Beteta *
322f52228b8SJoe Beteta */
323f52228b8SJoe Beteta static inline uint32_t
skd_reg_read32(struct skd_device * skdev,uint32_t offset)324f52228b8SJoe Beteta skd_reg_read32(struct skd_device *skdev, uint32_t offset)
325f52228b8SJoe Beteta {
326f52228b8SJoe Beteta uint32_t *addr;
327f52228b8SJoe Beteta
328f52228b8SJoe Beteta ASSERT((offset & 0x3) == 0);
329f52228b8SJoe Beteta /* LINTED */
330f52228b8SJoe Beteta addr = (uint32_t *)(skdev->dev_iobase + offset);
331f52228b8SJoe Beteta return (ddi_get32(skdev->dev_handle, addr));
332f52228b8SJoe Beteta }
333f52228b8SJoe Beteta
334f52228b8SJoe Beteta /*
335f52228b8SJoe Beteta *
336f52228b8SJoe Beteta * Name: skd_reg_write32, writes a 32-bit value to specified address
337f52228b8SJoe Beteta *
338f52228b8SJoe Beteta * Inputs: skdev - device state structure.
339f52228b8SJoe Beteta * val - value to be written.
340f52228b8SJoe Beteta * offset - offset from PCI base address.
341f52228b8SJoe Beteta *
342f52228b8SJoe Beteta * Returns: Nothing.
343f52228b8SJoe Beteta *
344f52228b8SJoe Beteta */
345f52228b8SJoe Beteta static inline void
skd_reg_write32(struct skd_device * skdev,uint32_t val,uint32_t offset)346f52228b8SJoe Beteta skd_reg_write32(struct skd_device *skdev, uint32_t val, uint32_t offset)
347f52228b8SJoe Beteta {
348f52228b8SJoe Beteta uint32_t *addr;
349f52228b8SJoe Beteta
350f52228b8SJoe Beteta ASSERT((offset & 0x3) == 0);
351f52228b8SJoe Beteta /* LINTED */
352f52228b8SJoe Beteta addr = (uint32_t *)(skdev->dev_iobase + offset);
353f52228b8SJoe Beteta ddi_put32(skdev->dev_handle, addr, val);
354f52228b8SJoe Beteta }
355f52228b8SJoe Beteta
356f52228b8SJoe Beteta
357f52228b8SJoe Beteta /*
358f52228b8SJoe Beteta * Solaris skd routines
359f52228b8SJoe Beteta */
360f52228b8SJoe Beteta
361f52228b8SJoe Beteta /*
362f52228b8SJoe Beteta *
363f52228b8SJoe Beteta * Name: skd_name, generates the name of the driver.
364f52228b8SJoe Beteta *
365f52228b8SJoe Beteta * Inputs: skdev - device state structure
366f52228b8SJoe Beteta *
367f52228b8SJoe Beteta * Returns: char pointer to generated driver name.
368f52228b8SJoe Beteta *
369f52228b8SJoe Beteta */
370f52228b8SJoe Beteta static const char *
skd_name(struct skd_device * skdev)371f52228b8SJoe Beteta skd_name(struct skd_device *skdev)
372f52228b8SJoe Beteta {
373f52228b8SJoe Beteta (void) snprintf(skdev->id_str, sizeof (skdev->id_str), "%s:", DRV_NAME);
374f52228b8SJoe Beteta
375f52228b8SJoe Beteta return (skdev->id_str);
376f52228b8SJoe Beteta }
377f52228b8SJoe Beteta
378f52228b8SJoe Beteta /*
379f52228b8SJoe Beteta *
380f52228b8SJoe Beteta * Name: skd_pci_find_capability, searches the PCI capability
381f52228b8SJoe Beteta * list for the specified capability.
382f52228b8SJoe Beteta *
383f52228b8SJoe Beteta * Inputs: skdev - device state structure.
384f52228b8SJoe Beteta * cap - capability sought.
385f52228b8SJoe Beteta *
386f52228b8SJoe Beteta * Returns: Returns position where capability was found.
387f52228b8SJoe Beteta * If not found, returns zero.
388f52228b8SJoe Beteta *
389f52228b8SJoe Beteta */
390f52228b8SJoe Beteta static int
skd_pci_find_capability(struct skd_device * skdev,int cap)391f52228b8SJoe Beteta skd_pci_find_capability(struct skd_device *skdev, int cap)
392f52228b8SJoe Beteta {
393f52228b8SJoe Beteta uint16_t status;
394f52228b8SJoe Beteta uint8_t pos, id, hdr;
395f52228b8SJoe Beteta int ttl = 48;
396f52228b8SJoe Beteta
397f52228b8SJoe Beteta status = pci_config_get16(skdev->pci_handle, PCI_CONF_STAT);
398f52228b8SJoe Beteta
399f52228b8SJoe Beteta if (!(status & PCI_STAT_CAP))
400f52228b8SJoe Beteta return (0);
401f52228b8SJoe Beteta
402f52228b8SJoe Beteta hdr = pci_config_get8(skdev->pci_handle, PCI_CONF_HEADER);
403f52228b8SJoe Beteta
404f52228b8SJoe Beteta if ((hdr & PCI_HEADER_TYPE_M) != 0)
405f52228b8SJoe Beteta return (0);
406f52228b8SJoe Beteta
407f52228b8SJoe Beteta pos = pci_config_get8(skdev->pci_handle, PCI_CONF_CAP_PTR);
408f52228b8SJoe Beteta
409f52228b8SJoe Beteta while (ttl-- && pos >= 0x40) {
410f52228b8SJoe Beteta pos &= ~3;
411f52228b8SJoe Beteta id = pci_config_get8(skdev->pci_handle, pos+PCI_CAP_ID);
412f52228b8SJoe Beteta if (id == 0xff)
413f52228b8SJoe Beteta break;
414f52228b8SJoe Beteta if (id == cap)
415f52228b8SJoe Beteta return (pos);
416f52228b8SJoe Beteta pos = pci_config_get8(skdev->pci_handle, pos+PCI_CAP_NEXT_PTR);
417f52228b8SJoe Beteta }
418f52228b8SJoe Beteta
419f52228b8SJoe Beteta return (0);
420f52228b8SJoe Beteta }
421f52228b8SJoe Beteta
422f52228b8SJoe Beteta /*
423f52228b8SJoe Beteta *
424f52228b8SJoe Beteta * Name: skd_io_done, called to conclude an I/O operation.
425f52228b8SJoe Beteta *
426f52228b8SJoe Beteta * Inputs: skdev - device state structure.
427f52228b8SJoe Beteta * pbuf - I/O request
428f52228b8SJoe Beteta * error - contain error value.
429f52228b8SJoe Beteta * mode - debug only.
430f52228b8SJoe Beteta *
431f52228b8SJoe Beteta * Returns: Nothing.
432f52228b8SJoe Beteta *
433f52228b8SJoe Beteta */
434f52228b8SJoe Beteta static void
skd_io_done(skd_device_t * skdev,skd_buf_private_t * pbuf,int error,int mode)435f52228b8SJoe Beteta skd_io_done(skd_device_t *skdev, skd_buf_private_t *pbuf,
436f52228b8SJoe Beteta int error, int mode)
437f52228b8SJoe Beteta {
438f52228b8SJoe Beteta bd_xfer_t *xfer;
439f52228b8SJoe Beteta
440f52228b8SJoe Beteta ASSERT(pbuf != NULL);
441f52228b8SJoe Beteta
442f52228b8SJoe Beteta xfer = pbuf->x_xfer;
443f52228b8SJoe Beteta
444f52228b8SJoe Beteta switch (mode) {
445f52228b8SJoe Beteta case SKD_IODONE_WIOC:
446f52228b8SJoe Beteta skdev->iodone_wioc++;
447f52228b8SJoe Beteta break;
448f52228b8SJoe Beteta case SKD_IODONE_WNIOC:
449f52228b8SJoe Beteta skdev->iodone_wnioc++;
450f52228b8SJoe Beteta break;
451f52228b8SJoe Beteta case SKD_IODONE_WDEBUG:
452f52228b8SJoe Beteta skdev->iodone_wdebug++;
453f52228b8SJoe Beteta break;
454f52228b8SJoe Beteta default:
455f52228b8SJoe Beteta skdev->iodone_unknown++;
456f52228b8SJoe Beteta }
457f52228b8SJoe Beteta
458f52228b8SJoe Beteta if (error) {
459f52228b8SJoe Beteta skdev->ios_errors++;
460f52228b8SJoe Beteta cmn_err(CE_WARN,
461f52228b8SJoe Beteta "!%s:skd_io_done:ERR=%d %lld-%ld %s", skdev->name,
462f52228b8SJoe Beteta error, xfer->x_blkno, xfer->x_nblks,
463f52228b8SJoe Beteta (pbuf->dir & B_READ) ? "Read" : "Write");
464f52228b8SJoe Beteta }
465f52228b8SJoe Beteta
466f52228b8SJoe Beteta kmem_free(pbuf, sizeof (skd_buf_private_t));
467f52228b8SJoe Beteta
468f52228b8SJoe Beteta bd_xfer_done(xfer, error);
469f52228b8SJoe Beteta }
470f52228b8SJoe Beteta
471f52228b8SJoe Beteta /*
472f52228b8SJoe Beteta * QUIESCE DEVICE
473f52228b8SJoe Beteta */
474f52228b8SJoe Beteta
475f52228b8SJoe Beteta /*
476f52228b8SJoe Beteta *
477f52228b8SJoe Beteta * Name: skd_sys_quiesce_dev, quiets the device
478f52228b8SJoe Beteta *
479f52228b8SJoe Beteta * Inputs: dip - dev info strucuture
480f52228b8SJoe Beteta *
481f52228b8SJoe Beteta * Returns: Zero.
482f52228b8SJoe Beteta *
483f52228b8SJoe Beteta */
484f52228b8SJoe Beteta static int
skd_sys_quiesce_dev(dev_info_t * dip)485f52228b8SJoe Beteta skd_sys_quiesce_dev(dev_info_t *dip)
486f52228b8SJoe Beteta {
487f52228b8SJoe Beteta skd_device_t *skdev;
488f52228b8SJoe Beteta
489f52228b8SJoe Beteta skdev = ddi_get_soft_state(skd_state, ddi_get_instance(dip));
490f52228b8SJoe Beteta
491f52228b8SJoe Beteta /* make sure Dcmn_err() doesn't actually print anything */
492f52228b8SJoe Beteta skd_dbg_level = 0;
493f52228b8SJoe Beteta
494f52228b8SJoe Beteta skd_disable_interrupts(skdev);
495f52228b8SJoe Beteta skd_soft_reset(skdev);
496f52228b8SJoe Beteta
497f52228b8SJoe Beteta return (0);
498f52228b8SJoe Beteta }
499f52228b8SJoe Beteta
500f52228b8SJoe Beteta /*
501f52228b8SJoe Beteta *
502f52228b8SJoe Beteta * Name: skd_quiesce_dev, quiets the device, but doesn't really do much.
503f52228b8SJoe Beteta *
504f52228b8SJoe Beteta * Inputs: skdev - Device state.
505f52228b8SJoe Beteta *
506f52228b8SJoe Beteta * Returns: -EINVAL if device is not in proper state otherwise
507f52228b8SJoe Beteta * returns zero.
508f52228b8SJoe Beteta *
509f52228b8SJoe Beteta */
510f52228b8SJoe Beteta static int
skd_quiesce_dev(skd_device_t * skdev)511f52228b8SJoe Beteta skd_quiesce_dev(skd_device_t *skdev)
512f52228b8SJoe Beteta {
513f52228b8SJoe Beteta int rc = 0;
514f52228b8SJoe Beteta
515f52228b8SJoe Beteta if (skd_dbg_level)
516f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "skd_quiece_dev:");
517f52228b8SJoe Beteta
518f52228b8SJoe Beteta switch (skdev->state) {
519f52228b8SJoe Beteta case SKD_DRVR_STATE_BUSY:
520f52228b8SJoe Beteta case SKD_DRVR_STATE_BUSY_IMMINENT:
521f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "%s: stopping queue", skdev->name);
522f52228b8SJoe Beteta break;
523f52228b8SJoe Beteta case SKD_DRVR_STATE_ONLINE:
524f52228b8SJoe Beteta case SKD_DRVR_STATE_STOPPING:
525f52228b8SJoe Beteta case SKD_DRVR_STATE_SYNCING:
526f52228b8SJoe Beteta case SKD_DRVR_STATE_PAUSING:
527f52228b8SJoe Beteta case SKD_DRVR_STATE_PAUSED:
528f52228b8SJoe Beteta case SKD_DRVR_STATE_STARTING:
529f52228b8SJoe Beteta case SKD_DRVR_STATE_RESTARTING:
530f52228b8SJoe Beteta case SKD_DRVR_STATE_RESUMING:
531f52228b8SJoe Beteta default:
532f52228b8SJoe Beteta rc = -EINVAL;
533f52228b8SJoe Beteta cmn_err(CE_NOTE, "state [%d] not implemented", skdev->state);
534f52228b8SJoe Beteta }
535f52228b8SJoe Beteta
536f52228b8SJoe Beteta return (rc);
537f52228b8SJoe Beteta }
538f52228b8SJoe Beteta
539f52228b8SJoe Beteta /*
540f52228b8SJoe Beteta * UNQUIESCE DEVICE:
541f52228b8SJoe Beteta * Note: Assumes lock is held to protect device state.
542f52228b8SJoe Beteta */
543f52228b8SJoe Beteta /*
544f52228b8SJoe Beteta *
545f52228b8SJoe Beteta * Name: skd_unquiesce_dev, awkens the device
546f52228b8SJoe Beteta *
547f52228b8SJoe Beteta * Inputs: skdev - Device state.
548f52228b8SJoe Beteta *
549f52228b8SJoe Beteta * Returns: -EINVAL if device is not in proper state otherwise
550f52228b8SJoe Beteta * returns zero.
551f52228b8SJoe Beteta *
552f52228b8SJoe Beteta */
553f52228b8SJoe Beteta static int
skd_unquiesce_dev(struct skd_device * skdev)554f52228b8SJoe Beteta skd_unquiesce_dev(struct skd_device *skdev)
555f52228b8SJoe Beteta {
556f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "skd_unquiece_dev:");
557f52228b8SJoe Beteta
558f52228b8SJoe Beteta skd_log_skdev(skdev, "unquiesce");
559f52228b8SJoe Beteta if (skdev->state == SKD_DRVR_STATE_ONLINE) {
560f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "**** device already ONLINE");
561f52228b8SJoe Beteta
562f52228b8SJoe Beteta return (0);
563f52228b8SJoe Beteta }
564f52228b8SJoe Beteta if (skdev->drive_state != FIT_SR_DRIVE_ONLINE) {
565f52228b8SJoe Beteta /*
566f52228b8SJoe Beteta * If there has been an state change to other than
567f52228b8SJoe Beteta * ONLINE, we will rely on controller state change
568f52228b8SJoe Beteta * to come back online and restart the queue.
569f52228b8SJoe Beteta * The BUSY state means that driver is ready to
570f52228b8SJoe Beteta * continue normal processing but waiting for controller
571f52228b8SJoe Beteta * to become available.
572f52228b8SJoe Beteta */
573f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_BUSY;
574f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "drive BUSY state\n");
575f52228b8SJoe Beteta
576f52228b8SJoe Beteta return (0);
577f52228b8SJoe Beteta }
578f52228b8SJoe Beteta /*
579f52228b8SJoe Beteta * Drive just come online, driver is either in startup,
580f52228b8SJoe Beteta * paused performing a task, or bust waiting for hardware.
581f52228b8SJoe Beteta */
582f52228b8SJoe Beteta switch (skdev->state) {
583f52228b8SJoe Beteta case SKD_DRVR_STATE_PAUSED:
584f52228b8SJoe Beteta case SKD_DRVR_STATE_BUSY:
585f52228b8SJoe Beteta case SKD_DRVR_STATE_BUSY_IMMINENT:
586f52228b8SJoe Beteta case SKD_DRVR_STATE_BUSY_ERASE:
587f52228b8SJoe Beteta case SKD_DRVR_STATE_STARTING:
588f52228b8SJoe Beteta case SKD_DRVR_STATE_RESTARTING:
589f52228b8SJoe Beteta case SKD_DRVR_STATE_FAULT:
590f52228b8SJoe Beteta case SKD_DRVR_STATE_IDLE:
591f52228b8SJoe Beteta case SKD_DRVR_STATE_LOAD:
592f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_ONLINE;
593f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "%s: sTec s1120 ONLINE", skdev->name);
594f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "%s: Starting request queue", skdev->name);
595f52228b8SJoe Beteta Dcmn_err(CE_NOTE,
596f52228b8SJoe Beteta "%s: queue depth limit=%d hard=%d soft=%d lowat=%d",
597f52228b8SJoe Beteta skdev->name,
598f52228b8SJoe Beteta skdev->queue_depth_limit,
599f52228b8SJoe Beteta skdev->hard_queue_depth_limit,
600f52228b8SJoe Beteta skdev->soft_queue_depth_limit,
601f52228b8SJoe Beteta skdev->queue_depth_lowat);
602f52228b8SJoe Beteta
603f52228b8SJoe Beteta skdev->gendisk_on = 1;
604f52228b8SJoe Beteta cv_signal(&skdev->cv_waitq);
605f52228b8SJoe Beteta break;
606f52228b8SJoe Beteta case SKD_DRVR_STATE_DISAPPEARED:
607f52228b8SJoe Beteta default:
608f52228b8SJoe Beteta cmn_err(CE_NOTE, "**** driver state %d, not implemented \n",
609f52228b8SJoe Beteta skdev->state);
610f52228b8SJoe Beteta return (-EBUSY);
611f52228b8SJoe Beteta }
612f52228b8SJoe Beteta
613f52228b8SJoe Beteta return (0);
614f52228b8SJoe Beteta }
615f52228b8SJoe Beteta
616f52228b8SJoe Beteta /*
617f52228b8SJoe Beteta * READ/WRITE REQUESTS
618f52228b8SJoe Beteta */
619f52228b8SJoe Beteta
620f52228b8SJoe Beteta /*
621f52228b8SJoe Beteta *
622f52228b8SJoe Beteta * Name: skd_blkdev_preop_sg_list, builds the S/G list from info
623f52228b8SJoe Beteta * passed in by the blkdev driver.
624f52228b8SJoe Beteta *
625f52228b8SJoe Beteta * Inputs: skdev - device state structure.
626f52228b8SJoe Beteta * skreq - request structure.
627f52228b8SJoe Beteta * sg_byte_count - data transfer byte count.
628f52228b8SJoe Beteta *
629f52228b8SJoe Beteta * Returns: Nothing.
630f52228b8SJoe Beteta *
631f52228b8SJoe Beteta */
632f52228b8SJoe Beteta /*ARGSUSED*/
633f52228b8SJoe Beteta static void
skd_blkdev_preop_sg_list(struct skd_device * skdev,struct skd_request_context * skreq,uint32_t * sg_byte_count)634f52228b8SJoe Beteta skd_blkdev_preop_sg_list(struct skd_device *skdev,
635f52228b8SJoe Beteta struct skd_request_context *skreq, uint32_t *sg_byte_count)
636f52228b8SJoe Beteta {
637f52228b8SJoe Beteta bd_xfer_t *xfer;
638f52228b8SJoe Beteta skd_buf_private_t *pbuf;
639f52228b8SJoe Beteta int i, bcount = 0;
640f52228b8SJoe Beteta uint_t n_sg;
641f52228b8SJoe Beteta
642f52228b8SJoe Beteta *sg_byte_count = 0;
643f52228b8SJoe Beteta
644f52228b8SJoe Beteta ASSERT(skreq->sg_data_dir == SKD_DATA_DIR_HOST_TO_CARD ||
645f52228b8SJoe Beteta skreq->sg_data_dir == SKD_DATA_DIR_CARD_TO_HOST);
646f52228b8SJoe Beteta
647f52228b8SJoe Beteta pbuf = skreq->pbuf;
648f52228b8SJoe Beteta ASSERT(pbuf != NULL);
649f52228b8SJoe Beteta
650f52228b8SJoe Beteta xfer = pbuf->x_xfer;
651f52228b8SJoe Beteta n_sg = xfer->x_ndmac;
652f52228b8SJoe Beteta
653f52228b8SJoe Beteta ASSERT(n_sg <= skdev->sgs_per_request);
654f52228b8SJoe Beteta
655f52228b8SJoe Beteta skreq->n_sg = n_sg;
656f52228b8SJoe Beteta
657f52228b8SJoe Beteta skreq->io_dma_handle = xfer->x_dmah;
658f52228b8SJoe Beteta
659f52228b8SJoe Beteta skreq->total_sg_bcount = 0;
660f52228b8SJoe Beteta
661f52228b8SJoe Beteta for (i = 0; i < n_sg; i++) {
662f52228b8SJoe Beteta ddi_dma_cookie_t *cookiep = &xfer->x_dmac;
663f52228b8SJoe Beteta struct fit_sg_descriptor *sgd;
664f52228b8SJoe Beteta uint32_t cnt = (uint32_t)cookiep->dmac_size;
665f52228b8SJoe Beteta
666f52228b8SJoe Beteta bcount += cnt;
667f52228b8SJoe Beteta
668f52228b8SJoe Beteta sgd = &skreq->sksg_list[i];
669f52228b8SJoe Beteta sgd->control = FIT_SGD_CONTROL_NOT_LAST;
670f52228b8SJoe Beteta sgd->byte_count = cnt;
671f52228b8SJoe Beteta sgd->host_side_addr = cookiep->dmac_laddress;
672f52228b8SJoe Beteta sgd->dev_side_addr = 0; /* not used */
673f52228b8SJoe Beteta *sg_byte_count += cnt;
674f52228b8SJoe Beteta
675f52228b8SJoe Beteta skreq->total_sg_bcount += cnt;
676f52228b8SJoe Beteta
677f52228b8SJoe Beteta if ((i + 1) != n_sg)
678f52228b8SJoe Beteta ddi_dma_nextcookie(skreq->io_dma_handle, &xfer->x_dmac);
679f52228b8SJoe Beteta }
680f52228b8SJoe Beteta
681f52228b8SJoe Beteta skreq->sksg_list[n_sg - 1].next_desc_ptr = 0LL;
682f52228b8SJoe Beteta skreq->sksg_list[n_sg - 1].control = FIT_SGD_CONTROL_LAST;
683f52228b8SJoe Beteta
684f52228b8SJoe Beteta (void) ddi_dma_sync(skreq->sksg_dma_address.dma_handle, 0, 0,
685f52228b8SJoe Beteta DDI_DMA_SYNC_FORDEV);
686f52228b8SJoe Beteta }
687f52228b8SJoe Beteta
688f52228b8SJoe Beteta /*
689f52228b8SJoe Beteta *
690f52228b8SJoe Beteta * Name: skd_blkdev_postop_sg_list, deallocates DMA
691f52228b8SJoe Beteta *
692f52228b8SJoe Beteta * Inputs: skdev - device state structure.
693f52228b8SJoe Beteta * skreq - skreq data structure.
694f52228b8SJoe Beteta *
695f52228b8SJoe Beteta * Returns: Nothing.
696f52228b8SJoe Beteta *
697f52228b8SJoe Beteta */
698f52228b8SJoe Beteta /* ARGSUSED */ /* Upstream common source with other platforms. */
699f52228b8SJoe Beteta static void
skd_blkdev_postop_sg_list(struct skd_device * skdev,struct skd_request_context * skreq)700f52228b8SJoe Beteta skd_blkdev_postop_sg_list(struct skd_device *skdev,
701f52228b8SJoe Beteta struct skd_request_context *skreq)
702f52228b8SJoe Beteta {
703f52228b8SJoe Beteta /*
704f52228b8SJoe Beteta * restore the next ptr for next IO request so we
705f52228b8SJoe Beteta * don't have to set it every time.
706f52228b8SJoe Beteta */
707f52228b8SJoe Beteta skreq->sksg_list[skreq->n_sg - 1].next_desc_ptr =
708f52228b8SJoe Beteta skreq->sksg_dma_address.cookies->dmac_laddress +
709f52228b8SJoe Beteta ((skreq->n_sg) * sizeof (struct fit_sg_descriptor));
710f52228b8SJoe Beteta }
711f52228b8SJoe Beteta
712f52228b8SJoe Beteta /*
713f52228b8SJoe Beteta *
714f52228b8SJoe Beteta * Name: skd_start, initiates an I/O.
715f52228b8SJoe Beteta *
716f52228b8SJoe Beteta * Inputs: skdev - device state structure.
717f52228b8SJoe Beteta *
718f52228b8SJoe Beteta * Returns: EAGAIN if devicfe is not ONLINE.
719f52228b8SJoe Beteta * On error, if the caller is the blkdev driver, return
720f52228b8SJoe Beteta * the error value. Otherwise, return zero.
721f52228b8SJoe Beteta *
722f52228b8SJoe Beteta */
723f52228b8SJoe Beteta /* Upstream common source with other platforms. */
724f52228b8SJoe Beteta static void
skd_start(skd_device_t * skdev)725f52228b8SJoe Beteta skd_start(skd_device_t *skdev)
726f52228b8SJoe Beteta {
727f52228b8SJoe Beteta struct skd_fitmsg_context *skmsg = NULL;
728f52228b8SJoe Beteta struct fit_msg_hdr *fmh = NULL;
729f52228b8SJoe Beteta struct skd_request_context *skreq = NULL;
730f52228b8SJoe Beteta struct waitqueue *waitq = &skdev->waitqueue;
731f52228b8SJoe Beteta struct skd_scsi_request *scsi_req;
732f52228b8SJoe Beteta skd_buf_private_t *pbuf = NULL;
733f52228b8SJoe Beteta int bcount;
734f52228b8SJoe Beteta
735f52228b8SJoe Beteta uint32_t lba;
736f52228b8SJoe Beteta uint32_t count;
737f52228b8SJoe Beteta uint32_t timo_slot;
738f52228b8SJoe Beteta void *cmd_ptr;
739f52228b8SJoe Beteta uint32_t sg_byte_count = 0;
740f52228b8SJoe Beteta
741f52228b8SJoe Beteta /*
742f52228b8SJoe Beteta * Stop conditions:
743f52228b8SJoe Beteta * - There are no more native requests
744f52228b8SJoe Beteta * - There are already the maximum number of requests is progress
745f52228b8SJoe Beteta * - There are no more skd_request_context entries
746f52228b8SJoe Beteta * - There are no more FIT msg buffers
747f52228b8SJoe Beteta */
748f52228b8SJoe Beteta for (;;) {
749f52228b8SJoe Beteta /* Are too many requests already in progress? */
750f52228b8SJoe Beteta if (skdev->queue_depth_busy >= skdev->queue_depth_limit) {
751f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "qdepth %d, limit %d\n",
752f52228b8SJoe Beteta skdev->queue_depth_busy,
753f52228b8SJoe Beteta skdev->queue_depth_limit);
754f52228b8SJoe Beteta break;
755f52228b8SJoe Beteta }
756f52228b8SJoe Beteta
757f52228b8SJoe Beteta WAITQ_LOCK(skdev);
758f52228b8SJoe Beteta if (SIMPLEQ_EMPTY(waitq)) {
759f52228b8SJoe Beteta WAITQ_UNLOCK(skdev);
760f52228b8SJoe Beteta break;
761f52228b8SJoe Beteta }
762f52228b8SJoe Beteta
763f52228b8SJoe Beteta /* Is a skd_request_context available? */
764f52228b8SJoe Beteta skreq = skdev->skreq_free_list;
765f52228b8SJoe Beteta if (skreq == NULL) {
766f52228b8SJoe Beteta WAITQ_UNLOCK(skdev);
767f52228b8SJoe Beteta break;
768f52228b8SJoe Beteta }
769f52228b8SJoe Beteta
770f52228b8SJoe Beteta ASSERT(skreq->state == SKD_REQ_STATE_IDLE);
771f52228b8SJoe Beteta ASSERT((skreq->id & SKD_ID_INCR) == 0);
772f52228b8SJoe Beteta
773f52228b8SJoe Beteta skdev->skreq_free_list = skreq->next;
774f52228b8SJoe Beteta
775f52228b8SJoe Beteta skreq->state = SKD_REQ_STATE_BUSY;
776f52228b8SJoe Beteta skreq->id += SKD_ID_INCR;
777f52228b8SJoe Beteta
778f52228b8SJoe Beteta /* Start a new FIT msg if there is none in progress. */
779f52228b8SJoe Beteta if (skmsg == NULL) {
780f52228b8SJoe Beteta /* Are there any FIT msg buffers available? */
781f52228b8SJoe Beteta skmsg = skdev->skmsg_free_list;
782f52228b8SJoe Beteta if (skmsg == NULL) {
783f52228b8SJoe Beteta WAITQ_UNLOCK(skdev);
784f52228b8SJoe Beteta break;
785f52228b8SJoe Beteta }
786f52228b8SJoe Beteta
787f52228b8SJoe Beteta ASSERT(skmsg->state == SKD_MSG_STATE_IDLE);
788f52228b8SJoe Beteta ASSERT((skmsg->id & SKD_ID_INCR) == 0);
789f52228b8SJoe Beteta
790f52228b8SJoe Beteta skdev->skmsg_free_list = skmsg->next;
791f52228b8SJoe Beteta
792f52228b8SJoe Beteta skmsg->state = SKD_MSG_STATE_BUSY;
793f52228b8SJoe Beteta skmsg->id += SKD_ID_INCR;
794f52228b8SJoe Beteta
795f52228b8SJoe Beteta /* Initialize the FIT msg header */
796f52228b8SJoe Beteta fmh = (struct fit_msg_hdr *)skmsg->msg_buf64;
797f52228b8SJoe Beteta bzero(fmh, sizeof (*fmh)); /* Too expensive */
798f52228b8SJoe Beteta fmh->protocol_id = FIT_PROTOCOL_ID_SOFIT;
799f52228b8SJoe Beteta skmsg->length = sizeof (struct fit_msg_hdr);
800f52228b8SJoe Beteta }
801f52228b8SJoe Beteta
802f52228b8SJoe Beteta /*
803f52228b8SJoe Beteta * At this point we are committed to either start or reject
804f52228b8SJoe Beteta * the native request. Note that a FIT msg may have just been
805f52228b8SJoe Beteta * started but contains no SoFIT requests yet.
806f52228b8SJoe Beteta * Now - dequeue pbuf.
807f52228b8SJoe Beteta */
808f52228b8SJoe Beteta pbuf = skd_get_queued_pbuf(skdev);
809f52228b8SJoe Beteta WAITQ_UNLOCK(skdev);
810f52228b8SJoe Beteta
811f52228b8SJoe Beteta skreq->pbuf = pbuf;
812f52228b8SJoe Beteta lba = pbuf->x_xfer->x_blkno;
813f52228b8SJoe Beteta count = pbuf->x_xfer->x_nblks;
814f52228b8SJoe Beteta skreq->did_complete = 0;
815f52228b8SJoe Beteta
816f52228b8SJoe Beteta skreq->fitmsg_id = skmsg->id;
817f52228b8SJoe Beteta
818f52228b8SJoe Beteta Dcmn_err(CE_NOTE,
819f52228b8SJoe Beteta "pbuf=%p lba=%u(0x%x) count=%u(0x%x) dir=%x\n",
820f52228b8SJoe Beteta (void *)pbuf, lba, lba, count, count, pbuf->dir);
821f52228b8SJoe Beteta
822f52228b8SJoe Beteta /*
823f52228b8SJoe Beteta * Transcode the request.
824f52228b8SJoe Beteta */
825f52228b8SJoe Beteta cmd_ptr = &skmsg->msg_buf[skmsg->length];
826f52228b8SJoe Beteta bzero(cmd_ptr, 32); /* This is too expensive */
827f52228b8SJoe Beteta
828f52228b8SJoe Beteta scsi_req = cmd_ptr;
829f52228b8SJoe Beteta scsi_req->hdr.tag = skreq->id;
830f52228b8SJoe Beteta scsi_req->hdr.sg_list_dma_address =
831f52228b8SJoe Beteta cpu_to_be64(skreq->sksg_dma_address.cookies->dmac_laddress);
832f52228b8SJoe Beteta scsi_req->cdb[1] = 0;
833f52228b8SJoe Beteta scsi_req->cdb[2] = (lba & 0xff000000) >> 24;
834f52228b8SJoe Beteta scsi_req->cdb[3] = (lba & 0xff0000) >> 16;
835f52228b8SJoe Beteta scsi_req->cdb[4] = (lba & 0xff00) >> 8;
836f52228b8SJoe Beteta scsi_req->cdb[5] = (lba & 0xff);
837f52228b8SJoe Beteta scsi_req->cdb[6] = 0;
838f52228b8SJoe Beteta scsi_req->cdb[7] = (count & 0xff00) >> 8;
839f52228b8SJoe Beteta scsi_req->cdb[8] = count & 0xff;
840f52228b8SJoe Beteta scsi_req->cdb[9] = 0;
841f52228b8SJoe Beteta
842f52228b8SJoe Beteta if (pbuf->dir & B_READ) {
843f52228b8SJoe Beteta scsi_req->cdb[0] = 0x28;
844f52228b8SJoe Beteta skreq->sg_data_dir = SKD_DATA_DIR_CARD_TO_HOST;
845f52228b8SJoe Beteta } else {
846f52228b8SJoe Beteta scsi_req->cdb[0] = 0x2a;
847f52228b8SJoe Beteta skreq->sg_data_dir = SKD_DATA_DIR_HOST_TO_CARD;
848f52228b8SJoe Beteta }
849f52228b8SJoe Beteta
850f52228b8SJoe Beteta skd_blkdev_preop_sg_list(skdev, skreq, &sg_byte_count);
851f52228b8SJoe Beteta
852f52228b8SJoe Beteta scsi_req->hdr.sg_list_len_bytes = cpu_to_be32(sg_byte_count);
853f52228b8SJoe Beteta
854f52228b8SJoe Beteta bcount = (sg_byte_count + 511) / 512;
855f52228b8SJoe Beteta scsi_req->cdb[7] = (bcount & 0xff00) >> 8;
856f52228b8SJoe Beteta scsi_req->cdb[8] = bcount & 0xff;
857f52228b8SJoe Beteta
858f52228b8SJoe Beteta Dcmn_err(CE_NOTE,
859f52228b8SJoe Beteta "skd_start: pbuf=%p skreq->id=%x opc=%x ====>>>>>",
860f52228b8SJoe Beteta (void *)pbuf, skreq->id, *scsi_req->cdb);
861f52228b8SJoe Beteta
862f52228b8SJoe Beteta skmsg->length += sizeof (struct skd_scsi_request);
863f52228b8SJoe Beteta fmh->num_protocol_cmds_coalesced++;
864f52228b8SJoe Beteta
865f52228b8SJoe Beteta /*
866f52228b8SJoe Beteta * Update the active request counts.
867f52228b8SJoe Beteta * Capture the timeout timestamp.
868f52228b8SJoe Beteta */
869f52228b8SJoe Beteta skreq->timeout_stamp = skdev->timeout_stamp;
870f52228b8SJoe Beteta timo_slot = skreq->timeout_stamp & SKD_TIMEOUT_SLOT_MASK;
871f52228b8SJoe Beteta
872f52228b8SJoe Beteta atomic_inc_32(&skdev->timeout_slot[timo_slot]);
873f52228b8SJoe Beteta atomic_inc_32(&skdev->queue_depth_busy);
874f52228b8SJoe Beteta
875f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "req=0x%x busy=%d timo_slot=%d",
876f52228b8SJoe Beteta skreq->id, skdev->queue_depth_busy, timo_slot);
877f52228b8SJoe Beteta /*
878f52228b8SJoe Beteta * If the FIT msg buffer is full send it.
879f52228b8SJoe Beteta */
880f52228b8SJoe Beteta if (skmsg->length >= SKD_N_FITMSG_BYTES ||
881f52228b8SJoe Beteta fmh->num_protocol_cmds_coalesced >= skd_max_req_per_msg) {
882f52228b8SJoe Beteta
883f52228b8SJoe Beteta atomic_inc_64(&skdev->active_cmds);
884f52228b8SJoe Beteta pbuf->skreq = skreq;
885f52228b8SJoe Beteta
886f52228b8SJoe Beteta skdev->fitmsg_sent1++;
887f52228b8SJoe Beteta skd_send_fitmsg(skdev, skmsg);
888f52228b8SJoe Beteta
889f52228b8SJoe Beteta skmsg = NULL;
890f52228b8SJoe Beteta fmh = NULL;
891f52228b8SJoe Beteta }
892f52228b8SJoe Beteta }
893f52228b8SJoe Beteta
894f52228b8SJoe Beteta /*
895f52228b8SJoe Beteta * Is a FIT msg in progress? If it is empty put the buffer back
896f52228b8SJoe Beteta * on the free list. If it is non-empty send what we got.
897f52228b8SJoe Beteta * This minimizes latency when there are fewer requests than
898f52228b8SJoe Beteta * what fits in a FIT msg.
899f52228b8SJoe Beteta */
900f52228b8SJoe Beteta if (skmsg != NULL) {
901f52228b8SJoe Beteta ASSERT(skmsg->length > sizeof (struct fit_msg_hdr));
902f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "sending msg=%p, len %d",
903f52228b8SJoe Beteta (void *)skmsg, skmsg->length);
904f52228b8SJoe Beteta
905f52228b8SJoe Beteta skdev->active_cmds++;
906f52228b8SJoe Beteta
907f52228b8SJoe Beteta skdev->fitmsg_sent2++;
908f52228b8SJoe Beteta skd_send_fitmsg(skdev, skmsg);
909f52228b8SJoe Beteta }
910f52228b8SJoe Beteta }
911f52228b8SJoe Beteta
912f52228b8SJoe Beteta /*
913f52228b8SJoe Beteta *
914f52228b8SJoe Beteta * Name: skd_end_request
915f52228b8SJoe Beteta *
916f52228b8SJoe Beteta * Inputs: skdev - device state structure.
917f52228b8SJoe Beteta * skreq - request structure.
918f52228b8SJoe Beteta * error - I/O error value.
919f52228b8SJoe Beteta *
920f52228b8SJoe Beteta * Returns: Nothing.
921f52228b8SJoe Beteta *
922f52228b8SJoe Beteta */
923f52228b8SJoe Beteta static void
skd_end_request(struct skd_device * skdev,struct skd_request_context * skreq,int error)924f52228b8SJoe Beteta skd_end_request(struct skd_device *skdev,
925f52228b8SJoe Beteta struct skd_request_context *skreq, int error)
926f52228b8SJoe Beteta {
927f52228b8SJoe Beteta skdev->ios_completed++;
928f52228b8SJoe Beteta skd_io_done(skdev, skreq->pbuf, error, SKD_IODONE_WIOC);
929f52228b8SJoe Beteta skreq->pbuf = NULL;
930f52228b8SJoe Beteta skreq->did_complete = 1;
931f52228b8SJoe Beteta }
932f52228b8SJoe Beteta
933f52228b8SJoe Beteta /*
934f52228b8SJoe Beteta *
935f52228b8SJoe Beteta * Name: skd_end_request_abnormal
936f52228b8SJoe Beteta *
937f52228b8SJoe Beteta * Inputs: skdev - device state structure.
938f52228b8SJoe Beteta * pbuf - I/O request.
939f52228b8SJoe Beteta * error - I/O error value.
940f52228b8SJoe Beteta * mode - debug
941f52228b8SJoe Beteta *
942f52228b8SJoe Beteta * Returns: Nothing.
943f52228b8SJoe Beteta *
944f52228b8SJoe Beteta */
945f52228b8SJoe Beteta static void
skd_end_request_abnormal(skd_device_t * skdev,skd_buf_private_t * pbuf,int error,int mode)946f52228b8SJoe Beteta skd_end_request_abnormal(skd_device_t *skdev, skd_buf_private_t *pbuf,
947f52228b8SJoe Beteta int error, int mode)
948f52228b8SJoe Beteta {
949f52228b8SJoe Beteta skd_io_done(skdev, pbuf, error, mode);
950f52228b8SJoe Beteta }
951f52228b8SJoe Beteta
952f52228b8SJoe Beteta /*
953f52228b8SJoe Beteta *
954f52228b8SJoe Beteta * Name: skd_request_fn_not_online, handles the condition
955f52228b8SJoe Beteta * of the device not being online.
956f52228b8SJoe Beteta *
957f52228b8SJoe Beteta * Inputs: skdev - device state structure.
958f52228b8SJoe Beteta *
959f52228b8SJoe Beteta * Returns: nothing (void).
960f52228b8SJoe Beteta *
961f52228b8SJoe Beteta */
962f52228b8SJoe Beteta static void
skd_request_fn_not_online(skd_device_t * skdev)963f52228b8SJoe Beteta skd_request_fn_not_online(skd_device_t *skdev)
964f52228b8SJoe Beteta {
965f52228b8SJoe Beteta int error;
966f52228b8SJoe Beteta skd_buf_private_t *pbuf;
967f52228b8SJoe Beteta
968f52228b8SJoe Beteta ASSERT(skdev->state != SKD_DRVR_STATE_ONLINE);
969f52228b8SJoe Beteta
970f52228b8SJoe Beteta skd_log_skdev(skdev, "req_not_online");
971f52228b8SJoe Beteta
972f52228b8SJoe Beteta switch (skdev->state) {
973f52228b8SJoe Beteta case SKD_DRVR_STATE_PAUSING:
974f52228b8SJoe Beteta case SKD_DRVR_STATE_PAUSED:
975f52228b8SJoe Beteta case SKD_DRVR_STATE_STARTING:
976f52228b8SJoe Beteta case SKD_DRVR_STATE_RESTARTING:
977f52228b8SJoe Beteta case SKD_DRVR_STATE_WAIT_BOOT:
978f52228b8SJoe Beteta /*
979f52228b8SJoe Beteta * In case of starting, we haven't started the queue,
980f52228b8SJoe Beteta * so we can't get here... but requests are
981f52228b8SJoe Beteta * possibly hanging out waiting for us because we
982f52228b8SJoe Beteta * reported the dev/skd/0 already. They'll wait
983f52228b8SJoe Beteta * forever if connect doesn't complete.
984f52228b8SJoe Beteta * What to do??? delay dev/skd/0 ??
985f52228b8SJoe Beteta */
986f52228b8SJoe Beteta case SKD_DRVR_STATE_BUSY:
987f52228b8SJoe Beteta case SKD_DRVR_STATE_BUSY_IMMINENT:
988f52228b8SJoe Beteta case SKD_DRVR_STATE_BUSY_ERASE:
989f52228b8SJoe Beteta case SKD_DRVR_STATE_DRAINING_TIMEOUT:
990f52228b8SJoe Beteta return;
991f52228b8SJoe Beteta
992f52228b8SJoe Beteta case SKD_DRVR_STATE_BUSY_SANITIZE:
993f52228b8SJoe Beteta case SKD_DRVR_STATE_STOPPING:
994f52228b8SJoe Beteta case SKD_DRVR_STATE_SYNCING:
995f52228b8SJoe Beteta case SKD_DRVR_STATE_FAULT:
996f52228b8SJoe Beteta case SKD_DRVR_STATE_DISAPPEARED:
997f52228b8SJoe Beteta default:
998f52228b8SJoe Beteta error = -EIO;
999f52228b8SJoe Beteta break;
1000f52228b8SJoe Beteta }
1001f52228b8SJoe Beteta
1002f52228b8SJoe Beteta /*
1003f52228b8SJoe Beteta * If we get here, terminate all pending block requeusts
1004f52228b8SJoe Beteta * with EIO and any scsi pass thru with appropriate sense
1005f52228b8SJoe Beteta */
1006f52228b8SJoe Beteta ASSERT(WAITQ_LOCK_HELD(skdev));
1007f52228b8SJoe Beteta if (SIMPLEQ_EMPTY(&skdev->waitqueue))
1008f52228b8SJoe Beteta return;
1009f52228b8SJoe Beteta
1010f52228b8SJoe Beteta while ((pbuf = skd_get_queued_pbuf(skdev)))
1011f52228b8SJoe Beteta skd_end_request_abnormal(skdev, pbuf, error, SKD_IODONE_WNIOC);
1012f52228b8SJoe Beteta
1013f52228b8SJoe Beteta cv_signal(&skdev->cv_waitq);
1014f52228b8SJoe Beteta }
1015f52228b8SJoe Beteta
1016f52228b8SJoe Beteta /*
1017f52228b8SJoe Beteta * TIMER
1018f52228b8SJoe Beteta */
1019f52228b8SJoe Beteta
1020f52228b8SJoe Beteta static void skd_timer_tick_not_online(struct skd_device *skdev);
1021f52228b8SJoe Beteta
1022f52228b8SJoe Beteta /*
1023f52228b8SJoe Beteta *
1024f52228b8SJoe Beteta * Name: skd_timer_tick, monitors requests for timeouts.
1025f52228b8SJoe Beteta *
1026f52228b8SJoe Beteta * Inputs: skdev - device state structure.
1027f52228b8SJoe Beteta *
1028f52228b8SJoe Beteta * Returns: Nothing.
1029f52228b8SJoe Beteta *
1030f52228b8SJoe Beteta */
1031f52228b8SJoe Beteta static void
skd_timer_tick(skd_device_t * skdev)1032f52228b8SJoe Beteta skd_timer_tick(skd_device_t *skdev)
1033f52228b8SJoe Beteta {
1034f52228b8SJoe Beteta uint32_t timo_slot;
1035f52228b8SJoe Beteta
1036f52228b8SJoe Beteta skdev->timer_active = 1;
1037f52228b8SJoe Beteta
1038f52228b8SJoe Beteta if (skdev->state != SKD_DRVR_STATE_ONLINE) {
1039f52228b8SJoe Beteta skd_timer_tick_not_online(skdev);
1040f52228b8SJoe Beteta goto timer_func_out;
1041f52228b8SJoe Beteta }
1042f52228b8SJoe Beteta
1043f52228b8SJoe Beteta skdev->timeout_stamp++;
1044f52228b8SJoe Beteta timo_slot = skdev->timeout_stamp & SKD_TIMEOUT_SLOT_MASK;
1045f52228b8SJoe Beteta
1046f52228b8SJoe Beteta /*
1047f52228b8SJoe Beteta * All requests that happened during the previous use of
1048f52228b8SJoe Beteta * this slot should be done by now. The previous use was
1049f52228b8SJoe Beteta * over 7 seconds ago.
1050f52228b8SJoe Beteta */
1051f52228b8SJoe Beteta if (skdev->timeout_slot[timo_slot] == 0) {
1052f52228b8SJoe Beteta goto timer_func_out;
1053f52228b8SJoe Beteta }
1054f52228b8SJoe Beteta
1055f52228b8SJoe Beteta /* Something is overdue */
1056f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "found %d timeouts, draining busy=%d",
1057f52228b8SJoe Beteta skdev->timeout_slot[timo_slot],
1058f52228b8SJoe Beteta skdev->queue_depth_busy);
1059f52228b8SJoe Beteta skdev->timer_countdown = SKD_TIMER_SECONDS(3);
1060f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_DRAINING_TIMEOUT;
1061f52228b8SJoe Beteta skdev->timo_slot = timo_slot;
1062f52228b8SJoe Beteta
1063f52228b8SJoe Beteta timer_func_out:
1064f52228b8SJoe Beteta skdev->timer_active = 0;
1065f52228b8SJoe Beteta }
1066f52228b8SJoe Beteta
1067f52228b8SJoe Beteta /*
1068f52228b8SJoe Beteta *
1069f52228b8SJoe Beteta * Name: skd_timer_tick_not_online, handles various device
1070f52228b8SJoe Beteta * state transitions.
1071f52228b8SJoe Beteta *
1072f52228b8SJoe Beteta * Inputs: skdev - device state structure.
1073f52228b8SJoe Beteta *
1074f52228b8SJoe Beteta * Returns: Nothing.
1075f52228b8SJoe Beteta *
1076f52228b8SJoe Beteta */
1077f52228b8SJoe Beteta static void
skd_timer_tick_not_online(struct skd_device * skdev)1078f52228b8SJoe Beteta skd_timer_tick_not_online(struct skd_device *skdev)
1079f52228b8SJoe Beteta {
1080f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "skd_skd_timer_tick_not_online: state=%d tmo=%d",
1081f52228b8SJoe Beteta skdev->state, skdev->timer_countdown);
1082f52228b8SJoe Beteta
1083f52228b8SJoe Beteta ASSERT(skdev->state != SKD_DRVR_STATE_ONLINE);
1084f52228b8SJoe Beteta
1085f52228b8SJoe Beteta switch (skdev->state) {
1086f52228b8SJoe Beteta case SKD_DRVR_STATE_IDLE:
1087f52228b8SJoe Beteta case SKD_DRVR_STATE_LOAD:
1088f52228b8SJoe Beteta break;
1089f52228b8SJoe Beteta case SKD_DRVR_STATE_BUSY_SANITIZE:
1090f52228b8SJoe Beteta cmn_err(CE_WARN, "!drive busy sanitize[%x], driver[%x]\n",
1091f52228b8SJoe Beteta skdev->drive_state, skdev->state);
1092f52228b8SJoe Beteta break;
1093f52228b8SJoe Beteta
1094f52228b8SJoe Beteta case SKD_DRVR_STATE_BUSY:
1095f52228b8SJoe Beteta case SKD_DRVR_STATE_BUSY_IMMINENT:
1096f52228b8SJoe Beteta case SKD_DRVR_STATE_BUSY_ERASE:
1097f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "busy[%x], countdown=%d\n",
1098f52228b8SJoe Beteta skdev->state, skdev->timer_countdown);
1099f52228b8SJoe Beteta if (skdev->timer_countdown > 0) {
1100f52228b8SJoe Beteta skdev->timer_countdown--;
1101f52228b8SJoe Beteta return;
1102f52228b8SJoe Beteta }
1103f52228b8SJoe Beteta cmn_err(CE_WARN, "!busy[%x], timedout=%d, restarting device.",
1104f52228b8SJoe Beteta skdev->state, skdev->timer_countdown);
1105f52228b8SJoe Beteta skd_restart_device(skdev);
1106f52228b8SJoe Beteta break;
1107f52228b8SJoe Beteta
1108f52228b8SJoe Beteta case SKD_DRVR_STATE_WAIT_BOOT:
1109f52228b8SJoe Beteta case SKD_DRVR_STATE_STARTING:
1110f52228b8SJoe Beteta if (skdev->timer_countdown > 0) {
1111f52228b8SJoe Beteta skdev->timer_countdown--;
1112f52228b8SJoe Beteta return;
1113f52228b8SJoe Beteta }
1114f52228b8SJoe Beteta /*
1115f52228b8SJoe Beteta * For now, we fault the drive. Could attempt resets to
1116f52228b8SJoe Beteta * revcover at some point.
1117f52228b8SJoe Beteta */
1118f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_FAULT;
1119f52228b8SJoe Beteta
1120f52228b8SJoe Beteta cmn_err(CE_WARN, "!(%s): DriveFault Connect Timeout (%x)",
1121f52228b8SJoe Beteta skd_name(skdev), skdev->drive_state);
1122f52228b8SJoe Beteta
1123f52228b8SJoe Beteta /* start the queue so we can respond with error to requests */
1124f52228b8SJoe Beteta skd_start(skdev);
1125f52228b8SJoe Beteta
1126f52228b8SJoe Beteta /* wakeup anyone waiting for startup complete */
1127f52228b8SJoe Beteta skdev->gendisk_on = -1;
1128f52228b8SJoe Beteta
1129f52228b8SJoe Beteta cv_signal(&skdev->cv_waitq);
1130f52228b8SJoe Beteta break;
1131f52228b8SJoe Beteta
1132f52228b8SJoe Beteta
1133f52228b8SJoe Beteta case SKD_DRVR_STATE_PAUSING:
1134f52228b8SJoe Beteta case SKD_DRVR_STATE_PAUSED:
1135f52228b8SJoe Beteta break;
1136f52228b8SJoe Beteta
1137f52228b8SJoe Beteta case SKD_DRVR_STATE_DRAINING_TIMEOUT:
1138f52228b8SJoe Beteta cmn_err(CE_WARN,
1139f52228b8SJoe Beteta "!%s: draining busy [%d] tick[%d] qdb[%d] tmls[%d]\n",
1140f52228b8SJoe Beteta skdev->name,
1141f52228b8SJoe Beteta skdev->timo_slot,
1142f52228b8SJoe Beteta skdev->timer_countdown,
1143f52228b8SJoe Beteta skdev->queue_depth_busy,
1144f52228b8SJoe Beteta skdev->timeout_slot[skdev->timo_slot]);
1145f52228b8SJoe Beteta /* if the slot has cleared we can let the I/O continue */
1146f52228b8SJoe Beteta if (skdev->timeout_slot[skdev->timo_slot] == 0) {
1147f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "Slot drained, starting queue.");
1148f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_ONLINE;
1149f52228b8SJoe Beteta skd_start(skdev);
1150f52228b8SJoe Beteta return;
1151f52228b8SJoe Beteta }
1152f52228b8SJoe Beteta if (skdev->timer_countdown > 0) {
1153f52228b8SJoe Beteta skdev->timer_countdown--;
1154f52228b8SJoe Beteta return;
1155f52228b8SJoe Beteta }
1156f52228b8SJoe Beteta skd_restart_device(skdev);
1157f52228b8SJoe Beteta break;
1158f52228b8SJoe Beteta
1159f52228b8SJoe Beteta case SKD_DRVR_STATE_RESTARTING:
1160f52228b8SJoe Beteta if (skdev->timer_countdown > 0) {
1161f52228b8SJoe Beteta skdev->timer_countdown--;
1162f52228b8SJoe Beteta
1163f52228b8SJoe Beteta return;
1164f52228b8SJoe Beteta }
1165f52228b8SJoe Beteta /*
1166f52228b8SJoe Beteta * For now, we fault the drive. Could attempt resets to
1167f52228b8SJoe Beteta * revcover at some point.
1168f52228b8SJoe Beteta */
1169f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_FAULT;
1170f52228b8SJoe Beteta cmn_err(CE_WARN, "!(%s): DriveFault Reconnect Timeout (%x)\n",
1171f52228b8SJoe Beteta skd_name(skdev), skdev->drive_state);
1172f52228b8SJoe Beteta
1173f52228b8SJoe Beteta /*
1174f52228b8SJoe Beteta * Recovering does two things:
1175f52228b8SJoe Beteta * 1. completes IO with error
1176f52228b8SJoe Beteta * 2. reclaims dma resources
1177f52228b8SJoe Beteta * When is it safe to recover requests?
1178f52228b8SJoe Beteta * - if the drive state is faulted
1179f52228b8SJoe Beteta * - if the state is still soft reset after out timeout
1180f52228b8SJoe Beteta * - if the drive registers are dead (state = FF)
1181f52228b8SJoe Beteta */
1182f52228b8SJoe Beteta
1183f52228b8SJoe Beteta if ((skdev->drive_state == FIT_SR_DRIVE_SOFT_RESET) ||
1184f52228b8SJoe Beteta (skdev->drive_state == FIT_SR_DRIVE_FAULT) ||
1185f52228b8SJoe Beteta (skdev->drive_state == FIT_SR_DRIVE_STATE_MASK)) {
1186f52228b8SJoe Beteta /*
1187f52228b8SJoe Beteta * It never came out of soft reset. Try to
1188f52228b8SJoe Beteta * recover the requests and then let them
1189f52228b8SJoe Beteta * fail. This is to mitigate hung processes.
1190f52228b8SJoe Beteta *
1191f52228b8SJoe Beteta * Acquire the interrupt lock since these lists are
1192f52228b8SJoe Beteta * manipulated by interrupt handlers.
1193f52228b8SJoe Beteta */
1194f52228b8SJoe Beteta ASSERT(!WAITQ_LOCK_HELD(skdev));
1195f52228b8SJoe Beteta INTR_LOCK(skdev);
1196f52228b8SJoe Beteta skd_recover_requests(skdev);
1197f52228b8SJoe Beteta INTR_UNLOCK(skdev);
1198f52228b8SJoe Beteta }
1199f52228b8SJoe Beteta /* start the queue so we can respond with error to requests */
1200f52228b8SJoe Beteta skd_start(skdev);
1201f52228b8SJoe Beteta /* wakeup anyone waiting for startup complete */
1202f52228b8SJoe Beteta skdev->gendisk_on = -1;
1203f52228b8SJoe Beteta cv_signal(&skdev->cv_waitq);
1204f52228b8SJoe Beteta break;
1205f52228b8SJoe Beteta
1206f52228b8SJoe Beteta case SKD_DRVR_STATE_RESUMING:
1207f52228b8SJoe Beteta case SKD_DRVR_STATE_STOPPING:
1208f52228b8SJoe Beteta case SKD_DRVR_STATE_SYNCING:
1209f52228b8SJoe Beteta case SKD_DRVR_STATE_FAULT:
1210f52228b8SJoe Beteta case SKD_DRVR_STATE_DISAPPEARED:
1211f52228b8SJoe Beteta default:
1212f52228b8SJoe Beteta break;
1213f52228b8SJoe Beteta }
1214f52228b8SJoe Beteta }
1215f52228b8SJoe Beteta
1216f52228b8SJoe Beteta /*
1217f52228b8SJoe Beteta *
1218f52228b8SJoe Beteta * Name: skd_timer, kicks off the timer processing.
1219f52228b8SJoe Beteta *
1220f52228b8SJoe Beteta * Inputs: skdev - device state structure.
1221f52228b8SJoe Beteta *
1222f52228b8SJoe Beteta * Returns: Nothing.
1223f52228b8SJoe Beteta *
1224f52228b8SJoe Beteta */
1225f52228b8SJoe Beteta static void
skd_timer(void * arg)1226f52228b8SJoe Beteta skd_timer(void *arg)
1227f52228b8SJoe Beteta {
1228f52228b8SJoe Beteta skd_device_t *skdev = (skd_device_t *)arg;
1229f52228b8SJoe Beteta
1230f52228b8SJoe Beteta /* Someone set us to 0, don't bother rescheduling. */
1231f52228b8SJoe Beteta ADAPTER_STATE_LOCK(skdev);
1232f52228b8SJoe Beteta if (skdev->skd_timer_timeout_id != 0) {
1233f52228b8SJoe Beteta ADAPTER_STATE_UNLOCK(skdev);
1234f52228b8SJoe Beteta /* Pardon the drop-and-then-acquire logic here. */
1235f52228b8SJoe Beteta skd_timer_tick(skdev);
1236f52228b8SJoe Beteta ADAPTER_STATE_LOCK(skdev);
1237f52228b8SJoe Beteta /* Restart timer, if not being stopped. */
1238f52228b8SJoe Beteta if (skdev->skd_timer_timeout_id != 0) {
1239f52228b8SJoe Beteta skdev->skd_timer_timeout_id =
1240f52228b8SJoe Beteta timeout(skd_timer, arg, skd_timer_ticks);
1241f52228b8SJoe Beteta }
1242f52228b8SJoe Beteta }
1243f52228b8SJoe Beteta ADAPTER_STATE_UNLOCK(skdev);
1244f52228b8SJoe Beteta }
1245f52228b8SJoe Beteta
1246f52228b8SJoe Beteta /*
1247f52228b8SJoe Beteta *
1248f52228b8SJoe Beteta * Name: skd_start_timer, kicks off the 1-second timer.
1249f52228b8SJoe Beteta *
1250f52228b8SJoe Beteta * Inputs: skdev - device state structure.
1251f52228b8SJoe Beteta *
1252f52228b8SJoe Beteta * Returns: Zero.
1253f52228b8SJoe Beteta *
1254f52228b8SJoe Beteta */
1255f52228b8SJoe Beteta static void
skd_start_timer(struct skd_device * skdev)1256f52228b8SJoe Beteta skd_start_timer(struct skd_device *skdev)
1257f52228b8SJoe Beteta {
1258f52228b8SJoe Beteta /* Start one second driver timer. */
1259f52228b8SJoe Beteta ADAPTER_STATE_LOCK(skdev);
1260f52228b8SJoe Beteta ASSERT(skdev->skd_timer_timeout_id == 0);
1261f52228b8SJoe Beteta
1262f52228b8SJoe Beteta /*
1263f52228b8SJoe Beteta * Do first "timeout tick" right away, but not in this
1264f52228b8SJoe Beteta * thread.
1265f52228b8SJoe Beteta */
1266f52228b8SJoe Beteta skdev->skd_timer_timeout_id = timeout(skd_timer, skdev, 1);
1267f52228b8SJoe Beteta ADAPTER_STATE_UNLOCK(skdev);
1268f52228b8SJoe Beteta }
1269f52228b8SJoe Beteta
1270f52228b8SJoe Beteta /*
1271f52228b8SJoe Beteta * INTERNAL REQUESTS -- generated by driver itself
1272f52228b8SJoe Beteta */
1273f52228b8SJoe Beteta
1274f52228b8SJoe Beteta /*
1275f52228b8SJoe Beteta *
1276f52228b8SJoe Beteta * Name: skd_format_internal_skspcl, setups the internal
1277f52228b8SJoe Beteta * FIT request message.
1278f52228b8SJoe Beteta *
1279f52228b8SJoe Beteta * Inputs: skdev - device state structure.
1280f52228b8SJoe Beteta *
1281f52228b8SJoe Beteta * Returns: One.
1282f52228b8SJoe Beteta *
1283f52228b8SJoe Beteta */
1284f52228b8SJoe Beteta static int
skd_format_internal_skspcl(struct skd_device * skdev)1285f52228b8SJoe Beteta skd_format_internal_skspcl(struct skd_device *skdev)
1286f52228b8SJoe Beteta {
1287f52228b8SJoe Beteta struct skd_special_context *skspcl = &skdev->internal_skspcl;
1288f52228b8SJoe Beteta struct fit_sg_descriptor *sgd = &skspcl->req.sksg_list[0];
1289f52228b8SJoe Beteta struct fit_msg_hdr *fmh;
1290f52228b8SJoe Beteta uint64_t dma_address;
1291f52228b8SJoe Beteta struct skd_scsi_request *scsi;
1292f52228b8SJoe Beteta
1293f52228b8SJoe Beteta fmh = (struct fit_msg_hdr *)&skspcl->msg_buf64[0];
1294f52228b8SJoe Beteta fmh->protocol_id = FIT_PROTOCOL_ID_SOFIT;
1295f52228b8SJoe Beteta fmh->num_protocol_cmds_coalesced = 1;
1296f52228b8SJoe Beteta
1297f52228b8SJoe Beteta /* Instead of 64-bytes in, use 8-(64-bit-words) for linted alignment. */
1298f52228b8SJoe Beteta scsi = (struct skd_scsi_request *)&skspcl->msg_buf64[8];
1299f52228b8SJoe Beteta bzero(scsi, sizeof (*scsi));
1300f52228b8SJoe Beteta dma_address = skspcl->req.sksg_dma_address.cookies->_dmu._dmac_ll;
1301f52228b8SJoe Beteta scsi->hdr.sg_list_dma_address = cpu_to_be64(dma_address);
1302f52228b8SJoe Beteta sgd->control = FIT_SGD_CONTROL_LAST;
1303f52228b8SJoe Beteta sgd->byte_count = 0;
1304f52228b8SJoe Beteta sgd->host_side_addr = skspcl->db_dma_address.cookies->_dmu._dmac_ll;
1305f52228b8SJoe Beteta sgd->dev_side_addr = 0; /* not used */
1306f52228b8SJoe Beteta sgd->next_desc_ptr = 0LL;
1307f52228b8SJoe Beteta
1308f52228b8SJoe Beteta return (1);
1309f52228b8SJoe Beteta }
1310f52228b8SJoe Beteta
1311f52228b8SJoe Beteta /*
1312f52228b8SJoe Beteta *
1313f52228b8SJoe Beteta * Name: skd_send_internal_skspcl, send internal requests to
1314f52228b8SJoe Beteta * the hardware.
1315f52228b8SJoe Beteta *
1316f52228b8SJoe Beteta * Inputs: skdev - device state structure.
1317f52228b8SJoe Beteta * skspcl - request structure
1318f52228b8SJoe Beteta * opcode - just what it says
1319f52228b8SJoe Beteta *
1320f52228b8SJoe Beteta * Returns: Nothing.
1321f52228b8SJoe Beteta *
1322f52228b8SJoe Beteta */
1323f52228b8SJoe Beteta void
skd_send_internal_skspcl(struct skd_device * skdev,struct skd_special_context * skspcl,uint8_t opcode)1324f52228b8SJoe Beteta skd_send_internal_skspcl(struct skd_device *skdev,
1325f52228b8SJoe Beteta struct skd_special_context *skspcl, uint8_t opcode)
1326f52228b8SJoe Beteta {
1327f52228b8SJoe Beteta struct fit_sg_descriptor *sgd = &skspcl->req.sksg_list[0];
1328f52228b8SJoe Beteta struct skd_scsi_request *scsi;
1329f52228b8SJoe Beteta
1330f52228b8SJoe Beteta if (SKD_REQ_STATE_IDLE != skspcl->req.state) {
1331f52228b8SJoe Beteta /*
1332f52228b8SJoe Beteta * A refresh is already in progress.
1333f52228b8SJoe Beteta * Just wait for it to finish.
1334f52228b8SJoe Beteta */
1335f52228b8SJoe Beteta return;
1336f52228b8SJoe Beteta }
1337f52228b8SJoe Beteta
1338f52228b8SJoe Beteta ASSERT(0 == (skspcl->req.id & SKD_ID_INCR));
1339f52228b8SJoe Beteta skspcl->req.state = SKD_REQ_STATE_BUSY;
1340f52228b8SJoe Beteta skspcl->req.id += SKD_ID_INCR;
1341f52228b8SJoe Beteta
1342f52228b8SJoe Beteta /* Instead of 64-bytes in, use 8-(64-bit-words) for linted alignment. */
1343f52228b8SJoe Beteta scsi = (struct skd_scsi_request *)&skspcl->msg_buf64[8];
1344f52228b8SJoe Beteta scsi->hdr.tag = skspcl->req.id;
1345f52228b8SJoe Beteta
1346f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "internal skspcl: opcode=%x req.id=%x ==========>",
1347f52228b8SJoe Beteta opcode, skspcl->req.id);
1348f52228b8SJoe Beteta
1349f52228b8SJoe Beteta switch (opcode) {
1350f52228b8SJoe Beteta case TEST_UNIT_READY:
1351f52228b8SJoe Beteta scsi->cdb[0] = TEST_UNIT_READY;
1352f52228b8SJoe Beteta scsi->cdb[1] = 0x00;
1353f52228b8SJoe Beteta scsi->cdb[2] = 0x00;
1354f52228b8SJoe Beteta scsi->cdb[3] = 0x00;
1355f52228b8SJoe Beteta scsi->cdb[4] = 0x00;
1356f52228b8SJoe Beteta scsi->cdb[5] = 0x00;
1357f52228b8SJoe Beteta sgd->byte_count = 0;
1358f52228b8SJoe Beteta scsi->hdr.sg_list_len_bytes = 0;
1359f52228b8SJoe Beteta break;
1360f52228b8SJoe Beteta case READ_CAPACITY_EXT:
1361f52228b8SJoe Beteta scsi->cdb[0] = READ_CAPACITY_EXT;
1362f52228b8SJoe Beteta scsi->cdb[1] = 0x10;
1363f52228b8SJoe Beteta scsi->cdb[2] = 0x00;
1364f52228b8SJoe Beteta scsi->cdb[3] = 0x00;
1365f52228b8SJoe Beteta scsi->cdb[4] = 0x00;
1366f52228b8SJoe Beteta scsi->cdb[5] = 0x00;
1367f52228b8SJoe Beteta scsi->cdb[6] = 0x00;
1368f52228b8SJoe Beteta scsi->cdb[7] = 0x00;
1369f52228b8SJoe Beteta scsi->cdb[8] = 0x00;
1370f52228b8SJoe Beteta scsi->cdb[9] = 0x00;
1371f52228b8SJoe Beteta scsi->cdb[10] = 0x00;
1372f52228b8SJoe Beteta scsi->cdb[11] = 0x00;
1373f52228b8SJoe Beteta scsi->cdb[12] = 0x00;
1374f52228b8SJoe Beteta scsi->cdb[13] = 0x20;
1375f52228b8SJoe Beteta scsi->cdb[14] = 0x00;
1376f52228b8SJoe Beteta scsi->cdb[15] = 0x00;
1377f52228b8SJoe Beteta sgd->byte_count = SKD_N_READ_CAP_EXT_BYTES;
1378f52228b8SJoe Beteta scsi->hdr.sg_list_len_bytes = cpu_to_be32(sgd->byte_count);
1379f52228b8SJoe Beteta break;
1380f52228b8SJoe Beteta case 0x28:
1381f52228b8SJoe Beteta (void) memset(skspcl->data_buf, 0x65, SKD_N_INTERNAL_BYTES);
1382f52228b8SJoe Beteta
1383f52228b8SJoe Beteta scsi->cdb[0] = 0x28;
1384f52228b8SJoe Beteta scsi->cdb[1] = 0x00;
1385f52228b8SJoe Beteta scsi->cdb[2] = 0x00;
1386f52228b8SJoe Beteta scsi->cdb[3] = 0x00;
1387f52228b8SJoe Beteta scsi->cdb[4] = 0x00;
1388f52228b8SJoe Beteta scsi->cdb[5] = 0x00;
1389f52228b8SJoe Beteta scsi->cdb[6] = 0x00;
1390f52228b8SJoe Beteta scsi->cdb[7] = 0x00;
1391f52228b8SJoe Beteta scsi->cdb[8] = 0x01;
1392f52228b8SJoe Beteta scsi->cdb[9] = 0x00;
1393f52228b8SJoe Beteta sgd->byte_count = SKD_N_INTERNAL_BYTES;
1394f52228b8SJoe Beteta scsi->hdr.sg_list_len_bytes = cpu_to_be32(SKD_N_INTERNAL_BYTES);
1395f52228b8SJoe Beteta break;
1396f52228b8SJoe Beteta case INQUIRY:
1397f52228b8SJoe Beteta scsi->cdb[0] = INQUIRY;
1398f52228b8SJoe Beteta scsi->cdb[1] = 0x01; /* evpd */
1399f52228b8SJoe Beteta scsi->cdb[2] = 0x80; /* serial number page */
1400f52228b8SJoe Beteta scsi->cdb[3] = 0x00;
1401f52228b8SJoe Beteta scsi->cdb[4] = 0x10;
1402f52228b8SJoe Beteta scsi->cdb[5] = 0x00;
1403f52228b8SJoe Beteta sgd->byte_count = 16; /* SKD_N_INQ_BYTES */;
1404f52228b8SJoe Beteta scsi->hdr.sg_list_len_bytes = cpu_to_be32(sgd->byte_count);
1405f52228b8SJoe Beteta break;
1406f52228b8SJoe Beteta case INQUIRY2:
1407f52228b8SJoe Beteta scsi->cdb[0] = INQUIRY;
1408f52228b8SJoe Beteta scsi->cdb[1] = 0x00;
1409f52228b8SJoe Beteta scsi->cdb[2] = 0x00; /* serial number page */
1410f52228b8SJoe Beteta scsi->cdb[3] = 0x00;
1411f52228b8SJoe Beteta scsi->cdb[4] = 0x24;
1412f52228b8SJoe Beteta scsi->cdb[5] = 0x00;
1413f52228b8SJoe Beteta sgd->byte_count = 36; /* SKD_N_INQ_BYTES */;
1414f52228b8SJoe Beteta scsi->hdr.sg_list_len_bytes = cpu_to_be32(sgd->byte_count);
1415f52228b8SJoe Beteta break;
1416f52228b8SJoe Beteta case SYNCHRONIZE_CACHE:
1417f52228b8SJoe Beteta scsi->cdb[0] = SYNCHRONIZE_CACHE;
1418f52228b8SJoe Beteta scsi->cdb[1] = 0x00;
1419f52228b8SJoe Beteta scsi->cdb[2] = 0x00;
1420f52228b8SJoe Beteta scsi->cdb[3] = 0x00;
1421f52228b8SJoe Beteta scsi->cdb[4] = 0x00;
1422f52228b8SJoe Beteta scsi->cdb[5] = 0x00;
1423f52228b8SJoe Beteta scsi->cdb[6] = 0x00;
1424f52228b8SJoe Beteta scsi->cdb[7] = 0x00;
1425f52228b8SJoe Beteta scsi->cdb[8] = 0x00;
1426f52228b8SJoe Beteta scsi->cdb[9] = 0x00;
1427f52228b8SJoe Beteta sgd->byte_count = 0;
1428f52228b8SJoe Beteta scsi->hdr.sg_list_len_bytes = 0;
1429f52228b8SJoe Beteta break;
1430f52228b8SJoe Beteta default:
1431f52228b8SJoe Beteta ASSERT("Don't know what to send");
1432f52228b8SJoe Beteta return;
1433f52228b8SJoe Beteta
1434f52228b8SJoe Beteta }
1435f52228b8SJoe Beteta
1436f52228b8SJoe Beteta skd_send_special_fitmsg(skdev, skspcl);
1437f52228b8SJoe Beteta }
1438f52228b8SJoe Beteta
1439f52228b8SJoe Beteta /*
1440f52228b8SJoe Beteta *
1441f52228b8SJoe Beteta * Name: skd_refresh_device_data, sends a TUR command.
1442f52228b8SJoe Beteta *
1443f52228b8SJoe Beteta * Inputs: skdev - device state structure.
1444f52228b8SJoe Beteta *
1445f52228b8SJoe Beteta * Returns: Nothing.
1446f52228b8SJoe Beteta *
1447f52228b8SJoe Beteta */
1448f52228b8SJoe Beteta static void
skd_refresh_device_data(struct skd_device * skdev)1449f52228b8SJoe Beteta skd_refresh_device_data(struct skd_device *skdev)
1450f52228b8SJoe Beteta {
1451f52228b8SJoe Beteta struct skd_special_context *skspcl = &skdev->internal_skspcl;
1452f52228b8SJoe Beteta
1453f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "refresh_device_data: state=%d", skdev->state);
1454f52228b8SJoe Beteta
1455f52228b8SJoe Beteta skd_send_internal_skspcl(skdev, skspcl, TEST_UNIT_READY);
1456f52228b8SJoe Beteta }
1457f52228b8SJoe Beteta
1458f52228b8SJoe Beteta /*
1459f52228b8SJoe Beteta *
1460f52228b8SJoe Beteta * Name: skd_complete_internal, handles the completion of
1461f52228b8SJoe Beteta * driver-initiated I/O requests.
1462f52228b8SJoe Beteta *
1463f52228b8SJoe Beteta * Inputs: skdev - device state structure.
1464f52228b8SJoe Beteta * skcomp - completion structure.
1465f52228b8SJoe Beteta * skerr - error structure.
1466f52228b8SJoe Beteta * skspcl - request structure.
1467f52228b8SJoe Beteta *
1468f52228b8SJoe Beteta * Returns: Nothing.
1469f52228b8SJoe Beteta *
1470f52228b8SJoe Beteta */
1471f52228b8SJoe Beteta /* ARGSUSED */ /* Upstream common source with other platforms. */
1472f52228b8SJoe Beteta static void
skd_complete_internal(struct skd_device * skdev,volatile struct fit_completion_entry_v1 * skcomp,volatile struct fit_comp_error_info * skerr,struct skd_special_context * skspcl)1473f52228b8SJoe Beteta skd_complete_internal(struct skd_device *skdev,
1474f52228b8SJoe Beteta volatile struct fit_completion_entry_v1 *skcomp,
1475f52228b8SJoe Beteta volatile struct fit_comp_error_info *skerr,
1476f52228b8SJoe Beteta struct skd_special_context *skspcl)
1477f52228b8SJoe Beteta {
1478f52228b8SJoe Beteta uint8_t *buf = skspcl->data_buf;
1479f52228b8SJoe Beteta uint8_t status = 2;
1480f52228b8SJoe Beteta /* Instead of 64-bytes in, use 8-(64-bit-words) for linted alignment. */
1481f52228b8SJoe Beteta struct skd_scsi_request *scsi =
1482f52228b8SJoe Beteta (struct skd_scsi_request *)&skspcl->msg_buf64[8];
1483f52228b8SJoe Beteta
1484f52228b8SJoe Beteta ASSERT(skspcl == &skdev->internal_skspcl);
1485f52228b8SJoe Beteta
1486f52228b8SJoe Beteta (void) ddi_dma_sync(skspcl->db_dma_address.dma_handle, 0, 0,
1487f52228b8SJoe Beteta DDI_DMA_SYNC_FORKERNEL);
1488f52228b8SJoe Beteta (void) ddi_dma_sync(skspcl->mb_dma_address.dma_handle, 0, 0,
1489f52228b8SJoe Beteta DDI_DMA_SYNC_FORKERNEL);
1490f52228b8SJoe Beteta
1491f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "complete internal %x", scsi->cdb[0]);
1492f52228b8SJoe Beteta
1493f52228b8SJoe Beteta skspcl->req.completion = *skcomp;
1494f52228b8SJoe Beteta skspcl->req.state = SKD_REQ_STATE_IDLE;
1495f52228b8SJoe Beteta skspcl->req.id += SKD_ID_INCR;
1496f52228b8SJoe Beteta
1497f52228b8SJoe Beteta status = skspcl->req.completion.status;
1498f52228b8SJoe Beteta
1499f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "<<<<====== complete_internal: opc=%x", *scsi->cdb);
1500f52228b8SJoe Beteta
1501f52228b8SJoe Beteta switch (scsi->cdb[0]) {
1502f52228b8SJoe Beteta case TEST_UNIT_READY:
1503f52228b8SJoe Beteta if (SAM_STAT_GOOD == status) {
1504f52228b8SJoe Beteta skd_send_internal_skspcl(skdev, skspcl,
1505f52228b8SJoe Beteta READ_CAPACITY_EXT);
1506f52228b8SJoe Beteta } else {
1507f52228b8SJoe Beteta if (skdev->state == SKD_DRVR_STATE_STOPPING) {
1508f52228b8SJoe Beteta cmn_err(CE_WARN,
1509f52228b8SJoe Beteta "!%s: TUR failed, don't send anymore"
1510f52228b8SJoe Beteta "state 0x%x", skdev->name, skdev->state);
1511f52228b8SJoe Beteta
1512f52228b8SJoe Beteta return;
1513f52228b8SJoe Beteta }
1514f52228b8SJoe Beteta
1515f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "%s: TUR failed, retry skerr",
1516f52228b8SJoe Beteta skdev->name);
1517f52228b8SJoe Beteta skd_send_internal_skspcl(skdev, skspcl, 0x00);
1518f52228b8SJoe Beteta }
1519f52228b8SJoe Beteta break;
1520f52228b8SJoe Beteta case READ_CAPACITY_EXT: {
1521f52228b8SJoe Beteta uint64_t cap, Nblocks;
1522f52228b8SJoe Beteta uint64_t xbuf[1];
1523f52228b8SJoe Beteta
1524f52228b8SJoe Beteta skdev->read_cap_is_valid = 0;
1525f52228b8SJoe Beteta if (SAM_STAT_GOOD == status) {
1526f52228b8SJoe Beteta bcopy(buf, xbuf, 8);
1527f52228b8SJoe Beteta cap = be64_to_cpu(*xbuf);
1528f52228b8SJoe Beteta skdev->read_cap_last_lba = cap;
1529f52228b8SJoe Beteta skdev->read_cap_blocksize =
1530f52228b8SJoe Beteta (buf[8] << 24) | (buf[9] << 16) |
1531f52228b8SJoe Beteta (buf[10] << 8) | buf[11];
1532f52228b8SJoe Beteta
1533f52228b8SJoe Beteta cap *= skdev->read_cap_blocksize;
1534f52228b8SJoe Beteta Dcmn_err(CE_NOTE, " Last LBA: %" PRIu64 " (0x%" PRIx64
1535f52228b8SJoe Beteta "), blk sz: %d, Capacity: %" PRIu64 "GB\n",
1536f52228b8SJoe Beteta skdev->read_cap_last_lba,
1537f52228b8SJoe Beteta skdev->read_cap_last_lba,
1538f52228b8SJoe Beteta skdev->read_cap_blocksize,
1539f52228b8SJoe Beteta cap >> 30ULL);
1540f52228b8SJoe Beteta
1541f52228b8SJoe Beteta Nblocks = skdev->read_cap_last_lba + 1;
1542f52228b8SJoe Beteta
1543f52228b8SJoe Beteta skdev->Nblocks = Nblocks;
1544f52228b8SJoe Beteta skdev->read_cap_is_valid = 1;
1545f52228b8SJoe Beteta
1546f52228b8SJoe Beteta skd_send_internal_skspcl(skdev, skspcl, INQUIRY2);
1547f52228b8SJoe Beteta
1548f52228b8SJoe Beteta } else {
1549f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "**** READCAP failed, retry TUR");
1550f52228b8SJoe Beteta skd_send_internal_skspcl(skdev, skspcl,
1551f52228b8SJoe Beteta TEST_UNIT_READY);
1552f52228b8SJoe Beteta }
1553f52228b8SJoe Beteta break;
1554f52228b8SJoe Beteta }
1555f52228b8SJoe Beteta case INQUIRY:
1556f52228b8SJoe Beteta skdev->inquiry_is_valid = 0;
1557f52228b8SJoe Beteta if (SAM_STAT_GOOD == status) {
1558f52228b8SJoe Beteta skdev->inquiry_is_valid = 1;
1559f52228b8SJoe Beteta
1560f52228b8SJoe Beteta if (scsi->cdb[1] == 0x1) {
1561f52228b8SJoe Beteta bcopy(&buf[4], skdev->inq_serial_num, 12);
1562f52228b8SJoe Beteta skdev->inq_serial_num[12] = '\0';
1563f52228b8SJoe Beteta } else {
1564f52228b8SJoe Beteta char *tmp = skdev->inq_vendor_id;
1565f52228b8SJoe Beteta
1566f52228b8SJoe Beteta bcopy(&buf[8], tmp, 8);
1567f52228b8SJoe Beteta tmp[8] = '\0';
1568f52228b8SJoe Beteta
1569f52228b8SJoe Beteta tmp = skdev->inq_product_id;
1570f52228b8SJoe Beteta bcopy(&buf[16], tmp, 16);
1571f52228b8SJoe Beteta tmp[16] = '\0';
1572f52228b8SJoe Beteta
1573f52228b8SJoe Beteta tmp = skdev->inq_product_rev;
1574f52228b8SJoe Beteta bcopy(&buf[32], tmp, 4);
1575f52228b8SJoe Beteta tmp[4] = '\0';
1576f52228b8SJoe Beteta }
1577f52228b8SJoe Beteta }
1578f52228b8SJoe Beteta
1579f52228b8SJoe Beteta if (skdev->state != SKD_DRVR_STATE_ONLINE)
1580f52228b8SJoe Beteta if (skd_unquiesce_dev(skdev) < 0)
1581f52228b8SJoe Beteta cmn_err(CE_NOTE, "** failed, to ONLINE device");
1582f52228b8SJoe Beteta break;
1583f52228b8SJoe Beteta case SYNCHRONIZE_CACHE:
1584f52228b8SJoe Beteta skdev->sync_done = (SAM_STAT_GOOD == status) ? 1 : -1;
1585f52228b8SJoe Beteta
1586f52228b8SJoe Beteta cv_signal(&skdev->cv_waitq);
1587f52228b8SJoe Beteta break;
1588f52228b8SJoe Beteta
1589f52228b8SJoe Beteta default:
1590f52228b8SJoe Beteta ASSERT("we didn't send this");
1591f52228b8SJoe Beteta }
1592f52228b8SJoe Beteta }
1593f52228b8SJoe Beteta
1594f52228b8SJoe Beteta /*
1595f52228b8SJoe Beteta * FIT MESSAGES
1596f52228b8SJoe Beteta */
1597f52228b8SJoe Beteta
1598f52228b8SJoe Beteta /*
1599f52228b8SJoe Beteta *
1600f52228b8SJoe Beteta * Name: skd_send_fitmsg, send a FIT message to the hardware.
1601f52228b8SJoe Beteta *
1602f52228b8SJoe Beteta * Inputs: skdev - device state structure.
1603f52228b8SJoe Beteta * skmsg - FIT message structure.
1604f52228b8SJoe Beteta *
1605f52228b8SJoe Beteta * Returns: Nothing.
1606f52228b8SJoe Beteta *
1607f52228b8SJoe Beteta */
1608f52228b8SJoe Beteta /* ARGSUSED */ /* Upstream common source with other platforms. */
1609f52228b8SJoe Beteta static void
skd_send_fitmsg(struct skd_device * skdev,struct skd_fitmsg_context * skmsg)1610f52228b8SJoe Beteta skd_send_fitmsg(struct skd_device *skdev,
1611f52228b8SJoe Beteta struct skd_fitmsg_context *skmsg)
1612f52228b8SJoe Beteta {
1613f52228b8SJoe Beteta uint64_t qcmd;
1614f52228b8SJoe Beteta struct fit_msg_hdr *fmh;
1615f52228b8SJoe Beteta
1616f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "msgbuf's DMA addr: 0x%" PRIx64 ", qdepth_busy=%d",
1617f52228b8SJoe Beteta skmsg->mb_dma_address.cookies->dmac_laddress,
1618f52228b8SJoe Beteta skdev->queue_depth_busy);
1619f52228b8SJoe Beteta
1620f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "msg_buf 0x%p, offset %x", (void *)skmsg->msg_buf,
1621f52228b8SJoe Beteta skmsg->offset);
1622f52228b8SJoe Beteta
1623f52228b8SJoe Beteta qcmd = skmsg->mb_dma_address.cookies->dmac_laddress;
1624f52228b8SJoe Beteta qcmd |= FIT_QCMD_QID_NORMAL;
1625f52228b8SJoe Beteta
1626f52228b8SJoe Beteta fmh = (struct fit_msg_hdr *)skmsg->msg_buf64;
1627f52228b8SJoe Beteta skmsg->outstanding = fmh->num_protocol_cmds_coalesced;
1628f52228b8SJoe Beteta
1629f52228b8SJoe Beteta if (skdev->dbg_level > 1) {
1630f52228b8SJoe Beteta uint8_t *bp = skmsg->msg_buf;
1631f52228b8SJoe Beteta int i;
1632f52228b8SJoe Beteta
1633f52228b8SJoe Beteta for (i = 0; i < skmsg->length; i += 8) {
1634f52228b8SJoe Beteta Dcmn_err(CE_NOTE, " msg[%2d] %02x %02x %02x %02x "
1635f52228b8SJoe Beteta "%02x %02x %02x %02x",
1636f52228b8SJoe Beteta i, bp[i + 0], bp[i + 1], bp[i + 2],
1637f52228b8SJoe Beteta bp[i + 3], bp[i + 4], bp[i + 5],
1638f52228b8SJoe Beteta bp[i + 6], bp[i + 7]);
1639f52228b8SJoe Beteta if (i == 0) i = 64 - 8;
1640f52228b8SJoe Beteta }
1641f52228b8SJoe Beteta }
1642f52228b8SJoe Beteta
1643f52228b8SJoe Beteta (void) ddi_dma_sync(skmsg->mb_dma_address.dma_handle, 0, 0,
1644f52228b8SJoe Beteta DDI_DMA_SYNC_FORDEV);
1645f52228b8SJoe Beteta
1646f52228b8SJoe Beteta ASSERT(skmsg->length > sizeof (struct fit_msg_hdr));
1647f52228b8SJoe Beteta if (skmsg->length > 256) {
1648f52228b8SJoe Beteta qcmd |= FIT_QCMD_MSGSIZE_512;
1649f52228b8SJoe Beteta } else if (skmsg->length > 128) {
1650f52228b8SJoe Beteta qcmd |= FIT_QCMD_MSGSIZE_256;
1651f52228b8SJoe Beteta } else if (skmsg->length > 64) {
1652f52228b8SJoe Beteta qcmd |= FIT_QCMD_MSGSIZE_128;
1653f52228b8SJoe Beteta }
1654f52228b8SJoe Beteta
1655f52228b8SJoe Beteta skdev->ios_started++;
1656f52228b8SJoe Beteta
1657f52228b8SJoe Beteta SKD_WRITEQ(skdev, qcmd, FIT_Q_COMMAND);
1658f52228b8SJoe Beteta }
1659f52228b8SJoe Beteta
1660f52228b8SJoe Beteta /*
1661f52228b8SJoe Beteta *
1662f52228b8SJoe Beteta * Name: skd_send_special_fitmsg, send a special FIT message
1663f52228b8SJoe Beteta * to the hardware used driver-originated I/O requests.
1664f52228b8SJoe Beteta *
1665f52228b8SJoe Beteta * Inputs: skdev - device state structure.
1666f52228b8SJoe Beteta * skspcl - skspcl structure.
1667f52228b8SJoe Beteta *
1668f52228b8SJoe Beteta * Returns: Nothing.
1669f52228b8SJoe Beteta *
1670f52228b8SJoe Beteta */
1671f52228b8SJoe Beteta static void
skd_send_special_fitmsg(struct skd_device * skdev,struct skd_special_context * skspcl)1672f52228b8SJoe Beteta skd_send_special_fitmsg(struct skd_device *skdev,
1673f52228b8SJoe Beteta struct skd_special_context *skspcl)
1674f52228b8SJoe Beteta {
1675f52228b8SJoe Beteta uint64_t qcmd;
1676f52228b8SJoe Beteta
1677f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "send_special_fitmsg: pt 1");
1678f52228b8SJoe Beteta
1679f52228b8SJoe Beteta if (skdev->dbg_level > 1) {
1680f52228b8SJoe Beteta uint8_t *bp = skspcl->msg_buf;
1681f52228b8SJoe Beteta int i;
1682f52228b8SJoe Beteta
1683f52228b8SJoe Beteta for (i = 0; i < SKD_N_SPECIAL_FITMSG_BYTES; i += 8) {
1684f52228b8SJoe Beteta cmn_err(CE_NOTE,
1685f52228b8SJoe Beteta " spcl[%2d] %02x %02x %02x %02x "
1686f52228b8SJoe Beteta "%02x %02x %02x %02x\n", i,
1687f52228b8SJoe Beteta bp[i + 0], bp[i + 1], bp[i + 2], bp[i + 3],
1688f52228b8SJoe Beteta bp[i + 4], bp[i + 5], bp[i + 6], bp[i + 7]);
1689f52228b8SJoe Beteta if (i == 0) i = 64 - 8;
1690f52228b8SJoe Beteta }
1691f52228b8SJoe Beteta
1692f52228b8SJoe Beteta for (i = 0; i < skspcl->req.n_sg; i++) {
1693f52228b8SJoe Beteta struct fit_sg_descriptor *sgd =
1694f52228b8SJoe Beteta &skspcl->req.sksg_list[i];
1695f52228b8SJoe Beteta
1696f52228b8SJoe Beteta cmn_err(CE_NOTE, " sg[%d] count=%u ctrl=0x%x "
1697f52228b8SJoe Beteta "addr=0x%" PRIx64 " next=0x%" PRIx64,
1698f52228b8SJoe Beteta i, sgd->byte_count, sgd->control,
1699f52228b8SJoe Beteta sgd->host_side_addr, sgd->next_desc_ptr);
1700f52228b8SJoe Beteta }
1701f52228b8SJoe Beteta }
1702f52228b8SJoe Beteta
1703f52228b8SJoe Beteta (void) ddi_dma_sync(skspcl->mb_dma_address.dma_handle, 0, 0,
1704f52228b8SJoe Beteta DDI_DMA_SYNC_FORDEV);
1705f52228b8SJoe Beteta (void) ddi_dma_sync(skspcl->db_dma_address.dma_handle, 0, 0,
1706f52228b8SJoe Beteta DDI_DMA_SYNC_FORDEV);
1707f52228b8SJoe Beteta
1708f52228b8SJoe Beteta /*
1709f52228b8SJoe Beteta * Special FIT msgs are always 128 bytes: a 64-byte FIT hdr
1710f52228b8SJoe Beteta * and one 64-byte SSDI command.
1711f52228b8SJoe Beteta */
1712f52228b8SJoe Beteta qcmd = skspcl->mb_dma_address.cookies->dmac_laddress;
1713f52228b8SJoe Beteta
1714f52228b8SJoe Beteta qcmd |= FIT_QCMD_QID_NORMAL + FIT_QCMD_MSGSIZE_128;
1715f52228b8SJoe Beteta
1716f52228b8SJoe Beteta SKD_WRITEQ(skdev, qcmd, FIT_Q_COMMAND);
1717f52228b8SJoe Beteta }
1718f52228b8SJoe Beteta
1719f52228b8SJoe Beteta /*
1720f52228b8SJoe Beteta * COMPLETION QUEUE
1721f52228b8SJoe Beteta */
1722f52228b8SJoe Beteta
1723f52228b8SJoe Beteta static void skd_complete_other(struct skd_device *skdev,
1724f52228b8SJoe Beteta volatile struct fit_completion_entry_v1 *skcomp,
1725f52228b8SJoe Beteta volatile struct fit_comp_error_info *skerr);
1726f52228b8SJoe Beteta
1727f52228b8SJoe Beteta struct sns_info {
1728f52228b8SJoe Beteta uint8_t type;
1729f52228b8SJoe Beteta uint8_t stat;
1730f52228b8SJoe Beteta uint8_t key;
1731f52228b8SJoe Beteta uint8_t asc;
1732f52228b8SJoe Beteta uint8_t ascq;
1733f52228b8SJoe Beteta uint8_t mask;
1734f52228b8SJoe Beteta enum skd_check_status_action action;
1735f52228b8SJoe Beteta };
1736f52228b8SJoe Beteta
1737f52228b8SJoe Beteta static struct sns_info skd_chkstat_table[] = {
1738f52228b8SJoe Beteta /* Good */
1739f52228b8SJoe Beteta {0x70, 0x02, RECOVERED_ERROR, 0, 0, 0x1c, SKD_CHECK_STATUS_REPORT_GOOD},
1740f52228b8SJoe Beteta
1741f52228b8SJoe Beteta /* Smart alerts */
1742f52228b8SJoe Beteta {0x70, 0x02, NO_SENSE, 0x0B, 0x00, 0x1E, /* warnings */
1743f52228b8SJoe Beteta SKD_CHECK_STATUS_REPORT_SMART_ALERT},
1744f52228b8SJoe Beteta {0x70, 0x02, NO_SENSE, 0x5D, 0x00, 0x1E, /* thresholds */
1745f52228b8SJoe Beteta SKD_CHECK_STATUS_REPORT_SMART_ALERT},
1746f52228b8SJoe Beteta {0x70, 0x02, RECOVERED_ERROR, 0x0B, 0x01, 0x1F, /* temp over trigger */
1747f52228b8SJoe Beteta SKD_CHECK_STATUS_REPORT_SMART_ALERT},
1748f52228b8SJoe Beteta
1749f52228b8SJoe Beteta /* Retry (with limits) */
1750f52228b8SJoe Beteta {0x70, 0x02, ABORTED_COMMAND, 0, 0, 0x1C, /* DMA errors */
1751f52228b8SJoe Beteta SKD_CHECK_STATUS_REQUEUE_REQUEST},
1752f52228b8SJoe Beteta {0x70, 0x02, UNIT_ATTENTION, 0x0B, 0x00, 0x1E, /* warnings */
1753f52228b8SJoe Beteta SKD_CHECK_STATUS_REQUEUE_REQUEST},
1754f52228b8SJoe Beteta {0x70, 0x02, UNIT_ATTENTION, 0x5D, 0x00, 0x1E, /* thresholds */
1755f52228b8SJoe Beteta SKD_CHECK_STATUS_REQUEUE_REQUEST},
1756f52228b8SJoe Beteta {0x70, 0x02, UNIT_ATTENTION, 0x80, 0x30, 0x1F, /* backup power */
1757f52228b8SJoe Beteta SKD_CHECK_STATUS_REQUEUE_REQUEST},
1758f52228b8SJoe Beteta
1759f52228b8SJoe Beteta /* Busy (or about to be) */
1760f52228b8SJoe Beteta {0x70, 0x02, UNIT_ATTENTION, 0x3f, 0x01, 0x1F, /* fw changed */
1761f52228b8SJoe Beteta SKD_CHECK_STATUS_BUSY_IMMINENT},
1762f52228b8SJoe Beteta };
1763f52228b8SJoe Beteta
1764f52228b8SJoe Beteta /*
1765f52228b8SJoe Beteta *
1766f52228b8SJoe Beteta * Name: skd_check_status, checks the return status from a
1767f52228b8SJoe Beteta * completed I/O request.
1768f52228b8SJoe Beteta *
1769f52228b8SJoe Beteta * Inputs: skdev - device state structure.
1770f52228b8SJoe Beteta * cmp_status - SCSI status byte.
1771f52228b8SJoe Beteta * skerr - the error data structure.
1772f52228b8SJoe Beteta *
1773f52228b8SJoe Beteta * Returns: Depending on the error condition, return the action
1774f52228b8SJoe Beteta * to be taken as specified in the skd_chkstat_table.
1775f52228b8SJoe Beteta * If no corresponding value is found in the table
1776f52228b8SJoe Beteta * return SKD_CHECK_STATUS_REPORT_GOOD is no error otherwise
1777f52228b8SJoe Beteta * return SKD_CHECK_STATUS_REPORT_ERROR.
1778f52228b8SJoe Beteta *
1779f52228b8SJoe Beteta */
1780f52228b8SJoe Beteta static enum skd_check_status_action
skd_check_status(struct skd_device * skdev,uint8_t cmp_status,volatile struct fit_comp_error_info * skerr)1781f52228b8SJoe Beteta skd_check_status(struct skd_device *skdev, uint8_t cmp_status,
1782f52228b8SJoe Beteta volatile struct fit_comp_error_info *skerr)
1783f52228b8SJoe Beteta {
1784f52228b8SJoe Beteta /*
1785f52228b8SJoe Beteta * Look up status and sense data to decide how to handle the error
1786f52228b8SJoe Beteta * from the device.
1787f52228b8SJoe Beteta * mask says which fields must match e.g., mask=0x18 means check
1788f52228b8SJoe Beteta * type and stat, ignore key, asc, ascq.
1789f52228b8SJoe Beteta */
1790f52228b8SJoe Beteta int i, n;
1791f52228b8SJoe Beteta
1792f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "(%s): key/asc/ascq %02x/%02x/%02x",
1793f52228b8SJoe Beteta skd_name(skdev), skerr->key, skerr->code, skerr->qual);
1794f52228b8SJoe Beteta
1795f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "stat: t=%02x stat=%02x k=%02x c=%02x q=%02x",
1796f52228b8SJoe Beteta skerr->type, cmp_status, skerr->key, skerr->code, skerr->qual);
1797f52228b8SJoe Beteta
1798f52228b8SJoe Beteta /* Does the info match an entry in the good category? */
1799f52228b8SJoe Beteta n = sizeof (skd_chkstat_table) / sizeof (skd_chkstat_table[0]);
1800f52228b8SJoe Beteta for (i = 0; i < n; i++) {
1801f52228b8SJoe Beteta struct sns_info *sns = &skd_chkstat_table[i];
1802f52228b8SJoe Beteta
1803f52228b8SJoe Beteta if (sns->mask & 0x10)
1804f52228b8SJoe Beteta if (skerr->type != sns->type) continue;
1805f52228b8SJoe Beteta
1806f52228b8SJoe Beteta if (sns->mask & 0x08)
1807f52228b8SJoe Beteta if (cmp_status != sns->stat) continue;
1808f52228b8SJoe Beteta
1809f52228b8SJoe Beteta if (sns->mask & 0x04)
1810f52228b8SJoe Beteta if (skerr->key != sns->key) continue;
1811f52228b8SJoe Beteta
1812f52228b8SJoe Beteta if (sns->mask & 0x02)
1813f52228b8SJoe Beteta if (skerr->code != sns->asc) continue;
1814f52228b8SJoe Beteta
1815f52228b8SJoe Beteta if (sns->mask & 0x01)
1816f52228b8SJoe Beteta if (skerr->qual != sns->ascq) continue;
1817f52228b8SJoe Beteta
1818f52228b8SJoe Beteta if (sns->action == SKD_CHECK_STATUS_REPORT_SMART_ALERT) {
1819f52228b8SJoe Beteta cmn_err(CE_WARN, "!(%s):SMART Alert: sense key/asc/ascq"
1820f52228b8SJoe Beteta " %02x/%02x/%02x",
1821f52228b8SJoe Beteta skd_name(skdev), skerr->key,
1822f52228b8SJoe Beteta skerr->code, skerr->qual);
1823f52228b8SJoe Beteta }
1824f52228b8SJoe Beteta
1825f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "skd_check_status: returning %x",
1826f52228b8SJoe Beteta sns->action);
1827f52228b8SJoe Beteta
1828f52228b8SJoe Beteta return (sns->action);
1829f52228b8SJoe Beteta }
1830f52228b8SJoe Beteta
1831f52228b8SJoe Beteta /*
1832f52228b8SJoe Beteta * No other match, so nonzero status means error,
1833f52228b8SJoe Beteta * zero status means good
1834f52228b8SJoe Beteta */
1835f52228b8SJoe Beteta if (cmp_status) {
1836f52228b8SJoe Beteta cmn_err(CE_WARN,
1837f52228b8SJoe Beteta "!%s: status check: qdepth=%d skmfl=%p (%d) skrfl=%p (%d)",
1838f52228b8SJoe Beteta skdev->name,
1839f52228b8SJoe Beteta skdev->queue_depth_busy,
1840f52228b8SJoe Beteta (void *)skdev->skmsg_free_list, skd_list_skmsg(skdev, 0),
1841f52228b8SJoe Beteta (void *)skdev->skreq_free_list, skd_list_skreq(skdev, 0));
1842f52228b8SJoe Beteta
1843f52228b8SJoe Beteta cmn_err(CE_WARN, "!%s: t=%02x stat=%02x k=%02x c=%02x q=%02x",
1844f52228b8SJoe Beteta skdev->name, skerr->type, cmp_status, skerr->key,
1845f52228b8SJoe Beteta skerr->code, skerr->qual);
1846f52228b8SJoe Beteta
1847f52228b8SJoe Beteta return (SKD_CHECK_STATUS_REPORT_ERROR);
1848f52228b8SJoe Beteta }
1849f52228b8SJoe Beteta
1850f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "status check good default");
1851f52228b8SJoe Beteta
1852f52228b8SJoe Beteta return (SKD_CHECK_STATUS_REPORT_GOOD);
1853f52228b8SJoe Beteta }
1854f52228b8SJoe Beteta
1855f52228b8SJoe Beteta /*
1856f52228b8SJoe Beteta *
1857f52228b8SJoe Beteta * Name: skd_isr_completion_posted, handles I/O completions.
1858f52228b8SJoe Beteta *
1859f52228b8SJoe Beteta * Inputs: skdev - device state structure.
1860f52228b8SJoe Beteta *
1861f52228b8SJoe Beteta * Returns: Nothing.
1862f52228b8SJoe Beteta *
1863f52228b8SJoe Beteta */
1864f52228b8SJoe Beteta static void
skd_isr_completion_posted(struct skd_device * skdev)1865f52228b8SJoe Beteta skd_isr_completion_posted(struct skd_device *skdev)
1866f52228b8SJoe Beteta {
1867f52228b8SJoe Beteta volatile struct fit_completion_entry_v1 *skcmp = NULL;
1868f52228b8SJoe Beteta volatile struct fit_comp_error_info *skerr;
1869f52228b8SJoe Beteta struct skd_fitmsg_context *skmsg;
1870f52228b8SJoe Beteta struct skd_request_context *skreq;
1871f52228b8SJoe Beteta skd_buf_private_t *pbuf;
1872f52228b8SJoe Beteta uint16_t req_id;
1873f52228b8SJoe Beteta uint32_t req_slot;
1874f52228b8SJoe Beteta uint32_t timo_slot;
1875f52228b8SJoe Beteta uint32_t msg_slot;
1876f52228b8SJoe Beteta uint16_t cmp_cntxt = 0;
1877f52228b8SJoe Beteta uint8_t cmp_status = 0;
1878f52228b8SJoe Beteta uint8_t cmp_cycle = 0;
1879f52228b8SJoe Beteta uint32_t cmp_bytes = 0;
1880f52228b8SJoe Beteta
1881f52228b8SJoe Beteta (void) ddi_dma_sync(skdev->cq_dma_address.dma_handle, 0, 0,
1882f52228b8SJoe Beteta DDI_DMA_SYNC_FORKERNEL);
1883f52228b8SJoe Beteta
1884f52228b8SJoe Beteta for (;;) {
1885f52228b8SJoe Beteta ASSERT(skdev->skcomp_ix < SKD_N_COMPLETION_ENTRY);
1886f52228b8SJoe Beteta
1887f52228b8SJoe Beteta WAITQ_LOCK(skdev);
1888f52228b8SJoe Beteta
1889f52228b8SJoe Beteta skcmp = &skdev->skcomp_table[skdev->skcomp_ix];
1890f52228b8SJoe Beteta cmp_cycle = skcmp->cycle;
1891f52228b8SJoe Beteta cmp_cntxt = skcmp->tag;
1892f52228b8SJoe Beteta cmp_status = skcmp->status;
1893f52228b8SJoe Beteta cmp_bytes = be32_to_cpu(skcmp->num_returned_bytes);
1894f52228b8SJoe Beteta
1895f52228b8SJoe Beteta skerr = &skdev->skerr_table[skdev->skcomp_ix];
1896f52228b8SJoe Beteta
1897f52228b8SJoe Beteta Dcmn_err(CE_NOTE,
1898f52228b8SJoe Beteta "cycle=%d ix=%d got cycle=%d cmdctxt=0x%x stat=%d "
1899f52228b8SJoe Beteta "qdepth_busy=%d rbytes=0x%x proto=%d",
1900f52228b8SJoe Beteta skdev->skcomp_cycle, skdev->skcomp_ix,
1901f52228b8SJoe Beteta cmp_cycle, cmp_cntxt, cmp_status,
1902f52228b8SJoe Beteta skdev->queue_depth_busy, cmp_bytes, skdev->proto_ver);
1903f52228b8SJoe Beteta
1904f52228b8SJoe Beteta if (cmp_cycle != skdev->skcomp_cycle) {
1905f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "%s:end of completions", skdev->name);
1906f52228b8SJoe Beteta
1907f52228b8SJoe Beteta WAITQ_UNLOCK(skdev);
1908f52228b8SJoe Beteta break;
1909f52228b8SJoe Beteta }
1910f52228b8SJoe Beteta
1911f52228b8SJoe Beteta
1912f52228b8SJoe Beteta skdev->n_req++;
1913f52228b8SJoe Beteta
1914f52228b8SJoe Beteta /*
1915f52228b8SJoe Beteta * Update the completion queue head index and possibly
1916f52228b8SJoe Beteta * the completion cycle count.
1917f52228b8SJoe Beteta */
1918f52228b8SJoe Beteta skdev->skcomp_ix++;
1919f52228b8SJoe Beteta if (skdev->skcomp_ix >= SKD_N_COMPLETION_ENTRY) {
1920f52228b8SJoe Beteta skdev->skcomp_ix = 0;
1921f52228b8SJoe Beteta skdev->skcomp_cycle++; /* 8-bit wrap-around */
1922f52228b8SJoe Beteta }
1923f52228b8SJoe Beteta
1924f52228b8SJoe Beteta
1925f52228b8SJoe Beteta /*
1926f52228b8SJoe Beteta * The command context is a unique 32-bit ID. The low order
1927f52228b8SJoe Beteta * bits help locate the request. The request is usually a
1928f52228b8SJoe Beteta * r/w request (see skd_start() above) or a special request.
1929f52228b8SJoe Beteta */
1930f52228b8SJoe Beteta req_id = cmp_cntxt;
1931f52228b8SJoe Beteta req_slot = req_id & SKD_ID_SLOT_AND_TABLE_MASK;
1932f52228b8SJoe Beteta
1933f52228b8SJoe Beteta Dcmn_err(CE_NOTE,
1934f52228b8SJoe Beteta "<<<< completion_posted 1: req_id=%x req_slot=%x",
1935f52228b8SJoe Beteta req_id, req_slot);
1936f52228b8SJoe Beteta
1937f52228b8SJoe Beteta /* Is this other than a r/w request? */
1938f52228b8SJoe Beteta if (req_slot >= skdev->num_req_context) {
1939f52228b8SJoe Beteta /*
1940f52228b8SJoe Beteta * This is not a completion for a r/w request.
1941f52228b8SJoe Beteta */
1942f52228b8SJoe Beteta skd_complete_other(skdev, skcmp, skerr);
1943f52228b8SJoe Beteta WAITQ_UNLOCK(skdev);
1944f52228b8SJoe Beteta continue;
1945f52228b8SJoe Beteta }
1946f52228b8SJoe Beteta
1947f52228b8SJoe Beteta skreq = &skdev->skreq_table[req_slot];
1948f52228b8SJoe Beteta
1949f52228b8SJoe Beteta /*
1950f52228b8SJoe Beteta * Make sure the request ID for the slot matches.
1951f52228b8SJoe Beteta */
1952f52228b8SJoe Beteta ASSERT(skreq->id == req_id);
1953f52228b8SJoe Beteta
1954f52228b8SJoe Beteta if (SKD_REQ_STATE_ABORTED == skreq->state) {
1955f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "reclaim req %p id=%04x\n",
1956f52228b8SJoe Beteta (void *)skreq, skreq->id);
1957f52228b8SJoe Beteta /*
1958f52228b8SJoe Beteta * a previously timed out command can
1959f52228b8SJoe Beteta * now be cleaned up
1960f52228b8SJoe Beteta */
1961f52228b8SJoe Beteta msg_slot = skreq->fitmsg_id & SKD_ID_SLOT_MASK;
1962f52228b8SJoe Beteta ASSERT(msg_slot < skdev->num_fitmsg_context);
1963f52228b8SJoe Beteta skmsg = &skdev->skmsg_table[msg_slot];
1964f52228b8SJoe Beteta if (skmsg->id == skreq->fitmsg_id) {
1965f52228b8SJoe Beteta ASSERT(skmsg->outstanding > 0);
1966f52228b8SJoe Beteta skmsg->outstanding--;
1967f52228b8SJoe Beteta if (skmsg->outstanding == 0) {
1968f52228b8SJoe Beteta ASSERT(SKD_MSG_STATE_BUSY ==
1969f52228b8SJoe Beteta skmsg->state);
1970f52228b8SJoe Beteta skmsg->state = SKD_MSG_STATE_IDLE;
1971f52228b8SJoe Beteta skmsg->id += SKD_ID_INCR;
1972f52228b8SJoe Beteta skmsg->next = skdev->skmsg_free_list;
1973f52228b8SJoe Beteta skdev->skmsg_free_list = skmsg;
1974f52228b8SJoe Beteta }
1975f52228b8SJoe Beteta }
1976f52228b8SJoe Beteta /*
1977f52228b8SJoe Beteta * Reclaim the skd_request_context
1978f52228b8SJoe Beteta */
1979f52228b8SJoe Beteta skreq->state = SKD_REQ_STATE_IDLE;
1980f52228b8SJoe Beteta skreq->id += SKD_ID_INCR;
1981f52228b8SJoe Beteta skreq->next = skdev->skreq_free_list;
1982f52228b8SJoe Beteta skdev->skreq_free_list = skreq;
1983f52228b8SJoe Beteta WAITQ_UNLOCK(skdev);
1984f52228b8SJoe Beteta continue;
1985f52228b8SJoe Beteta }
1986f52228b8SJoe Beteta
1987f52228b8SJoe Beteta skreq->completion.status = cmp_status;
1988f52228b8SJoe Beteta
1989f52228b8SJoe Beteta pbuf = skreq->pbuf;
1990f52228b8SJoe Beteta ASSERT(pbuf != NULL);
1991f52228b8SJoe Beteta
1992f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "<<<< completion_posted 2: pbuf=%p "
1993f52228b8SJoe Beteta "req_id=%x req_slot=%x", (void *)pbuf, req_id, req_slot);
1994f52228b8SJoe Beteta if (cmp_status && skdev->disks_initialized) {
1995f52228b8SJoe Beteta cmn_err(CE_WARN, "!%s: "
1996f52228b8SJoe Beteta "I/O err: pbuf=%p blkno=%lld (%llx) nbklks=%ld ",
1997f52228b8SJoe Beteta skdev->name, (void *)pbuf, pbuf->x_xfer->x_blkno,
1998f52228b8SJoe Beteta pbuf->x_xfer->x_blkno, pbuf->x_xfer->x_nblks);
1999f52228b8SJoe Beteta }
2000f52228b8SJoe Beteta
2001f52228b8SJoe Beteta ASSERT(skdev->active_cmds);
2002f52228b8SJoe Beteta atomic_dec_64(&skdev->active_cmds);
2003f52228b8SJoe Beteta
2004f52228b8SJoe Beteta if (SAM_STAT_GOOD == cmp_status) {
2005f52228b8SJoe Beteta /* Release DMA resources for the request. */
2006f52228b8SJoe Beteta if (pbuf->x_xfer->x_nblks != 0)
2007f52228b8SJoe Beteta skd_blkdev_postop_sg_list(skdev, skreq);
2008f52228b8SJoe Beteta WAITQ_UNLOCK(skdev);
2009f52228b8SJoe Beteta skd_end_request(skdev, skreq, 0);
2010f52228b8SJoe Beteta WAITQ_LOCK(skdev);
2011f52228b8SJoe Beteta } else {
2012f52228b8SJoe Beteta switch (skd_check_status(skdev, cmp_status, skerr)) {
2013f52228b8SJoe Beteta case SKD_CHECK_STATUS_REPORT_GOOD:
2014f52228b8SJoe Beteta case SKD_CHECK_STATUS_REPORT_SMART_ALERT:
2015f52228b8SJoe Beteta WAITQ_UNLOCK(skdev);
2016f52228b8SJoe Beteta skd_end_request(skdev, skreq, 0);
2017f52228b8SJoe Beteta WAITQ_LOCK(skdev);
2018f52228b8SJoe Beteta break;
2019f52228b8SJoe Beteta
2020f52228b8SJoe Beteta case SKD_CHECK_STATUS_BUSY_IMMINENT:
2021f52228b8SJoe Beteta skd_log_skreq(skdev, skreq, "retry(busy)");
2022f52228b8SJoe Beteta skd_queue(skdev, pbuf);
2023f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_BUSY_IMMINENT;
2024f52228b8SJoe Beteta skdev->timer_countdown = SKD_TIMER_MINUTES(20);
2025f52228b8SJoe Beteta
2026f52228b8SJoe Beteta (void) skd_quiesce_dev(skdev);
2027f52228b8SJoe Beteta break;
2028f52228b8SJoe Beteta
2029f52228b8SJoe Beteta /* FALLTHRU */
2030f52228b8SJoe Beteta case SKD_CHECK_STATUS_REPORT_ERROR:
2031f52228b8SJoe Beteta /* fall thru to report error */
2032f52228b8SJoe Beteta default:
2033f52228b8SJoe Beteta /*
2034f52228b8SJoe Beteta * Save the entire completion
2035f52228b8SJoe Beteta * and error entries for
2036f52228b8SJoe Beteta * later error interpretation.
2037f52228b8SJoe Beteta */
2038f52228b8SJoe Beteta skreq->completion = *skcmp;
2039f52228b8SJoe Beteta skreq->err_info = *skerr;
2040f52228b8SJoe Beteta WAITQ_UNLOCK(skdev);
2041f52228b8SJoe Beteta skd_end_request(skdev, skreq, -EIO);
2042f52228b8SJoe Beteta WAITQ_LOCK(skdev);
2043f52228b8SJoe Beteta break;
2044f52228b8SJoe Beteta }
2045f52228b8SJoe Beteta }
2046f52228b8SJoe Beteta
2047f52228b8SJoe Beteta /*
2048f52228b8SJoe Beteta * Reclaim the FIT msg buffer if this is
2049f52228b8SJoe Beteta * the first of the requests it carried to
2050f52228b8SJoe Beteta * be completed. The FIT msg buffer used to
2051f52228b8SJoe Beteta * send this request cannot be reused until
2052f52228b8SJoe Beteta * we are sure the s1120 card has copied
2053f52228b8SJoe Beteta * it to its memory. The FIT msg might have
2054f52228b8SJoe Beteta * contained several requests. As soon as
2055f52228b8SJoe Beteta * any of them are completed we know that
2056f52228b8SJoe Beteta * the entire FIT msg was transferred.
2057f52228b8SJoe Beteta * Only the first completed request will
2058f52228b8SJoe Beteta * match the FIT msg buffer id. The FIT
2059f52228b8SJoe Beteta * msg buffer id is immediately updated.
2060f52228b8SJoe Beteta * When subsequent requests complete the FIT
2061f52228b8SJoe Beteta * msg buffer id won't match, so we know
2062f52228b8SJoe Beteta * quite cheaply that it is already done.
2063f52228b8SJoe Beteta */
2064f52228b8SJoe Beteta msg_slot = skreq->fitmsg_id & SKD_ID_SLOT_MASK;
2065f52228b8SJoe Beteta
2066f52228b8SJoe Beteta ASSERT(msg_slot < skdev->num_fitmsg_context);
2067f52228b8SJoe Beteta skmsg = &skdev->skmsg_table[msg_slot];
2068f52228b8SJoe Beteta if (skmsg->id == skreq->fitmsg_id) {
2069f52228b8SJoe Beteta ASSERT(SKD_MSG_STATE_BUSY == skmsg->state);
2070f52228b8SJoe Beteta skmsg->state = SKD_MSG_STATE_IDLE;
2071f52228b8SJoe Beteta skmsg->id += SKD_ID_INCR;
2072f52228b8SJoe Beteta skmsg->next = skdev->skmsg_free_list;
2073f52228b8SJoe Beteta skdev->skmsg_free_list = skmsg;
2074f52228b8SJoe Beteta }
2075f52228b8SJoe Beteta
2076f52228b8SJoe Beteta /*
2077f52228b8SJoe Beteta * Decrease the number of active requests.
2078f52228b8SJoe Beteta * This also decrements the count in the
2079f52228b8SJoe Beteta * timeout slot.
2080f52228b8SJoe Beteta */
2081f52228b8SJoe Beteta timo_slot = skreq->timeout_stamp & SKD_TIMEOUT_SLOT_MASK;
2082f52228b8SJoe Beteta ASSERT(skdev->timeout_slot[timo_slot] > 0);
2083f52228b8SJoe Beteta ASSERT(skdev->queue_depth_busy > 0);
2084f52228b8SJoe Beteta
2085f52228b8SJoe Beteta atomic_dec_32(&skdev->timeout_slot[timo_slot]);
2086f52228b8SJoe Beteta atomic_dec_32(&skdev->queue_depth_busy);
2087f52228b8SJoe Beteta
2088f52228b8SJoe Beteta /*
2089f52228b8SJoe Beteta * Reclaim the skd_request_context
2090f52228b8SJoe Beteta */
2091f52228b8SJoe Beteta skreq->state = SKD_REQ_STATE_IDLE;
2092f52228b8SJoe Beteta skreq->id += SKD_ID_INCR;
2093f52228b8SJoe Beteta skreq->next = skdev->skreq_free_list;
2094f52228b8SJoe Beteta skdev->skreq_free_list = skreq;
2095f52228b8SJoe Beteta
2096f52228b8SJoe Beteta WAITQ_UNLOCK(skdev);
2097f52228b8SJoe Beteta
2098f52228b8SJoe Beteta /*
2099f52228b8SJoe Beteta * make sure the lock is held by caller.
2100f52228b8SJoe Beteta */
2101f52228b8SJoe Beteta if ((skdev->state == SKD_DRVR_STATE_PAUSING) &&
2102f52228b8SJoe Beteta (0 == skdev->queue_depth_busy)) {
2103f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_PAUSED;
2104f52228b8SJoe Beteta cv_signal(&skdev->cv_waitq);
2105f52228b8SJoe Beteta }
2106f52228b8SJoe Beteta } /* for(;;) */
2107f52228b8SJoe Beteta }
2108f52228b8SJoe Beteta
2109f52228b8SJoe Beteta /*
2110f52228b8SJoe Beteta *
2111f52228b8SJoe Beteta * Name: skd_complete_other, handle the completion of a
2112f52228b8SJoe Beteta * non-r/w request.
2113f52228b8SJoe Beteta *
2114f52228b8SJoe Beteta * Inputs: skdev - device state structure.
2115f52228b8SJoe Beteta * skcomp - FIT completion structure.
2116f52228b8SJoe Beteta * skerr - error structure.
2117f52228b8SJoe Beteta *
2118f52228b8SJoe Beteta * Returns: Nothing.
2119f52228b8SJoe Beteta *
2120f52228b8SJoe Beteta */
2121f52228b8SJoe Beteta static void
skd_complete_other(struct skd_device * skdev,volatile struct fit_completion_entry_v1 * skcomp,volatile struct fit_comp_error_info * skerr)2122f52228b8SJoe Beteta skd_complete_other(struct skd_device *skdev,
2123f52228b8SJoe Beteta volatile struct fit_completion_entry_v1 *skcomp,
2124f52228b8SJoe Beteta volatile struct fit_comp_error_info *skerr)
2125f52228b8SJoe Beteta {
2126f52228b8SJoe Beteta uint32_t req_id = 0;
2127f52228b8SJoe Beteta uint32_t req_table;
2128f52228b8SJoe Beteta uint32_t req_slot;
2129f52228b8SJoe Beteta struct skd_special_context *skspcl;
2130f52228b8SJoe Beteta
2131f52228b8SJoe Beteta req_id = skcomp->tag;
2132f52228b8SJoe Beteta req_table = req_id & SKD_ID_TABLE_MASK;
2133f52228b8SJoe Beteta req_slot = req_id & SKD_ID_SLOT_MASK;
2134f52228b8SJoe Beteta
2135f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "complete_other: table=0x%x id=0x%x slot=%d",
2136f52228b8SJoe Beteta req_table, req_id, req_slot);
2137f52228b8SJoe Beteta
2138f52228b8SJoe Beteta /*
2139f52228b8SJoe Beteta * Based on the request id, determine how to dispatch this completion.
2140f52228b8SJoe Beteta * This swich/case is finding the good cases and forwarding the
2141f52228b8SJoe Beteta * completion entry. Errors are reported below the switch.
2142f52228b8SJoe Beteta */
2143f52228b8SJoe Beteta ASSERT(req_table == SKD_ID_INTERNAL);
2144f52228b8SJoe Beteta ASSERT(req_slot == 0);
2145f52228b8SJoe Beteta
2146f52228b8SJoe Beteta skspcl = &skdev->internal_skspcl;
2147f52228b8SJoe Beteta ASSERT(skspcl->req.id == req_id);
2148f52228b8SJoe Beteta ASSERT(skspcl->req.state == SKD_REQ_STATE_BUSY);
2149f52228b8SJoe Beteta
2150f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "<<<<== complete_other: ID_INTERNAL");
2151f52228b8SJoe Beteta skd_complete_internal(skdev, skcomp, skerr, skspcl);
2152f52228b8SJoe Beteta }
2153f52228b8SJoe Beteta
2154f52228b8SJoe Beteta /*
2155f52228b8SJoe Beteta *
2156f52228b8SJoe Beteta * Name: skd_reset_skcomp, does what it says, resetting completion
2157f52228b8SJoe Beteta * tables.
2158f52228b8SJoe Beteta *
2159f52228b8SJoe Beteta * Inputs: skdev - device state structure.
2160f52228b8SJoe Beteta *
2161f52228b8SJoe Beteta * Returns: Nothing.
2162f52228b8SJoe Beteta *
2163f52228b8SJoe Beteta */
2164f52228b8SJoe Beteta static void
skd_reset_skcomp(struct skd_device * skdev)2165f52228b8SJoe Beteta skd_reset_skcomp(struct skd_device *skdev)
2166f52228b8SJoe Beteta {
2167f52228b8SJoe Beteta uint32_t nbytes;
2168f52228b8SJoe Beteta
2169f52228b8SJoe Beteta nbytes = sizeof (struct fit_completion_entry_v1) *
2170f52228b8SJoe Beteta SKD_N_COMPLETION_ENTRY;
2171f52228b8SJoe Beteta nbytes += sizeof (struct fit_comp_error_info) * SKD_N_COMPLETION_ENTRY;
2172f52228b8SJoe Beteta
2173f52228b8SJoe Beteta if (skdev->skcomp_table)
2174f52228b8SJoe Beteta bzero(skdev->skcomp_table, nbytes);
2175f52228b8SJoe Beteta
2176f52228b8SJoe Beteta skdev->skcomp_ix = 0;
2177f52228b8SJoe Beteta skdev->skcomp_cycle = 1;
2178f52228b8SJoe Beteta }
2179f52228b8SJoe Beteta
2180f52228b8SJoe Beteta
2181f52228b8SJoe Beteta
2182f52228b8SJoe Beteta /*
2183f52228b8SJoe Beteta * INTERRUPTS
2184f52228b8SJoe Beteta */
2185f52228b8SJoe Beteta
2186f52228b8SJoe Beteta /*
2187f52228b8SJoe Beteta *
2188f52228b8SJoe Beteta * Name: skd_isr_aif, handles the device interrupts.
2189f52228b8SJoe Beteta *
2190f52228b8SJoe Beteta * Inputs: arg - skdev device state structure.
2191f52228b8SJoe Beteta * intvec - not referenced
2192f52228b8SJoe Beteta *
2193f52228b8SJoe Beteta * Returns: DDI_INTR_CLAIMED if interrupt is handled otherwise
2194f52228b8SJoe Beteta * return DDI_INTR_UNCLAIMED.
2195f52228b8SJoe Beteta *
2196f52228b8SJoe Beteta */
2197f52228b8SJoe Beteta /* ARGSUSED */ /* Upstream common source with other platforms. */
2198f52228b8SJoe Beteta static uint_t
skd_isr_aif(caddr_t arg,caddr_t intvec)2199f52228b8SJoe Beteta skd_isr_aif(caddr_t arg, caddr_t intvec)
2200f52228b8SJoe Beteta {
2201f52228b8SJoe Beteta uint32_t intstat;
2202f52228b8SJoe Beteta uint32_t ack;
2203f52228b8SJoe Beteta int rc = DDI_INTR_UNCLAIMED;
2204f52228b8SJoe Beteta struct skd_device *skdev;
2205f52228b8SJoe Beteta
2206f52228b8SJoe Beteta skdev = (skd_device_t *)(uintptr_t)arg;
2207f52228b8SJoe Beteta
2208f52228b8SJoe Beteta ASSERT(skdev != NULL);
2209f52228b8SJoe Beteta
2210f52228b8SJoe Beteta skdev->intr_cntr++;
2211f52228b8SJoe Beteta
2212f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "skd_isr_aif: intr=%" PRId64 "\n", skdev->intr_cntr);
2213f52228b8SJoe Beteta
2214f52228b8SJoe Beteta for (;;) {
2215f52228b8SJoe Beteta
2216f52228b8SJoe Beteta ASSERT(!WAITQ_LOCK_HELD(skdev));
2217f52228b8SJoe Beteta INTR_LOCK(skdev);
2218f52228b8SJoe Beteta
2219f52228b8SJoe Beteta intstat = SKD_READL(skdev, FIT_INT_STATUS_HOST);
2220f52228b8SJoe Beteta
2221f52228b8SJoe Beteta ack = FIT_INT_DEF_MASK;
2222f52228b8SJoe Beteta ack &= intstat;
2223f52228b8SJoe Beteta
2224f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "intstat=0x%x ack=0x%x", intstat, ack);
2225f52228b8SJoe Beteta
2226f52228b8SJoe Beteta /*
2227f52228b8SJoe Beteta * As long as there is an int pending on device, keep
2228f52228b8SJoe Beteta * running loop. When none, get out, but if we've never
2229f52228b8SJoe Beteta * done any processing, call completion handler?
2230f52228b8SJoe Beteta */
2231f52228b8SJoe Beteta if (ack == 0) {
2232f52228b8SJoe Beteta /*
2233f52228b8SJoe Beteta * No interrupts on device, but run the completion
2234f52228b8SJoe Beteta * processor anyway?
2235f52228b8SJoe Beteta */
2236f52228b8SJoe Beteta if (rc == DDI_INTR_UNCLAIMED &&
2237f52228b8SJoe Beteta skdev->state == SKD_DRVR_STATE_ONLINE) {
2238f52228b8SJoe Beteta Dcmn_err(CE_NOTE,
2239f52228b8SJoe Beteta "1: Want isr_comp_posted call");
2240f52228b8SJoe Beteta skd_isr_completion_posted(skdev);
2241f52228b8SJoe Beteta }
2242f52228b8SJoe Beteta INTR_UNLOCK(skdev);
2243f52228b8SJoe Beteta
2244f52228b8SJoe Beteta break;
2245f52228b8SJoe Beteta }
2246f52228b8SJoe Beteta rc = DDI_INTR_CLAIMED;
2247f52228b8SJoe Beteta
2248f52228b8SJoe Beteta SKD_WRITEL(skdev, ack, FIT_INT_STATUS_HOST);
2249f52228b8SJoe Beteta
2250f52228b8SJoe Beteta if ((skdev->state != SKD_DRVR_STATE_LOAD) &&
2251f52228b8SJoe Beteta (skdev->state != SKD_DRVR_STATE_STOPPING)) {
2252f52228b8SJoe Beteta if (intstat & FIT_ISH_COMPLETION_POSTED) {
2253f52228b8SJoe Beteta Dcmn_err(CE_NOTE,
2254f52228b8SJoe Beteta "2: Want isr_comp_posted call");
2255f52228b8SJoe Beteta skd_isr_completion_posted(skdev);
2256f52228b8SJoe Beteta }
2257f52228b8SJoe Beteta
2258f52228b8SJoe Beteta if (intstat & FIT_ISH_FW_STATE_CHANGE) {
2259f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "isr: fwstate change");
2260f52228b8SJoe Beteta
2261f52228b8SJoe Beteta skd_isr_fwstate(skdev);
2262f52228b8SJoe Beteta if (skdev->state == SKD_DRVR_STATE_FAULT ||
2263f52228b8SJoe Beteta skdev->state ==
2264f52228b8SJoe Beteta SKD_DRVR_STATE_DISAPPEARED) {
2265f52228b8SJoe Beteta INTR_UNLOCK(skdev);
2266f52228b8SJoe Beteta
2267f52228b8SJoe Beteta return (rc);
2268f52228b8SJoe Beteta }
2269f52228b8SJoe Beteta }
2270f52228b8SJoe Beteta
2271f52228b8SJoe Beteta if (intstat & FIT_ISH_MSG_FROM_DEV) {
2272f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "isr: msg_from_dev change");
2273f52228b8SJoe Beteta skd_isr_msg_from_dev(skdev);
2274f52228b8SJoe Beteta }
2275f52228b8SJoe Beteta }
2276f52228b8SJoe Beteta
2277f52228b8SJoe Beteta INTR_UNLOCK(skdev);
2278f52228b8SJoe Beteta }
2279f52228b8SJoe Beteta
2280f52228b8SJoe Beteta if (!SIMPLEQ_EMPTY(&skdev->waitqueue))
2281f52228b8SJoe Beteta skd_start(skdev);
2282f52228b8SJoe Beteta
2283f52228b8SJoe Beteta return (rc);
2284f52228b8SJoe Beteta }
2285f52228b8SJoe Beteta
2286f52228b8SJoe Beteta /*
2287f52228b8SJoe Beteta *
2288f52228b8SJoe Beteta * Name: skd_drive_fault, set the drive state to DRV_STATE_FAULT.
2289f52228b8SJoe Beteta *
2290f52228b8SJoe Beteta * Inputs: skdev - device state structure.
2291f52228b8SJoe Beteta *
2292f52228b8SJoe Beteta * Returns: Nothing.
2293f52228b8SJoe Beteta *
2294f52228b8SJoe Beteta */
2295f52228b8SJoe Beteta static void
skd_drive_fault(struct skd_device * skdev)2296f52228b8SJoe Beteta skd_drive_fault(struct skd_device *skdev)
2297f52228b8SJoe Beteta {
2298f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_FAULT;
2299f52228b8SJoe Beteta cmn_err(CE_WARN, "!(%s): Drive FAULT\n",
2300f52228b8SJoe Beteta skd_name(skdev));
2301f52228b8SJoe Beteta }
2302f52228b8SJoe Beteta
2303f52228b8SJoe Beteta /*
2304f52228b8SJoe Beteta *
2305f52228b8SJoe Beteta * Name: skd_drive_disappeared, set the drive state to DISAPPEARED..
2306f52228b8SJoe Beteta *
2307f52228b8SJoe Beteta * Inputs: skdev - device state structure.
2308f52228b8SJoe Beteta *
2309f52228b8SJoe Beteta * Returns: Nothing.
2310f52228b8SJoe Beteta *
2311f52228b8SJoe Beteta */
2312f52228b8SJoe Beteta static void
skd_drive_disappeared(struct skd_device * skdev)2313f52228b8SJoe Beteta skd_drive_disappeared(struct skd_device *skdev)
2314f52228b8SJoe Beteta {
2315f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_DISAPPEARED;
2316f52228b8SJoe Beteta cmn_err(CE_WARN, "!(%s): Drive DISAPPEARED\n",
2317f52228b8SJoe Beteta skd_name(skdev));
2318f52228b8SJoe Beteta }
2319f52228b8SJoe Beteta
2320f52228b8SJoe Beteta /*
2321f52228b8SJoe Beteta *
2322f52228b8SJoe Beteta * Name: skd_isr_fwstate, handles the various device states.
2323f52228b8SJoe Beteta *
2324f52228b8SJoe Beteta * Inputs: skdev - device state structure.
2325f52228b8SJoe Beteta *
2326f52228b8SJoe Beteta * Returns: Nothing.
2327f52228b8SJoe Beteta *
2328f52228b8SJoe Beteta */
2329f52228b8SJoe Beteta static void
skd_isr_fwstate(struct skd_device * skdev)2330f52228b8SJoe Beteta skd_isr_fwstate(struct skd_device *skdev)
2331f52228b8SJoe Beteta {
2332f52228b8SJoe Beteta uint32_t sense;
2333f52228b8SJoe Beteta uint32_t state;
2334f52228b8SJoe Beteta int prev_driver_state;
2335f52228b8SJoe Beteta uint32_t mtd;
2336f52228b8SJoe Beteta
2337f52228b8SJoe Beteta prev_driver_state = skdev->state;
2338f52228b8SJoe Beteta
2339f52228b8SJoe Beteta sense = SKD_READL(skdev, FIT_STATUS);
2340f52228b8SJoe Beteta state = sense & FIT_SR_DRIVE_STATE_MASK;
2341f52228b8SJoe Beteta
2342f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "s1120 state %s(%d)=>%s(%d)",
2343f52228b8SJoe Beteta skd_drive_state_to_str(skdev->drive_state), skdev->drive_state,
2344f52228b8SJoe Beteta skd_drive_state_to_str(state), state);
2345f52228b8SJoe Beteta
2346f52228b8SJoe Beteta skdev->drive_state = state;
2347f52228b8SJoe Beteta
2348f52228b8SJoe Beteta switch (skdev->drive_state) {
2349f52228b8SJoe Beteta case FIT_SR_DRIVE_INIT:
2350f52228b8SJoe Beteta if (skdev->state == SKD_DRVR_STATE_PROTOCOL_MISMATCH) {
2351f52228b8SJoe Beteta skd_disable_interrupts(skdev);
2352f52228b8SJoe Beteta break;
2353f52228b8SJoe Beteta }
2354f52228b8SJoe Beteta if (skdev->state == SKD_DRVR_STATE_RESTARTING) {
2355f52228b8SJoe Beteta skd_recover_requests(skdev);
2356f52228b8SJoe Beteta }
2357f52228b8SJoe Beteta if (skdev->state == SKD_DRVR_STATE_WAIT_BOOT) {
2358f52228b8SJoe Beteta skdev->timer_countdown =
2359f52228b8SJoe Beteta SKD_TIMER_SECONDS(SKD_STARTING_TO);
2360f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_STARTING;
2361f52228b8SJoe Beteta skd_soft_reset(skdev);
2362f52228b8SJoe Beteta break;
2363f52228b8SJoe Beteta }
2364f52228b8SJoe Beteta mtd = FIT_MXD_CONS(FIT_MTD_FITFW_INIT, 0, 0);
2365f52228b8SJoe Beteta SKD_WRITEL(skdev, mtd, FIT_MSG_TO_DEVICE);
2366f52228b8SJoe Beteta skdev->last_mtd = mtd;
2367f52228b8SJoe Beteta break;
2368f52228b8SJoe Beteta
2369f52228b8SJoe Beteta case FIT_SR_DRIVE_ONLINE:
2370f52228b8SJoe Beteta skdev->queue_depth_limit = skdev->soft_queue_depth_limit;
2371f52228b8SJoe Beteta if (skdev->queue_depth_limit > skdev->hard_queue_depth_limit) {
2372f52228b8SJoe Beteta skdev->queue_depth_limit =
2373f52228b8SJoe Beteta skdev->hard_queue_depth_limit;
2374f52228b8SJoe Beteta }
2375f52228b8SJoe Beteta
2376f52228b8SJoe Beteta skdev->queue_depth_lowat = skdev->queue_depth_limit * 2 / 3 + 1;
2377f52228b8SJoe Beteta if (skdev->queue_depth_lowat < 1)
2378f52228b8SJoe Beteta skdev->queue_depth_lowat = 1;
2379f52228b8SJoe Beteta Dcmn_err(CE_NOTE,
2380f52228b8SJoe Beteta "%s queue depth limit=%d hard=%d soft=%d lowat=%d",
2381f52228b8SJoe Beteta DRV_NAME,
2382f52228b8SJoe Beteta skdev->queue_depth_limit,
2383f52228b8SJoe Beteta skdev->hard_queue_depth_limit,
2384f52228b8SJoe Beteta skdev->soft_queue_depth_limit,
2385f52228b8SJoe Beteta skdev->queue_depth_lowat);
2386f52228b8SJoe Beteta
2387f52228b8SJoe Beteta skd_refresh_device_data(skdev);
2388f52228b8SJoe Beteta break;
2389f52228b8SJoe Beteta case FIT_SR_DRIVE_BUSY:
2390f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_BUSY;
2391f52228b8SJoe Beteta skdev->timer_countdown = SKD_TIMER_MINUTES(20);
2392f52228b8SJoe Beteta (void) skd_quiesce_dev(skdev);
2393f52228b8SJoe Beteta break;
2394f52228b8SJoe Beteta case FIT_SR_DRIVE_BUSY_SANITIZE:
2395f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_BUSY_SANITIZE;
2396f52228b8SJoe Beteta skd_start(skdev);
2397f52228b8SJoe Beteta break;
2398f52228b8SJoe Beteta case FIT_SR_DRIVE_BUSY_ERASE:
2399f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_BUSY_ERASE;
2400f52228b8SJoe Beteta skdev->timer_countdown = SKD_TIMER_MINUTES(20);
2401f52228b8SJoe Beteta break;
2402f52228b8SJoe Beteta case FIT_SR_DRIVE_OFFLINE:
2403f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_IDLE;
2404f52228b8SJoe Beteta break;
2405f52228b8SJoe Beteta case FIT_SR_DRIVE_SOFT_RESET:
2406f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_RESTARTING;
2407f52228b8SJoe Beteta
2408f52228b8SJoe Beteta switch (skdev->state) {
2409f52228b8SJoe Beteta case SKD_DRVR_STATE_STARTING:
2410f52228b8SJoe Beteta case SKD_DRVR_STATE_RESTARTING:
2411f52228b8SJoe Beteta break;
2412f52228b8SJoe Beteta default:
2413f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_RESTARTING;
2414f52228b8SJoe Beteta break;
2415f52228b8SJoe Beteta }
2416f52228b8SJoe Beteta break;
2417f52228b8SJoe Beteta case FIT_SR_DRIVE_FW_BOOTING:
2418f52228b8SJoe Beteta Dcmn_err(CE_NOTE,
2419f52228b8SJoe Beteta "ISR FIT_SR_DRIVE_FW_BOOTING %s", skdev->name);
2420f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_WAIT_BOOT;
2421f52228b8SJoe Beteta skdev->timer_countdown = SKD_TIMER_SECONDS(SKD_WAIT_BOOT_TO);
2422f52228b8SJoe Beteta break;
2423f52228b8SJoe Beteta
2424f52228b8SJoe Beteta case FIT_SR_DRIVE_DEGRADED:
2425f52228b8SJoe Beteta case FIT_SR_PCIE_LINK_DOWN:
2426f52228b8SJoe Beteta case FIT_SR_DRIVE_NEED_FW_DOWNLOAD:
2427f52228b8SJoe Beteta break;
2428f52228b8SJoe Beteta
2429f52228b8SJoe Beteta case FIT_SR_DRIVE_FAULT:
2430f52228b8SJoe Beteta skd_drive_fault(skdev);
2431f52228b8SJoe Beteta skd_recover_requests(skdev);
2432f52228b8SJoe Beteta skd_start(skdev);
2433f52228b8SJoe Beteta break;
2434f52228b8SJoe Beteta
2435f52228b8SJoe Beteta case 0xFF:
2436f52228b8SJoe Beteta skd_drive_disappeared(skdev);
2437f52228b8SJoe Beteta skd_recover_requests(skdev);
2438f52228b8SJoe Beteta skd_start(skdev);
2439f52228b8SJoe Beteta break;
2440f52228b8SJoe Beteta default:
2441f52228b8SJoe Beteta /*
2442f52228b8SJoe Beteta * Uknown FW State. Wait for a state we recognize.
2443f52228b8SJoe Beteta */
2444f52228b8SJoe Beteta break;
2445f52228b8SJoe Beteta }
2446f52228b8SJoe Beteta
2447f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "Driver state %s(%d)=>%s(%d)",
2448f52228b8SJoe Beteta skd_skdev_state_to_str(prev_driver_state), prev_driver_state,
2449f52228b8SJoe Beteta skd_skdev_state_to_str(skdev->state), skdev->state);
2450f52228b8SJoe Beteta }
2451f52228b8SJoe Beteta
2452f52228b8SJoe Beteta /*
2453f52228b8SJoe Beteta *
2454f52228b8SJoe Beteta * Name: skd_recover_requests, attempts to recover requests.
2455f52228b8SJoe Beteta *
2456f52228b8SJoe Beteta * Inputs: skdev - device state structure.
2457f52228b8SJoe Beteta *
2458f52228b8SJoe Beteta * Returns: Nothing.
2459f52228b8SJoe Beteta *
2460f52228b8SJoe Beteta */
2461f52228b8SJoe Beteta static void
skd_recover_requests(struct skd_device * skdev)2462f52228b8SJoe Beteta skd_recover_requests(struct skd_device *skdev)
2463f52228b8SJoe Beteta {
2464f52228b8SJoe Beteta int i;
2465f52228b8SJoe Beteta
2466f52228b8SJoe Beteta ASSERT(INTR_LOCK_HELD(skdev));
2467f52228b8SJoe Beteta
2468f52228b8SJoe Beteta for (i = 0; i < skdev->num_req_context; i++) {
2469f52228b8SJoe Beteta struct skd_request_context *skreq = &skdev->skreq_table[i];
2470f52228b8SJoe Beteta
2471f52228b8SJoe Beteta if (skreq->state == SKD_REQ_STATE_BUSY) {
2472f52228b8SJoe Beteta skd_log_skreq(skdev, skreq, "requeue");
2473f52228b8SJoe Beteta
2474f52228b8SJoe Beteta ASSERT(0 != (skreq->id & SKD_ID_INCR));
2475f52228b8SJoe Beteta ASSERT(skreq->pbuf != NULL);
2476f52228b8SJoe Beteta /* Release DMA resources for the request. */
2477f52228b8SJoe Beteta skd_blkdev_postop_sg_list(skdev, skreq);
2478f52228b8SJoe Beteta
2479f52228b8SJoe Beteta skd_end_request(skdev, skreq, EAGAIN);
2480f52228b8SJoe Beteta skreq->pbuf = NULL;
2481f52228b8SJoe Beteta skreq->state = SKD_REQ_STATE_IDLE;
2482f52228b8SJoe Beteta skreq->id += SKD_ID_INCR;
2483f52228b8SJoe Beteta }
2484f52228b8SJoe Beteta if (i > 0) {
2485f52228b8SJoe Beteta skreq[-1].next = skreq;
2486f52228b8SJoe Beteta }
2487f52228b8SJoe Beteta skreq->next = NULL;
2488f52228b8SJoe Beteta }
2489f52228b8SJoe Beteta
2490f52228b8SJoe Beteta WAITQ_LOCK(skdev);
2491f52228b8SJoe Beteta skdev->skreq_free_list = skdev->skreq_table;
2492f52228b8SJoe Beteta WAITQ_UNLOCK(skdev);
2493f52228b8SJoe Beteta
2494f52228b8SJoe Beteta for (i = 0; i < skdev->num_fitmsg_context; i++) {
2495f52228b8SJoe Beteta struct skd_fitmsg_context *skmsg = &skdev->skmsg_table[i];
2496f52228b8SJoe Beteta
2497f52228b8SJoe Beteta if (skmsg->state == SKD_MSG_STATE_BUSY) {
2498f52228b8SJoe Beteta skd_log_skmsg(skdev, skmsg, "salvaged");
2499f52228b8SJoe Beteta ASSERT((skmsg->id & SKD_ID_INCR) != 0);
2500f52228b8SJoe Beteta skmsg->state = SKD_MSG_STATE_IDLE;
2501f52228b8SJoe Beteta skmsg->id &= ~SKD_ID_INCR;
2502f52228b8SJoe Beteta }
2503f52228b8SJoe Beteta if (i > 0) {
2504f52228b8SJoe Beteta skmsg[-1].next = skmsg;
2505f52228b8SJoe Beteta }
2506f52228b8SJoe Beteta skmsg->next = NULL;
2507f52228b8SJoe Beteta }
2508f52228b8SJoe Beteta WAITQ_LOCK(skdev);
2509f52228b8SJoe Beteta skdev->skmsg_free_list = skdev->skmsg_table;
2510f52228b8SJoe Beteta WAITQ_UNLOCK(skdev);
2511f52228b8SJoe Beteta
2512f52228b8SJoe Beteta for (i = 0; i < SKD_N_TIMEOUT_SLOT; i++) {
2513f52228b8SJoe Beteta skdev->timeout_slot[i] = 0;
2514f52228b8SJoe Beteta }
2515f52228b8SJoe Beteta skdev->queue_depth_busy = 0;
2516f52228b8SJoe Beteta }
2517f52228b8SJoe Beteta
2518f52228b8SJoe Beteta /*
2519f52228b8SJoe Beteta *
2520f52228b8SJoe Beteta * Name: skd_isr_msg_from_dev, handles a message from the device.
2521f52228b8SJoe Beteta *
2522f52228b8SJoe Beteta * Inputs: skdev - device state structure.
2523f52228b8SJoe Beteta *
2524f52228b8SJoe Beteta * Returns: Nothing.
2525f52228b8SJoe Beteta *
2526f52228b8SJoe Beteta */
2527f52228b8SJoe Beteta static void
skd_isr_msg_from_dev(struct skd_device * skdev)2528f52228b8SJoe Beteta skd_isr_msg_from_dev(struct skd_device *skdev)
2529f52228b8SJoe Beteta {
2530f52228b8SJoe Beteta uint32_t mfd;
2531f52228b8SJoe Beteta uint32_t mtd;
2532f52228b8SJoe Beteta
2533f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "skd_isr_msg_from_dev:");
2534f52228b8SJoe Beteta
2535f52228b8SJoe Beteta mfd = SKD_READL(skdev, FIT_MSG_FROM_DEVICE);
2536f52228b8SJoe Beteta
2537f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "mfd=0x%x last_mtd=0x%x\n", mfd, skdev->last_mtd);
2538f52228b8SJoe Beteta
2539f52228b8SJoe Beteta /*
2540f52228b8SJoe Beteta * ignore any mtd that is an ack for something we didn't send
2541f52228b8SJoe Beteta */
2542f52228b8SJoe Beteta if (FIT_MXD_TYPE(mfd) != FIT_MXD_TYPE(skdev->last_mtd)) {
2543f52228b8SJoe Beteta return;
2544f52228b8SJoe Beteta }
2545f52228b8SJoe Beteta
2546f52228b8SJoe Beteta switch (FIT_MXD_TYPE(mfd)) {
2547f52228b8SJoe Beteta case FIT_MTD_FITFW_INIT:
2548f52228b8SJoe Beteta skdev->proto_ver = FIT_PROTOCOL_MAJOR_VER(mfd);
2549f52228b8SJoe Beteta
2550f52228b8SJoe Beteta if (skdev->proto_ver != FIT_PROTOCOL_VERSION_1) {
2551f52228b8SJoe Beteta cmn_err(CE_WARN, "!(%s): protocol mismatch\n",
2552f52228b8SJoe Beteta skdev->name);
2553f52228b8SJoe Beteta cmn_err(CE_WARN, "!(%s): got=%d support=%d\n",
2554f52228b8SJoe Beteta skdev->name, skdev->proto_ver,
2555f52228b8SJoe Beteta FIT_PROTOCOL_VERSION_1);
2556f52228b8SJoe Beteta cmn_err(CE_WARN, "!(%s): please upgrade driver\n",
2557f52228b8SJoe Beteta skdev->name);
2558f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_PROTOCOL_MISMATCH;
2559f52228b8SJoe Beteta skd_soft_reset(skdev);
2560f52228b8SJoe Beteta break;
2561f52228b8SJoe Beteta }
2562f52228b8SJoe Beteta mtd = FIT_MXD_CONS(FIT_MTD_GET_CMDQ_DEPTH, 0, 0);
2563f52228b8SJoe Beteta SKD_WRITEL(skdev, mtd, FIT_MSG_TO_DEVICE);
2564f52228b8SJoe Beteta skdev->last_mtd = mtd;
2565f52228b8SJoe Beteta break;
2566f52228b8SJoe Beteta
2567f52228b8SJoe Beteta case FIT_MTD_GET_CMDQ_DEPTH:
2568f52228b8SJoe Beteta skdev->hard_queue_depth_limit = FIT_MXD_DATA(mfd);
2569f52228b8SJoe Beteta mtd = FIT_MXD_CONS(FIT_MTD_SET_COMPQ_DEPTH, 0,
2570f52228b8SJoe Beteta SKD_N_COMPLETION_ENTRY);
2571f52228b8SJoe Beteta SKD_WRITEL(skdev, mtd, FIT_MSG_TO_DEVICE);
2572f52228b8SJoe Beteta skdev->last_mtd = mtd;
2573f52228b8SJoe Beteta break;
2574f52228b8SJoe Beteta
2575f52228b8SJoe Beteta case FIT_MTD_SET_COMPQ_DEPTH:
2576f52228b8SJoe Beteta SKD_WRITEQ(skdev, skdev->cq_dma_address.cookies->dmac_laddress,
2577f52228b8SJoe Beteta FIT_MSG_TO_DEVICE_ARG);
2578f52228b8SJoe Beteta mtd = FIT_MXD_CONS(FIT_MTD_SET_COMPQ_ADDR, 0, 0);
2579f52228b8SJoe Beteta SKD_WRITEL(skdev, mtd, FIT_MSG_TO_DEVICE);
2580f52228b8SJoe Beteta skdev->last_mtd = mtd;
2581f52228b8SJoe Beteta break;
2582f52228b8SJoe Beteta
2583f52228b8SJoe Beteta case FIT_MTD_SET_COMPQ_ADDR:
2584f52228b8SJoe Beteta skd_reset_skcomp(skdev);
2585f52228b8SJoe Beteta mtd = FIT_MXD_CONS(FIT_MTD_ARM_QUEUE, 0, 0);
2586f52228b8SJoe Beteta SKD_WRITEL(skdev, mtd, FIT_MSG_TO_DEVICE);
2587f52228b8SJoe Beteta skdev->last_mtd = mtd;
2588f52228b8SJoe Beteta break;
2589f52228b8SJoe Beteta
2590f52228b8SJoe Beteta case FIT_MTD_ARM_QUEUE:
2591f52228b8SJoe Beteta skdev->last_mtd = 0;
2592f52228b8SJoe Beteta /*
2593f52228b8SJoe Beteta * State should be, or soon will be, FIT_SR_DRIVE_ONLINE.
2594f52228b8SJoe Beteta */
2595f52228b8SJoe Beteta break;
2596f52228b8SJoe Beteta
2597f52228b8SJoe Beteta default:
2598f52228b8SJoe Beteta break;
2599f52228b8SJoe Beteta }
2600f52228b8SJoe Beteta }
2601f52228b8SJoe Beteta
2602f52228b8SJoe Beteta
2603f52228b8SJoe Beteta /*
2604f52228b8SJoe Beteta *
2605f52228b8SJoe Beteta * Name: skd_disable_interrupts, issues command to disable
2606f52228b8SJoe Beteta * device interrupts.
2607f52228b8SJoe Beteta *
2608f52228b8SJoe Beteta * Inputs: skdev - device state structure.
2609f52228b8SJoe Beteta *
2610f52228b8SJoe Beteta * Returns: Nothing.
2611f52228b8SJoe Beteta *
2612f52228b8SJoe Beteta */
2613f52228b8SJoe Beteta static void
skd_disable_interrupts(struct skd_device * skdev)2614f52228b8SJoe Beteta skd_disable_interrupts(struct skd_device *skdev)
2615f52228b8SJoe Beteta {
2616f52228b8SJoe Beteta uint32_t sense;
2617f52228b8SJoe Beteta
2618f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "skd_disable_interrupts:");
2619f52228b8SJoe Beteta
2620f52228b8SJoe Beteta sense = SKD_READL(skdev, FIT_CONTROL);
2621f52228b8SJoe Beteta sense &= ~FIT_CR_ENABLE_INTERRUPTS;
2622f52228b8SJoe Beteta SKD_WRITEL(skdev, sense, FIT_CONTROL);
2623f52228b8SJoe Beteta
2624f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "sense 0x%x", sense);
2625f52228b8SJoe Beteta
2626f52228b8SJoe Beteta /*
2627f52228b8SJoe Beteta * Note that the 1s is written. A 1-bit means
2628f52228b8SJoe Beteta * disable, a 0 means enable.
2629f52228b8SJoe Beteta */
2630f52228b8SJoe Beteta SKD_WRITEL(skdev, ~0, FIT_INT_MASK_HOST);
2631f52228b8SJoe Beteta }
2632f52228b8SJoe Beteta
2633f52228b8SJoe Beteta /*
2634f52228b8SJoe Beteta *
2635f52228b8SJoe Beteta * Name: skd_enable_interrupts, issues command to enable
2636f52228b8SJoe Beteta * device interrupts.
2637f52228b8SJoe Beteta *
2638f52228b8SJoe Beteta * Inputs: skdev - device state structure.
2639f52228b8SJoe Beteta *
2640f52228b8SJoe Beteta * Returns: Nothing.
2641f52228b8SJoe Beteta *
2642f52228b8SJoe Beteta */
2643f52228b8SJoe Beteta static void
skd_enable_interrupts(struct skd_device * skdev)2644f52228b8SJoe Beteta skd_enable_interrupts(struct skd_device *skdev)
2645f52228b8SJoe Beteta {
2646f52228b8SJoe Beteta uint32_t val;
2647f52228b8SJoe Beteta
2648f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "skd_enable_interrupts:");
2649f52228b8SJoe Beteta
2650f52228b8SJoe Beteta /* unmask interrupts first */
2651f52228b8SJoe Beteta val = FIT_ISH_FW_STATE_CHANGE +
2652f52228b8SJoe Beteta FIT_ISH_COMPLETION_POSTED +
2653f52228b8SJoe Beteta FIT_ISH_MSG_FROM_DEV;
2654f52228b8SJoe Beteta
2655f52228b8SJoe Beteta /*
2656f52228b8SJoe Beteta * Note that the compliment of mask is written. A 1-bit means
2657f52228b8SJoe Beteta * disable, a 0 means enable.
2658f52228b8SJoe Beteta */
2659f52228b8SJoe Beteta SKD_WRITEL(skdev, ~val, FIT_INT_MASK_HOST);
2660f52228b8SJoe Beteta
2661f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "interrupt mask=0x%x", ~val);
2662f52228b8SJoe Beteta
2663f52228b8SJoe Beteta val = SKD_READL(skdev, FIT_CONTROL);
2664f52228b8SJoe Beteta val |= FIT_CR_ENABLE_INTERRUPTS;
2665f52228b8SJoe Beteta
2666f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "control=0x%x", val);
2667f52228b8SJoe Beteta
2668f52228b8SJoe Beteta SKD_WRITEL(skdev, val, FIT_CONTROL);
2669f52228b8SJoe Beteta }
2670f52228b8SJoe Beteta
2671f52228b8SJoe Beteta /*
2672f52228b8SJoe Beteta *
2673f52228b8SJoe Beteta * Name: skd_soft_reset, issues a soft reset to the hardware.
2674f52228b8SJoe Beteta *
2675f52228b8SJoe Beteta * Inputs: skdev - device state structure.
2676f52228b8SJoe Beteta *
2677f52228b8SJoe Beteta * Returns: Nothing.
2678f52228b8SJoe Beteta *
2679f52228b8SJoe Beteta */
2680f52228b8SJoe Beteta static void
skd_soft_reset(struct skd_device * skdev)2681f52228b8SJoe Beteta skd_soft_reset(struct skd_device *skdev)
2682f52228b8SJoe Beteta {
2683f52228b8SJoe Beteta uint32_t val;
2684f52228b8SJoe Beteta
2685f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "skd_soft_reset:");
2686f52228b8SJoe Beteta
2687f52228b8SJoe Beteta val = SKD_READL(skdev, FIT_CONTROL);
2688f52228b8SJoe Beteta val |= (FIT_CR_SOFT_RESET);
2689f52228b8SJoe Beteta
2690f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "soft_reset: control=0x%x", val);
2691f52228b8SJoe Beteta
2692f52228b8SJoe Beteta SKD_WRITEL(skdev, val, FIT_CONTROL);
2693f52228b8SJoe Beteta }
2694f52228b8SJoe Beteta
2695f52228b8SJoe Beteta /*
2696f52228b8SJoe Beteta *
2697f52228b8SJoe Beteta * Name: skd_start_device, gets the device going.
2698f52228b8SJoe Beteta *
2699f52228b8SJoe Beteta * Inputs: skdev - device state structure.
2700f52228b8SJoe Beteta *
2701f52228b8SJoe Beteta * Returns: Nothing.
2702f52228b8SJoe Beteta *
2703f52228b8SJoe Beteta */
2704f52228b8SJoe Beteta static void
skd_start_device(struct skd_device * skdev)2705f52228b8SJoe Beteta skd_start_device(struct skd_device *skdev)
2706f52228b8SJoe Beteta {
2707f52228b8SJoe Beteta uint32_t state;
2708f52228b8SJoe Beteta int delay_action = 0;
2709f52228b8SJoe Beteta
2710f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "skd_start_device:");
2711f52228b8SJoe Beteta
2712f52228b8SJoe Beteta /* ack all ghost interrupts */
2713f52228b8SJoe Beteta SKD_WRITEL(skdev, FIT_INT_DEF_MASK, FIT_INT_STATUS_HOST);
2714f52228b8SJoe Beteta
2715f52228b8SJoe Beteta state = SKD_READL(skdev, FIT_STATUS);
2716f52228b8SJoe Beteta
2717f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "initial status=0x%x", state);
2718f52228b8SJoe Beteta
2719f52228b8SJoe Beteta state &= FIT_SR_DRIVE_STATE_MASK;
2720f52228b8SJoe Beteta skdev->drive_state = state;
2721f52228b8SJoe Beteta skdev->last_mtd = 0;
2722f52228b8SJoe Beteta
2723f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_STARTING;
2724f52228b8SJoe Beteta skdev->timer_countdown = SKD_TIMER_SECONDS(SKD_STARTING_TO);
2725f52228b8SJoe Beteta
2726f52228b8SJoe Beteta skd_enable_interrupts(skdev);
2727f52228b8SJoe Beteta
2728f52228b8SJoe Beteta switch (skdev->drive_state) {
2729f52228b8SJoe Beteta case FIT_SR_DRIVE_OFFLINE:
2730f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "(%s): Drive offline...",
2731f52228b8SJoe Beteta skd_name(skdev));
2732f52228b8SJoe Beteta break;
2733f52228b8SJoe Beteta
2734f52228b8SJoe Beteta case FIT_SR_DRIVE_FW_BOOTING:
2735f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "FIT_SR_DRIVE_FW_BOOTING %s\n", skdev->name);
2736f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_WAIT_BOOT;
2737f52228b8SJoe Beteta skdev->timer_countdown = SKD_TIMER_SECONDS(SKD_WAIT_BOOT_TO);
2738f52228b8SJoe Beteta break;
2739f52228b8SJoe Beteta
2740f52228b8SJoe Beteta case FIT_SR_DRIVE_BUSY_SANITIZE:
2741f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "(%s): Start: BUSY_SANITIZE\n",
2742f52228b8SJoe Beteta skd_name(skdev));
2743f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_BUSY_SANITIZE;
2744f52228b8SJoe Beteta skdev->timer_countdown = SKD_TIMER_SECONDS(60);
2745f52228b8SJoe Beteta break;
2746f52228b8SJoe Beteta
2747f52228b8SJoe Beteta case FIT_SR_DRIVE_BUSY_ERASE:
2748f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "(%s): Start: BUSY_ERASE\n",
2749f52228b8SJoe Beteta skd_name(skdev));
2750f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_BUSY_ERASE;
2751f52228b8SJoe Beteta skdev->timer_countdown = SKD_TIMER_SECONDS(60);
2752f52228b8SJoe Beteta break;
2753f52228b8SJoe Beteta
2754f52228b8SJoe Beteta case FIT_SR_DRIVE_INIT:
2755f52228b8SJoe Beteta case FIT_SR_DRIVE_ONLINE:
2756f52228b8SJoe Beteta skd_soft_reset(skdev);
2757f52228b8SJoe Beteta
2758f52228b8SJoe Beteta break;
2759f52228b8SJoe Beteta
2760f52228b8SJoe Beteta case FIT_SR_DRIVE_BUSY:
2761f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "(%s): Drive Busy...\n",
2762f52228b8SJoe Beteta skd_name(skdev));
2763f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_BUSY;
2764f52228b8SJoe Beteta skdev->timer_countdown = SKD_TIMER_SECONDS(60);
2765f52228b8SJoe Beteta break;
2766f52228b8SJoe Beteta
2767f52228b8SJoe Beteta case FIT_SR_DRIVE_SOFT_RESET:
2768f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "(%s) drive soft reset in prog\n",
2769f52228b8SJoe Beteta skd_name(skdev));
2770f52228b8SJoe Beteta break;
2771f52228b8SJoe Beteta
2772f52228b8SJoe Beteta case FIT_SR_DRIVE_FAULT:
2773f52228b8SJoe Beteta /*
2774f52228b8SJoe Beteta * Fault state is bad...soft reset won't do it...
2775f52228b8SJoe Beteta * Hard reset, maybe, but does it work on device?
2776f52228b8SJoe Beteta * For now, just fault so the system doesn't hang.
2777f52228b8SJoe Beteta */
2778f52228b8SJoe Beteta skd_drive_fault(skdev);
2779f52228b8SJoe Beteta
2780f52228b8SJoe Beteta delay_action = 1;
2781f52228b8SJoe Beteta break;
2782f52228b8SJoe Beteta
2783f52228b8SJoe Beteta case 0xFF:
2784f52228b8SJoe Beteta skd_drive_disappeared(skdev);
2785f52228b8SJoe Beteta
2786f52228b8SJoe Beteta delay_action = 1;
2787f52228b8SJoe Beteta break;
2788f52228b8SJoe Beteta
2789f52228b8SJoe Beteta default:
2790f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "(%s) Start: unknown state %x\n",
2791f52228b8SJoe Beteta skd_name(skdev), skdev->drive_state);
2792f52228b8SJoe Beteta break;
2793f52228b8SJoe Beteta }
2794f52228b8SJoe Beteta
2795f52228b8SJoe Beteta state = SKD_READL(skdev, FIT_CONTROL);
2796f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "FIT Control Status=0x%x\n", state);
2797f52228b8SJoe Beteta
2798f52228b8SJoe Beteta state = SKD_READL(skdev, FIT_INT_STATUS_HOST);
2799f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "Intr Status=0x%x\n", state);
2800f52228b8SJoe Beteta
2801f52228b8SJoe Beteta state = SKD_READL(skdev, FIT_INT_MASK_HOST);
2802f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "Intr Mask=0x%x\n", state);
2803f52228b8SJoe Beteta
2804f52228b8SJoe Beteta state = SKD_READL(skdev, FIT_MSG_FROM_DEVICE);
2805f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "Msg from Dev=0x%x\n", state);
2806f52228b8SJoe Beteta
2807f52228b8SJoe Beteta state = SKD_READL(skdev, FIT_HW_VERSION);
2808f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "HW version=0x%x\n", state);
2809f52228b8SJoe Beteta
2810f52228b8SJoe Beteta if (delay_action) {
2811f52228b8SJoe Beteta /* start the queue so we can respond with error to requests */
2812f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "Starting %s queue\n", skdev->name);
2813f52228b8SJoe Beteta skd_start(skdev);
2814f52228b8SJoe Beteta skdev->gendisk_on = -1;
2815f52228b8SJoe Beteta cv_signal(&skdev->cv_waitq);
2816f52228b8SJoe Beteta }
2817f52228b8SJoe Beteta }
2818f52228b8SJoe Beteta
2819f52228b8SJoe Beteta /*
2820f52228b8SJoe Beteta *
2821f52228b8SJoe Beteta * Name: skd_restart_device, restart the hardware.
2822f52228b8SJoe Beteta *
2823f52228b8SJoe Beteta * Inputs: skdev - device state structure.
2824f52228b8SJoe Beteta *
2825f52228b8SJoe Beteta * Returns: Nothing.
2826f52228b8SJoe Beteta *
2827f52228b8SJoe Beteta */
2828f52228b8SJoe Beteta static void
skd_restart_device(struct skd_device * skdev)2829f52228b8SJoe Beteta skd_restart_device(struct skd_device *skdev)
2830f52228b8SJoe Beteta {
2831f52228b8SJoe Beteta uint32_t state;
2832f52228b8SJoe Beteta
2833f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "skd_restart_device:");
2834f52228b8SJoe Beteta
2835f52228b8SJoe Beteta /* ack all ghost interrupts */
2836f52228b8SJoe Beteta SKD_WRITEL(skdev, FIT_INT_DEF_MASK, FIT_INT_STATUS_HOST);
2837f52228b8SJoe Beteta
2838f52228b8SJoe Beteta state = SKD_READL(skdev, FIT_STATUS);
2839f52228b8SJoe Beteta
2840f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "skd_restart_device: drive status=0x%x\n", state);
2841f52228b8SJoe Beteta
2842f52228b8SJoe Beteta state &= FIT_SR_DRIVE_STATE_MASK;
2843f52228b8SJoe Beteta skdev->drive_state = state;
2844f52228b8SJoe Beteta skdev->last_mtd = 0;
2845f52228b8SJoe Beteta
2846f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_RESTARTING;
2847f52228b8SJoe Beteta skdev->timer_countdown = SKD_TIMER_MINUTES(4);
2848f52228b8SJoe Beteta
2849f52228b8SJoe Beteta skd_soft_reset(skdev);
2850f52228b8SJoe Beteta }
2851f52228b8SJoe Beteta
2852f52228b8SJoe Beteta /*
2853f52228b8SJoe Beteta *
2854f52228b8SJoe Beteta * Name: skd_stop_device, stops the device.
2855f52228b8SJoe Beteta *
2856f52228b8SJoe Beteta * Inputs: skdev - device state structure.
2857f52228b8SJoe Beteta *
2858f52228b8SJoe Beteta * Returns: Nothing.
2859f52228b8SJoe Beteta *
2860f52228b8SJoe Beteta */
2861f52228b8SJoe Beteta static void
skd_stop_device(struct skd_device * skdev)2862f52228b8SJoe Beteta skd_stop_device(struct skd_device *skdev)
2863f52228b8SJoe Beteta {
2864f52228b8SJoe Beteta clock_t cur_ticks, tmo;
2865f52228b8SJoe Beteta int secs;
2866f52228b8SJoe Beteta struct skd_special_context *skspcl = &skdev->internal_skspcl;
2867f52228b8SJoe Beteta
2868f52228b8SJoe Beteta if (SKD_DRVR_STATE_ONLINE != skdev->state) {
2869f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "(%s): skd_stop_device not online no sync\n",
2870f52228b8SJoe Beteta skdev->name);
2871f52228b8SJoe Beteta goto stop_out;
2872f52228b8SJoe Beteta }
2873f52228b8SJoe Beteta
2874f52228b8SJoe Beteta if (SKD_REQ_STATE_IDLE != skspcl->req.state) {
2875f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "(%s): skd_stop_device no special\n",
2876f52228b8SJoe Beteta skdev->name);
2877f52228b8SJoe Beteta goto stop_out;
2878f52228b8SJoe Beteta }
2879f52228b8SJoe Beteta
2880f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_SYNCING;
2881f52228b8SJoe Beteta skdev->sync_done = 0;
2882f52228b8SJoe Beteta
2883f52228b8SJoe Beteta skd_send_internal_skspcl(skdev, skspcl, SYNCHRONIZE_CACHE);
2884f52228b8SJoe Beteta
2885f52228b8SJoe Beteta secs = 10;
2886f52228b8SJoe Beteta mutex_enter(&skdev->skd_internalio_mutex);
2887f52228b8SJoe Beteta while (skdev->sync_done == 0) {
2888f52228b8SJoe Beteta cur_ticks = ddi_get_lbolt();
2889f52228b8SJoe Beteta tmo = cur_ticks + drv_usectohz(1000000 * secs);
2890f52228b8SJoe Beteta if (cv_timedwait(&skdev->cv_waitq,
2891f52228b8SJoe Beteta &skdev->skd_internalio_mutex, tmo) == -1) {
2892f52228b8SJoe Beteta /* Oops - timed out */
2893f52228b8SJoe Beteta
2894f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "stop_device - %d secs TMO", secs);
2895f52228b8SJoe Beteta }
2896f52228b8SJoe Beteta }
2897f52228b8SJoe Beteta
2898f52228b8SJoe Beteta mutex_exit(&skdev->skd_internalio_mutex);
2899f52228b8SJoe Beteta
2900f52228b8SJoe Beteta switch (skdev->sync_done) {
2901f52228b8SJoe Beteta case 0:
2902f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "(%s): skd_stop_device no sync\n",
2903f52228b8SJoe Beteta skdev->name);
2904f52228b8SJoe Beteta break;
2905f52228b8SJoe Beteta case 1:
2906f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "(%s): skd_stop_device sync done\n",
2907f52228b8SJoe Beteta skdev->name);
2908f52228b8SJoe Beteta break;
2909f52228b8SJoe Beteta default:
2910f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "(%s): skd_stop_device sync error\n",
2911f52228b8SJoe Beteta skdev->name);
2912f52228b8SJoe Beteta }
2913f52228b8SJoe Beteta
2914f52228b8SJoe Beteta
2915f52228b8SJoe Beteta stop_out:
2916f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_STOPPING;
2917f52228b8SJoe Beteta
2918f52228b8SJoe Beteta skd_disable_interrupts(skdev);
2919f52228b8SJoe Beteta
2920f52228b8SJoe Beteta /* ensure all ints on device are cleared */
2921f52228b8SJoe Beteta SKD_WRITEL(skdev, FIT_INT_DEF_MASK, FIT_INT_STATUS_HOST);
2922f52228b8SJoe Beteta /* soft reset the device to unload with a clean slate */
2923f52228b8SJoe Beteta SKD_WRITEL(skdev, FIT_CR_SOFT_RESET, FIT_CONTROL);
2924f52228b8SJoe Beteta }
2925f52228b8SJoe Beteta
2926f52228b8SJoe Beteta /*
2927f52228b8SJoe Beteta * CONSTRUCT
2928f52228b8SJoe Beteta */
2929f52228b8SJoe Beteta
2930f52228b8SJoe Beteta static int skd_cons_skcomp(struct skd_device *);
2931f52228b8SJoe Beteta static int skd_cons_skmsg(struct skd_device *);
2932f52228b8SJoe Beteta static int skd_cons_skreq(struct skd_device *);
2933f52228b8SJoe Beteta static int skd_cons_sksb(struct skd_device *);
2934f52228b8SJoe Beteta static struct fit_sg_descriptor *skd_cons_sg_list(struct skd_device *, uint32_t,
2935f52228b8SJoe Beteta dma_mem_t *);
2936f52228b8SJoe Beteta
2937f52228b8SJoe Beteta /*
2938f52228b8SJoe Beteta *
2939f52228b8SJoe Beteta * Name: skd_construct, calls other routines to build device
2940f52228b8SJoe Beteta * interface structures.
2941f52228b8SJoe Beteta *
2942f52228b8SJoe Beteta * Inputs: skdev - device state structure.
2943f52228b8SJoe Beteta * instance - DDI instance number.
2944f52228b8SJoe Beteta *
2945f52228b8SJoe Beteta * Returns: Returns DDI_FAILURE on any failure otherwise returns
2946f52228b8SJoe Beteta * DDI_SUCCESS.
2947f52228b8SJoe Beteta *
2948f52228b8SJoe Beteta */
2949f52228b8SJoe Beteta /* ARGSUSED */ /* Upstream common source with other platforms. */
2950f52228b8SJoe Beteta static int
skd_construct(skd_device_t * skdev,int instance)2951f52228b8SJoe Beteta skd_construct(skd_device_t *skdev, int instance)
2952f52228b8SJoe Beteta {
2953f52228b8SJoe Beteta int rc = 0;
2954f52228b8SJoe Beteta
2955f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_LOAD;
2956f52228b8SJoe Beteta skdev->irq_type = skd_isr_type;
2957f52228b8SJoe Beteta skdev->soft_queue_depth_limit = skd_max_queue_depth;
2958f52228b8SJoe Beteta skdev->hard_queue_depth_limit = 10; /* until GET_CMDQ_DEPTH */
2959f52228b8SJoe Beteta
2960f52228b8SJoe Beteta skdev->num_req_context = skd_max_queue_depth;
2961f52228b8SJoe Beteta skdev->num_fitmsg_context = skd_max_queue_depth;
2962f52228b8SJoe Beteta
2963f52228b8SJoe Beteta skdev->queue_depth_limit = skdev->hard_queue_depth_limit;
2964f52228b8SJoe Beteta skdev->queue_depth_lowat = 1;
2965f52228b8SJoe Beteta skdev->proto_ver = 99; /* initialize to invalid value */
2966f52228b8SJoe Beteta skdev->sgs_per_request = skd_sgs_per_request;
2967f52228b8SJoe Beteta skdev->dbg_level = skd_dbg_level;
2968f52228b8SJoe Beteta
2969f52228b8SJoe Beteta rc = skd_cons_skcomp(skdev);
2970f52228b8SJoe Beteta if (rc < 0) {
2971f52228b8SJoe Beteta goto err_out;
2972f52228b8SJoe Beteta }
2973f52228b8SJoe Beteta
2974f52228b8SJoe Beteta rc = skd_cons_skmsg(skdev);
2975f52228b8SJoe Beteta if (rc < 0) {
2976f52228b8SJoe Beteta goto err_out;
2977f52228b8SJoe Beteta }
2978f52228b8SJoe Beteta
2979f52228b8SJoe Beteta rc = skd_cons_skreq(skdev);
2980f52228b8SJoe Beteta if (rc < 0) {
2981f52228b8SJoe Beteta goto err_out;
2982f52228b8SJoe Beteta }
2983f52228b8SJoe Beteta
2984f52228b8SJoe Beteta rc = skd_cons_sksb(skdev);
2985f52228b8SJoe Beteta if (rc < 0) {
2986f52228b8SJoe Beteta goto err_out;
2987f52228b8SJoe Beteta }
2988f52228b8SJoe Beteta
2989f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "CONSTRUCT VICTORY");
2990f52228b8SJoe Beteta
2991f52228b8SJoe Beteta return (DDI_SUCCESS);
2992f52228b8SJoe Beteta
2993f52228b8SJoe Beteta err_out:
2994f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "construct failed\n");
2995f52228b8SJoe Beteta skd_destruct(skdev);
2996f52228b8SJoe Beteta
2997f52228b8SJoe Beteta return (DDI_FAILURE);
2998f52228b8SJoe Beteta }
2999f52228b8SJoe Beteta
3000f52228b8SJoe Beteta /*
3001f52228b8SJoe Beteta *
3002f52228b8SJoe Beteta * Name: skd_free_phys, frees DMA memory.
3003f52228b8SJoe Beteta *
3004f52228b8SJoe Beteta * Inputs: skdev - device state structure.
3005f52228b8SJoe Beteta * mem - DMA info.
3006f52228b8SJoe Beteta *
3007f52228b8SJoe Beteta * Returns: Nothing.
3008f52228b8SJoe Beteta *
3009f52228b8SJoe Beteta */
3010f52228b8SJoe Beteta static void
skd_free_phys(skd_device_t * skdev,dma_mem_t * mem)3011f52228b8SJoe Beteta skd_free_phys(skd_device_t *skdev, dma_mem_t *mem)
3012f52228b8SJoe Beteta {
3013f52228b8SJoe Beteta _NOTE(ARGUNUSED(skdev));
3014f52228b8SJoe Beteta
3015f52228b8SJoe Beteta if (mem == NULL || mem->dma_handle == NULL)
3016f52228b8SJoe Beteta return;
3017f52228b8SJoe Beteta
3018f52228b8SJoe Beteta (void) ddi_dma_unbind_handle(mem->dma_handle);
3019f52228b8SJoe Beteta
3020f52228b8SJoe Beteta if (mem->acc_handle != NULL) {
3021f52228b8SJoe Beteta ddi_dma_mem_free(&mem->acc_handle);
3022f52228b8SJoe Beteta mem->acc_handle = NULL;
3023f52228b8SJoe Beteta }
3024f52228b8SJoe Beteta
3025f52228b8SJoe Beteta mem->bp = NULL;
3026f52228b8SJoe Beteta ddi_dma_free_handle(&mem->dma_handle);
3027f52228b8SJoe Beteta mem->dma_handle = NULL;
3028f52228b8SJoe Beteta }
3029f52228b8SJoe Beteta
3030f52228b8SJoe Beteta /*
3031f52228b8SJoe Beteta *
3032f52228b8SJoe Beteta * Name: skd_alloc_dma_mem, allocates DMA memory.
3033f52228b8SJoe Beteta *
3034f52228b8SJoe Beteta * Inputs: skdev - device state structure.
3035f52228b8SJoe Beteta * mem - DMA data structure.
3036f52228b8SJoe Beteta * sleep - indicates whether called routine can sleep.
3037f52228b8SJoe Beteta * atype - specified 32 or 64 bit allocation.
3038f52228b8SJoe Beteta *
3039f52228b8SJoe Beteta * Returns: Void pointer to mem->bp on success else NULL.
3040f52228b8SJoe Beteta * NOTE: There are some failure modes even if sleep is set
3041f52228b8SJoe Beteta * to KM_SLEEP, so callers MUST check the return code even
3042f52228b8SJoe Beteta * if KM_SLEEP is passed in.
3043f52228b8SJoe Beteta *
3044f52228b8SJoe Beteta */
3045f52228b8SJoe Beteta static void *
skd_alloc_dma_mem(skd_device_t * skdev,dma_mem_t * mem,uint8_t atype)3046f52228b8SJoe Beteta skd_alloc_dma_mem(skd_device_t *skdev, dma_mem_t *mem, uint8_t atype)
3047f52228b8SJoe Beteta {
3048f52228b8SJoe Beteta size_t rlen;
3049f52228b8SJoe Beteta uint_t cnt;
3050f52228b8SJoe Beteta ddi_dma_attr_t dma_attr = skd_64bit_io_dma_attr;
3051f52228b8SJoe Beteta ddi_device_acc_attr_t acc_attr = {
3052f52228b8SJoe Beteta DDI_DEVICE_ATTR_V0,
3053f52228b8SJoe Beteta DDI_STRUCTURE_LE_ACC,
3054f52228b8SJoe Beteta DDI_STRICTORDER_ACC
3055f52228b8SJoe Beteta };
3056f52228b8SJoe Beteta
3057f52228b8SJoe Beteta if (atype == ATYPE_32BIT)
3058f52228b8SJoe Beteta dma_attr.dma_attr_addr_hi = SKD_DMA_HIGH_32BIT_ADDRESS;
3059f52228b8SJoe Beteta
3060f52228b8SJoe Beteta dma_attr.dma_attr_sgllen = 1;
3061f52228b8SJoe Beteta
3062f52228b8SJoe Beteta /*
3063f52228b8SJoe Beteta * Allocate DMA memory.
3064f52228b8SJoe Beteta */
3065f52228b8SJoe Beteta if (ddi_dma_alloc_handle(skdev->dip, &dma_attr, DDI_DMA_SLEEP, NULL,
3066f52228b8SJoe Beteta &mem->dma_handle) != DDI_SUCCESS) {
3067f52228b8SJoe Beteta cmn_err(CE_WARN, "!alloc_dma_mem-1, failed");
3068f52228b8SJoe Beteta
3069f52228b8SJoe Beteta mem->dma_handle = NULL;
3070f52228b8SJoe Beteta
3071f52228b8SJoe Beteta return (NULL);
3072f52228b8SJoe Beteta }
3073f52228b8SJoe Beteta
3074f52228b8SJoe Beteta if (ddi_dma_mem_alloc(mem->dma_handle, mem->size, &acc_attr,
3075f52228b8SJoe Beteta DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, (caddr_t *)&mem->bp, &rlen,
3076f52228b8SJoe Beteta &mem->acc_handle) != DDI_SUCCESS) {
3077f52228b8SJoe Beteta cmn_err(CE_WARN, "!skd_alloc_dma_mem-2, failed");
3078f52228b8SJoe Beteta ddi_dma_free_handle(&mem->dma_handle);
3079f52228b8SJoe Beteta mem->dma_handle = NULL;
3080f52228b8SJoe Beteta mem->acc_handle = NULL;
3081f52228b8SJoe Beteta mem->bp = NULL;
3082f52228b8SJoe Beteta
3083f52228b8SJoe Beteta return (NULL);
3084f52228b8SJoe Beteta }
3085f52228b8SJoe Beteta bzero(mem->bp, mem->size);
3086f52228b8SJoe Beteta
3087f52228b8SJoe Beteta if (ddi_dma_addr_bind_handle(mem->dma_handle, NULL, mem->bp,
3088f52228b8SJoe Beteta mem->size, (DDI_DMA_CONSISTENT | DDI_DMA_RDWR), DDI_DMA_SLEEP, NULL,
3089f52228b8SJoe Beteta &mem->cookie, &cnt) != DDI_DMA_MAPPED) {
3090f52228b8SJoe Beteta cmn_err(CE_WARN, "!skd_alloc_dma_mem-3, failed");
3091f52228b8SJoe Beteta ddi_dma_mem_free(&mem->acc_handle);
3092f52228b8SJoe Beteta ddi_dma_free_handle(&mem->dma_handle);
3093f52228b8SJoe Beteta
3094f52228b8SJoe Beteta return (NULL);
3095f52228b8SJoe Beteta }
3096f52228b8SJoe Beteta
3097f52228b8SJoe Beteta if (cnt > 1) {
3098f52228b8SJoe Beteta (void) ddi_dma_unbind_handle(mem->dma_handle);
3099f52228b8SJoe Beteta cmn_err(CE_WARN, "!skd_alloc_dma_mem-4, failed, "
3100f52228b8SJoe Beteta "cookie_count %d > 1", cnt);
3101f52228b8SJoe Beteta skd_free_phys(skdev, mem);
3102f52228b8SJoe Beteta
3103f52228b8SJoe Beteta return (NULL);
3104f52228b8SJoe Beteta }
3105f52228b8SJoe Beteta mem->cookies = &mem->cookie;
3106f52228b8SJoe Beteta mem->cookies->dmac_size = mem->size;
3107f52228b8SJoe Beteta
3108f52228b8SJoe Beteta return (mem->bp);
3109f52228b8SJoe Beteta }
3110f52228b8SJoe Beteta
3111f52228b8SJoe Beteta /*
3112f52228b8SJoe Beteta *
3113f52228b8SJoe Beteta * Name: skd_cons_skcomp, allocates space for the skcomp table.
3114f52228b8SJoe Beteta *
3115f52228b8SJoe Beteta * Inputs: skdev - device state structure.
3116f52228b8SJoe Beteta *
3117f52228b8SJoe Beteta * Returns: -ENOMEM if no memory otherwise NULL.
3118f52228b8SJoe Beteta *
3119f52228b8SJoe Beteta */
3120f52228b8SJoe Beteta static int
skd_cons_skcomp(struct skd_device * skdev)3121f52228b8SJoe Beteta skd_cons_skcomp(struct skd_device *skdev)
3122f52228b8SJoe Beteta {
3123f52228b8SJoe Beteta uint64_t *dma_alloc;
3124f52228b8SJoe Beteta struct fit_completion_entry_v1 *skcomp;
3125f52228b8SJoe Beteta int rc = 0;
3126f52228b8SJoe Beteta uint32_t nbytes;
3127f52228b8SJoe Beteta dma_mem_t *mem;
3128f52228b8SJoe Beteta
3129f52228b8SJoe Beteta nbytes = sizeof (*skcomp) * SKD_N_COMPLETION_ENTRY;
3130f52228b8SJoe Beteta nbytes += sizeof (struct fit_comp_error_info) * SKD_N_COMPLETION_ENTRY;
3131f52228b8SJoe Beteta
3132f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "cons_skcomp: nbytes=%d,entries=%d", nbytes,
3133f52228b8SJoe Beteta SKD_N_COMPLETION_ENTRY);
3134f52228b8SJoe Beteta
3135f52228b8SJoe Beteta mem = &skdev->cq_dma_address;
3136f52228b8SJoe Beteta mem->size = nbytes;
3137f52228b8SJoe Beteta
3138f52228b8SJoe Beteta dma_alloc = skd_alloc_dma_mem(skdev, mem, ATYPE_64BIT);
3139f52228b8SJoe Beteta skcomp = (struct fit_completion_entry_v1 *)dma_alloc;
3140f52228b8SJoe Beteta if (skcomp == NULL) {
3141f52228b8SJoe Beteta rc = -ENOMEM;
3142f52228b8SJoe Beteta goto err_out;
3143f52228b8SJoe Beteta }
3144f52228b8SJoe Beteta
3145f52228b8SJoe Beteta bzero(skcomp, nbytes);
3146f52228b8SJoe Beteta
3147f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "cons_skcomp: skcomp=%p nbytes=%d",
3148f52228b8SJoe Beteta (void *)skcomp, nbytes);
3149f52228b8SJoe Beteta
3150f52228b8SJoe Beteta skdev->skcomp_table = skcomp;
3151f52228b8SJoe Beteta skdev->skerr_table = (struct fit_comp_error_info *)(dma_alloc +
3152f52228b8SJoe Beteta (SKD_N_COMPLETION_ENTRY * sizeof (*skcomp) / sizeof (uint64_t)));
3153f52228b8SJoe Beteta
3154f52228b8SJoe Beteta err_out:
3155f52228b8SJoe Beteta return (rc);
3156f52228b8SJoe Beteta }
3157f52228b8SJoe Beteta
3158f52228b8SJoe Beteta /*
3159f52228b8SJoe Beteta *
3160f52228b8SJoe Beteta * Name: skd_cons_skmsg, allocates space for the skmsg table.
3161f52228b8SJoe Beteta *
3162f52228b8SJoe Beteta * Inputs: skdev - device state structure.
3163f52228b8SJoe Beteta *
3164f52228b8SJoe Beteta * Returns: -ENOMEM if no memory otherwise NULL.
3165f52228b8SJoe Beteta *
3166f52228b8SJoe Beteta */
3167f52228b8SJoe Beteta static int
skd_cons_skmsg(struct skd_device * skdev)3168f52228b8SJoe Beteta skd_cons_skmsg(struct skd_device *skdev)
3169f52228b8SJoe Beteta {
3170f52228b8SJoe Beteta dma_mem_t *mem;
3171f52228b8SJoe Beteta int rc = 0;
3172f52228b8SJoe Beteta uint32_t i;
3173f52228b8SJoe Beteta
3174f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "skmsg_table kzalloc, struct %lu, count %u total %lu",
3175f52228b8SJoe Beteta (ulong_t)sizeof (struct skd_fitmsg_context),
3176f52228b8SJoe Beteta skdev->num_fitmsg_context,
3177f52228b8SJoe Beteta (ulong_t)(sizeof (struct skd_fitmsg_context) *
3178f52228b8SJoe Beteta skdev->num_fitmsg_context));
3179f52228b8SJoe Beteta
3180f52228b8SJoe Beteta skdev->skmsg_table = (struct skd_fitmsg_context *)kmem_zalloc(
3181f52228b8SJoe Beteta sizeof (struct skd_fitmsg_context) * skdev->num_fitmsg_context,
3182f52228b8SJoe Beteta KM_SLEEP);
3183f52228b8SJoe Beteta
3184f52228b8SJoe Beteta for (i = 0; i < skdev->num_fitmsg_context; i++) {
3185f52228b8SJoe Beteta struct skd_fitmsg_context *skmsg;
3186f52228b8SJoe Beteta
3187f52228b8SJoe Beteta skmsg = &skdev->skmsg_table[i];
3188f52228b8SJoe Beteta
3189f52228b8SJoe Beteta skmsg->id = i + SKD_ID_FIT_MSG;
3190f52228b8SJoe Beteta
3191f52228b8SJoe Beteta skmsg->state = SKD_MSG_STATE_IDLE;
3192f52228b8SJoe Beteta
3193f52228b8SJoe Beteta mem = &skmsg->mb_dma_address;
3194f52228b8SJoe Beteta mem->size = SKD_N_FITMSG_BYTES + 64;
3195f52228b8SJoe Beteta
3196f52228b8SJoe Beteta skmsg->msg_buf = skd_alloc_dma_mem(skdev, mem, ATYPE_64BIT);
3197f52228b8SJoe Beteta
3198f52228b8SJoe Beteta if (NULL == skmsg->msg_buf) {
3199f52228b8SJoe Beteta rc = -ENOMEM;
3200f52228b8SJoe Beteta i++;
3201f52228b8SJoe Beteta break;
3202f52228b8SJoe Beteta }
3203f52228b8SJoe Beteta
3204f52228b8SJoe Beteta skmsg->offset = 0;
3205f52228b8SJoe Beteta
3206f52228b8SJoe Beteta bzero(skmsg->msg_buf, SKD_N_FITMSG_BYTES);
3207f52228b8SJoe Beteta
3208f52228b8SJoe Beteta skmsg->next = &skmsg[1];
3209f52228b8SJoe Beteta }
3210f52228b8SJoe Beteta
3211f52228b8SJoe Beteta /* Free list is in order starting with the 0th entry. */
3212f52228b8SJoe Beteta skdev->skmsg_table[i - 1].next = NULL;
3213f52228b8SJoe Beteta skdev->skmsg_free_list = skdev->skmsg_table;
3214f52228b8SJoe Beteta
3215f52228b8SJoe Beteta return (rc);
3216f52228b8SJoe Beteta }
3217f52228b8SJoe Beteta
3218f52228b8SJoe Beteta /*
3219f52228b8SJoe Beteta *
3220f52228b8SJoe Beteta * Name: skd_cons_skreq, allocates space for the skreq table.
3221f52228b8SJoe Beteta *
3222f52228b8SJoe Beteta * Inputs: skdev - device state structure.
3223f52228b8SJoe Beteta *
3224f52228b8SJoe Beteta * Returns: -ENOMEM if no memory otherwise NULL.
3225f52228b8SJoe Beteta *
3226f52228b8SJoe Beteta */
3227f52228b8SJoe Beteta static int
skd_cons_skreq(struct skd_device * skdev)3228f52228b8SJoe Beteta skd_cons_skreq(struct skd_device *skdev)
3229f52228b8SJoe Beteta {
3230f52228b8SJoe Beteta int rc = 0;
3231f52228b8SJoe Beteta uint32_t i;
3232f52228b8SJoe Beteta
3233f52228b8SJoe Beteta Dcmn_err(CE_NOTE,
3234f52228b8SJoe Beteta "skreq_table kmem_zalloc, struct %lu, count %u total %lu",
3235f52228b8SJoe Beteta (ulong_t)sizeof (struct skd_request_context),
3236f52228b8SJoe Beteta skdev->num_req_context,
3237f52228b8SJoe Beteta (ulong_t) (sizeof (struct skd_request_context) *
3238f52228b8SJoe Beteta skdev->num_req_context));
3239f52228b8SJoe Beteta
3240f52228b8SJoe Beteta skdev->skreq_table = (struct skd_request_context *)kmem_zalloc(
3241f52228b8SJoe Beteta sizeof (struct skd_request_context) * skdev->num_req_context,
3242f52228b8SJoe Beteta KM_SLEEP);
3243f52228b8SJoe Beteta
3244f52228b8SJoe Beteta for (i = 0; i < skdev->num_req_context; i++) {
3245f52228b8SJoe Beteta struct skd_request_context *skreq;
3246f52228b8SJoe Beteta
3247f52228b8SJoe Beteta skreq = &skdev->skreq_table[i];
3248f52228b8SJoe Beteta
3249f52228b8SJoe Beteta skreq->id = (uint16_t)(i + SKD_ID_RW_REQUEST);
3250f52228b8SJoe Beteta skreq->state = SKD_REQ_STATE_IDLE;
3251f52228b8SJoe Beteta
3252f52228b8SJoe Beteta skreq->sksg_list = skd_cons_sg_list(skdev,
3253f52228b8SJoe Beteta skdev->sgs_per_request,
3254f52228b8SJoe Beteta &skreq->sksg_dma_address);
3255f52228b8SJoe Beteta
3256f52228b8SJoe Beteta if (NULL == skreq->sksg_list) {
3257f52228b8SJoe Beteta rc = -ENOMEM;
3258f52228b8SJoe Beteta goto err_out;
3259f52228b8SJoe Beteta }
3260f52228b8SJoe Beteta
3261f52228b8SJoe Beteta skreq->next = &skreq[1];
3262f52228b8SJoe Beteta }
3263f52228b8SJoe Beteta
3264f52228b8SJoe Beteta /* Free list is in order starting with the 0th entry. */
3265f52228b8SJoe Beteta skdev->skreq_table[i - 1].next = NULL;
3266f52228b8SJoe Beteta skdev->skreq_free_list = skdev->skreq_table;
3267f52228b8SJoe Beteta
3268f52228b8SJoe Beteta err_out:
3269f52228b8SJoe Beteta return (rc);
3270f52228b8SJoe Beteta }
3271f52228b8SJoe Beteta
3272f52228b8SJoe Beteta /*
3273f52228b8SJoe Beteta *
3274f52228b8SJoe Beteta * Name: skd_cons_sksb, allocates space for the skspcl msg buf
3275f52228b8SJoe Beteta * and data buf.
3276f52228b8SJoe Beteta *
3277f52228b8SJoe Beteta * Inputs: skdev - device state structure.
3278f52228b8SJoe Beteta *
3279f52228b8SJoe Beteta * Returns: -ENOMEM if no memory otherwise NULL.
3280f52228b8SJoe Beteta *
3281f52228b8SJoe Beteta */
3282f52228b8SJoe Beteta static int
skd_cons_sksb(struct skd_device * skdev)3283f52228b8SJoe Beteta skd_cons_sksb(struct skd_device *skdev)
3284f52228b8SJoe Beteta {
3285f52228b8SJoe Beteta int rc = 0;
3286f52228b8SJoe Beteta struct skd_special_context *skspcl;
3287f52228b8SJoe Beteta dma_mem_t *mem;
3288f52228b8SJoe Beteta uint32_t nbytes;
3289f52228b8SJoe Beteta
3290f52228b8SJoe Beteta skspcl = &skdev->internal_skspcl;
3291f52228b8SJoe Beteta
3292f52228b8SJoe Beteta skspcl->req.id = 0 + SKD_ID_INTERNAL;
3293f52228b8SJoe Beteta skspcl->req.state = SKD_REQ_STATE_IDLE;
3294f52228b8SJoe Beteta
3295f52228b8SJoe Beteta nbytes = SKD_N_INTERNAL_BYTES;
3296f52228b8SJoe Beteta
3297f52228b8SJoe Beteta mem = &skspcl->db_dma_address;
3298f52228b8SJoe Beteta mem->size = nbytes;
3299f52228b8SJoe Beteta
3300f52228b8SJoe Beteta /* data_buf's DMA pointer is skspcl->db_dma_address */
3301f52228b8SJoe Beteta skspcl->data_buf = skd_alloc_dma_mem(skdev, mem, ATYPE_64BIT);
3302f52228b8SJoe Beteta if (skspcl->data_buf == NULL) {
3303f52228b8SJoe Beteta rc = -ENOMEM;
3304f52228b8SJoe Beteta goto err_out;
3305f52228b8SJoe Beteta }
3306f52228b8SJoe Beteta
3307f52228b8SJoe Beteta bzero(skspcl->data_buf, nbytes);
3308f52228b8SJoe Beteta
3309f52228b8SJoe Beteta nbytes = SKD_N_SPECIAL_FITMSG_BYTES;
3310f52228b8SJoe Beteta
3311f52228b8SJoe Beteta mem = &skspcl->mb_dma_address;
3312f52228b8SJoe Beteta mem->size = nbytes;
3313f52228b8SJoe Beteta
3314f52228b8SJoe Beteta /* msg_buf DMA pointer is skspcl->mb_dma_address */
3315f52228b8SJoe Beteta skspcl->msg_buf = skd_alloc_dma_mem(skdev, mem, ATYPE_64BIT);
3316f52228b8SJoe Beteta if (skspcl->msg_buf == NULL) {
3317f52228b8SJoe Beteta rc = -ENOMEM;
3318f52228b8SJoe Beteta goto err_out;
3319f52228b8SJoe Beteta }
3320f52228b8SJoe Beteta
3321f52228b8SJoe Beteta
3322f52228b8SJoe Beteta bzero(skspcl->msg_buf, nbytes);
3323f52228b8SJoe Beteta
3324f52228b8SJoe Beteta skspcl->req.sksg_list = skd_cons_sg_list(skdev, 1,
3325f52228b8SJoe Beteta &skspcl->req.sksg_dma_address);
3326f52228b8SJoe Beteta
3327f52228b8SJoe Beteta
3328f52228b8SJoe Beteta if (skspcl->req.sksg_list == NULL) {
3329f52228b8SJoe Beteta rc = -ENOMEM;
3330f52228b8SJoe Beteta goto err_out;
3331f52228b8SJoe Beteta }
3332f52228b8SJoe Beteta
3333f52228b8SJoe Beteta if (skd_format_internal_skspcl(skdev) == 0) {
3334f52228b8SJoe Beteta rc = -EINVAL;
3335f52228b8SJoe Beteta goto err_out;
3336f52228b8SJoe Beteta }
3337f52228b8SJoe Beteta
3338f52228b8SJoe Beteta err_out:
3339f52228b8SJoe Beteta return (rc);
3340f52228b8SJoe Beteta }
3341f52228b8SJoe Beteta
3342f52228b8SJoe Beteta /*
3343f52228b8SJoe Beteta *
3344f52228b8SJoe Beteta * Name: skd_cons_sg_list, allocates the S/G list.
3345f52228b8SJoe Beteta *
3346f52228b8SJoe Beteta * Inputs: skdev - device state structure.
3347f52228b8SJoe Beteta * n_sg - Number of scatter-gather entries.
3348f52228b8SJoe Beteta * ret_dma_addr - S/G list DMA pointer.
3349f52228b8SJoe Beteta *
3350f52228b8SJoe Beteta * Returns: A list of FIT message descriptors.
3351f52228b8SJoe Beteta *
3352f52228b8SJoe Beteta */
3353f52228b8SJoe Beteta static struct fit_sg_descriptor
skd_cons_sg_list(struct skd_device * skdev,uint32_t n_sg,dma_mem_t * ret_dma_addr)3354f52228b8SJoe Beteta *skd_cons_sg_list(struct skd_device *skdev,
3355f52228b8SJoe Beteta uint32_t n_sg, dma_mem_t *ret_dma_addr)
3356f52228b8SJoe Beteta {
3357f52228b8SJoe Beteta struct fit_sg_descriptor *sg_list;
3358f52228b8SJoe Beteta uint32_t nbytes;
3359f52228b8SJoe Beteta dma_mem_t *mem;
3360f52228b8SJoe Beteta
3361f52228b8SJoe Beteta nbytes = sizeof (*sg_list) * n_sg;
3362f52228b8SJoe Beteta
3363f52228b8SJoe Beteta mem = ret_dma_addr;
3364f52228b8SJoe Beteta mem->size = nbytes;
3365f52228b8SJoe Beteta
3366f52228b8SJoe Beteta /* sg_list's DMA pointer is *ret_dma_addr */
3367f52228b8SJoe Beteta sg_list = skd_alloc_dma_mem(skdev, mem, ATYPE_32BIT);
3368f52228b8SJoe Beteta
3369f52228b8SJoe Beteta if (sg_list != NULL) {
3370f52228b8SJoe Beteta uint64_t dma_address = ret_dma_addr->cookie.dmac_laddress;
3371f52228b8SJoe Beteta uint32_t i;
3372f52228b8SJoe Beteta
3373f52228b8SJoe Beteta bzero(sg_list, nbytes);
3374f52228b8SJoe Beteta
3375f52228b8SJoe Beteta for (i = 0; i < n_sg - 1; i++) {
3376f52228b8SJoe Beteta uint64_t ndp_off;
3377f52228b8SJoe Beteta ndp_off = (i + 1) * sizeof (struct fit_sg_descriptor);
3378f52228b8SJoe Beteta
3379f52228b8SJoe Beteta sg_list[i].next_desc_ptr = dma_address + ndp_off;
3380f52228b8SJoe Beteta }
3381f52228b8SJoe Beteta sg_list[i].next_desc_ptr = 0LL;
3382f52228b8SJoe Beteta }
3383f52228b8SJoe Beteta
3384f52228b8SJoe Beteta return (sg_list);
3385f52228b8SJoe Beteta }
3386f52228b8SJoe Beteta
3387f52228b8SJoe Beteta /*
3388f52228b8SJoe Beteta * DESTRUCT (FREE)
3389f52228b8SJoe Beteta */
3390f52228b8SJoe Beteta
3391f52228b8SJoe Beteta static void skd_free_skcomp(struct skd_device *skdev);
3392f52228b8SJoe Beteta static void skd_free_skmsg(struct skd_device *skdev);
3393f52228b8SJoe Beteta static void skd_free_skreq(struct skd_device *skdev);
3394f52228b8SJoe Beteta static void skd_free_sksb(struct skd_device *skdev);
3395f52228b8SJoe Beteta
3396f52228b8SJoe Beteta static void skd_free_sg_list(struct skd_device *skdev,
3397f52228b8SJoe Beteta struct fit_sg_descriptor *sg_list,
3398f52228b8SJoe Beteta uint32_t n_sg, dma_mem_t dma_addr);
3399f52228b8SJoe Beteta
3400f52228b8SJoe Beteta /*
3401f52228b8SJoe Beteta *
3402f52228b8SJoe Beteta * Name: skd_destruct, call various rouines to deallocate
3403f52228b8SJoe Beteta * space acquired during initialization.
3404f52228b8SJoe Beteta *
3405f52228b8SJoe Beteta * Inputs: skdev - device state structure.
3406f52228b8SJoe Beteta *
3407f52228b8SJoe Beteta * Returns: Nothing.
3408f52228b8SJoe Beteta *
3409f52228b8SJoe Beteta */
3410f52228b8SJoe Beteta static void
skd_destruct(struct skd_device * skdev)3411f52228b8SJoe Beteta skd_destruct(struct skd_device *skdev)
3412f52228b8SJoe Beteta {
3413f52228b8SJoe Beteta if (skdev == NULL) {
3414f52228b8SJoe Beteta return;
3415f52228b8SJoe Beteta }
3416f52228b8SJoe Beteta
3417f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "destruct sksb");
3418f52228b8SJoe Beteta skd_free_sksb(skdev);
3419f52228b8SJoe Beteta
3420f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "destruct skreq");
3421f52228b8SJoe Beteta skd_free_skreq(skdev);
3422f52228b8SJoe Beteta
3423f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "destruct skmsg");
3424f52228b8SJoe Beteta skd_free_skmsg(skdev);
3425f52228b8SJoe Beteta
3426f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "destruct skcomp");
3427f52228b8SJoe Beteta skd_free_skcomp(skdev);
3428f52228b8SJoe Beteta
3429f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "DESTRUCT VICTORY");
3430f52228b8SJoe Beteta }
3431f52228b8SJoe Beteta
3432f52228b8SJoe Beteta /*
3433f52228b8SJoe Beteta *
3434f52228b8SJoe Beteta * Name: skd_free_skcomp, deallocates skcomp table DMA resources.
3435f52228b8SJoe Beteta *
3436f52228b8SJoe Beteta * Inputs: skdev - device state structure.
3437f52228b8SJoe Beteta *
3438f52228b8SJoe Beteta * Returns: Nothing.
3439f52228b8SJoe Beteta *
3440f52228b8SJoe Beteta */
3441f52228b8SJoe Beteta static void
skd_free_skcomp(struct skd_device * skdev)3442f52228b8SJoe Beteta skd_free_skcomp(struct skd_device *skdev)
3443f52228b8SJoe Beteta {
3444f52228b8SJoe Beteta if (skdev->skcomp_table != NULL) {
3445f52228b8SJoe Beteta skd_free_phys(skdev, &skdev->cq_dma_address);
3446f52228b8SJoe Beteta }
3447f52228b8SJoe Beteta
3448f52228b8SJoe Beteta skdev->skcomp_table = NULL;
3449f52228b8SJoe Beteta }
3450f52228b8SJoe Beteta
3451f52228b8SJoe Beteta /*
3452f52228b8SJoe Beteta *
3453f52228b8SJoe Beteta * Name: skd_free_skmsg, deallocates skmsg table DMA resources.
3454f52228b8SJoe Beteta *
3455f52228b8SJoe Beteta * Inputs: skdev - device state structure.
3456f52228b8SJoe Beteta *
3457f52228b8SJoe Beteta * Returns: Nothing.
3458f52228b8SJoe Beteta *
3459f52228b8SJoe Beteta */
3460f52228b8SJoe Beteta static void
skd_free_skmsg(struct skd_device * skdev)3461f52228b8SJoe Beteta skd_free_skmsg(struct skd_device *skdev)
3462f52228b8SJoe Beteta {
3463f52228b8SJoe Beteta uint32_t i;
3464f52228b8SJoe Beteta
3465f52228b8SJoe Beteta if (NULL == skdev->skmsg_table)
3466f52228b8SJoe Beteta return;
3467f52228b8SJoe Beteta
3468f52228b8SJoe Beteta for (i = 0; i < skdev->num_fitmsg_context; i++) {
3469f52228b8SJoe Beteta struct skd_fitmsg_context *skmsg;
3470f52228b8SJoe Beteta
3471f52228b8SJoe Beteta skmsg = &skdev->skmsg_table[i];
3472f52228b8SJoe Beteta
3473f52228b8SJoe Beteta if (skmsg->msg_buf != NULL) {
3474f52228b8SJoe Beteta skd_free_phys(skdev, &skmsg->mb_dma_address);
3475f52228b8SJoe Beteta }
3476f52228b8SJoe Beteta
3477f52228b8SJoe Beteta
3478f52228b8SJoe Beteta skmsg->msg_buf = NULL;
3479f52228b8SJoe Beteta }
3480f52228b8SJoe Beteta
3481f52228b8SJoe Beteta kmem_free(skdev->skmsg_table, sizeof (struct skd_fitmsg_context) *
3482f52228b8SJoe Beteta skdev->num_fitmsg_context);
3483f52228b8SJoe Beteta
3484f52228b8SJoe Beteta skdev->skmsg_table = NULL;
3485f52228b8SJoe Beteta
3486f52228b8SJoe Beteta }
3487f52228b8SJoe Beteta
3488f52228b8SJoe Beteta /*
3489f52228b8SJoe Beteta *
3490f52228b8SJoe Beteta * Name: skd_free_skreq, deallocates skspcl table DMA resources.
3491f52228b8SJoe Beteta *
3492f52228b8SJoe Beteta * Inputs: skdev - device state structure.
3493f52228b8SJoe Beteta *
3494f52228b8SJoe Beteta * Returns: Nothing.
3495f52228b8SJoe Beteta *
3496f52228b8SJoe Beteta */
3497f52228b8SJoe Beteta static void
skd_free_skreq(struct skd_device * skdev)3498f52228b8SJoe Beteta skd_free_skreq(struct skd_device *skdev)
3499f52228b8SJoe Beteta {
3500f52228b8SJoe Beteta uint32_t i;
3501f52228b8SJoe Beteta
3502f52228b8SJoe Beteta if (NULL == skdev->skreq_table)
3503f52228b8SJoe Beteta return;
3504f52228b8SJoe Beteta
3505f52228b8SJoe Beteta for (i = 0; i < skdev->num_req_context; i++) {
3506f52228b8SJoe Beteta struct skd_request_context *skreq;
3507f52228b8SJoe Beteta
3508f52228b8SJoe Beteta skreq = &skdev->skreq_table[i];
3509f52228b8SJoe Beteta
3510f52228b8SJoe Beteta skd_free_sg_list(skdev, skreq->sksg_list,
3511f52228b8SJoe Beteta skdev->sgs_per_request, skreq->sksg_dma_address);
3512f52228b8SJoe Beteta
3513f52228b8SJoe Beteta skreq->sksg_list = NULL;
3514f52228b8SJoe Beteta }
3515f52228b8SJoe Beteta
3516f52228b8SJoe Beteta kmem_free(skdev->skreq_table, sizeof (struct skd_request_context) *
3517f52228b8SJoe Beteta skdev->num_req_context);
3518f52228b8SJoe Beteta
3519f52228b8SJoe Beteta skdev->skreq_table = NULL;
3520f52228b8SJoe Beteta
3521f52228b8SJoe Beteta }
3522f52228b8SJoe Beteta
3523f52228b8SJoe Beteta /*
3524f52228b8SJoe Beteta *
3525f52228b8SJoe Beteta * Name: skd_free_sksb, deallocates skspcl data buf and
3526f52228b8SJoe Beteta * msg buf DMA resources.
3527f52228b8SJoe Beteta *
3528f52228b8SJoe Beteta * Inputs: skdev - device state structure.
3529f52228b8SJoe Beteta *
3530f52228b8SJoe Beteta * Returns: Nothing.
3531f52228b8SJoe Beteta *
3532f52228b8SJoe Beteta */
3533f52228b8SJoe Beteta static void
skd_free_sksb(struct skd_device * skdev)3534f52228b8SJoe Beteta skd_free_sksb(struct skd_device *skdev)
3535f52228b8SJoe Beteta {
3536f52228b8SJoe Beteta struct skd_special_context *skspcl;
3537f52228b8SJoe Beteta
3538f52228b8SJoe Beteta skspcl = &skdev->internal_skspcl;
3539f52228b8SJoe Beteta
3540f52228b8SJoe Beteta if (skspcl->data_buf != NULL) {
3541f52228b8SJoe Beteta skd_free_phys(skdev, &skspcl->db_dma_address);
3542f52228b8SJoe Beteta }
3543f52228b8SJoe Beteta
3544f52228b8SJoe Beteta skspcl->data_buf = NULL;
3545f52228b8SJoe Beteta
3546f52228b8SJoe Beteta if (skspcl->msg_buf != NULL) {
3547f52228b8SJoe Beteta skd_free_phys(skdev, &skspcl->mb_dma_address);
3548f52228b8SJoe Beteta }
3549f52228b8SJoe Beteta
3550f52228b8SJoe Beteta skspcl->msg_buf = NULL;
3551f52228b8SJoe Beteta
3552f52228b8SJoe Beteta skd_free_sg_list(skdev, skspcl->req.sksg_list, 1,
3553f52228b8SJoe Beteta skspcl->req.sksg_dma_address);
3554f52228b8SJoe Beteta
3555f52228b8SJoe Beteta skspcl->req.sksg_list = NULL;
3556f52228b8SJoe Beteta }
3557f52228b8SJoe Beteta
3558f52228b8SJoe Beteta /*
3559f52228b8SJoe Beteta *
3560f52228b8SJoe Beteta * Name: skd_free_sg_list, deallocates S/G DMA resources.
3561f52228b8SJoe Beteta *
3562f52228b8SJoe Beteta * Inputs: skdev - device state structure.
3563f52228b8SJoe Beteta * sg_list - S/G list itself.
3564f52228b8SJoe Beteta * n_sg - nukmber of segments
3565f52228b8SJoe Beteta * dma_addr - S/G list DMA address.
3566f52228b8SJoe Beteta *
3567f52228b8SJoe Beteta * Returns: Nothing.
3568f52228b8SJoe Beteta *
3569f52228b8SJoe Beteta */
3570f52228b8SJoe Beteta /* ARGSUSED */ /* Upstream common source with other platforms. */
3571f52228b8SJoe Beteta static void
skd_free_sg_list(struct skd_device * skdev,struct fit_sg_descriptor * sg_list,uint32_t n_sg,dma_mem_t dma_addr)3572f52228b8SJoe Beteta skd_free_sg_list(struct skd_device *skdev,
3573f52228b8SJoe Beteta struct fit_sg_descriptor *sg_list,
3574f52228b8SJoe Beteta uint32_t n_sg, dma_mem_t dma_addr)
3575f52228b8SJoe Beteta {
3576f52228b8SJoe Beteta if (sg_list != NULL) {
3577f52228b8SJoe Beteta skd_free_phys(skdev, &dma_addr);
3578f52228b8SJoe Beteta }
3579f52228b8SJoe Beteta }
3580f52228b8SJoe Beteta
3581f52228b8SJoe Beteta /*
3582f52228b8SJoe Beteta *
3583f52228b8SJoe Beteta * Name: skd_queue, queues the I/O request.
3584f52228b8SJoe Beteta *
3585f52228b8SJoe Beteta * Inputs: skdev - device state structure.
3586f52228b8SJoe Beteta * pbuf - I/O request
3587f52228b8SJoe Beteta *
3588f52228b8SJoe Beteta * Returns: Nothing.
3589f52228b8SJoe Beteta *
3590f52228b8SJoe Beteta */
3591f52228b8SJoe Beteta static void
skd_queue(skd_device_t * skdev,skd_buf_private_t * pbuf)3592f52228b8SJoe Beteta skd_queue(skd_device_t *skdev, skd_buf_private_t *pbuf)
3593f52228b8SJoe Beteta {
3594f52228b8SJoe Beteta struct waitqueue *waitq;
3595f52228b8SJoe Beteta
3596f52228b8SJoe Beteta ASSERT(skdev != NULL);
3597f52228b8SJoe Beteta ASSERT(pbuf != NULL);
3598f52228b8SJoe Beteta
3599f52228b8SJoe Beteta ASSERT(WAITQ_LOCK_HELD(skdev));
3600f52228b8SJoe Beteta
3601f52228b8SJoe Beteta waitq = &skdev->waitqueue;
3602f52228b8SJoe Beteta
3603f52228b8SJoe Beteta if (SIMPLEQ_EMPTY(waitq))
3604f52228b8SJoe Beteta SIMPLEQ_INSERT_HEAD(waitq, pbuf, sq);
3605f52228b8SJoe Beteta else
3606f52228b8SJoe Beteta SIMPLEQ_INSERT_TAIL(waitq, pbuf, sq);
3607f52228b8SJoe Beteta }
3608f52228b8SJoe Beteta
3609f52228b8SJoe Beteta /*
3610f52228b8SJoe Beteta *
3611f52228b8SJoe Beteta * Name: skd_list_skreq, displays the skreq table entries.
3612f52228b8SJoe Beteta *
3613f52228b8SJoe Beteta * Inputs: skdev - device state structure.
3614f52228b8SJoe Beteta * list - flag, if true displays the entry address.
3615f52228b8SJoe Beteta *
3616f52228b8SJoe Beteta * Returns: Returns number of skmsg entries found.
3617f52228b8SJoe Beteta *
3618f52228b8SJoe Beteta */
3619f52228b8SJoe Beteta /* ARGSUSED */ /* Upstream common source with other platforms. */
3620f52228b8SJoe Beteta static int
skd_list_skreq(skd_device_t * skdev,int list)3621f52228b8SJoe Beteta skd_list_skreq(skd_device_t *skdev, int list)
3622f52228b8SJoe Beteta {
3623f52228b8SJoe Beteta int inx = 0;
3624f52228b8SJoe Beteta struct skd_request_context *skreq;
3625f52228b8SJoe Beteta
3626f52228b8SJoe Beteta if (list) {
3627f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "skreq_table[0]\n");
3628f52228b8SJoe Beteta
3629f52228b8SJoe Beteta skreq = &skdev->skreq_table[0];
3630f52228b8SJoe Beteta while (skreq) {
3631f52228b8SJoe Beteta if (list)
3632f52228b8SJoe Beteta Dcmn_err(CE_NOTE,
3633f52228b8SJoe Beteta "%d: skreq=%p state=%d id=%x fid=%x "
3634f52228b8SJoe Beteta "pbuf=%p dir=%d comp=%d\n",
3635f52228b8SJoe Beteta inx, (void *)skreq, skreq->state,
3636f52228b8SJoe Beteta skreq->id, skreq->fitmsg_id,
3637f52228b8SJoe Beteta (void *)skreq->pbuf,
3638f52228b8SJoe Beteta skreq->sg_data_dir, skreq->did_complete);
3639f52228b8SJoe Beteta inx++;
3640f52228b8SJoe Beteta skreq = skreq->next;
3641f52228b8SJoe Beteta }
3642f52228b8SJoe Beteta }
3643f52228b8SJoe Beteta
3644f52228b8SJoe Beteta inx = 0;
3645f52228b8SJoe Beteta skreq = skdev->skreq_free_list;
3646f52228b8SJoe Beteta
3647f52228b8SJoe Beteta if (list)
3648f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "skreq_free_list\n");
3649f52228b8SJoe Beteta while (skreq) {
3650f52228b8SJoe Beteta if (list)
3651f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "%d: skreq=%p state=%d id=%x fid=%x "
3652f52228b8SJoe Beteta "pbuf=%p dir=%d\n", inx, (void *)skreq,
3653f52228b8SJoe Beteta skreq->state, skreq->id, skreq->fitmsg_id,
3654f52228b8SJoe Beteta (void *)skreq->pbuf, skreq->sg_data_dir);
3655f52228b8SJoe Beteta inx++;
3656f52228b8SJoe Beteta skreq = skreq->next;
3657f52228b8SJoe Beteta }
3658f52228b8SJoe Beteta
3659f52228b8SJoe Beteta return (inx);
3660f52228b8SJoe Beteta }
3661f52228b8SJoe Beteta
3662f52228b8SJoe Beteta /*
3663f52228b8SJoe Beteta *
3664f52228b8SJoe Beteta * Name: skd_list_skmsg, displays the skmsg table entries.
3665f52228b8SJoe Beteta *
3666f52228b8SJoe Beteta * Inputs: skdev - device state structure.
3667f52228b8SJoe Beteta * list - flag, if true displays the entry address.
3668f52228b8SJoe Beteta *
3669f52228b8SJoe Beteta * Returns: Returns number of skmsg entries found.
3670f52228b8SJoe Beteta *
3671f52228b8SJoe Beteta */
3672f52228b8SJoe Beteta static int
skd_list_skmsg(skd_device_t * skdev,int list)3673f52228b8SJoe Beteta skd_list_skmsg(skd_device_t *skdev, int list)
3674f52228b8SJoe Beteta {
3675f52228b8SJoe Beteta int inx = 0;
3676f52228b8SJoe Beteta struct skd_fitmsg_context *skmsgp;
3677f52228b8SJoe Beteta
3678f52228b8SJoe Beteta skmsgp = &skdev->skmsg_table[0];
3679f52228b8SJoe Beteta
3680f52228b8SJoe Beteta if (list) {
3681f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "skmsg_table[0]\n");
3682f52228b8SJoe Beteta
3683f52228b8SJoe Beteta while (skmsgp) {
3684f52228b8SJoe Beteta if (list)
3685f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "%d: skmsgp=%p id=%x outs=%d "
3686f52228b8SJoe Beteta "l=%d o=%d nxt=%p\n", inx, (void *)skmsgp,
3687f52228b8SJoe Beteta skmsgp->id, skmsgp->outstanding,
3688f52228b8SJoe Beteta skmsgp->length, skmsgp->offset,
3689f52228b8SJoe Beteta (void *)skmsgp->next);
3690f52228b8SJoe Beteta inx++;
3691f52228b8SJoe Beteta skmsgp = skmsgp->next;
3692f52228b8SJoe Beteta }
3693f52228b8SJoe Beteta }
3694f52228b8SJoe Beteta
3695f52228b8SJoe Beteta inx = 0;
3696f52228b8SJoe Beteta if (list)
3697f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "skmsg_free_list\n");
3698f52228b8SJoe Beteta skmsgp = skdev->skmsg_free_list;
3699f52228b8SJoe Beteta while (skmsgp) {
3700f52228b8SJoe Beteta if (list)
3701f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "%d: skmsgp=%p id=%x outs=%d l=%d "
3702f52228b8SJoe Beteta "o=%d nxt=%p\n",
3703f52228b8SJoe Beteta inx, (void *)skmsgp, skmsgp->id,
3704f52228b8SJoe Beteta skmsgp->outstanding, skmsgp->length,
3705f52228b8SJoe Beteta skmsgp->offset, (void *)skmsgp->next);
3706f52228b8SJoe Beteta inx++;
3707f52228b8SJoe Beteta skmsgp = skmsgp->next;
3708f52228b8SJoe Beteta }
3709f52228b8SJoe Beteta
3710f52228b8SJoe Beteta return (inx);
3711f52228b8SJoe Beteta }
3712f52228b8SJoe Beteta
3713f52228b8SJoe Beteta /*
3714f52228b8SJoe Beteta *
3715f52228b8SJoe Beteta * Name: skd_get_queue_pbuf, retrieves top of queue entry and
3716f52228b8SJoe Beteta * delinks entry from the queue.
3717f52228b8SJoe Beteta *
3718f52228b8SJoe Beteta * Inputs: skdev - device state structure.
3719f52228b8SJoe Beteta * drive - device number
3720f52228b8SJoe Beteta *
3721f52228b8SJoe Beteta * Returns: Returns the top of the job queue entry.
3722f52228b8SJoe Beteta *
3723f52228b8SJoe Beteta */
3724f52228b8SJoe Beteta static skd_buf_private_t
skd_get_queued_pbuf(skd_device_t * skdev)3725f52228b8SJoe Beteta *skd_get_queued_pbuf(skd_device_t *skdev)
3726f52228b8SJoe Beteta {
3727f52228b8SJoe Beteta skd_buf_private_t *pbuf;
3728f52228b8SJoe Beteta
3729f52228b8SJoe Beteta ASSERT(WAITQ_LOCK_HELD(skdev));
3730f52228b8SJoe Beteta pbuf = SIMPLEQ_FIRST(&skdev->waitqueue);
3731f52228b8SJoe Beteta if (pbuf != NULL)
3732f52228b8SJoe Beteta SIMPLEQ_REMOVE_HEAD(&skdev->waitqueue, sq);
3733f52228b8SJoe Beteta return (pbuf);
3734f52228b8SJoe Beteta }
3735f52228b8SJoe Beteta
3736f52228b8SJoe Beteta /*
3737f52228b8SJoe Beteta * PCI DRIVER GLUE
3738f52228b8SJoe Beteta */
3739f52228b8SJoe Beteta
3740f52228b8SJoe Beteta /*
3741f52228b8SJoe Beteta *
3742f52228b8SJoe Beteta * Name: skd_pci_info, logs certain device PCI info.
3743f52228b8SJoe Beteta *
3744f52228b8SJoe Beteta * Inputs: skdev - device state structure.
3745f52228b8SJoe Beteta *
3746f52228b8SJoe Beteta * Returns: str which contains the device speed info..
3747f52228b8SJoe Beteta *
3748f52228b8SJoe Beteta */
3749f52228b8SJoe Beteta static char *
skd_pci_info(struct skd_device * skdev,char * str,size_t len)3750f52228b8SJoe Beteta skd_pci_info(struct skd_device *skdev, char *str, size_t len)
3751f52228b8SJoe Beteta {
3752f52228b8SJoe Beteta int pcie_reg;
3753f52228b8SJoe Beteta
3754f52228b8SJoe Beteta str[0] = '\0';
3755f52228b8SJoe Beteta
3756f52228b8SJoe Beteta pcie_reg = skd_pci_find_capability(skdev, PCI_CAP_ID_EXP);
3757f52228b8SJoe Beteta
3758f52228b8SJoe Beteta if (pcie_reg) {
3759f52228b8SJoe Beteta uint16_t lstat, lspeed, lwidth;
3760f52228b8SJoe Beteta
3761f52228b8SJoe Beteta pcie_reg += 0x12;
3762f52228b8SJoe Beteta lstat = pci_config_get16(skdev->pci_handle, pcie_reg);
3763f52228b8SJoe Beteta lspeed = lstat & (0xF);
3764f52228b8SJoe Beteta lwidth = (lstat & 0x3F0) >> 4;
3765f52228b8SJoe Beteta
3766f52228b8SJoe Beteta (void) snprintf(str, len, "PCIe (%s rev %d)",
3767f52228b8SJoe Beteta lspeed == 1 ? "2.5GT/s" :
3768f52228b8SJoe Beteta lspeed == 2 ? "5.0GT/s" : "<unknown>",
3769f52228b8SJoe Beteta lwidth);
3770f52228b8SJoe Beteta }
3771f52228b8SJoe Beteta
3772f52228b8SJoe Beteta return (str);
3773f52228b8SJoe Beteta }
3774f52228b8SJoe Beteta
3775f52228b8SJoe Beteta /*
3776f52228b8SJoe Beteta * MODULE GLUE
3777f52228b8SJoe Beteta */
3778f52228b8SJoe Beteta
3779f52228b8SJoe Beteta /*
3780f52228b8SJoe Beteta *
3781f52228b8SJoe Beteta * Name: skd_init, initializes certain values.
3782f52228b8SJoe Beteta *
3783f52228b8SJoe Beteta * Inputs: skdev - device state structure.
3784f52228b8SJoe Beteta *
3785f52228b8SJoe Beteta * Returns: Zero.
3786f52228b8SJoe Beteta *
3787f52228b8SJoe Beteta */
3788f52228b8SJoe Beteta /* ARGSUSED */ /* Upstream common source with other platforms. */
3789f52228b8SJoe Beteta static int
skd_init(skd_device_t * skdev)3790f52228b8SJoe Beteta skd_init(skd_device_t *skdev)
3791f52228b8SJoe Beteta {
3792f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "skd_init: v%s-b%s\n", DRV_VERSION, DRV_BUILD_ID);
3793f52228b8SJoe Beteta
3794f52228b8SJoe Beteta if (skd_max_queue_depth < 1 ||
3795f52228b8SJoe Beteta skd_max_queue_depth > SKD_MAX_QUEUE_DEPTH) {
3796f52228b8SJoe Beteta cmn_err(CE_NOTE, "skd_max_q_depth %d invalid, re-set to %d\n",
3797f52228b8SJoe Beteta skd_max_queue_depth, SKD_MAX_QUEUE_DEPTH_DEFAULT);
3798f52228b8SJoe Beteta skd_max_queue_depth = SKD_MAX_QUEUE_DEPTH_DEFAULT;
3799f52228b8SJoe Beteta }
3800f52228b8SJoe Beteta
3801f52228b8SJoe Beteta if (skd_max_req_per_msg < 1 || skd_max_req_per_msg > 14) {
3802f52228b8SJoe Beteta cmn_err(CE_NOTE, "skd_max_req_per_msg %d invalid, set to %d\n",
3803f52228b8SJoe Beteta skd_max_req_per_msg, SKD_MAX_REQ_PER_MSG_DEFAULT);
3804f52228b8SJoe Beteta skd_max_req_per_msg = SKD_MAX_REQ_PER_MSG_DEFAULT;
3805f52228b8SJoe Beteta }
3806f52228b8SJoe Beteta
3807f52228b8SJoe Beteta
3808f52228b8SJoe Beteta if (skd_sgs_per_request < 1 || skd_sgs_per_request > 4096) {
3809f52228b8SJoe Beteta cmn_err(CE_NOTE, "skd_sg_per_request %d invalid, set to %d\n",
3810f52228b8SJoe Beteta skd_sgs_per_request, SKD_N_SG_PER_REQ_DEFAULT);
3811f52228b8SJoe Beteta skd_sgs_per_request = SKD_N_SG_PER_REQ_DEFAULT;
3812f52228b8SJoe Beteta }
3813f52228b8SJoe Beteta
3814f52228b8SJoe Beteta if (skd_dbg_level < 0 || skd_dbg_level > 2) {
3815f52228b8SJoe Beteta cmn_err(CE_NOTE, "skd_dbg_level %d invalid, re-set to %d\n",
3816f52228b8SJoe Beteta skd_dbg_level, 0);
3817f52228b8SJoe Beteta skd_dbg_level = 0;
3818f52228b8SJoe Beteta }
3819f52228b8SJoe Beteta
3820f52228b8SJoe Beteta return (0);
3821f52228b8SJoe Beteta }
3822f52228b8SJoe Beteta
3823f52228b8SJoe Beteta /*
3824f52228b8SJoe Beteta *
3825f52228b8SJoe Beteta * Name: skd_exit, exits the driver & logs the fact.
3826f52228b8SJoe Beteta *
3827f52228b8SJoe Beteta * Inputs: none.
3828f52228b8SJoe Beteta *
3829f52228b8SJoe Beteta * Returns: Nothing.
3830f52228b8SJoe Beteta *
3831f52228b8SJoe Beteta */
3832f52228b8SJoe Beteta static void
skd_exit(void)3833f52228b8SJoe Beteta skd_exit(void)
3834f52228b8SJoe Beteta {
3835f52228b8SJoe Beteta cmn_err(CE_NOTE, "skd v%s unloading", DRV_VERSION);
3836f52228b8SJoe Beteta }
3837f52228b8SJoe Beteta
3838f52228b8SJoe Beteta /*
3839f52228b8SJoe Beteta *
3840f52228b8SJoe Beteta * Name: skd_drive_state_to_str, converts binary drive state
3841f52228b8SJoe Beteta * to its corresponding string value.
3842f52228b8SJoe Beteta *
3843f52228b8SJoe Beteta * Inputs: Drive state.
3844f52228b8SJoe Beteta *
3845f52228b8SJoe Beteta * Returns: String representing drive state.
3846f52228b8SJoe Beteta *
3847f52228b8SJoe Beteta */
3848f52228b8SJoe Beteta const char *
skd_drive_state_to_str(int state)3849f52228b8SJoe Beteta skd_drive_state_to_str(int state)
3850f52228b8SJoe Beteta {
3851f52228b8SJoe Beteta switch (state) {
3852f52228b8SJoe Beteta case FIT_SR_DRIVE_OFFLINE: return ("OFFLINE");
3853f52228b8SJoe Beteta case FIT_SR_DRIVE_INIT: return ("INIT");
3854f52228b8SJoe Beteta case FIT_SR_DRIVE_ONLINE: return ("ONLINE");
3855f52228b8SJoe Beteta case FIT_SR_DRIVE_BUSY: return ("BUSY");
3856f52228b8SJoe Beteta case FIT_SR_DRIVE_FAULT: return ("FAULT");
3857f52228b8SJoe Beteta case FIT_SR_DRIVE_DEGRADED: return ("DEGRADED");
3858f52228b8SJoe Beteta case FIT_SR_PCIE_LINK_DOWN: return ("LINK_DOWN");
3859f52228b8SJoe Beteta case FIT_SR_DRIVE_SOFT_RESET: return ("SOFT_RESET");
3860f52228b8SJoe Beteta case FIT_SR_DRIVE_NEED_FW_DOWNLOAD: return ("NEED_FW");
3861f52228b8SJoe Beteta case FIT_SR_DRIVE_INIT_FAULT: return ("INIT_FAULT");
3862f52228b8SJoe Beteta case FIT_SR_DRIVE_BUSY_SANITIZE:return ("BUSY_SANITIZE");
3863f52228b8SJoe Beteta case FIT_SR_DRIVE_BUSY_ERASE: return ("BUSY_ERASE");
3864f52228b8SJoe Beteta case FIT_SR_DRIVE_FW_BOOTING: return ("FW_BOOTING");
3865f52228b8SJoe Beteta default: return ("???");
3866f52228b8SJoe Beteta }
3867f52228b8SJoe Beteta }
3868f52228b8SJoe Beteta
3869f52228b8SJoe Beteta /*
3870f52228b8SJoe Beteta *
3871f52228b8SJoe Beteta * Name: skd_skdev_state_to_str, converts binary driver state
3872f52228b8SJoe Beteta * to its corresponding string value.
3873f52228b8SJoe Beteta *
3874f52228b8SJoe Beteta * Inputs: Driver state.
3875f52228b8SJoe Beteta *
3876f52228b8SJoe Beteta * Returns: String representing driver state.
3877f52228b8SJoe Beteta *
3878f52228b8SJoe Beteta */
3879f52228b8SJoe Beteta static const char *
skd_skdev_state_to_str(enum skd_drvr_state state)3880f52228b8SJoe Beteta skd_skdev_state_to_str(enum skd_drvr_state state)
3881f52228b8SJoe Beteta {
3882f52228b8SJoe Beteta switch (state) {
3883f52228b8SJoe Beteta case SKD_DRVR_STATE_LOAD: return ("LOAD");
3884f52228b8SJoe Beteta case SKD_DRVR_STATE_IDLE: return ("IDLE");
3885f52228b8SJoe Beteta case SKD_DRVR_STATE_BUSY: return ("BUSY");
3886f52228b8SJoe Beteta case SKD_DRVR_STATE_STARTING: return ("STARTING");
3887f52228b8SJoe Beteta case SKD_DRVR_STATE_ONLINE: return ("ONLINE");
3888f52228b8SJoe Beteta case SKD_DRVR_STATE_PAUSING: return ("PAUSING");
3889f52228b8SJoe Beteta case SKD_DRVR_STATE_PAUSED: return ("PAUSED");
3890f52228b8SJoe Beteta case SKD_DRVR_STATE_DRAINING_TIMEOUT: return ("DRAINING_TIMEOUT");
3891f52228b8SJoe Beteta case SKD_DRVR_STATE_RESTARTING: return ("RESTARTING");
3892f52228b8SJoe Beteta case SKD_DRVR_STATE_RESUMING: return ("RESUMING");
3893f52228b8SJoe Beteta case SKD_DRVR_STATE_STOPPING: return ("STOPPING");
3894f52228b8SJoe Beteta case SKD_DRVR_STATE_SYNCING: return ("SYNCING");
3895f52228b8SJoe Beteta case SKD_DRVR_STATE_FAULT: return ("FAULT");
3896f52228b8SJoe Beteta case SKD_DRVR_STATE_DISAPPEARED: return ("DISAPPEARED");
3897f52228b8SJoe Beteta case SKD_DRVR_STATE_BUSY_ERASE: return ("BUSY_ERASE");
3898f52228b8SJoe Beteta case SKD_DRVR_STATE_BUSY_SANITIZE:return ("BUSY_SANITIZE");
3899f52228b8SJoe Beteta case SKD_DRVR_STATE_BUSY_IMMINENT: return ("BUSY_IMMINENT");
3900f52228b8SJoe Beteta case SKD_DRVR_STATE_WAIT_BOOT: return ("WAIT_BOOT");
3901f52228b8SJoe Beteta
3902f52228b8SJoe Beteta default: return ("???");
3903f52228b8SJoe Beteta }
3904f52228b8SJoe Beteta }
3905f52228b8SJoe Beteta
3906f52228b8SJoe Beteta /*
3907f52228b8SJoe Beteta *
3908f52228b8SJoe Beteta * Name: skd_skmsg_state_to_str, converts binary driver state
3909f52228b8SJoe Beteta * to its corresponding string value.
3910f52228b8SJoe Beteta *
3911f52228b8SJoe Beteta * Inputs: Msg state.
3912f52228b8SJoe Beteta *
3913f52228b8SJoe Beteta * Returns: String representing msg state.
3914f52228b8SJoe Beteta *
3915f52228b8SJoe Beteta */
3916f52228b8SJoe Beteta static const char *
skd_skmsg_state_to_str(enum skd_fit_msg_state state)3917f52228b8SJoe Beteta skd_skmsg_state_to_str(enum skd_fit_msg_state state)
3918f52228b8SJoe Beteta {
3919f52228b8SJoe Beteta switch (state) {
3920f52228b8SJoe Beteta case SKD_MSG_STATE_IDLE: return ("IDLE");
3921f52228b8SJoe Beteta case SKD_MSG_STATE_BUSY: return ("BUSY");
3922f52228b8SJoe Beteta default: return ("???");
3923f52228b8SJoe Beteta }
3924f52228b8SJoe Beteta }
3925f52228b8SJoe Beteta
3926f52228b8SJoe Beteta /*
3927f52228b8SJoe Beteta *
3928f52228b8SJoe Beteta * Name: skd_skreq_state_to_str, converts binary req state
3929f52228b8SJoe Beteta * to its corresponding string value.
3930f52228b8SJoe Beteta *
3931f52228b8SJoe Beteta * Inputs: Req state.
3932f52228b8SJoe Beteta *
3933f52228b8SJoe Beteta * Returns: String representing req state.
3934f52228b8SJoe Beteta *
3935f52228b8SJoe Beteta */
3936f52228b8SJoe Beteta static const char *
skd_skreq_state_to_str(enum skd_req_state state)3937f52228b8SJoe Beteta skd_skreq_state_to_str(enum skd_req_state state)
3938f52228b8SJoe Beteta {
3939f52228b8SJoe Beteta switch (state) {
3940f52228b8SJoe Beteta case SKD_REQ_STATE_IDLE: return ("IDLE");
3941f52228b8SJoe Beteta case SKD_REQ_STATE_SETUP: return ("SETUP");
3942f52228b8SJoe Beteta case SKD_REQ_STATE_BUSY: return ("BUSY");
3943f52228b8SJoe Beteta case SKD_REQ_STATE_COMPLETED: return ("COMPLETED");
3944f52228b8SJoe Beteta case SKD_REQ_STATE_TIMEOUT: return ("TIMEOUT");
3945f52228b8SJoe Beteta case SKD_REQ_STATE_ABORTED: return ("ABORTED");
3946f52228b8SJoe Beteta default: return ("???");
3947f52228b8SJoe Beteta }
3948f52228b8SJoe Beteta }
3949f52228b8SJoe Beteta
3950f52228b8SJoe Beteta /*
3951f52228b8SJoe Beteta *
3952f52228b8SJoe Beteta * Name: skd_log_skdev, logs device state & parameters.
3953f52228b8SJoe Beteta *
3954f52228b8SJoe Beteta * Inputs: skdev - device state structure.
3955f52228b8SJoe Beteta * event - event (string) to log.
3956f52228b8SJoe Beteta *
3957f52228b8SJoe Beteta * Returns: Nothing.
3958f52228b8SJoe Beteta *
3959f52228b8SJoe Beteta */
3960f52228b8SJoe Beteta static void
skd_log_skdev(struct skd_device * skdev,const char * event)3961f52228b8SJoe Beteta skd_log_skdev(struct skd_device *skdev, const char *event)
3962f52228b8SJoe Beteta {
3963f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "log_skdev(%s) skdev=%p event='%s'",
3964f52228b8SJoe Beteta skdev->name, (void *)skdev, event);
3965f52228b8SJoe Beteta Dcmn_err(CE_NOTE, " drive_state=%s(%d) driver_state=%s(%d)",
3966f52228b8SJoe Beteta skd_drive_state_to_str(skdev->drive_state), skdev->drive_state,
3967f52228b8SJoe Beteta skd_skdev_state_to_str(skdev->state), skdev->state);
3968f52228b8SJoe Beteta Dcmn_err(CE_NOTE, " busy=%d limit=%d soft=%d hard=%d lowat=%d",
3969f52228b8SJoe Beteta skdev->queue_depth_busy, skdev->queue_depth_limit,
3970f52228b8SJoe Beteta skdev->soft_queue_depth_limit, skdev->hard_queue_depth_limit,
3971f52228b8SJoe Beteta skdev->queue_depth_lowat);
3972f52228b8SJoe Beteta Dcmn_err(CE_NOTE, " timestamp=0x%x cycle=%d cycle_ix=%d",
3973f52228b8SJoe Beteta skdev->timeout_stamp, skdev->skcomp_cycle, skdev->skcomp_ix);
3974f52228b8SJoe Beteta }
3975f52228b8SJoe Beteta
3976f52228b8SJoe Beteta /*
3977f52228b8SJoe Beteta *
3978f52228b8SJoe Beteta * Name: skd_log_skmsg, logs the skmsg event.
3979f52228b8SJoe Beteta *
3980f52228b8SJoe Beteta * Inputs: skdev - device state structure.
3981f52228b8SJoe Beteta * skmsg - FIT message structure.
3982f52228b8SJoe Beteta * event - event string to log.
3983f52228b8SJoe Beteta *
3984f52228b8SJoe Beteta * Returns: Nothing.
3985f52228b8SJoe Beteta *
3986f52228b8SJoe Beteta */
3987f52228b8SJoe Beteta static void
skd_log_skmsg(struct skd_device * skdev,struct skd_fitmsg_context * skmsg,const char * event)3988f52228b8SJoe Beteta skd_log_skmsg(struct skd_device *skdev,
3989f52228b8SJoe Beteta struct skd_fitmsg_context *skmsg, const char *event)
3990f52228b8SJoe Beteta {
3991f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "log_skmsg:(%s) skmsg=%p event='%s'",
3992f52228b8SJoe Beteta skdev->name, (void *)skmsg, event);
3993f52228b8SJoe Beteta Dcmn_err(CE_NOTE, " state=%s(%d) id=0x%04x length=%d",
3994f52228b8SJoe Beteta skd_skmsg_state_to_str(skmsg->state), skmsg->state,
3995f52228b8SJoe Beteta skmsg->id, skmsg->length);
3996f52228b8SJoe Beteta }
3997f52228b8SJoe Beteta
3998f52228b8SJoe Beteta /*
3999f52228b8SJoe Beteta *
4000f52228b8SJoe Beteta * Name: skd_log_skreq, logs the skreq event.
4001f52228b8SJoe Beteta *
4002f52228b8SJoe Beteta * Inputs: skdev - device state structure.
4003f52228b8SJoe Beteta * skreq -skreq structure.
4004f52228b8SJoe Beteta * event - event string to log.
4005f52228b8SJoe Beteta *
4006f52228b8SJoe Beteta * Returns: Nothing.
4007f52228b8SJoe Beteta *
4008f52228b8SJoe Beteta */
4009f52228b8SJoe Beteta static void
skd_log_skreq(struct skd_device * skdev,struct skd_request_context * skreq,const char * event)4010f52228b8SJoe Beteta skd_log_skreq(struct skd_device *skdev,
4011f52228b8SJoe Beteta struct skd_request_context *skreq, const char *event)
4012f52228b8SJoe Beteta {
4013f52228b8SJoe Beteta skd_buf_private_t *pbuf;
4014f52228b8SJoe Beteta
4015f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "log_skreq: (%s) skreq=%p pbuf=%p event='%s'",
4016f52228b8SJoe Beteta skdev->name, (void *)skreq, (void *)skreq->pbuf, event);
4017f52228b8SJoe Beteta
4018f52228b8SJoe Beteta Dcmn_err(CE_NOTE, " state=%s(%d) id=0x%04x fitmsg=0x%04x",
4019f52228b8SJoe Beteta skd_skreq_state_to_str(skreq->state), skreq->state,
4020f52228b8SJoe Beteta skreq->id, skreq->fitmsg_id);
4021f52228b8SJoe Beteta Dcmn_err(CE_NOTE, " timo=0x%x sg_dir=%d n_sg=%d",
4022f52228b8SJoe Beteta skreq->timeout_stamp, skreq->sg_data_dir, skreq->n_sg);
4023f52228b8SJoe Beteta
4024f52228b8SJoe Beteta if ((pbuf = skreq->pbuf) != NULL) {
4025f52228b8SJoe Beteta uint32_t lba, count;
4026f52228b8SJoe Beteta lba = pbuf->x_xfer->x_blkno;
4027f52228b8SJoe Beteta count = pbuf->x_xfer->x_nblks;
4028f52228b8SJoe Beteta Dcmn_err(CE_NOTE, " pbuf=%p lba=%u(0x%x) count=%u(0x%x) ",
4029f52228b8SJoe Beteta (void *)pbuf, lba, lba, count, count);
4030f52228b8SJoe Beteta Dcmn_err(CE_NOTE, " dir=%s "
4031f52228b8SJoe Beteta " intrs=%" PRId64 " qdepth=%d",
4032f52228b8SJoe Beteta (pbuf->dir & B_READ) ? "Read" : "Write",
4033f52228b8SJoe Beteta skdev->intr_cntr, skdev->queue_depth_busy);
4034f52228b8SJoe Beteta } else {
4035f52228b8SJoe Beteta Dcmn_err(CE_NOTE, " req=NULL\n");
4036f52228b8SJoe Beteta }
4037f52228b8SJoe Beteta }
4038f52228b8SJoe Beteta
4039f52228b8SJoe Beteta /*
4040f52228b8SJoe Beteta *
4041f52228b8SJoe Beteta * Name: skd_init_mutex, initializes all mutexes.
4042f52228b8SJoe Beteta *
4043f52228b8SJoe Beteta * Inputs: skdev - device state structure.
4044f52228b8SJoe Beteta *
4045f52228b8SJoe Beteta * Returns: DDI_FAILURE on failure otherwise DDI_SUCCESS.
4046f52228b8SJoe Beteta *
4047f52228b8SJoe Beteta */
4048f52228b8SJoe Beteta static int
skd_init_mutex(skd_device_t * skdev)4049f52228b8SJoe Beteta skd_init_mutex(skd_device_t *skdev)
4050f52228b8SJoe Beteta {
4051f52228b8SJoe Beteta void *intr;
4052f52228b8SJoe Beteta
4053f52228b8SJoe Beteta Dcmn_err(CE_CONT, "(%s%d): init_mutex flags=%x", DRV_NAME,
4054f52228b8SJoe Beteta skdev->instance, skdev->flags);
4055f52228b8SJoe Beteta
4056f52228b8SJoe Beteta intr = (void *)(uintptr_t)skdev->intr_pri;
4057f52228b8SJoe Beteta
4058f52228b8SJoe Beteta if (skdev->flags & SKD_MUTEX_INITED)
4059f52228b8SJoe Beteta cmn_err(CE_NOTE, "init_mutex: Oh-Oh - already INITED");
4060f52228b8SJoe Beteta
4061f52228b8SJoe Beteta /* mutexes to protect the adapter state structure. */
4062f52228b8SJoe Beteta mutex_init(&skdev->skd_lock_mutex, NULL, MUTEX_DRIVER,
4063f52228b8SJoe Beteta DDI_INTR_PRI(intr));
4064f52228b8SJoe Beteta mutex_init(&skdev->skd_intr_mutex, NULL, MUTEX_DRIVER,
4065f52228b8SJoe Beteta DDI_INTR_PRI(intr));
4066f52228b8SJoe Beteta mutex_init(&skdev->waitqueue_mutex, NULL, MUTEX_DRIVER,
4067f52228b8SJoe Beteta DDI_INTR_PRI(intr));
4068f52228b8SJoe Beteta mutex_init(&skdev->skd_internalio_mutex, NULL, MUTEX_DRIVER,
4069f52228b8SJoe Beteta DDI_INTR_PRI(intr));
4070f52228b8SJoe Beteta
4071f52228b8SJoe Beteta cv_init(&skdev->cv_waitq, NULL, CV_DRIVER, NULL);
4072f52228b8SJoe Beteta
4073f52228b8SJoe Beteta skdev->flags |= SKD_MUTEX_INITED;
4074f52228b8SJoe Beteta if (skdev->flags & SKD_MUTEX_DESTROYED)
4075f52228b8SJoe Beteta skdev->flags &= ~SKD_MUTEX_DESTROYED;
4076f52228b8SJoe Beteta
4077f52228b8SJoe Beteta Dcmn_err(CE_CONT, "init_mutex (%s%d): done, flags=%x", DRV_NAME,
4078f52228b8SJoe Beteta skdev->instance, skdev->flags);
4079f52228b8SJoe Beteta
4080f52228b8SJoe Beteta return (DDI_SUCCESS);
4081f52228b8SJoe Beteta }
4082f52228b8SJoe Beteta
4083f52228b8SJoe Beteta /*
4084f52228b8SJoe Beteta *
4085f52228b8SJoe Beteta * Name: skd_destroy_mutex, destroys all mutexes.
4086f52228b8SJoe Beteta *
4087f52228b8SJoe Beteta * Inputs: skdev - device state structure.
4088f52228b8SJoe Beteta *
4089f52228b8SJoe Beteta * Returns: Nothing.
4090f52228b8SJoe Beteta *
4091f52228b8SJoe Beteta */
4092f52228b8SJoe Beteta static void
skd_destroy_mutex(skd_device_t * skdev)4093f52228b8SJoe Beteta skd_destroy_mutex(skd_device_t *skdev)
4094f52228b8SJoe Beteta {
4095f52228b8SJoe Beteta if ((skdev->flags & SKD_MUTEX_DESTROYED) == 0) {
4096f52228b8SJoe Beteta if (skdev->flags & SKD_MUTEX_INITED) {
4097f52228b8SJoe Beteta mutex_destroy(&skdev->waitqueue_mutex);
4098f52228b8SJoe Beteta mutex_destroy(&skdev->skd_intr_mutex);
4099f52228b8SJoe Beteta mutex_destroy(&skdev->skd_lock_mutex);
4100f52228b8SJoe Beteta mutex_destroy(&skdev->skd_internalio_mutex);
4101f52228b8SJoe Beteta
4102f52228b8SJoe Beteta cv_destroy(&skdev->cv_waitq);
4103f52228b8SJoe Beteta
4104f52228b8SJoe Beteta skdev->flags |= SKD_MUTEX_DESTROYED;
4105f52228b8SJoe Beteta
4106f52228b8SJoe Beteta if (skdev->flags & SKD_MUTEX_INITED)
4107f52228b8SJoe Beteta skdev->flags &= ~SKD_MUTEX_INITED;
4108f52228b8SJoe Beteta }
4109f52228b8SJoe Beteta }
4110f52228b8SJoe Beteta }
4111f52228b8SJoe Beteta
4112f52228b8SJoe Beteta /*
4113f52228b8SJoe Beteta *
4114f52228b8SJoe Beteta * Name: skd_setup_intr, setup the interrupt handling
4115f52228b8SJoe Beteta *
4116f52228b8SJoe Beteta * Inputs: skdev - device state structure.
4117f52228b8SJoe Beteta * intr_type - requested DDI interrupt type.
4118f52228b8SJoe Beteta *
4119f52228b8SJoe Beteta * Returns: DDI_FAILURE on failure otherwise DDI_SUCCESS.
4120f52228b8SJoe Beteta *
4121f52228b8SJoe Beteta */
4122f52228b8SJoe Beteta static int
skd_setup_intr(skd_device_t * skdev,int intr_type)4123f52228b8SJoe Beteta skd_setup_intr(skd_device_t *skdev, int intr_type)
4124f52228b8SJoe Beteta {
4125f52228b8SJoe Beteta int32_t count = 0;
4126f52228b8SJoe Beteta int32_t avail = 0;
4127f52228b8SJoe Beteta int32_t actual = 0;
4128f52228b8SJoe Beteta int32_t ret;
4129f52228b8SJoe Beteta uint32_t i;
4130f52228b8SJoe Beteta
4131f52228b8SJoe Beteta Dcmn_err(CE_CONT, "(%s%d): setup_intr", DRV_NAME, skdev->instance);
4132f52228b8SJoe Beteta
4133f52228b8SJoe Beteta /* Get number of interrupts the platform h/w supports */
4134f52228b8SJoe Beteta if (((ret = ddi_intr_get_nintrs(skdev->dip, intr_type, &count)) !=
4135f52228b8SJoe Beteta DDI_SUCCESS) || count == 0) {
4136f52228b8SJoe Beteta cmn_err(CE_WARN, "!intr_setup failed, nintrs ret=%xh, cnt=%xh",
4137f52228b8SJoe Beteta ret, count);
4138f52228b8SJoe Beteta
4139f52228b8SJoe Beteta return (DDI_FAILURE);
4140f52228b8SJoe Beteta }
4141f52228b8SJoe Beteta
4142f52228b8SJoe Beteta /* Get number of available system interrupts */
4143f52228b8SJoe Beteta if (((ret = ddi_intr_get_navail(skdev->dip, intr_type, &avail)) !=
4144f52228b8SJoe Beteta DDI_SUCCESS) || avail == 0) {
4145f52228b8SJoe Beteta cmn_err(CE_WARN, "!intr_setup failed, navail ret=%xh, "
4146f52228b8SJoe Beteta "avail=%xh", ret, avail);
4147f52228b8SJoe Beteta
4148f52228b8SJoe Beteta return (DDI_FAILURE);
4149f52228b8SJoe Beteta }
4150f52228b8SJoe Beteta
4151f52228b8SJoe Beteta if (intr_type == DDI_INTR_TYPE_MSIX && avail < SKD_MSIX_MAXAIF) {
4152f52228b8SJoe Beteta cmn_err(CE_WARN, "!intr_setup failed, min MSI-X h/w vectors "
4153f52228b8SJoe Beteta "req'd: %d, avail: %d",
4154f52228b8SJoe Beteta SKD_MSIX_MAXAIF, count);
4155f52228b8SJoe Beteta
4156f52228b8SJoe Beteta return (DDI_FAILURE);
4157f52228b8SJoe Beteta }
4158f52228b8SJoe Beteta
4159f52228b8SJoe Beteta /* Allocate space for interrupt handles */
4160f52228b8SJoe Beteta skdev->hsize = sizeof (ddi_intr_handle_t) * avail;
4161f52228b8SJoe Beteta skdev->htable = kmem_zalloc(skdev->hsize, KM_SLEEP);
4162f52228b8SJoe Beteta
4163f52228b8SJoe Beteta /* Allocate the interrupts */
4164f52228b8SJoe Beteta if ((ret = ddi_intr_alloc(skdev->dip, skdev->htable, intr_type,
4165f52228b8SJoe Beteta 0, count, &actual, 0)) != DDI_SUCCESS) {
4166f52228b8SJoe Beteta cmn_err(CE_WARN, "!intr_setup failed, intr_alloc ret=%xh, "
4167f52228b8SJoe Beteta "count = %xh, " "actual=%xh", ret, count, actual);
4168f52228b8SJoe Beteta
4169f52228b8SJoe Beteta skd_release_intr(skdev);
4170f52228b8SJoe Beteta
4171f52228b8SJoe Beteta return (DDI_FAILURE);
4172f52228b8SJoe Beteta }
4173f52228b8SJoe Beteta
4174f52228b8SJoe Beteta skdev->intr_cnt = actual;
4175f52228b8SJoe Beteta
4176f52228b8SJoe Beteta if (intr_type == DDI_INTR_TYPE_FIXED)
4177f52228b8SJoe Beteta (void) ddi_intr_set_pri(skdev->htable[0], 10);
4178f52228b8SJoe Beteta
4179f52228b8SJoe Beteta /* Get interrupt priority */
4180f52228b8SJoe Beteta if ((ret = ddi_intr_get_pri(skdev->htable[0], &skdev->intr_pri)) !=
4181f52228b8SJoe Beteta DDI_SUCCESS) {
4182f52228b8SJoe Beteta cmn_err(CE_WARN, "!intr_setup failed, get_pri ret=%xh", ret);
4183f52228b8SJoe Beteta skd_release_intr(skdev);
4184f52228b8SJoe Beteta
4185f52228b8SJoe Beteta return (ret);
4186f52228b8SJoe Beteta }
4187f52228b8SJoe Beteta
4188f52228b8SJoe Beteta /* Add the interrupt handlers */
4189f52228b8SJoe Beteta for (i = 0; i < actual; i++) {
4190f52228b8SJoe Beteta if ((ret = ddi_intr_add_handler(skdev->htable[i],
4191f52228b8SJoe Beteta skd_isr_aif, (void *)skdev, (void *)((ulong_t)i))) !=
4192f52228b8SJoe Beteta DDI_SUCCESS) {
4193f52228b8SJoe Beteta cmn_err(CE_WARN, "!intr_setup failed, addh#=%xh, "
4194f52228b8SJoe Beteta "act=%xh, ret=%xh", i, actual, ret);
4195f52228b8SJoe Beteta skd_release_intr(skdev);
4196f52228b8SJoe Beteta
4197f52228b8SJoe Beteta return (ret);
4198f52228b8SJoe Beteta }
4199f52228b8SJoe Beteta }
4200f52228b8SJoe Beteta
4201f52228b8SJoe Beteta /* Setup mutexes */
4202f52228b8SJoe Beteta if ((ret = skd_init_mutex(skdev)) != DDI_SUCCESS) {
4203f52228b8SJoe Beteta cmn_err(CE_WARN, "!intr_setup failed, mutex init ret=%xh", ret);
4204f52228b8SJoe Beteta skd_release_intr(skdev);
4205f52228b8SJoe Beteta
4206f52228b8SJoe Beteta return (ret);
4207f52228b8SJoe Beteta }
4208f52228b8SJoe Beteta
4209f52228b8SJoe Beteta /* Get the capabilities */
4210f52228b8SJoe Beteta (void) ddi_intr_get_cap(skdev->htable[0], &skdev->intr_cap);
4211f52228b8SJoe Beteta
4212f52228b8SJoe Beteta /* Enable interrupts */
4213f52228b8SJoe Beteta if (skdev->intr_cap & DDI_INTR_FLAG_BLOCK) {
4214f52228b8SJoe Beteta if ((ret = ddi_intr_block_enable(skdev->htable,
4215f52228b8SJoe Beteta skdev->intr_cnt)) != DDI_SUCCESS) {
4216f52228b8SJoe Beteta cmn_err(CE_WARN, "!failed, intr_setup block enable, "
4217f52228b8SJoe Beteta "ret=%xh", ret);
4218f52228b8SJoe Beteta skd_destroy_mutex(skdev);
4219f52228b8SJoe Beteta skd_release_intr(skdev);
4220f52228b8SJoe Beteta
4221f52228b8SJoe Beteta return (ret);
4222f52228b8SJoe Beteta }
4223f52228b8SJoe Beteta } else {
4224f52228b8SJoe Beteta for (i = 0; i < skdev->intr_cnt; i++) {
4225f52228b8SJoe Beteta if ((ret = ddi_intr_enable(skdev->htable[i])) !=
4226f52228b8SJoe Beteta DDI_SUCCESS) {
4227f52228b8SJoe Beteta cmn_err(CE_WARN, "!intr_setup failed, "
4228f52228b8SJoe Beteta "intr enable, ret=%xh", ret);
4229f52228b8SJoe Beteta skd_destroy_mutex(skdev);
4230f52228b8SJoe Beteta skd_release_intr(skdev);
4231f52228b8SJoe Beteta
4232f52228b8SJoe Beteta return (ret);
4233f52228b8SJoe Beteta }
4234f52228b8SJoe Beteta }
4235f52228b8SJoe Beteta }
4236f52228b8SJoe Beteta
4237f52228b8SJoe Beteta if (intr_type == DDI_INTR_TYPE_FIXED)
4238f52228b8SJoe Beteta (void) ddi_intr_clr_mask(skdev->htable[0]);
4239f52228b8SJoe Beteta
4240f52228b8SJoe Beteta skdev->irq_type = intr_type;
4241f52228b8SJoe Beteta
4242f52228b8SJoe Beteta return (DDI_SUCCESS);
4243f52228b8SJoe Beteta }
4244f52228b8SJoe Beteta
4245f52228b8SJoe Beteta /*
4246f52228b8SJoe Beteta *
4247f52228b8SJoe Beteta * Name: skd_disable_intr, disable interrupt handling.
4248f52228b8SJoe Beteta *
4249f52228b8SJoe Beteta * Inputs: skdev - device state structure.
4250f52228b8SJoe Beteta *
4251f52228b8SJoe Beteta * Returns: Nothing.
4252f52228b8SJoe Beteta *
4253f52228b8SJoe Beteta */
4254f52228b8SJoe Beteta static void
skd_disable_intr(skd_device_t * skdev)4255f52228b8SJoe Beteta skd_disable_intr(skd_device_t *skdev)
4256f52228b8SJoe Beteta {
4257f52228b8SJoe Beteta uint32_t i, rval;
4258f52228b8SJoe Beteta
4259f52228b8SJoe Beteta if (skdev->intr_cap & DDI_INTR_FLAG_BLOCK) {
4260f52228b8SJoe Beteta /* Remove AIF block interrupts (MSI/MSI-X) */
4261f52228b8SJoe Beteta if ((rval = ddi_intr_block_disable(skdev->htable,
4262f52228b8SJoe Beteta skdev->intr_cnt)) != DDI_SUCCESS) {
4263f52228b8SJoe Beteta cmn_err(CE_WARN, "!failed intr block disable, rval=%x",
4264f52228b8SJoe Beteta rval);
4265f52228b8SJoe Beteta }
4266f52228b8SJoe Beteta } else {
4267f52228b8SJoe Beteta /* Remove AIF non-block interrupts (fixed). */
4268f52228b8SJoe Beteta for (i = 0; i < skdev->intr_cnt; i++) {
4269f52228b8SJoe Beteta if ((rval = ddi_intr_disable(skdev->htable[i])) !=
4270f52228b8SJoe Beteta DDI_SUCCESS) {
4271f52228b8SJoe Beteta cmn_err(CE_WARN, "!failed intr disable, "
4272f52228b8SJoe Beteta "intr#=%xh, " "rval=%xh", i, rval);
4273f52228b8SJoe Beteta }
4274f52228b8SJoe Beteta }
4275f52228b8SJoe Beteta }
4276f52228b8SJoe Beteta }
4277f52228b8SJoe Beteta
4278f52228b8SJoe Beteta /*
4279f52228b8SJoe Beteta *
4280f52228b8SJoe Beteta * Name: skd_release_intr, disables interrupt handling.
4281f52228b8SJoe Beteta *
4282f52228b8SJoe Beteta * Inputs: skdev - device state structure.
4283f52228b8SJoe Beteta *
4284f52228b8SJoe Beteta * Returns: Nothing.
4285f52228b8SJoe Beteta *
4286f52228b8SJoe Beteta */
4287f52228b8SJoe Beteta static void
skd_release_intr(skd_device_t * skdev)4288f52228b8SJoe Beteta skd_release_intr(skd_device_t *skdev)
4289f52228b8SJoe Beteta {
4290f52228b8SJoe Beteta int32_t i;
4291f52228b8SJoe Beteta int rval;
4292f52228b8SJoe Beteta
4293f52228b8SJoe Beteta
4294f52228b8SJoe Beteta Dcmn_err(CE_CONT, "REL_INTR intr_cnt=%d", skdev->intr_cnt);
4295f52228b8SJoe Beteta
4296f52228b8SJoe Beteta if (skdev->irq_type == 0) {
4297f52228b8SJoe Beteta Dcmn_err(CE_CONT, "release_intr: (%s%d): done",
4298f52228b8SJoe Beteta DRV_NAME, skdev->instance);
4299f52228b8SJoe Beteta return;
4300f52228b8SJoe Beteta }
4301f52228b8SJoe Beteta
4302f52228b8SJoe Beteta if (skdev->htable != NULL && skdev->hsize > 0) {
4303f52228b8SJoe Beteta i = (int32_t)skdev->hsize / (int32_t)sizeof (ddi_intr_handle_t);
4304f52228b8SJoe Beteta
4305f52228b8SJoe Beteta while (i-- > 0) {
4306f52228b8SJoe Beteta if (skdev->htable[i] == 0) {
4307f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "htable[%x]=0h", i);
4308f52228b8SJoe Beteta continue;
4309f52228b8SJoe Beteta }
4310f52228b8SJoe Beteta
4311f52228b8SJoe Beteta if ((rval = ddi_intr_disable(skdev->htable[i])) !=
4312f52228b8SJoe Beteta DDI_SUCCESS)
4313f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "release_intr: intr_disable "
4314f52228b8SJoe Beteta "htable[%d], rval=%d", i, rval);
4315f52228b8SJoe Beteta
4316f52228b8SJoe Beteta if (i < skdev->intr_cnt) {
4317f52228b8SJoe Beteta if ((rval = ddi_intr_remove_handler(
4318f52228b8SJoe Beteta skdev->htable[i])) != DDI_SUCCESS)
4319f52228b8SJoe Beteta cmn_err(CE_WARN, "!release_intr: "
4320f52228b8SJoe Beteta "intr_remove_handler FAILED, "
4321f52228b8SJoe Beteta "rval=%d", rval);
4322f52228b8SJoe Beteta
4323f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "release_intr: "
4324f52228b8SJoe Beteta "remove_handler htable[%d]", i);
4325f52228b8SJoe Beteta }
4326f52228b8SJoe Beteta
4327f52228b8SJoe Beteta if ((rval = ddi_intr_free(skdev->htable[i])) !=
4328f52228b8SJoe Beteta DDI_SUCCESS)
4329f52228b8SJoe Beteta cmn_err(CE_WARN, "!release_intr: intr_free "
4330f52228b8SJoe Beteta "FAILED, rval=%d", rval);
4331f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "release_intr: intr_free htable[%d]",
4332f52228b8SJoe Beteta i);
4333f52228b8SJoe Beteta }
4334f52228b8SJoe Beteta
4335f52228b8SJoe Beteta kmem_free(skdev->htable, skdev->hsize);
4336f52228b8SJoe Beteta skdev->htable = NULL;
4337f52228b8SJoe Beteta }
4338f52228b8SJoe Beteta
4339f52228b8SJoe Beteta skdev->hsize = 0;
4340f52228b8SJoe Beteta skdev->intr_cnt = 0;
4341f52228b8SJoe Beteta skdev->intr_pri = 0;
4342f52228b8SJoe Beteta skdev->intr_cap = 0;
4343f52228b8SJoe Beteta skdev->irq_type = 0;
4344f52228b8SJoe Beteta }
4345f52228b8SJoe Beteta
4346f52228b8SJoe Beteta /*
4347f52228b8SJoe Beteta *
4348f52228b8SJoe Beteta * Name: skd_dealloc_resources, deallocate resources allocated
4349f52228b8SJoe Beteta * during attach.
4350f52228b8SJoe Beteta *
4351f52228b8SJoe Beteta * Inputs: dip - DDI device info pointer.
4352f52228b8SJoe Beteta * skdev - device state structure.
4353f52228b8SJoe Beteta * seq - bit flag representing allocated item.
4354f52228b8SJoe Beteta * instance - device instance.
4355f52228b8SJoe Beteta *
4356f52228b8SJoe Beteta * Returns: Nothing.
4357f52228b8SJoe Beteta *
4358f52228b8SJoe Beteta */
4359f52228b8SJoe Beteta /* ARGSUSED */ /* Upstream common source with other platforms. */
4360f52228b8SJoe Beteta static void
skd_dealloc_resources(dev_info_t * dip,skd_device_t * skdev,uint32_t seq,int instance)4361f52228b8SJoe Beteta skd_dealloc_resources(dev_info_t *dip, skd_device_t *skdev,
4362f52228b8SJoe Beteta uint32_t seq, int instance)
4363f52228b8SJoe Beteta {
4364f52228b8SJoe Beteta
4365f52228b8SJoe Beteta if (skdev == NULL)
4366f52228b8SJoe Beteta return;
4367f52228b8SJoe Beteta
4368f52228b8SJoe Beteta if (seq & SKD_CONSTRUCTED)
4369f52228b8SJoe Beteta skd_destruct(skdev);
4370f52228b8SJoe Beteta
4371f52228b8SJoe Beteta if (seq & SKD_INTR_ADDED) {
4372f52228b8SJoe Beteta skd_disable_intr(skdev);
4373f52228b8SJoe Beteta skd_release_intr(skdev);
4374f52228b8SJoe Beteta }
4375f52228b8SJoe Beteta
4376f52228b8SJoe Beteta if (seq & SKD_DEV_IOBASE_MAPPED)
4377f52228b8SJoe Beteta ddi_regs_map_free(&skdev->dev_handle);
4378f52228b8SJoe Beteta
4379f52228b8SJoe Beteta if (seq & SKD_IOMAP_IOBASE_MAPPED)
4380f52228b8SJoe Beteta ddi_regs_map_free(&skdev->iomap_handle);
4381f52228b8SJoe Beteta
4382f52228b8SJoe Beteta if (seq & SKD_REGS_MAPPED)
4383f52228b8SJoe Beteta ddi_regs_map_free(&skdev->iobase_handle);
4384f52228b8SJoe Beteta
4385f52228b8SJoe Beteta if (seq & SKD_CONFIG_SPACE_SETUP)
4386f52228b8SJoe Beteta pci_config_teardown(&skdev->pci_handle);
4387f52228b8SJoe Beteta
4388f52228b8SJoe Beteta if (seq & SKD_SOFT_STATE_ALLOCED) {
4389f52228b8SJoe Beteta if (skdev->pathname &&
4390f52228b8SJoe Beteta (skdev->flags & SKD_PATHNAME_ALLOCED)) {
4391f52228b8SJoe Beteta kmem_free(skdev->pathname,
4392f52228b8SJoe Beteta strlen(skdev->pathname)+1);
4393f52228b8SJoe Beteta }
4394f52228b8SJoe Beteta }
4395f52228b8SJoe Beteta
4396f52228b8SJoe Beteta if (skdev->s1120_devid)
4397f52228b8SJoe Beteta ddi_devid_free(skdev->s1120_devid);
4398f52228b8SJoe Beteta }
4399f52228b8SJoe Beteta
4400f52228b8SJoe Beteta /*
4401f52228b8SJoe Beteta *
4402f52228b8SJoe Beteta * Name: skd_setup_interrupt, sets up the appropriate interrupt type
4403f52228b8SJoe Beteta * msi, msix, or fixed.
4404f52228b8SJoe Beteta *
4405f52228b8SJoe Beteta * Inputs: skdev - device state structure.
4406f52228b8SJoe Beteta *
4407f52228b8SJoe Beteta * Returns: DDI_FAILURE on failure otherwise DDI_SUCCESS.
4408f52228b8SJoe Beteta *
4409f52228b8SJoe Beteta */
4410f52228b8SJoe Beteta static int
skd_setup_interrupts(skd_device_t * skdev)4411f52228b8SJoe Beteta skd_setup_interrupts(skd_device_t *skdev)
4412f52228b8SJoe Beteta {
4413f52228b8SJoe Beteta int32_t rval = DDI_FAILURE;
4414f52228b8SJoe Beteta int32_t i;
4415f52228b8SJoe Beteta int32_t itypes = 0;
4416f52228b8SJoe Beteta
4417f52228b8SJoe Beteta /*
4418f52228b8SJoe Beteta * See what types of interrupts this adapter and platform support
4419f52228b8SJoe Beteta */
4420f52228b8SJoe Beteta if ((i = ddi_intr_get_supported_types(skdev->dip, &itypes)) !=
4421f52228b8SJoe Beteta DDI_SUCCESS) {
4422f52228b8SJoe Beteta cmn_err(CE_NOTE, "intr supported types failed, rval=%xh, ", i);
4423f52228b8SJoe Beteta return (DDI_FAILURE);
4424f52228b8SJoe Beteta }
4425f52228b8SJoe Beteta
4426f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "%s:supported interrupts types: %x",
4427f52228b8SJoe Beteta skdev->name, itypes);
4428f52228b8SJoe Beteta
4429f52228b8SJoe Beteta itypes &= skdev->irq_type;
4430f52228b8SJoe Beteta
4431f52228b8SJoe Beteta if (!skd_disable_msix && (itypes & DDI_INTR_TYPE_MSIX) &&
4432f52228b8SJoe Beteta (rval = skd_setup_intr(skdev, DDI_INTR_TYPE_MSIX)) == DDI_SUCCESS) {
4433f52228b8SJoe Beteta cmn_err(CE_NOTE, "!%s: successful MSI-X setup",
4434f52228b8SJoe Beteta skdev->name);
4435f52228b8SJoe Beteta } else if (!skd_disable_msi && (itypes & DDI_INTR_TYPE_MSI) &&
4436f52228b8SJoe Beteta (rval = skd_setup_intr(skdev, DDI_INTR_TYPE_MSI)) == DDI_SUCCESS) {
4437f52228b8SJoe Beteta cmn_err(CE_NOTE, "!%s: successful MSI setup",
4438f52228b8SJoe Beteta skdev->name);
4439f52228b8SJoe Beteta } else if ((itypes & DDI_INTR_TYPE_FIXED) &&
4440f52228b8SJoe Beteta (rval = skd_setup_intr(skdev, DDI_INTR_TYPE_FIXED))
4441f52228b8SJoe Beteta == DDI_SUCCESS) {
4442f52228b8SJoe Beteta cmn_err(CE_NOTE, "!%s: successful fixed intr setup",
4443f52228b8SJoe Beteta skdev->name);
4444f52228b8SJoe Beteta } else {
4445f52228b8SJoe Beteta cmn_err(CE_WARN, "!%s: no supported interrupt types",
4446f52228b8SJoe Beteta skdev->name);
4447f52228b8SJoe Beteta return (DDI_FAILURE);
4448f52228b8SJoe Beteta }
4449f52228b8SJoe Beteta
4450f52228b8SJoe Beteta Dcmn_err(CE_CONT, "%s: setup interrupts done", skdev->name);
4451f52228b8SJoe Beteta
4452f52228b8SJoe Beteta return (rval);
4453f52228b8SJoe Beteta }
4454f52228b8SJoe Beteta
4455f52228b8SJoe Beteta /*
4456f52228b8SJoe Beteta *
4457f52228b8SJoe Beteta * Name: skd_get_properties, retrieves properties from skd.conf.
4458f52228b8SJoe Beteta *
4459f52228b8SJoe Beteta * Inputs: skdev - device state structure.
4460f52228b8SJoe Beteta * dip - dev_info data structure.
4461f52228b8SJoe Beteta *
4462f52228b8SJoe Beteta * Returns: Nothing.
4463f52228b8SJoe Beteta *
4464f52228b8SJoe Beteta */
4465f52228b8SJoe Beteta /* ARGSUSED */ /* Upstream common source with other platforms. */
4466f52228b8SJoe Beteta static void
skd_get_properties(dev_info_t * dip,skd_device_t * skdev)4467f52228b8SJoe Beteta skd_get_properties(dev_info_t *dip, skd_device_t *skdev)
4468f52228b8SJoe Beteta {
4469f52228b8SJoe Beteta int prop_value;
4470f52228b8SJoe Beteta
4471f52228b8SJoe Beteta skd_isr_type = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
4472f52228b8SJoe Beteta "intr-type-cap", -1);
4473f52228b8SJoe Beteta
4474f52228b8SJoe Beteta prop_value = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
4475f52228b8SJoe Beteta "max-scsi-reqs", -1);
4476f52228b8SJoe Beteta if (prop_value >= 1 && prop_value <= SKD_MAX_QUEUE_DEPTH)
4477f52228b8SJoe Beteta skd_max_queue_depth = prop_value;
4478f52228b8SJoe Beteta
4479f52228b8SJoe Beteta prop_value = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
4480f52228b8SJoe Beteta "max-scsi-reqs-per-msg", -1);
4481f52228b8SJoe Beteta if (prop_value >= 1 && prop_value <= SKD_MAX_REQ_PER_MSG)
4482f52228b8SJoe Beteta skd_max_req_per_msg = prop_value;
4483f52228b8SJoe Beteta
4484f52228b8SJoe Beteta prop_value = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
4485f52228b8SJoe Beteta "max-sgs-per-req", -1);
4486f52228b8SJoe Beteta if (prop_value >= 1 && prop_value <= SKD_MAX_N_SG_PER_REQ)
4487f52228b8SJoe Beteta skd_sgs_per_request = prop_value;
4488f52228b8SJoe Beteta
4489f52228b8SJoe Beteta prop_value = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
4490f52228b8SJoe Beteta "dbg-level", -1);
4491f52228b8SJoe Beteta if (prop_value >= 1 && prop_value <= 2)
4492f52228b8SJoe Beteta skd_dbg_level = prop_value;
4493f52228b8SJoe Beteta }
4494f52228b8SJoe Beteta
4495f52228b8SJoe Beteta /*
4496f52228b8SJoe Beteta *
4497f52228b8SJoe Beteta * Name: skd_wait_for_s1120, wait for device to finish
4498f52228b8SJoe Beteta * its initialization.
4499f52228b8SJoe Beteta *
4500f52228b8SJoe Beteta * Inputs: skdev - device state structure.
4501f52228b8SJoe Beteta *
4502f52228b8SJoe Beteta * Returns: DDI_SUCCESS or DDI_FAILURE.
4503f52228b8SJoe Beteta *
4504f52228b8SJoe Beteta */
4505f52228b8SJoe Beteta static int
skd_wait_for_s1120(skd_device_t * skdev)4506f52228b8SJoe Beteta skd_wait_for_s1120(skd_device_t *skdev)
4507f52228b8SJoe Beteta {
4508f52228b8SJoe Beteta clock_t cur_ticks, tmo;
4509f52228b8SJoe Beteta int loop_cntr = 0;
4510f52228b8SJoe Beteta int rc = DDI_FAILURE;
4511f52228b8SJoe Beteta
4512f52228b8SJoe Beteta mutex_enter(&skdev->skd_internalio_mutex);
4513f52228b8SJoe Beteta
4514f52228b8SJoe Beteta while (skdev->gendisk_on == 0) {
4515f52228b8SJoe Beteta cur_ticks = ddi_get_lbolt();
4516f52228b8SJoe Beteta tmo = cur_ticks + drv_usectohz(MICROSEC);
4517f52228b8SJoe Beteta if (cv_timedwait(&skdev->cv_waitq,
4518f52228b8SJoe Beteta &skdev->skd_internalio_mutex, tmo) == -1) {
4519f52228b8SJoe Beteta /* Oops - timed out */
4520f52228b8SJoe Beteta if (loop_cntr++ > 10)
4521f52228b8SJoe Beteta break;
4522f52228b8SJoe Beteta }
4523f52228b8SJoe Beteta }
4524f52228b8SJoe Beteta
4525f52228b8SJoe Beteta mutex_exit(&skdev->skd_internalio_mutex);
4526f52228b8SJoe Beteta
4527f52228b8SJoe Beteta if (skdev->gendisk_on == 1)
4528f52228b8SJoe Beteta rc = DDI_SUCCESS;
4529f52228b8SJoe Beteta
4530f52228b8SJoe Beteta return (rc);
4531f52228b8SJoe Beteta }
4532f52228b8SJoe Beteta
4533f52228b8SJoe Beteta /*
4534f52228b8SJoe Beteta *
4535f52228b8SJoe Beteta * Name: skd_update_props, updates certain device properties.
4536f52228b8SJoe Beteta *
4537f52228b8SJoe Beteta * Inputs: skdev - device state structure.
4538f52228b8SJoe Beteta * dip - dev info structure
4539f52228b8SJoe Beteta *
4540f52228b8SJoe Beteta * Returns: Nothing.
4541f52228b8SJoe Beteta *
4542f52228b8SJoe Beteta */
4543f52228b8SJoe Beteta static void
skd_update_props(skd_device_t * skdev,dev_info_t * dip)4544f52228b8SJoe Beteta skd_update_props(skd_device_t *skdev, dev_info_t *dip)
4545f52228b8SJoe Beteta {
4546f52228b8SJoe Beteta int blksize = 512;
4547f52228b8SJoe Beteta
4548f52228b8SJoe Beteta if ((ddi_prop_update_int64(DDI_DEV_T_NONE, dip, "device-nblocks",
4549f52228b8SJoe Beteta skdev->Nblocks) != DDI_SUCCESS) ||
4550f52228b8SJoe Beteta (ddi_prop_update_int(DDI_DEV_T_NONE, dip, "device-blksize",
4551f52228b8SJoe Beteta blksize) != DDI_SUCCESS)) {
4552f52228b8SJoe Beteta cmn_err(CE_NOTE, "%s: FAILED to create driver properties",
4553f52228b8SJoe Beteta skdev->name);
4554f52228b8SJoe Beteta }
4555f52228b8SJoe Beteta }
4556f52228b8SJoe Beteta
4557f52228b8SJoe Beteta /*
4558f52228b8SJoe Beteta *
4559f52228b8SJoe Beteta * Name: skd_setup_devid, sets up device ID info.
4560f52228b8SJoe Beteta *
4561f52228b8SJoe Beteta * Inputs: skdev - device state structure.
4562f52228b8SJoe Beteta * devid - Device ID for the DDI.
4563f52228b8SJoe Beteta *
4564f52228b8SJoe Beteta * Returns: DDI_SUCCESS or DDI_FAILURE.
4565f52228b8SJoe Beteta *
4566f52228b8SJoe Beteta */
4567f52228b8SJoe Beteta static int
skd_setup_devid(skd_device_t * skdev,ddi_devid_t * devid)4568f52228b8SJoe Beteta skd_setup_devid(skd_device_t *skdev, ddi_devid_t *devid)
4569f52228b8SJoe Beteta {
4570f52228b8SJoe Beteta int rc, sz_model, sz_sn, sz;
4571f52228b8SJoe Beteta
4572*bef9e21aSHans Rosenfeld sz_model = scsi_ascii_inquiry_len(skdev->inq_product_id,
4573*bef9e21aSHans Rosenfeld strlen(skdev->inq_product_id));
4574*bef9e21aSHans Rosenfeld sz_sn = scsi_ascii_inquiry_len(skdev->inq_serial_num,
4575*bef9e21aSHans Rosenfeld strlen(skdev->inq_serial_num));
4576f52228b8SJoe Beteta sz = sz_model + sz_sn + 1;
4577f52228b8SJoe Beteta
4578*bef9e21aSHans Rosenfeld (void) snprintf(skdev->devid_str, sizeof (skdev->devid_str),
4579*bef9e21aSHans Rosenfeld "%.*s=%.*s", sz_model, skdev->inq_product_id, sz_sn,
4580*bef9e21aSHans Rosenfeld skdev->inq_serial_num);
4581f52228b8SJoe Beteta rc = ddi_devid_init(skdev->dip, DEVID_SCSI_SERIAL, sz,
4582f52228b8SJoe Beteta skdev->devid_str, devid);
4583f52228b8SJoe Beteta
4584f52228b8SJoe Beteta if (rc != DDI_SUCCESS)
4585f52228b8SJoe Beteta cmn_err(CE_WARN, "!%s: devid_init FAILED", skdev->name);
4586f52228b8SJoe Beteta
4587f52228b8SJoe Beteta return (rc);
4588f52228b8SJoe Beteta
4589f52228b8SJoe Beteta }
4590f52228b8SJoe Beteta
4591f52228b8SJoe Beteta /*
4592f52228b8SJoe Beteta *
4593f52228b8SJoe Beteta * Name: skd_bd_attach, attach to blkdev driver
4594f52228b8SJoe Beteta *
4595f52228b8SJoe Beteta * Inputs: skdev - device state structure.
4596f52228b8SJoe Beteta * dip - device info structure.
4597f52228b8SJoe Beteta *
4598f52228b8SJoe Beteta * Returns: DDI_SUCCESS or DDI_FAILURE.
4599f52228b8SJoe Beteta *
4600f52228b8SJoe Beteta */
4601f52228b8SJoe Beteta static int
skd_bd_attach(dev_info_t * dip,skd_device_t * skdev)4602f52228b8SJoe Beteta skd_bd_attach(dev_info_t *dip, skd_device_t *skdev)
4603f52228b8SJoe Beteta {
4604f52228b8SJoe Beteta int rv;
4605f52228b8SJoe Beteta
4606f52228b8SJoe Beteta skdev->s_bdh = bd_alloc_handle(skdev, &skd_bd_ops,
4607f52228b8SJoe Beteta &skd_64bit_io_dma_attr, KM_SLEEP);
4608f52228b8SJoe Beteta
4609f52228b8SJoe Beteta if (skdev->s_bdh == NULL) {
4610f52228b8SJoe Beteta cmn_err(CE_WARN, "!skd_bd_attach: FAILED");
4611f52228b8SJoe Beteta
4612f52228b8SJoe Beteta return (DDI_FAILURE);
4613f52228b8SJoe Beteta }
4614f52228b8SJoe Beteta
4615f52228b8SJoe Beteta rv = bd_attach_handle(dip, skdev->s_bdh);
4616f52228b8SJoe Beteta
4617f52228b8SJoe Beteta if (rv != DDI_SUCCESS) {
4618f52228b8SJoe Beteta cmn_err(CE_WARN, "!bd_attach_handle FAILED\n");
4619f52228b8SJoe Beteta } else {
4620f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "bd_attach_handle OK\n");
4621f52228b8SJoe Beteta skdev->bd_attached++;
4622f52228b8SJoe Beteta }
4623f52228b8SJoe Beteta
4624f52228b8SJoe Beteta return (rv);
4625f52228b8SJoe Beteta }
4626f52228b8SJoe Beteta
4627f52228b8SJoe Beteta /*
4628f52228b8SJoe Beteta *
4629f52228b8SJoe Beteta * Name: skd_bd_detach, detach from the blkdev driver.
4630f52228b8SJoe Beteta *
4631f52228b8SJoe Beteta * Inputs: skdev - device state structure.
4632f52228b8SJoe Beteta *
4633f52228b8SJoe Beteta * Returns: Nothing.
4634f52228b8SJoe Beteta *
4635f52228b8SJoe Beteta */
4636f52228b8SJoe Beteta static void
skd_bd_detach(skd_device_t * skdev)4637f52228b8SJoe Beteta skd_bd_detach(skd_device_t *skdev)
4638f52228b8SJoe Beteta {
4639f52228b8SJoe Beteta if (skdev->bd_attached)
4640f52228b8SJoe Beteta (void) bd_detach_handle(skdev->s_bdh);
4641f52228b8SJoe Beteta
4642f52228b8SJoe Beteta bd_free_handle(skdev->s_bdh);
4643f52228b8SJoe Beteta }
4644f52228b8SJoe Beteta
4645f52228b8SJoe Beteta /*
4646f52228b8SJoe Beteta *
4647f52228b8SJoe Beteta * Name: skd_attach, attach sdk device driver
4648f52228b8SJoe Beteta *
4649f52228b8SJoe Beteta * Inputs: dip - device info structure.
4650f52228b8SJoe Beteta * cmd - DDI attach argument (ATTACH, RESUME, etc.)
4651f52228b8SJoe Beteta *
4652f52228b8SJoe Beteta * Returns: DDI_SUCCESS or DDI_FAILURE.
4653f52228b8SJoe Beteta *
4654f52228b8SJoe Beteta */
4655f52228b8SJoe Beteta static int
skd_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)4656f52228b8SJoe Beteta skd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
4657f52228b8SJoe Beteta {
4658f52228b8SJoe Beteta int instance;
4659f52228b8SJoe Beteta int nregs;
4660f52228b8SJoe Beteta skd_device_t *skdev = NULL;
4661f52228b8SJoe Beteta int inx;
4662f52228b8SJoe Beteta uint16_t cmd_reg;
4663f52228b8SJoe Beteta int progress = 0;
4664f52228b8SJoe Beteta char name[MAXPATHLEN];
4665f52228b8SJoe Beteta off_t regsize;
4666f52228b8SJoe Beteta char pci_str[32];
4667f52228b8SJoe Beteta char fw_version[8];
4668f52228b8SJoe Beteta
4669f52228b8SJoe Beteta instance = ddi_get_instance(dip);
4670f52228b8SJoe Beteta
4671f52228b8SJoe Beteta (void) ddi_get_parent_data(dip);
4672f52228b8SJoe Beteta
4673f52228b8SJoe Beteta switch (cmd) {
4674f52228b8SJoe Beteta case DDI_ATTACH:
4675f52228b8SJoe Beteta break;
4676f52228b8SJoe Beteta
4677f52228b8SJoe Beteta case DDI_RESUME:
4678f52228b8SJoe Beteta /* Re-enable timer */
4679f52228b8SJoe Beteta skd_start_timer(skdev);
4680f52228b8SJoe Beteta
4681f52228b8SJoe Beteta return (DDI_SUCCESS);
4682f52228b8SJoe Beteta
4683f52228b8SJoe Beteta default:
4684f52228b8SJoe Beteta return (DDI_FAILURE);
4685f52228b8SJoe Beteta }
4686f52228b8SJoe Beteta
4687f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "sTec S1120 Driver v%s Instance: %d",
4688f52228b8SJoe Beteta VERSIONSTR, instance);
4689f52228b8SJoe Beteta
4690f52228b8SJoe Beteta /*
4691f52228b8SJoe Beteta * Check that hardware is installed in a DMA-capable slot
4692f52228b8SJoe Beteta */
4693f52228b8SJoe Beteta if (ddi_slaveonly(dip) == DDI_SUCCESS) {
4694f52228b8SJoe Beteta cmn_err(CE_WARN, "!%s%d: installed in a "
4695f52228b8SJoe Beteta "slot that isn't DMA-capable slot", DRV_NAME, instance);
4696f52228b8SJoe Beteta return (DDI_FAILURE);
4697f52228b8SJoe Beteta }
4698f52228b8SJoe Beteta
4699f52228b8SJoe Beteta /*
4700f52228b8SJoe Beteta * No support for high-level interrupts
4701f52228b8SJoe Beteta */
4702f52228b8SJoe Beteta if (ddi_intr_hilevel(dip, 0) != 0) {
4703f52228b8SJoe Beteta cmn_err(CE_WARN, "!%s%d: High level interrupt not supported",
4704f52228b8SJoe Beteta DRV_NAME, instance);
4705f52228b8SJoe Beteta return (DDI_FAILURE);
4706f52228b8SJoe Beteta }
4707f52228b8SJoe Beteta
4708f52228b8SJoe Beteta /*
4709f52228b8SJoe Beteta * Allocate our per-device-instance structure
4710f52228b8SJoe Beteta */
4711f52228b8SJoe Beteta if (ddi_soft_state_zalloc(skd_state, instance) !=
4712f52228b8SJoe Beteta DDI_SUCCESS) {
4713f52228b8SJoe Beteta cmn_err(CE_WARN, "!%s%d: soft state zalloc failed ",
4714f52228b8SJoe Beteta DRV_NAME, instance);
4715f52228b8SJoe Beteta return (DDI_FAILURE);
4716f52228b8SJoe Beteta }
4717f52228b8SJoe Beteta
4718f52228b8SJoe Beteta progress |= SKD_SOFT_STATE_ALLOCED;
4719f52228b8SJoe Beteta
4720f52228b8SJoe Beteta skdev = ddi_get_soft_state(skd_state, instance);
4721f52228b8SJoe Beteta if (skdev == NULL) {
4722f52228b8SJoe Beteta cmn_err(CE_WARN, "!%s%d: Unable to get soft state structure",
4723f52228b8SJoe Beteta DRV_NAME, instance);
4724f52228b8SJoe Beteta goto skd_attach_failed;
4725f52228b8SJoe Beteta }
4726f52228b8SJoe Beteta
4727f52228b8SJoe Beteta (void) snprintf(skdev->name, sizeof (skdev->name),
4728f52228b8SJoe Beteta DRV_NAME "%d", instance);
4729f52228b8SJoe Beteta
4730f52228b8SJoe Beteta skdev->dip = dip;
4731f52228b8SJoe Beteta skdev->instance = instance;
4732f52228b8SJoe Beteta
4733f52228b8SJoe Beteta ddi_set_driver_private(dip, skdev);
4734f52228b8SJoe Beteta
4735f52228b8SJoe Beteta (void) ddi_pathname(dip, name);
4736f52228b8SJoe Beteta for (inx = strlen(name); inx; inx--) {
4737f52228b8SJoe Beteta if (name[inx] == ',') {
4738f52228b8SJoe Beteta name[inx] = '\0';
4739f52228b8SJoe Beteta break;
4740f52228b8SJoe Beteta }
4741f52228b8SJoe Beteta if (name[inx] == '@') {
4742f52228b8SJoe Beteta break;
4743f52228b8SJoe Beteta }
4744f52228b8SJoe Beteta }
4745f52228b8SJoe Beteta
4746f52228b8SJoe Beteta skdev->pathname = kmem_zalloc(strlen(name) + 1, KM_SLEEP);
4747f52228b8SJoe Beteta (void) strlcpy(skdev->pathname, name, strlen(name) + 1);
4748f52228b8SJoe Beteta
4749f52228b8SJoe Beteta progress |= SKD_PATHNAME_ALLOCED;
4750f52228b8SJoe Beteta skdev->flags |= SKD_PATHNAME_ALLOCED;
4751f52228b8SJoe Beteta
4752f52228b8SJoe Beteta if (pci_config_setup(dip, &skdev->pci_handle) != DDI_SUCCESS) {
4753f52228b8SJoe Beteta cmn_err(CE_WARN, "!%s%d: pci_config_setup FAILED",
4754f52228b8SJoe Beteta DRV_NAME, instance);
4755f52228b8SJoe Beteta goto skd_attach_failed;
4756f52228b8SJoe Beteta }
4757f52228b8SJoe Beteta
4758f52228b8SJoe Beteta progress |= SKD_CONFIG_SPACE_SETUP;
4759f52228b8SJoe Beteta
4760f52228b8SJoe Beteta /* Save adapter path. */
4761f52228b8SJoe Beteta
4762f52228b8SJoe Beteta (void) ddi_dev_nregs(dip, &nregs);
4763f52228b8SJoe Beteta
4764f52228b8SJoe Beteta /*
4765f52228b8SJoe Beteta * 0x0 Configuration Space
4766f52228b8SJoe Beteta * 0x1 I/O Space
4767f52228b8SJoe Beteta * 0x2 s1120 register space
4768f52228b8SJoe Beteta */
4769f52228b8SJoe Beteta if (ddi_dev_regsize(dip, 1, ®size) != DDI_SUCCESS ||
4770f52228b8SJoe Beteta ddi_regs_map_setup(dip, 1, &skdev->iobase, 0, regsize,
4771f52228b8SJoe Beteta &dev_acc_attr, &skdev->iobase_handle) != DDI_SUCCESS) {
4772f52228b8SJoe Beteta cmn_err(CE_WARN, "!%s%d: regs_map_setup(mem) failed",
4773f52228b8SJoe Beteta DRV_NAME, instance);
4774f52228b8SJoe Beteta goto skd_attach_failed;
4775f52228b8SJoe Beteta }
4776f52228b8SJoe Beteta progress |= SKD_REGS_MAPPED;
4777f52228b8SJoe Beteta
4778f52228b8SJoe Beteta skdev->iomap_iobase = skdev->iobase;
4779f52228b8SJoe Beteta skdev->iomap_handle = skdev->iobase_handle;
4780f52228b8SJoe Beteta
4781f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "%s: PCI iobase=%ph, iomap=%ph, regnum=%d, "
4782f52228b8SJoe Beteta "regsize=%ld", skdev->name, (void *)skdev->iobase,
4783f52228b8SJoe Beteta (void *)skdev->iomap_iobase, 1, regsize);
4784f52228b8SJoe Beteta
4785f52228b8SJoe Beteta if (ddi_dev_regsize(dip, 2, ®size) != DDI_SUCCESS ||
4786f52228b8SJoe Beteta ddi_regs_map_setup(dip, 2, &skdev->dev_iobase, 0, regsize,
4787f52228b8SJoe Beteta &dev_acc_attr, &skdev->dev_handle) != DDI_SUCCESS) {
4788f52228b8SJoe Beteta cmn_err(CE_WARN, "!%s%d: regs_map_setup(mem) failed",
4789f52228b8SJoe Beteta DRV_NAME, instance);
4790f52228b8SJoe Beteta
4791f52228b8SJoe Beteta goto skd_attach_failed;
4792f52228b8SJoe Beteta }
4793f52228b8SJoe Beteta
4794f52228b8SJoe Beteta skdev->dev_memsize = (int)regsize;
4795f52228b8SJoe Beteta
4796f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "%s: DEV iobase=%ph regsize=%d",
4797f52228b8SJoe Beteta skdev->name, (void *)skdev->dev_iobase,
4798f52228b8SJoe Beteta skdev->dev_memsize);
4799f52228b8SJoe Beteta
4800f52228b8SJoe Beteta progress |= SKD_DEV_IOBASE_MAPPED;
4801f52228b8SJoe Beteta
4802f52228b8SJoe Beteta cmd_reg = pci_config_get16(skdev->pci_handle, PCI_CONF_COMM);
4803f52228b8SJoe Beteta cmd_reg |= (PCI_COMM_ME | PCI_COMM_INTX_DISABLE);
4804f52228b8SJoe Beteta cmd_reg &= ~PCI_COMM_PARITY_DETECT;
4805f52228b8SJoe Beteta pci_config_put16(skdev->pci_handle, PCI_CONF_COMM, cmd_reg);
4806f52228b8SJoe Beteta
4807f52228b8SJoe Beteta /* Get adapter PCI device information. */
4808f52228b8SJoe Beteta skdev->vendor_id = pci_config_get16(skdev->pci_handle, PCI_CONF_VENID);
4809f52228b8SJoe Beteta skdev->device_id = pci_config_get16(skdev->pci_handle, PCI_CONF_DEVID);
4810f52228b8SJoe Beteta
4811f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "%s: %x-%x card detected",
4812f52228b8SJoe Beteta skdev->name, skdev->vendor_id, skdev->device_id);
4813f52228b8SJoe Beteta
4814f52228b8SJoe Beteta skd_get_properties(dip, skdev);
4815f52228b8SJoe Beteta
4816f52228b8SJoe Beteta (void) skd_init(skdev);
4817f52228b8SJoe Beteta
4818f52228b8SJoe Beteta if (skd_construct(skdev, instance)) {
4819f52228b8SJoe Beteta cmn_err(CE_WARN, "!%s: construct FAILED", skdev->name);
4820f52228b8SJoe Beteta goto skd_attach_failed;
4821f52228b8SJoe Beteta }
4822f52228b8SJoe Beteta
4823f52228b8SJoe Beteta progress |= SKD_PROBED;
4824f52228b8SJoe Beteta progress |= SKD_CONSTRUCTED;
4825f52228b8SJoe Beteta
4826f52228b8SJoe Beteta SIMPLEQ_INIT(&skdev->waitqueue);
4827f52228b8SJoe Beteta
4828f52228b8SJoe Beteta /*
4829f52228b8SJoe Beteta * Setup interrupt handler
4830f52228b8SJoe Beteta */
4831f52228b8SJoe Beteta if (skd_setup_interrupts(skdev) != DDI_SUCCESS) {
4832f52228b8SJoe Beteta cmn_err(CE_WARN, "!%s: Unable to add interrupt",
4833f52228b8SJoe Beteta skdev->name);
4834f52228b8SJoe Beteta goto skd_attach_failed;
4835f52228b8SJoe Beteta }
4836f52228b8SJoe Beteta
4837f52228b8SJoe Beteta progress |= SKD_INTR_ADDED;
4838f52228b8SJoe Beteta
4839f52228b8SJoe Beteta ADAPTER_STATE_LOCK(skdev);
4840f52228b8SJoe Beteta skdev->flags |= SKD_ATTACHED;
4841f52228b8SJoe Beteta ADAPTER_STATE_UNLOCK(skdev);
4842f52228b8SJoe Beteta
4843f52228b8SJoe Beteta skdev->d_blkshift = 9;
4844f52228b8SJoe Beteta progress |= SKD_ATTACHED;
4845f52228b8SJoe Beteta
4846f52228b8SJoe Beteta
4847f52228b8SJoe Beteta skd_start_device(skdev);
4848f52228b8SJoe Beteta
4849f52228b8SJoe Beteta ADAPTER_STATE_LOCK(skdev);
4850f52228b8SJoe Beteta skdev->progress = progress;
4851f52228b8SJoe Beteta ADAPTER_STATE_UNLOCK(skdev);
4852f52228b8SJoe Beteta
4853f52228b8SJoe Beteta /*
4854f52228b8SJoe Beteta * Give the board a chance to
4855f52228b8SJoe Beteta * complete its initialization.
4856f52228b8SJoe Beteta */
4857f52228b8SJoe Beteta if (skdev->gendisk_on != 1)
4858f52228b8SJoe Beteta (void) skd_wait_for_s1120(skdev);
4859f52228b8SJoe Beteta
4860f52228b8SJoe Beteta if (skdev->gendisk_on != 1) {
4861f52228b8SJoe Beteta cmn_err(CE_WARN, "!%s: s1120 failed to come ONLINE",
4862f52228b8SJoe Beteta skdev->name);
4863f52228b8SJoe Beteta goto skd_attach_failed;
4864f52228b8SJoe Beteta }
4865f52228b8SJoe Beteta
4866f52228b8SJoe Beteta ddi_report_dev(dip);
4867f52228b8SJoe Beteta
4868f52228b8SJoe Beteta skd_send_internal_skspcl(skdev, &skdev->internal_skspcl, INQUIRY);
4869f52228b8SJoe Beteta
4870f52228b8SJoe Beteta skdev->disks_initialized++;
4871f52228b8SJoe Beteta
4872f52228b8SJoe Beteta (void) strcpy(fw_version, "???");
4873f52228b8SJoe Beteta (void) skd_pci_info(skdev, pci_str, sizeof (pci_str));
4874f52228b8SJoe Beteta Dcmn_err(CE_NOTE, " sTec S1120 Driver(%s) version %s-b%s",
4875f52228b8SJoe Beteta DRV_NAME, DRV_VERSION, DRV_BUILD_ID);
4876f52228b8SJoe Beteta
4877f52228b8SJoe Beteta Dcmn_err(CE_NOTE, " sTec S1120 %04x:%04x %s 64 bit",
4878f52228b8SJoe Beteta skdev->vendor_id, skdev->device_id, pci_str);
4879f52228b8SJoe Beteta
4880f52228b8SJoe Beteta Dcmn_err(CE_NOTE, " sTec S1120 %s\n", skdev->pathname);
4881f52228b8SJoe Beteta
4882f52228b8SJoe Beteta if (*skdev->inq_serial_num)
4883f52228b8SJoe Beteta Dcmn_err(CE_NOTE, " sTec S1120 serial#=%s",
4884f52228b8SJoe Beteta skdev->inq_serial_num);
4885f52228b8SJoe Beteta
4886f52228b8SJoe Beteta if (*skdev->inq_product_id &&
4887f52228b8SJoe Beteta *skdev->inq_product_rev)
4888f52228b8SJoe Beteta Dcmn_err(CE_NOTE, " sTec S1120 prod ID=%s prod rev=%s",
4889f52228b8SJoe Beteta skdev->inq_product_id, skdev->inq_product_rev);
4890f52228b8SJoe Beteta
4891f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "%s: intr-type-cap: %d",
4892f52228b8SJoe Beteta skdev->name, skdev->irq_type);
4893f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "%s: max-scsi-reqs: %d",
4894f52228b8SJoe Beteta skdev->name, skd_max_queue_depth);
4895f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "%s: max-sgs-per-req: %d",
4896f52228b8SJoe Beteta skdev->name, skd_sgs_per_request);
4897f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "%s: max-scsi-req-per-msg: %d",
4898f52228b8SJoe Beteta skdev->name, skd_max_req_per_msg);
4899f52228b8SJoe Beteta
4900f52228b8SJoe Beteta if (skd_bd_attach(dip, skdev) == DDI_FAILURE)
4901f52228b8SJoe Beteta goto skd_attach_failed;
4902f52228b8SJoe Beteta
4903f52228b8SJoe Beteta skd_update_props(skdev, dip);
4904f52228b8SJoe Beteta
4905f52228b8SJoe Beteta /* Enable timer */
4906f52228b8SJoe Beteta skd_start_timer(skdev);
4907f52228b8SJoe Beteta
4908f52228b8SJoe Beteta ADAPTER_STATE_LOCK(skdev);
4909f52228b8SJoe Beteta skdev->progress = progress;
4910f52228b8SJoe Beteta ADAPTER_STATE_UNLOCK(skdev);
4911f52228b8SJoe Beteta
4912f52228b8SJoe Beteta skdev->attached = 1;
4913f52228b8SJoe Beteta return (DDI_SUCCESS);
4914f52228b8SJoe Beteta
4915f52228b8SJoe Beteta skd_attach_failed:
4916f52228b8SJoe Beteta skd_dealloc_resources(dip, skdev, progress, instance);
4917f52228b8SJoe Beteta
4918f52228b8SJoe Beteta if ((skdev->flags & SKD_MUTEX_DESTROYED) == 0) {
4919f52228b8SJoe Beteta skd_destroy_mutex(skdev);
4920f52228b8SJoe Beteta }
4921f52228b8SJoe Beteta
4922f52228b8SJoe Beteta ddi_soft_state_free(skd_state, instance);
4923f52228b8SJoe Beteta
4924f52228b8SJoe Beteta cmn_err(CE_WARN, "!skd_attach FAILED: progress=%x", progress);
4925f52228b8SJoe Beteta return (DDI_FAILURE);
4926f52228b8SJoe Beteta }
4927f52228b8SJoe Beteta
4928f52228b8SJoe Beteta /*
4929f52228b8SJoe Beteta *
4930f52228b8SJoe Beteta * Name: skd_halt
4931f52228b8SJoe Beteta *
4932f52228b8SJoe Beteta * Inputs: skdev - device state structure.
4933f52228b8SJoe Beteta *
4934f52228b8SJoe Beteta * Returns: Nothing.
4935f52228b8SJoe Beteta *
4936f52228b8SJoe Beteta */
4937f52228b8SJoe Beteta static void
skd_halt(skd_device_t * skdev)4938f52228b8SJoe Beteta skd_halt(skd_device_t *skdev)
4939f52228b8SJoe Beteta {
4940f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "%s: halt/suspend ......", skdev->name);
4941f52228b8SJoe Beteta }
4942f52228b8SJoe Beteta
4943f52228b8SJoe Beteta /*
4944f52228b8SJoe Beteta *
4945f52228b8SJoe Beteta * Name: skd_detach, detaches driver from the system.
4946f52228b8SJoe Beteta *
4947f52228b8SJoe Beteta * Inputs: dip - device info structure.
4948f52228b8SJoe Beteta *
4949f52228b8SJoe Beteta * Returns: DDI_SUCCESS on successful detach otherwise DDI_FAILURE.
4950f52228b8SJoe Beteta *
4951f52228b8SJoe Beteta */
4952f52228b8SJoe Beteta static int
skd_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)4953f52228b8SJoe Beteta skd_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
4954f52228b8SJoe Beteta {
4955f52228b8SJoe Beteta skd_buf_private_t *pbuf;
4956f52228b8SJoe Beteta skd_device_t *skdev;
4957f52228b8SJoe Beteta int instance;
4958f52228b8SJoe Beteta timeout_id_t timer_id = NULL;
4959f52228b8SJoe Beteta int rv1 = DDI_SUCCESS;
4960f52228b8SJoe Beteta struct skd_special_context *skspcl;
4961f52228b8SJoe Beteta
4962f52228b8SJoe Beteta instance = ddi_get_instance(dip);
4963f52228b8SJoe Beteta
4964f52228b8SJoe Beteta skdev = ddi_get_soft_state(skd_state, instance);
4965f52228b8SJoe Beteta if (skdev == NULL) {
4966f52228b8SJoe Beteta cmn_err(CE_WARN, "!detach failed: NULL skd state");
4967f52228b8SJoe Beteta
4968f52228b8SJoe Beteta return (DDI_FAILURE);
4969f52228b8SJoe Beteta }
4970f52228b8SJoe Beteta
4971f52228b8SJoe Beteta Dcmn_err(CE_CONT, "skd_detach(%d): entered", instance);
4972f52228b8SJoe Beteta
4973f52228b8SJoe Beteta switch (cmd) {
4974f52228b8SJoe Beteta case DDI_DETACH:
4975f52228b8SJoe Beteta /* Test for packet cache inuse. */
4976f52228b8SJoe Beteta ADAPTER_STATE_LOCK(skdev);
4977f52228b8SJoe Beteta
4978f52228b8SJoe Beteta /* Stop command/event processing. */
4979f52228b8SJoe Beteta skdev->flags |= (SKD_SUSPENDED | SKD_CMD_ABORT_TMO);
4980f52228b8SJoe Beteta
4981f52228b8SJoe Beteta /* Disable driver timer if no adapters. */
4982f52228b8SJoe Beteta if (skdev->skd_timer_timeout_id != 0) {
4983f52228b8SJoe Beteta timer_id = skdev->skd_timer_timeout_id;
4984f52228b8SJoe Beteta skdev->skd_timer_timeout_id = 0;
4985f52228b8SJoe Beteta }
4986f52228b8SJoe Beteta ADAPTER_STATE_UNLOCK(skdev);
4987f52228b8SJoe Beteta
4988f52228b8SJoe Beteta if (timer_id != 0) {
4989f52228b8SJoe Beteta (void) untimeout(timer_id);
4990f52228b8SJoe Beteta }
4991f52228b8SJoe Beteta
4992f52228b8SJoe Beteta #ifdef SKD_PM
4993f52228b8SJoe Beteta if (skdev->power_level != LOW_POWER_LEVEL) {
4994f52228b8SJoe Beteta skd_halt(skdev);
4995f52228b8SJoe Beteta skdev->power_level = LOW_POWER_LEVEL;
4996f52228b8SJoe Beteta }
4997f52228b8SJoe Beteta #endif
4998f52228b8SJoe Beteta skspcl = &skdev->internal_skspcl;
4999f52228b8SJoe Beteta skd_send_internal_skspcl(skdev, skspcl, SYNCHRONIZE_CACHE);
5000f52228b8SJoe Beteta
5001f52228b8SJoe Beteta skd_stop_device(skdev);
5002f52228b8SJoe Beteta
5003f52228b8SJoe Beteta /*
5004f52228b8SJoe Beteta * Clear request queue.
5005f52228b8SJoe Beteta */
5006f52228b8SJoe Beteta while (!SIMPLEQ_EMPTY(&skdev->waitqueue)) {
5007f52228b8SJoe Beteta pbuf = skd_get_queued_pbuf(skdev);
5008f52228b8SJoe Beteta skd_end_request_abnormal(skdev, pbuf, ECANCELED,
5009f52228b8SJoe Beteta SKD_IODONE_WNIOC);
5010f52228b8SJoe Beteta Dcmn_err(CE_NOTE,
5011f52228b8SJoe Beteta "detach: cancelled pbuf %p %ld <%s> %lld\n",
5012f52228b8SJoe Beteta (void *)pbuf, pbuf->x_xfer->x_nblks,
5013f52228b8SJoe Beteta (pbuf->dir & B_READ) ? "Read" : "Write",
5014f52228b8SJoe Beteta pbuf->x_xfer->x_blkno);
5015f52228b8SJoe Beteta }
5016f52228b8SJoe Beteta
5017f52228b8SJoe Beteta skd_bd_detach(skdev);
5018f52228b8SJoe Beteta
5019f52228b8SJoe Beteta skd_dealloc_resources(dip, skdev, skdev->progress, instance);
5020f52228b8SJoe Beteta
5021f52228b8SJoe Beteta if ((skdev->flags & SKD_MUTEX_DESTROYED) == 0) {
5022f52228b8SJoe Beteta skd_destroy_mutex(skdev);
5023f52228b8SJoe Beteta }
5024f52228b8SJoe Beteta
5025f52228b8SJoe Beteta ddi_soft_state_free(skd_state, instance);
5026f52228b8SJoe Beteta
5027f52228b8SJoe Beteta skd_exit();
5028f52228b8SJoe Beteta
5029f52228b8SJoe Beteta break;
5030f52228b8SJoe Beteta
5031f52228b8SJoe Beteta case DDI_SUSPEND:
5032f52228b8SJoe Beteta /* Block timer. */
5033f52228b8SJoe Beteta
5034f52228b8SJoe Beteta ADAPTER_STATE_LOCK(skdev);
5035f52228b8SJoe Beteta skdev->flags |= SKD_SUSPENDED;
5036f52228b8SJoe Beteta
5037f52228b8SJoe Beteta /* Disable driver timer if last adapter. */
5038f52228b8SJoe Beteta if (skdev->skd_timer_timeout_id != 0) {
5039f52228b8SJoe Beteta timer_id = skdev->skd_timer_timeout_id;
5040f52228b8SJoe Beteta skdev->skd_timer_timeout_id = 0;
5041f52228b8SJoe Beteta }
5042f52228b8SJoe Beteta ADAPTER_STATE_UNLOCK(skdev);
5043f52228b8SJoe Beteta
5044f52228b8SJoe Beteta if (timer_id != 0) {
5045f52228b8SJoe Beteta (void) untimeout(timer_id);
5046f52228b8SJoe Beteta }
5047f52228b8SJoe Beteta
5048f52228b8SJoe Beteta ddi_prop_remove_all(dip);
5049f52228b8SJoe Beteta
5050f52228b8SJoe Beteta skd_halt(skdev);
5051f52228b8SJoe Beteta
5052f52228b8SJoe Beteta break;
5053f52228b8SJoe Beteta default:
5054f52228b8SJoe Beteta rv1 = DDI_FAILURE;
5055f52228b8SJoe Beteta break;
5056f52228b8SJoe Beteta }
5057f52228b8SJoe Beteta
5058f52228b8SJoe Beteta if (rv1 != DDI_SUCCESS) {
5059f52228b8SJoe Beteta cmn_err(CE_WARN, "!skd_detach, failed, rv1=%x", rv1);
5060f52228b8SJoe Beteta } else {
5061f52228b8SJoe Beteta Dcmn_err(CE_CONT, "skd_detach: exiting");
5062f52228b8SJoe Beteta }
5063f52228b8SJoe Beteta
5064f52228b8SJoe Beteta if (rv1 != DDI_SUCCESS)
5065f52228b8SJoe Beteta return (DDI_FAILURE);
5066f52228b8SJoe Beteta
5067f52228b8SJoe Beteta return (rv1);
5068f52228b8SJoe Beteta }
5069f52228b8SJoe Beteta
5070f52228b8SJoe Beteta /*
5071f52228b8SJoe Beteta *
5072f52228b8SJoe Beteta * Name: skd_devid_init, calls skd_setup_devid to setup
5073f52228b8SJoe Beteta * the device's devid structure.
5074f52228b8SJoe Beteta *
5075f52228b8SJoe Beteta * Inputs: arg - device state structure.
5076f52228b8SJoe Beteta * dip - dev_info structure.
5077f52228b8SJoe Beteta * devid - devid structure.
5078f52228b8SJoe Beteta *
5079f52228b8SJoe Beteta * Returns: Nothing.
5080f52228b8SJoe Beteta *
5081f52228b8SJoe Beteta */
5082f52228b8SJoe Beteta /* ARGSUSED */ /* Upstream common source with other platforms. */
5083f52228b8SJoe Beteta static int
skd_devid_init(void * arg,dev_info_t * dip,ddi_devid_t * devid)5084f52228b8SJoe Beteta skd_devid_init(void *arg, dev_info_t *dip, ddi_devid_t *devid)
5085f52228b8SJoe Beteta {
5086f52228b8SJoe Beteta skd_device_t *skdev = arg;
5087f52228b8SJoe Beteta
5088f52228b8SJoe Beteta (void) skd_setup_devid(skdev, devid);
5089f52228b8SJoe Beteta
5090f52228b8SJoe Beteta return (0);
5091f52228b8SJoe Beteta }
5092f52228b8SJoe Beteta
5093f52228b8SJoe Beteta /*
5094f52228b8SJoe Beteta *
5095f52228b8SJoe Beteta * Name: skd_bd_driveinfo, retrieves device's info.
5096f52228b8SJoe Beteta *
5097f52228b8SJoe Beteta * Inputs: drive - drive data structure.
5098f52228b8SJoe Beteta * arg - device state structure.
5099f52228b8SJoe Beteta *
5100f52228b8SJoe Beteta * Returns: Nothing.
5101f52228b8SJoe Beteta *
5102f52228b8SJoe Beteta */
5103f52228b8SJoe Beteta static void
skd_bd_driveinfo(void * arg,bd_drive_t * drive)5104f52228b8SJoe Beteta skd_bd_driveinfo(void *arg, bd_drive_t *drive)
5105f52228b8SJoe Beteta {
5106f52228b8SJoe Beteta skd_device_t *skdev = arg;
5107f52228b8SJoe Beteta
5108f52228b8SJoe Beteta drive->d_qsize = (skdev->queue_depth_limit * 4) / 5;
5109f52228b8SJoe Beteta drive->d_maxxfer = SKD_DMA_MAXXFER;
5110f52228b8SJoe Beteta drive->d_removable = B_FALSE;
5111f52228b8SJoe Beteta drive->d_hotpluggable = B_FALSE;
5112f52228b8SJoe Beteta drive->d_target = 0;
5113f52228b8SJoe Beteta drive->d_lun = 0;
5114510a6847SHans Rosenfeld
5115510a6847SHans Rosenfeld if (skdev->inquiry_is_valid != 0) {
5116510a6847SHans Rosenfeld drive->d_vendor = skdev->inq_vendor_id;
5117510a6847SHans Rosenfeld drive->d_vendor_len = strlen(drive->d_vendor);
5118510a6847SHans Rosenfeld
5119510a6847SHans Rosenfeld drive->d_product = skdev->inq_product_id;
5120510a6847SHans Rosenfeld drive->d_product_len = strlen(drive->d_product);
5121510a6847SHans Rosenfeld
5122510a6847SHans Rosenfeld drive->d_serial = skdev->inq_serial_num;
5123510a6847SHans Rosenfeld drive->d_serial_len = strlen(drive->d_serial);
5124510a6847SHans Rosenfeld
5125510a6847SHans Rosenfeld drive->d_revision = skdev->inq_product_rev;
5126510a6847SHans Rosenfeld drive->d_revision_len = strlen(drive->d_revision);
5127510a6847SHans Rosenfeld }
5128f52228b8SJoe Beteta }
5129f52228b8SJoe Beteta
5130f52228b8SJoe Beteta /*
5131f52228b8SJoe Beteta *
5132f52228b8SJoe Beteta * Name: skd_bd_mediainfo, retrieves device media info.
5133f52228b8SJoe Beteta *
5134f52228b8SJoe Beteta * Inputs: arg - device state structure.
5135f52228b8SJoe Beteta * media - container for media info.
5136f52228b8SJoe Beteta *
5137f52228b8SJoe Beteta * Returns: Zero.
5138f52228b8SJoe Beteta *
5139f52228b8SJoe Beteta */
5140f52228b8SJoe Beteta static int
skd_bd_mediainfo(void * arg,bd_media_t * media)5141f52228b8SJoe Beteta skd_bd_mediainfo(void *arg, bd_media_t *media)
5142f52228b8SJoe Beteta {
5143f52228b8SJoe Beteta skd_device_t *skdev = arg;
5144f52228b8SJoe Beteta
5145f52228b8SJoe Beteta media->m_nblks = skdev->Nblocks;
5146f52228b8SJoe Beteta media->m_blksize = 512;
5147f52228b8SJoe Beteta media->m_pblksize = 4096;
5148f52228b8SJoe Beteta media->m_readonly = B_FALSE;
5149f52228b8SJoe Beteta media->m_solidstate = B_TRUE;
5150f52228b8SJoe Beteta
5151f52228b8SJoe Beteta return (0);
5152f52228b8SJoe Beteta }
5153f52228b8SJoe Beteta
5154f52228b8SJoe Beteta /*
5155f52228b8SJoe Beteta *
5156f52228b8SJoe Beteta * Name: skd_rw, performs R/W requests for blkdev driver.
5157f52228b8SJoe Beteta *
5158f52228b8SJoe Beteta * Inputs: skdev - device state structure.
5159f52228b8SJoe Beteta * xfer - tranfer structure.
5160f52228b8SJoe Beteta * dir - I/O direction.
5161f52228b8SJoe Beteta *
5162f52228b8SJoe Beteta * Returns: EAGAIN if device is not online. EIO if blkdev wants us to
5163f52228b8SJoe Beteta * be a dump device (for now).
5164f52228b8SJoe Beteta * Value returned by skd_start().
5165f52228b8SJoe Beteta *
5166f52228b8SJoe Beteta */
5167f52228b8SJoe Beteta static int
skd_rw(skd_device_t * skdev,bd_xfer_t * xfer,int dir)5168f52228b8SJoe Beteta skd_rw(skd_device_t *skdev, bd_xfer_t *xfer, int dir)
5169f52228b8SJoe Beteta {
5170f52228b8SJoe Beteta skd_buf_private_t *pbuf;
5171f52228b8SJoe Beteta
5172f52228b8SJoe Beteta /*
5173f52228b8SJoe Beteta * The x_flags structure element is not defined in Oracle Solaris
5174f52228b8SJoe Beteta */
5175f52228b8SJoe Beteta /* We'll need to fix this in order to support dump on this device. */
5176f52228b8SJoe Beteta if (xfer->x_flags & BD_XFER_POLL)
5177f52228b8SJoe Beteta return (EIO);
5178f52228b8SJoe Beteta
5179f52228b8SJoe Beteta if (skdev->state != SKD_DRVR_STATE_ONLINE) {
5180f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "Device - not ONLINE");
5181f52228b8SJoe Beteta
5182f52228b8SJoe Beteta skd_request_fn_not_online(skdev);
5183f52228b8SJoe Beteta
5184f52228b8SJoe Beteta return (EAGAIN);
5185f52228b8SJoe Beteta }
5186f52228b8SJoe Beteta
5187f52228b8SJoe Beteta pbuf = kmem_zalloc(sizeof (skd_buf_private_t), KM_NOSLEEP);
5188f52228b8SJoe Beteta if (pbuf == NULL)
5189f52228b8SJoe Beteta return (ENOMEM);
5190f52228b8SJoe Beteta
5191f52228b8SJoe Beteta WAITQ_LOCK(skdev);
5192f52228b8SJoe Beteta pbuf->dir = dir;
5193f52228b8SJoe Beteta pbuf->x_xfer = xfer;
5194f52228b8SJoe Beteta
5195f52228b8SJoe Beteta skd_queue(skdev, pbuf);
5196f52228b8SJoe Beteta skdev->ios_queued++;
5197f52228b8SJoe Beteta WAITQ_UNLOCK(skdev);
5198f52228b8SJoe Beteta
5199f52228b8SJoe Beteta skd_start(skdev);
5200f52228b8SJoe Beteta
5201f52228b8SJoe Beteta return (0);
5202f52228b8SJoe Beteta }
5203f52228b8SJoe Beteta
5204f52228b8SJoe Beteta /*
5205f52228b8SJoe Beteta *
5206f52228b8SJoe Beteta * Name: skd_bd_read, performs blkdev read requests.
5207f52228b8SJoe Beteta *
5208f52228b8SJoe Beteta * Inputs: arg - device state structure.
5209f52228b8SJoe Beteta * xfer - tranfer request structure.
5210f52228b8SJoe Beteta *
5211f52228b8SJoe Beteta * Returns: Value return by skd_rw().
5212f52228b8SJoe Beteta *
5213f52228b8SJoe Beteta */
5214f52228b8SJoe Beteta static int
skd_bd_read(void * arg,bd_xfer_t * xfer)5215f52228b8SJoe Beteta skd_bd_read(void *arg, bd_xfer_t *xfer)
5216f52228b8SJoe Beteta {
5217f52228b8SJoe Beteta return (skd_rw(arg, xfer, B_READ));
5218f52228b8SJoe Beteta }
5219f52228b8SJoe Beteta
5220f52228b8SJoe Beteta /*
5221f52228b8SJoe Beteta *
5222f52228b8SJoe Beteta * Name: skd_bd_write, performs blkdev write requests.
5223f52228b8SJoe Beteta *
5224f52228b8SJoe Beteta * Inputs: arg - device state structure.
5225f52228b8SJoe Beteta * xfer - tranfer request structure.
5226f52228b8SJoe Beteta *
5227f52228b8SJoe Beteta * Returns: Value return by skd_rw().
5228f52228b8SJoe Beteta *
5229f52228b8SJoe Beteta */
5230f52228b8SJoe Beteta static int
skd_bd_write(void * arg,bd_xfer_t * xfer)5231f52228b8SJoe Beteta skd_bd_write(void *arg, bd_xfer_t *xfer)
5232f52228b8SJoe Beteta {
5233f52228b8SJoe Beteta return (skd_rw(arg, xfer, B_WRITE));
5234f52228b8SJoe Beteta }
5235