xref: /illumos-gate/usr/src/uts/common/io/skd/skd.c (revision fd5e5f43)
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, &regsize) != 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, &regsize) != 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