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