1*8226594fSRick McNeal /*
2*8226594fSRick McNeal  * This file and its contents are supplied under the terms of the
3*8226594fSRick McNeal  * Common Development and Distribution License ("CDDL"), version 1.0.
4*8226594fSRick McNeal  * You may only use this file in accordance with the terms of version
5*8226594fSRick McNeal  * 1.0 of the CDDL.
6*8226594fSRick McNeal  *
7*8226594fSRick McNeal  * A full copy of the text of the CDDL should have accompanied this
8*8226594fSRick McNeal  * source.  A copy of the CDDL is also available via the Internet at
9*8226594fSRick McNeal  * http://www.illumos.org/license/CDDL.
10*8226594fSRick McNeal  */
11*8226594fSRick McNeal 
12*8226594fSRick McNeal /*
13*8226594fSRick McNeal  * Copyright 2023 Tintri by DDN, Inc. All rights reserved.
14*8226594fSRick McNeal  * Copyright 2019 RackTop Systems, Inc.
15*8226594fSRick McNeal  */
16*8226594fSRick McNeal 
17*8226594fSRick McNeal /*
18*8226594fSRick McNeal  * Utility routines that have common usage throughout the driver.
19*8226594fSRick McNeal  */
20*8226594fSRick McNeal #include <smartpqi.h>
21*8226594fSRick McNeal 
22*8226594fSRick McNeal /* ---- Forward declarations for support/utility functions ---- */
23*8226594fSRick McNeal static void reinit_io(pqi_io_request_t *io);
24*8226594fSRick McNeal static void dump_raid(pqi_state_t *s, void *v, pqi_index_t idx);
25*8226594fSRick McNeal static void dump_aio(void *v);
26*8226594fSRick McNeal static void show_error_detail(pqi_state_t *s);
27*8226594fSRick McNeal static void cmd_start_time(pqi_cmd_t *c);
28*8226594fSRick McNeal static void cmd_finish_task(void *v);
29*8226594fSRick McNeal 
30*8226594fSRick McNeal 
31*8226594fSRick McNeal /*
32*8226594fSRick McNeal  * Entry points for this file
33*8226594fSRick McNeal  */
34*8226594fSRick McNeal 
35*8226594fSRick McNeal #ifdef DEBUG
36*8226594fSRick McNeal int	pqi_shuffle_delay = 0;
37*8226594fSRick McNeal #endif	/* DEBUG */
38*8226594fSRick McNeal 
39*8226594fSRick McNeal static void
cmd_remove_group(pqi_cmd_t * c)40*8226594fSRick McNeal cmd_remove_group(pqi_cmd_t *c)
41*8226594fSRick McNeal {
42*8226594fSRick McNeal 	pqi_io_request_t	*io = c->pc_io_rqst;
43*8226594fSRick McNeal 	pqi_device_t		*d = c->pc_device;
44*8226594fSRick McNeal 
45*8226594fSRick McNeal 	/*
46*8226594fSRick McNeal 	 * This would be a good place to send a SCSI TASK MANAGEMENT
47*8226594fSRick McNeal 	 * command to cancel an individual command, but we don't
48*8226594fSRick McNeal 	 * have any documentation on the HBA to describe how that
49*8226594fSRick McNeal 	 * might be done.
50*8226594fSRick McNeal 	 */
51*8226594fSRick McNeal 	if (io != NULL) {
52*8226594fSRick McNeal 		pqi_queue_group_t	*qg = io->io_queue_group;
53*8226594fSRick McNeal 		int			path = io->io_queue_path;
54*8226594fSRick McNeal 
55*8226594fSRick McNeal 		/*
56*8226594fSRick McNeal 		 * The lock ordering is such that the driver must drop
57*8226594fSRick McNeal 		 * the device lock in order to grab the queue lock.
58*8226594fSRick McNeal 		 * We must also drop the cmd mutex to prevent possible deadlock.
59*8226594fSRick McNeal 		 */
60*8226594fSRick McNeal 		mutex_exit(&c->pc_mutex);
61*8226594fSRick McNeal 		mutex_exit(&d->pd_mutex);
62*8226594fSRick McNeal 		mutex_enter(&qg->submit_lock[path]);
63*8226594fSRick McNeal 		if (list_link_active(&io->io_list_node)) {
64*8226594fSRick McNeal 			list_remove(&qg->request_list[path], io);
65*8226594fSRick McNeal 		}
66*8226594fSRick McNeal 		mutex_exit(&qg->submit_lock[path]);
67*8226594fSRick McNeal #ifdef DEBUG
68*8226594fSRick McNeal 		if (pqi_shuffle_delay != 0) { /* try to force deadlock error */
69*8226594fSRick McNeal 			pqi_state_t	*s = c->pc_softc;
70*8226594fSRick McNeal 			pqi_lun_reset(s, d);
71*8226594fSRick McNeal 			delay(pqi_shuffle_delay * drv_usectohz(1000000));
72*8226594fSRick McNeal 		}
73*8226594fSRick McNeal #endif	/* DEBUG */
74*8226594fSRick McNeal 		mutex_enter(&d->pd_mutex);
75*8226594fSRick McNeal 		mutex_enter(&c->pc_mutex);
76*8226594fSRick McNeal 	}
77*8226594fSRick McNeal }
78*8226594fSRick McNeal 
79*8226594fSRick McNeal pqi_cmd_action_t
pqi_cmd_action_nolock(pqi_cmd_t * c,pqi_cmd_action_t a)80*8226594fSRick McNeal pqi_cmd_action_nolock(pqi_cmd_t *c, pqi_cmd_action_t a)
81*8226594fSRick McNeal {
82*8226594fSRick McNeal 	pqi_device_t	*d = c->pc_device;
83*8226594fSRick McNeal 	pqi_state_t	*s = c->pc_softc;
84*8226594fSRick McNeal 	struct scsi_pkt	*pkt;
85*8226594fSRick McNeal 
86*8226594fSRick McNeal 	mutex_enter(&c->pc_mutex);
87*8226594fSRick McNeal 	/*
88*8226594fSRick McNeal 	 * Don't change cmd if we are in middle of a timeout.
89*8226594fSRick McNeal 	 */
90*8226594fSRick McNeal 	if ((c->pc_flags & PQI_FLAG_TIMED_OUT) != 0) {
91*8226594fSRick McNeal 		a = PQI_CMD_FAIL;
92*8226594fSRick McNeal 		goto skipto;
93*8226594fSRick McNeal 	}
94*8226594fSRick McNeal 	c->pc_last_action = c->pc_cur_action;
95*8226594fSRick McNeal 	c->pc_cur_action = a;
96*8226594fSRick McNeal 	switch (a) {
97*8226594fSRick McNeal 	case PQI_CMD_QUEUE:
98*8226594fSRick McNeal 		list_insert_tail(&d->pd_cmd_list, c);
99*8226594fSRick McNeal 
100*8226594fSRick McNeal 		/*
101*8226594fSRick McNeal 		 * Set the start time now in case the HBA hangs. That will
102*8226594fSRick McNeal 		 * allow the timeout processing to handle these commands, which
103*8226594fSRick McNeal 		 * in theory have been started but not really started, without
104*8226594fSRick McNeal 		 * the need for special handling logic in the timeout scan.
105*8226594fSRick McNeal 		 */
106*8226594fSRick McNeal 		cmd_start_time(c);
107*8226594fSRick McNeal 		break;
108*8226594fSRick McNeal 
109*8226594fSRick McNeal 	case PQI_CMD_START:
110*8226594fSRick McNeal 		if (c->pc_last_action == PQI_CMD_FAIL) {
111*8226594fSRick McNeal 			list_remove(&d->pd_cmd_list, c);
112*8226594fSRick McNeal 
113*8226594fSRick McNeal 			pkt = CMD2PKT(c);
114*8226594fSRick McNeal 			if (pkt == NULL) {
115*8226594fSRick McNeal 				pqi_io_request_t	*io = c->pc_io_rqst;
116*8226594fSRick McNeal 
117*8226594fSRick McNeal 				io->io_status = PQI_DATA_IN_OUT_TIMEOUT;
118*8226594fSRick McNeal 				(*io->io_cb)(io, io->io_context);
119*8226594fSRick McNeal 				pqi_free_io(io);
120*8226594fSRick McNeal 				c->pc_io_rqst = NULL;
121*8226594fSRick McNeal 			} else {
122*8226594fSRick McNeal 				pqi_free_io(c->pc_io_rqst);
123*8226594fSRick McNeal 				c->pc_io_rqst = NULL;
124*8226594fSRick McNeal 				(void) ddi_taskq_dispatch(s->s_complete_taskq,
125*8226594fSRick McNeal 				    cmd_finish_task, c, 0);
126*8226594fSRick McNeal 			}
127*8226594fSRick McNeal 			a = PQI_CMD_FAIL;
128*8226594fSRick McNeal 		} else {
129*8226594fSRick McNeal 			/*
130*8226594fSRick McNeal 			 * Now that the command is actually being sent to the
131*8226594fSRick McNeal 			 * HBA reset the start so that a timeout will occur
132*8226594fSRick McNeal 			 * only after the HBA has had the command for some
133*8226594fSRick McNeal 			 * amount of time as defined by the SCSI packet.
134*8226594fSRick McNeal 			 */
135*8226594fSRick McNeal 			cmd_start_time(c);
136*8226594fSRick McNeal 		}
137*8226594fSRick McNeal 		break;
138*8226594fSRick McNeal 
139*8226594fSRick McNeal 	case PQI_CMD_FAIL:
140*8226594fSRick McNeal 		if (c->pc_last_action == PQI_CMD_START) {
141*8226594fSRick McNeal 			/*
142*8226594fSRick McNeal 			 * There's no means to cancel a command that has
143*8226594fSRick McNeal 			 * been passed to the HBA, at least none without more
144*8226594fSRick McNeal 			 * documentation. So, if the command has been passed
145*8226594fSRick McNeal 			 * to the HBA the queue slot must remain active until
146*8226594fSRick McNeal 			 * the command completes. If it fails to complete
147*8226594fSRick McNeal 			 * then it will be freed by cmd_timeout_scan() when
148*8226594fSRick McNeal 			 * the action is PQI_CMD_TIMEOUT. So, for now keep
149*8226594fSRick McNeal 			 * the action as being PQI_CMD_START.
150*8226594fSRick McNeal 			 */
151*8226594fSRick McNeal 			a = PQI_CMD_START;
152*8226594fSRick McNeal 		} else {
153*8226594fSRick McNeal 			/*
154*8226594fSRick McNeal 			 * Don't do any actual processing here to cancel and
155*8226594fSRick McNeal 			 * free the command. By leaving the pc_cur_action
156*8226594fSRick McNeal 			 * set to PQI_CMD_FAIL the command will be freed
157*8226594fSRick McNeal 			 * when pqi_start_io() calls pqi_cmd_action(). The need
158*8226594fSRick McNeal 			 * for handling the error case in this manner is due
159*8226594fSRick McNeal 			 * to a small window in pqi_start_io() where the command
160*8226594fSRick McNeal 			 * has been removed from the group queue and before
161*8226594fSRick McNeal 			 * pqi_cmd_action() is called. It would be possible
162*8226594fSRick McNeal 			 * to fix by adding an additional lock to
163*8226594fSRick McNeal 			 * pqi_io_request_t or handle the issue in this manner.
164*8226594fSRick McNeal 			 * Less locks == good.
165*8226594fSRick McNeal 			 */
166*8226594fSRick McNeal 			/*
167*8226594fSRick McNeal 			 * We could have come in here during a cmd timeout
168*8226594fSRick McNeal 			 * lock shuffle so last action might be timeout here.
169*8226594fSRick McNeal 			 */
170*8226594fSRick McNeal 			ASSERT(c->pc_last_action == PQI_CMD_TIMEOUT ||
171*8226594fSRick McNeal 			    c->pc_last_action == PQI_CMD_QUEUE);
172*8226594fSRick McNeal 		}
173*8226594fSRick McNeal 		break;
174*8226594fSRick McNeal 
175*8226594fSRick McNeal 	case PQI_CMD_TIMEOUT:
176*8226594fSRick McNeal 		list_remove(&d->pd_cmd_list, c);
177*8226594fSRick McNeal 		/*
178*8226594fSRick McNeal 		 * Set a flag to prevent this command from changing while we
179*8226594fSRick McNeal 		 * shuffle locks below.
180*8226594fSRick McNeal 		 */
181*8226594fSRick McNeal 		c->pc_flags |= PQI_FLAG_TIMED_OUT;
182*8226594fSRick McNeal 		cmd_remove_group(c);
183*8226594fSRick McNeal 
184*8226594fSRick McNeal 		/*
185*8226594fSRick McNeal 		 * When a timeout has occurred it means something has gone
186*8226594fSRick McNeal 		 * wrong with the HBA or drive.  Timed out io requests are
187*8226594fSRick McNeal 		 * marked and the cmd was marked and removed from the chain
188*8226594fSRick McNeal 		 * above so it should not have changed state when we dropped
189*8226594fSRick McNeal 		 * and re-grabbed the locks.
190*8226594fSRick McNeal 		 */
191*8226594fSRick McNeal 		ASSERT3U(c->pc_cur_action, ==, PQI_CMD_TIMEOUT);
192*8226594fSRick McNeal 
193*8226594fSRick McNeal 		c->pc_flags &= ~PQI_FLAG_TIMED_OUT;
194*8226594fSRick McNeal 		/*
195*8226594fSRick McNeal 		 * Internal commands to the driver will not have a SCSI packet
196*8226594fSRick McNeal 		 * associated.
197*8226594fSRick McNeal 		 */
198*8226594fSRick McNeal 		pkt = CMD2PKT(c);
199*8226594fSRick McNeal 		if (pkt == NULL) {
200*8226594fSRick McNeal 			pqi_io_request_t	*io = c->pc_io_rqst;
201*8226594fSRick McNeal 
202*8226594fSRick McNeal 			io->io_status = PQI_DATA_IN_OUT_TIMEOUT;
203*8226594fSRick McNeal 			(*io->io_cb)(io, io->io_context);
204*8226594fSRick McNeal 			pqi_free_io(c->pc_io_rqst);
205*8226594fSRick McNeal 			c->pc_io_rqst = NULL;
206*8226594fSRick McNeal 		} else {
207*8226594fSRick McNeal 			pqi_free_io(c->pc_io_rqst);
208*8226594fSRick McNeal 			c->pc_io_rqst = NULL;
209*8226594fSRick McNeal 			mutex_exit(&c->pc_mutex);
210*8226594fSRick McNeal 			(void) ddi_taskq_dispatch(s->s_complete_taskq,
211*8226594fSRick McNeal 			    cmd_finish_task, c, 0);
212*8226594fSRick McNeal 			return (a);
213*8226594fSRick McNeal 		}
214*8226594fSRick McNeal 		break;
215*8226594fSRick McNeal 
216*8226594fSRick McNeal 	case PQI_CMD_CMPLT:
217*8226594fSRick McNeal 		if (c->pc_last_action == PQI_CMD_TIMEOUT)
218*8226594fSRick McNeal 			break;
219*8226594fSRick McNeal 
220*8226594fSRick McNeal 		list_remove(&d->pd_cmd_list, c);
221*8226594fSRick McNeal 
222*8226594fSRick McNeal 		pqi_free_io(c->pc_io_rqst);
223*8226594fSRick McNeal 		c->pc_io_rqst = NULL;
224*8226594fSRick McNeal 		if (CMD2PKT(c) != NULL) {
225*8226594fSRick McNeal 			/*
226*8226594fSRick McNeal 			 * ddi_taskq_dispatch doesn't always start a separate
227*8226594fSRick McNeal 			 * thread. Under some conditions this will turn into
228*8226594fSRick McNeal 			 * a direct call to cmd_finish_task(). That in turn
229*8226594fSRick McNeal 			 * calls into the SCSA layer which can call
230*8226594fSRick McNeal 			 * tran_ini_pkt which will eventually try to call
231*8226594fSRick McNeal 			 * pqi_cmd_action(). So, need to drop the mutex before
232*8226594fSRick McNeal 			 * making the call to ddi_taskq_dispatch and then
233*8226594fSRick McNeal 			 * return.
234*8226594fSRick McNeal 			 */
235*8226594fSRick McNeal 			mutex_exit(&c->pc_mutex);
236*8226594fSRick McNeal 			(void) ddi_taskq_dispatch(s->s_complete_taskq,
237*8226594fSRick McNeal 			    cmd_finish_task, c, 0);
238*8226594fSRick McNeal 			return (a);
239*8226594fSRick McNeal 		}
240*8226594fSRick McNeal 		break;
241*8226594fSRick McNeal 
242*8226594fSRick McNeal 	default:
243*8226594fSRick McNeal 		cmn_err(CE_PANIC,
244*8226594fSRick McNeal 		    "%s: Unknown action request: %d", __func__, a);
245*8226594fSRick McNeal 	}
246*8226594fSRick McNeal skipto:
247*8226594fSRick McNeal 	mutex_exit(&c->pc_mutex);
248*8226594fSRick McNeal 	return (a);
249*8226594fSRick McNeal }
250*8226594fSRick McNeal 
251*8226594fSRick McNeal pqi_cmd_action_t
pqi_cmd_action(pqi_cmd_t * c,pqi_cmd_action_t a)252*8226594fSRick McNeal pqi_cmd_action(pqi_cmd_t *c, pqi_cmd_action_t a)
253*8226594fSRick McNeal {
254*8226594fSRick McNeal 	pqi_device_t		*d = c->pc_device;
255*8226594fSRick McNeal 	pqi_cmd_action_t	rval;
256*8226594fSRick McNeal 
257*8226594fSRick McNeal 	mutex_enter(&d->pd_mutex);
258*8226594fSRick McNeal 	rval = pqi_cmd_action_nolock(c, a);
259*8226594fSRick McNeal 	mutex_exit(&d->pd_mutex);
260*8226594fSRick McNeal 
261*8226594fSRick McNeal 	return (rval);
262*8226594fSRick McNeal }
263*8226594fSRick McNeal 
264*8226594fSRick McNeal boolean_t
pqi_is_offline(pqi_state_t * s)265*8226594fSRick McNeal pqi_is_offline(pqi_state_t *s)
266*8226594fSRick McNeal {
267*8226594fSRick McNeal 	return (s->s_offline);
268*8226594fSRick McNeal }
269*8226594fSRick McNeal 
270*8226594fSRick McNeal /*
271*8226594fSRick McNeal  * pqi_alloc_io -- return next available slot.
272*8226594fSRick McNeal  */
273*8226594fSRick McNeal pqi_io_request_t *
pqi_alloc_io(pqi_state_t * s)274*8226594fSRick McNeal pqi_alloc_io(pqi_state_t *s)
275*8226594fSRick McNeal {
276*8226594fSRick McNeal 	pqi_io_request_t	*io	= NULL;
277*8226594fSRick McNeal 	uint16_t		loop;
278*8226594fSRick McNeal 	uint16_t		i;
279*8226594fSRick McNeal 
280*8226594fSRick McNeal 	mutex_enter(&s->s_io_mutex);
281*8226594fSRick McNeal 	i = s->s_next_io_slot; /* just a hint */
282*8226594fSRick McNeal 	s->s_io_need++;
283*8226594fSRick McNeal 	for (;;) {
284*8226594fSRick McNeal 		for (loop = 0; loop < s->s_max_io_slots; loop++) {
285*8226594fSRick McNeal 			/*
286*8226594fSRick McNeal 			 * Controller offline can only occur if the HBA is going
287*8226594fSRick McNeal 			 * through reset due to firmware hang.
288*8226594fSRick McNeal 			 */
289*8226594fSRick McNeal 			if (pqi_is_offline(s)) {
290*8226594fSRick McNeal 				mutex_exit(&s->s_io_mutex);
291*8226594fSRick McNeal 				return (NULL);
292*8226594fSRick McNeal 			}
293*8226594fSRick McNeal 			io = &s->s_io_rqst_pool[i];
294*8226594fSRick McNeal 			i = (i + 1) % s->s_max_io_slots;
295*8226594fSRick McNeal 			if (io->io_refcount == 0) {
296*8226594fSRick McNeal 				io->io_refcount = 1;
297*8226594fSRick McNeal 				break;
298*8226594fSRick McNeal 			}
299*8226594fSRick McNeal 		}
300*8226594fSRick McNeal 		if (loop != s->s_max_io_slots)
301*8226594fSRick McNeal 			break;
302*8226594fSRick McNeal 
303*8226594fSRick McNeal 		s->s_io_had2wait++;
304*8226594fSRick McNeal 		s->s_io_wait_cnt++;
305*8226594fSRick McNeal 		if (cv_wait_sig(&s->s_io_condvar, &s->s_io_mutex) == 0) {
306*8226594fSRick McNeal 			s->s_io_sig++;
307*8226594fSRick McNeal 			io = NULL;
308*8226594fSRick McNeal 			break;
309*8226594fSRick McNeal 		}
310*8226594fSRick McNeal 		i = s->s_next_io_slot; /* just a hint */
311*8226594fSRick McNeal 	}
312*8226594fSRick McNeal 	s->s_next_io_slot = i;
313*8226594fSRick McNeal 	mutex_exit(&s->s_io_mutex);
314*8226594fSRick McNeal 
315*8226594fSRick McNeal 	if (io != NULL)
316*8226594fSRick McNeal 		reinit_io(io);
317*8226594fSRick McNeal 	return (io);
318*8226594fSRick McNeal }
319*8226594fSRick McNeal 
320*8226594fSRick McNeal void
pqi_free_io(pqi_io_request_t * io)321*8226594fSRick McNeal pqi_free_io(pqi_io_request_t *io)
322*8226594fSRick McNeal {
323*8226594fSRick McNeal 	pqi_state_t	*s = io->io_softc;
324*8226594fSRick McNeal 
325*8226594fSRick McNeal 	mutex_enter(&s->s_io_mutex);
326*8226594fSRick McNeal 	ASSERT(io->io_refcount == 1);
327*8226594fSRick McNeal 	io->io_refcount = 0;
328*8226594fSRick McNeal 	reinit_io(io);
329*8226594fSRick McNeal 	if (s->s_io_wait_cnt != 0) {
330*8226594fSRick McNeal 		s->s_io_wait_cnt--;
331*8226594fSRick McNeal 		cv_signal(&s->s_io_condvar);
332*8226594fSRick McNeal 	}
333*8226594fSRick McNeal 	mutex_exit(&s->s_io_mutex);
334*8226594fSRick McNeal }
335*8226594fSRick McNeal 
336*8226594fSRick McNeal 
337*8226594fSRick McNeal /*
338*8226594fSRick McNeal  * Time out an in progress i/o.
339*8226594fSRick McNeal  * If the i/o has been serviced then return false (can't timeout),
340*8226594fSRick McNeal  * otherwise increment the generation counter and return true.
341*8226594fSRick McNeal  */
342*8226594fSRick McNeal boolean_t
pqi_timeout_io(pqi_io_request_t * io)343*8226594fSRick McNeal pqi_timeout_io(pqi_io_request_t *io)
344*8226594fSRick McNeal {
345*8226594fSRick McNeal 	mutex_enter(&io->io_lock);
346*8226594fSRick McNeal 	if (io->io_serviced) {
347*8226594fSRick McNeal 		/*
348*8226594fSRick McNeal 		 * Can't timeout this io, it's already been serviced.
349*8226594fSRick McNeal 		 */
350*8226594fSRick McNeal 		mutex_exit(&io->io_lock);
351*8226594fSRick McNeal 		return (B_FALSE);
352*8226594fSRick McNeal 	}
353*8226594fSRick McNeal 	io->io_gen = (io->io_gen + 1) % PQI_NGENS;
354*8226594fSRick McNeal 	mutex_exit(&io->io_lock);
355*8226594fSRick McNeal 	return (B_TRUE);
356*8226594fSRick McNeal }
357*8226594fSRick McNeal 
358*8226594fSRick McNeal /*
359*8226594fSRick McNeal  * Check if an i/o is serviceable (generation counter matches).
360*8226594fSRick McNeal  * If so, mark it as serviced and return true.
361*8226594fSRick McNeal  * Otherwise, return false.
362*8226594fSRick McNeal  */
363*8226594fSRick McNeal boolean_t
pqi_service_io(pqi_io_request_t * io,uint8_t generation)364*8226594fSRick McNeal pqi_service_io(pqi_io_request_t *io, uint8_t generation)
365*8226594fSRick McNeal {
366*8226594fSRick McNeal 	mutex_enter(&io->io_lock);
367*8226594fSRick McNeal 	if (io->io_gen != generation) {
368*8226594fSRick McNeal 		/*
369*8226594fSRick McNeal 		 * Can't service this io, it's already been timed out.
370*8226594fSRick McNeal 		 */
371*8226594fSRick McNeal 		mutex_exit(&io->io_lock);
372*8226594fSRick McNeal 		return (B_FALSE);
373*8226594fSRick McNeal 	}
374*8226594fSRick McNeal 	io->io_serviced = B_TRUE;
375*8226594fSRick McNeal 	mutex_exit(&io->io_lock);
376*8226594fSRick McNeal 	return (B_TRUE);
377*8226594fSRick McNeal }
378*8226594fSRick McNeal 
379*8226594fSRick McNeal void
pqi_dump_io(pqi_io_request_t * io)380*8226594fSRick McNeal pqi_dump_io(pqi_io_request_t *io)
381*8226594fSRick McNeal {
382*8226594fSRick McNeal 	pqi_iu_header_t	*hdr = io->io_iu;
383*8226594fSRick McNeal 	pqi_state_t	*s;
384*8226594fSRick McNeal 
385*8226594fSRick McNeal 	if (io->io_cmd != NULL) {
386*8226594fSRick McNeal 		s = io->io_cmd->pc_softc;
387*8226594fSRick McNeal 	} else {
388*8226594fSRick McNeal 		/*
389*8226594fSRick McNeal 		 * Early on, during driver attach, commands are run without
390*8226594fSRick McNeal 		 * a pqi_cmd_t structure associated. These io requests are
391*8226594fSRick McNeal 		 * low level operations direct to the HBA. So, grab a
392*8226594fSRick McNeal 		 * reference to the first and only instance through the
393*8226594fSRick McNeal 		 * DDI interface. Even though there might be multiple HBA's
394*8226594fSRick McNeal 		 * grabbing the first is okay since dump_raid() only references
395*8226594fSRick McNeal 		 * the debug level which will be the same for all the
396*8226594fSRick McNeal 		 * controllers.
397*8226594fSRick McNeal 		 */
398*8226594fSRick McNeal 		s = ddi_get_soft_state(pqi_state, 0);
399*8226594fSRick McNeal 	}
400*8226594fSRick McNeal 
401*8226594fSRick McNeal 	if (hdr->iu_type == PQI_REQUEST_IU_AIO_PATH_IO) {
402*8226594fSRick McNeal 		dump_aio(io->io_iu);
403*8226594fSRick McNeal 	} else if (hdr->iu_type == PQI_REQUEST_IU_RAID_PATH_IO) {
404*8226594fSRick McNeal 		dump_raid(s, io->io_iu, io->io_pi);
405*8226594fSRick McNeal 	}
406*8226594fSRick McNeal }
407*8226594fSRick McNeal 
408*8226594fSRick McNeal static uint_t supported_event_types[] = {
409*8226594fSRick McNeal 	PQI_EVENT_TYPE_HOTPLUG,
410*8226594fSRick McNeal 	PQI_EVENT_TYPE_HARDWARE,
411*8226594fSRick McNeal 	PQI_EVENT_TYPE_PHYSICAL_DEVICE,
412*8226594fSRick McNeal 	PQI_EVENT_TYPE_LOGICAL_DEVICE,
413*8226594fSRick McNeal 	PQI_EVENT_TYPE_AIO_STATE_CHANGE,
414*8226594fSRick McNeal 	PQI_EVENT_TYPE_AIO_CONFIG_CHANGE,
415*8226594fSRick McNeal 	PQI_EVENT_TYPE_HEARTBEAT
416*8226594fSRick McNeal };
417*8226594fSRick McNeal 
418*8226594fSRick McNeal int
pqi_map_event(uint8_t event)419*8226594fSRick McNeal pqi_map_event(uint8_t event)
420*8226594fSRick McNeal {
421*8226594fSRick McNeal 	int i;
422*8226594fSRick McNeal 
423*8226594fSRick McNeal 	for (i = 0; i < sizeof (supported_event_types) / sizeof (uint_t); i++)
424*8226594fSRick McNeal 		if (supported_event_types[i] == event)
425*8226594fSRick McNeal 			return (i);
426*8226594fSRick McNeal 	return (-1);
427*8226594fSRick McNeal }
428*8226594fSRick McNeal 
429*8226594fSRick McNeal boolean_t
pqi_supported_event(uint8_t event)430*8226594fSRick McNeal pqi_supported_event(uint8_t event)
431*8226594fSRick McNeal {
432*8226594fSRick McNeal 	return (pqi_map_event(event) == -1 ? B_FALSE : B_TRUE);
433*8226594fSRick McNeal }
434*8226594fSRick McNeal 
435*8226594fSRick McNeal char *
pqi_event_to_str(uint8_t event)436*8226594fSRick McNeal pqi_event_to_str(uint8_t event)
437*8226594fSRick McNeal {
438*8226594fSRick McNeal 	switch (event) {
439*8226594fSRick McNeal 	case PQI_EVENT_TYPE_HOTPLUG: return ("Hotplug");
440*8226594fSRick McNeal 	case PQI_EVENT_TYPE_HARDWARE: return ("Hardware");
441*8226594fSRick McNeal 	case PQI_EVENT_TYPE_PHYSICAL_DEVICE:
442*8226594fSRick McNeal 		return ("Physical Device");
443*8226594fSRick McNeal 	case PQI_EVENT_TYPE_LOGICAL_DEVICE: return ("logical Device");
444*8226594fSRick McNeal 	case PQI_EVENT_TYPE_AIO_STATE_CHANGE:
445*8226594fSRick McNeal 		return ("AIO State Change");
446*8226594fSRick McNeal 	case PQI_EVENT_TYPE_AIO_CONFIG_CHANGE:
447*8226594fSRick McNeal 		return ("AIO Config Change");
448*8226594fSRick McNeal 	case PQI_EVENT_TYPE_HEARTBEAT: return ("Heartbeat");
449*8226594fSRick McNeal 	default: return ("Unsupported Event Type");
450*8226594fSRick McNeal 	}
451*8226594fSRick McNeal }
452*8226594fSRick McNeal 
453*8226594fSRick McNeal char *
bool_to_str(int v)454*8226594fSRick McNeal bool_to_str(int v)
455*8226594fSRick McNeal {
456*8226594fSRick McNeal 	return (v ? "T" : "f");
457*8226594fSRick McNeal }
458*8226594fSRick McNeal 
459*8226594fSRick McNeal char *
dtype_to_str(int t)460*8226594fSRick McNeal dtype_to_str(int t)
461*8226594fSRick McNeal {
462*8226594fSRick McNeal 	switch (t) {
463*8226594fSRick McNeal 	case DTYPE_DIRECT: return ("Direct");
464*8226594fSRick McNeal 	case DTYPE_SEQUENTIAL: return ("Sequential");
465*8226594fSRick McNeal 	case DTYPE_ESI: return ("ESI");
466*8226594fSRick McNeal 	case DTYPE_ARRAY_CTRL: return ("RAID");
467*8226594fSRick McNeal 	default: return ("Ughknown");
468*8226594fSRick McNeal 	}
469*8226594fSRick McNeal }
470*8226594fSRick McNeal 
471*8226594fSRick McNeal static ddi_dma_attr_t single_dma_attrs = {
472*8226594fSRick McNeal 	.dma_attr_version =	DMA_ATTR_V0,
473*8226594fSRick McNeal 	.dma_attr_addr_lo =	0x0ull,
474*8226594fSRick McNeal 	.dma_attr_addr_hi =	0xffffffffffffffffull,
475*8226594fSRick McNeal 	.dma_attr_count_max =	0x7ffffull,
476*8226594fSRick McNeal 	.dma_attr_align =	4096,
477*8226594fSRick McNeal 	.dma_attr_burstsizes =	0x78,
478*8226594fSRick McNeal 	.dma_attr_minxfer =	1,
479*8226594fSRick McNeal 	.dma_attr_maxxfer =	0x007ffffull,
480*8226594fSRick McNeal 	.dma_attr_seg =		0xffffffffull,
481*8226594fSRick McNeal 	.dma_attr_sgllen =	1,
482*8226594fSRick McNeal 	.dma_attr_granular =	512,
483*8226594fSRick McNeal 	.dma_attr_flags =	0,
484*8226594fSRick McNeal };
485*8226594fSRick McNeal 
486*8226594fSRick McNeal pqi_dma_overhead_t *
pqi_alloc_single(pqi_state_t * s,size_t len)487*8226594fSRick McNeal pqi_alloc_single(pqi_state_t *s, size_t len)
488*8226594fSRick McNeal {
489*8226594fSRick McNeal 	pqi_dma_overhead_t	*d;
490*8226594fSRick McNeal 	ddi_dma_cookie_t	cookie;
491*8226594fSRick McNeal 
492*8226594fSRick McNeal 	d = kmem_zalloc(sizeof (*d), KM_SLEEP);
493*8226594fSRick McNeal 	d->len_to_alloc = len;
494*8226594fSRick McNeal 
495*8226594fSRick McNeal 	if (ddi_dma_alloc_handle(s->s_dip, &single_dma_attrs,
496*8226594fSRick McNeal 	    DDI_DMA_SLEEP, 0, &d->handle) != DDI_SUCCESS)
497*8226594fSRick McNeal 		goto error_out;
498*8226594fSRick McNeal 
499*8226594fSRick McNeal 	if (ddi_dma_mem_alloc(d->handle, len, &s->s_reg_acc_attr,
500*8226594fSRick McNeal 	    DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, 0,
501*8226594fSRick McNeal 	    &d->alloc_memory, &len, &d->acc) != DDI_SUCCESS)
502*8226594fSRick McNeal 		goto error_out;
503*8226594fSRick McNeal 
504*8226594fSRick McNeal 	bzero(d->alloc_memory, len);
505*8226594fSRick McNeal 	if (ddi_dma_addr_bind_handle(d->handle, NULL, d->alloc_memory, len,
506*8226594fSRick McNeal 	    DDI_DMA_RDWR, DDI_DMA_SLEEP, 0, &cookie, &d->cookie_count) !=
507*8226594fSRick McNeal 	    DDI_SUCCESS)
508*8226594fSRick McNeal 		goto error_out;
509*8226594fSRick McNeal 
510*8226594fSRick McNeal 	d->dma_addr = cookie.dmac_laddress;
511*8226594fSRick McNeal 	if (d->cookie_count != 1)
512*8226594fSRick McNeal 		ddi_dma_nextcookie(d->handle, &d->second);
513*8226594fSRick McNeal 
514*8226594fSRick McNeal 	return (d);
515*8226594fSRick McNeal 
516*8226594fSRick McNeal error_out:
517*8226594fSRick McNeal 	pqi_free_single(s, d);
518*8226594fSRick McNeal 	return (NULL);
519*8226594fSRick McNeal }
520*8226594fSRick McNeal 
521*8226594fSRick McNeal void
pqi_free_single(pqi_state_t * s __unused,pqi_dma_overhead_t * d)522*8226594fSRick McNeal pqi_free_single(pqi_state_t *s __unused, pqi_dma_overhead_t *d)
523*8226594fSRick McNeal {
524*8226594fSRick McNeal 	(void) ddi_dma_unbind_handle(d->handle);
525*8226594fSRick McNeal 	if (d->alloc_memory != NULL)
526*8226594fSRick McNeal 		ddi_dma_mem_free(&d->acc);
527*8226594fSRick McNeal 	if (d->handle != NULL)
528*8226594fSRick McNeal 		ddi_dma_free_handle(&d->handle);
529*8226594fSRick McNeal 	kmem_free(d, sizeof (*d));
530*8226594fSRick McNeal }
531*8226594fSRick McNeal 
532*8226594fSRick McNeal void
pqi_show_dev_state(pqi_state_t * s)533*8226594fSRick McNeal pqi_show_dev_state(pqi_state_t *s)
534*8226594fSRick McNeal {
535*8226594fSRick McNeal 	uint32_t dev_status = G32(s, pqi_registers.device_status);
536*8226594fSRick McNeal 
537*8226594fSRick McNeal 	switch (dev_status & 0xf) {
538*8226594fSRick McNeal 	case 0:
539*8226594fSRick McNeal 		cmn_err(CE_NOTE, "Power_On_And_Reset");
540*8226594fSRick McNeal 		break;
541*8226594fSRick McNeal 
542*8226594fSRick McNeal 	case 1:
543*8226594fSRick McNeal 		cmn_err(CE_NOTE, "PQI_Status_Available");
544*8226594fSRick McNeal 		break;
545*8226594fSRick McNeal 
546*8226594fSRick McNeal 	case 2:
547*8226594fSRick McNeal 		cmn_err(CE_NOTE, "All_Registers_Ready");
548*8226594fSRick McNeal 		break;
549*8226594fSRick McNeal 
550*8226594fSRick McNeal 	case 3:
551*8226594fSRick McNeal 		cmn_err(CE_NOTE,
552*8226594fSRick McNeal 		    "Adminstrator_Queue_Pair_Ready");
553*8226594fSRick McNeal 		break;
554*8226594fSRick McNeal 
555*8226594fSRick McNeal 	case 4:
556*8226594fSRick McNeal 		cmn_err(CE_NOTE, "Error: %s %s",
557*8226594fSRick McNeal 		    dev_status & 0x100 ? "(OP OQ Error)" : "",
558*8226594fSRick McNeal 		    dev_status & 0x200 ? "(OP IQ Error)" : "");
559*8226594fSRick McNeal 		show_error_detail(s);
560*8226594fSRick McNeal 		break;
561*8226594fSRick McNeal 
562*8226594fSRick McNeal 	default:
563*8226594fSRick McNeal 		cmn_err(CE_WARN, "Unknown HBA status: 0x%x", dev_status);
564*8226594fSRick McNeal 		break;
565*8226594fSRick McNeal 	}
566*8226594fSRick McNeal }
567*8226594fSRick McNeal 
568*8226594fSRick McNeal char *
cdb_to_str(uint8_t scsi_cmd)569*8226594fSRick McNeal cdb_to_str(uint8_t scsi_cmd)
570*8226594fSRick McNeal {
571*8226594fSRick McNeal 	switch (scsi_cmd) {
572*8226594fSRick McNeal 	case SCMD_INQUIRY: return ("Inquiry");
573*8226594fSRick McNeal 	case SCMD_TEST_UNIT_READY: return ("TestUnitReady");
574*8226594fSRick McNeal 	case SCMD_READ: return ("Read");
575*8226594fSRick McNeal 	case SCMD_READ_G1: return ("Read G1");
576*8226594fSRick McNeal 	case SCMD_RESERVE: return ("Reserve");
577*8226594fSRick McNeal 	case SCMD_RELEASE: return ("Release");
578*8226594fSRick McNeal 	case SCMD_WRITE: return ("Write");
579*8226594fSRick McNeal 	case SCMD_WRITE_G1: return ("Write G1");
580*8226594fSRick McNeal 	case SCMD_START_STOP: return ("StartStop");
581*8226594fSRick McNeal 	case SCMD_READ_CAPACITY: return ("ReadCap");
582*8226594fSRick McNeal 	case SCMD_MODE_SENSE: return ("ModeSense");
583*8226594fSRick McNeal 	case SCMD_MODE_SELECT: return ("ModeSelect");
584*8226594fSRick McNeal 	case SCMD_SVC_ACTION_IN_G4: return ("ActionInG4");
585*8226594fSRick McNeal 	case SCMD_MAINTENANCE_IN: return ("MaintenanceIn");
586*8226594fSRick McNeal 	case SCMD_GDIAG: return ("ReceiveDiag");
587*8226594fSRick McNeal 	case SCMD_SDIAG: return ("SendDiag");
588*8226594fSRick McNeal 	case SCMD_LOG_SENSE_G1: return ("LogSenseG1");
589*8226594fSRick McNeal 	case SCMD_PERSISTENT_RESERVE_IN: return ("PgrReserveIn");
590*8226594fSRick McNeal 	case SCMD_PERSISTENT_RESERVE_OUT: return ("PgrReserveOut");
591*8226594fSRick McNeal 	case BMIC_READ: return ("BMIC Read");
592*8226594fSRick McNeal 	case BMIC_WRITE: return ("BMIC Write");
593*8226594fSRick McNeal 	case CISS_REPORT_LOG: return ("CISS Report Logical");
594*8226594fSRick McNeal 	case CISS_REPORT_PHYS: return ("CISS Report Physical");
595*8226594fSRick McNeal 	default: return ("unmapped");
596*8226594fSRick McNeal 	}
597*8226594fSRick McNeal }
598*8226594fSRick McNeal 
599*8226594fSRick McNeal char *
io_status_to_str(int val)600*8226594fSRick McNeal io_status_to_str(int val)
601*8226594fSRick McNeal {
602*8226594fSRick McNeal 	switch (val) {
603*8226594fSRick McNeal 	case PQI_DATA_IN_OUT_GOOD: return ("Good");
604*8226594fSRick McNeal 	case PQI_DATA_IN_OUT_UNDERFLOW: return ("Underflow");
605*8226594fSRick McNeal 	case PQI_DATA_IN_OUT_ERROR: return ("ERROR");
606*8226594fSRick McNeal 	case PQI_DATA_IN_OUT_PROTOCOL_ERROR: return ("Protocol Error");
607*8226594fSRick McNeal 	case PQI_DATA_IN_OUT_HARDWARE_ERROR: return ("Hardware Error");
608*8226594fSRick McNeal 	default: return ("UNHANDLED");
609*8226594fSRick McNeal 	}
610*8226594fSRick McNeal }
611*8226594fSRick McNeal 
612*8226594fSRick McNeal char *
scsi_status_to_str(uint8_t val)613*8226594fSRick McNeal scsi_status_to_str(uint8_t val)
614*8226594fSRick McNeal {
615*8226594fSRick McNeal 	switch (val) {
616*8226594fSRick McNeal 	case STATUS_GOOD: return ("Good");
617*8226594fSRick McNeal 	case STATUS_CHECK: return ("Check");
618*8226594fSRick McNeal 	case STATUS_MET: return ("Met");
619*8226594fSRick McNeal 	case STATUS_BUSY: return ("Busy");
620*8226594fSRick McNeal 	case STATUS_INTERMEDIATE: return ("Intermediate");
621*8226594fSRick McNeal 	case STATUS_RESERVATION_CONFLICT: return ("Reservation Conflict");
622*8226594fSRick McNeal 	case STATUS_TERMINATED: return ("Terminated");
623*8226594fSRick McNeal 	case STATUS_QFULL: return ("QFull");
624*8226594fSRick McNeal 	case STATUS_ACA_ACTIVE: return ("ACA Active");
625*8226594fSRick McNeal 	case STATUS_TASK_ABORT: return ("Task Abort");
626*8226594fSRick McNeal 	default: return ("Illegal Status");
627*8226594fSRick McNeal 	}
628*8226594fSRick McNeal }
629*8226594fSRick McNeal 
630*8226594fSRick McNeal char *
iu_type_to_str(int val)631*8226594fSRick McNeal iu_type_to_str(int val)
632*8226594fSRick McNeal {
633*8226594fSRick McNeal 	switch (val) {
634*8226594fSRick McNeal 	case PQI_RESPONSE_IU_RAID_PATH_IO_SUCCESS: return ("Success");
635*8226594fSRick McNeal 	case PQI_RESPONSE_IU_AIO_PATH_IO_SUCCESS: return ("AIO Success");
636*8226594fSRick McNeal 	case PQI_RESPONSE_IU_GENERAL_MANAGEMENT: return ("General");
637*8226594fSRick McNeal 	case PQI_RESPONSE_IU_RAID_PATH_IO_ERROR: return ("IO Error");
638*8226594fSRick McNeal 	case PQI_RESPONSE_IU_AIO_PATH_IO_ERROR: return ("AIO IO Error");
639*8226594fSRick McNeal 	case PQI_RESPONSE_IU_AIO_PATH_DISABLED: return ("AIO Path Disabled");
640*8226594fSRick McNeal 	default: return ("UNHANDLED");
641*8226594fSRick McNeal 	}
642*8226594fSRick McNeal }
643*8226594fSRick McNeal 
644*8226594fSRick McNeal void
pqi_free_mem_len(mem_len_pair_t * m)645*8226594fSRick McNeal pqi_free_mem_len(mem_len_pair_t *m)
646*8226594fSRick McNeal {
647*8226594fSRick McNeal 	kmem_free(m->mem, m->len);
648*8226594fSRick McNeal }
649*8226594fSRick McNeal 
650*8226594fSRick McNeal mem_len_pair_t
pqi_alloc_mem_len(int len)651*8226594fSRick McNeal pqi_alloc_mem_len(int len)
652*8226594fSRick McNeal {
653*8226594fSRick McNeal 	mem_len_pair_t m;
654*8226594fSRick McNeal 	m.len = len;
655*8226594fSRick McNeal 	m.mem = kmem_alloc(m.len, KM_SLEEP);
656*8226594fSRick McNeal 	*m.mem = '\0';
657*8226594fSRick McNeal 	return (m);
658*8226594fSRick McNeal }
659*8226594fSRick McNeal 
660*8226594fSRick McNeal /*
661*8226594fSRick McNeal  * []------------------------------------------------------------------[]
662*8226594fSRick McNeal  * | Support/utility functions for main functions above			|
663*8226594fSRick McNeal  * []------------------------------------------------------------------[]
664*8226594fSRick McNeal  */
665*8226594fSRick McNeal 
666*8226594fSRick McNeal typedef struct qual {
667*8226594fSRick McNeal 	int	q_val;
668*8226594fSRick McNeal 	char	*q_str;
669*8226594fSRick McNeal } qual_t;
670*8226594fSRick McNeal 
671*8226594fSRick McNeal typedef struct code_qual {
672*8226594fSRick McNeal 	int	cq_code;
673*8226594fSRick McNeal 	qual_t	*cq_list;
674*8226594fSRick McNeal } code_qual_t;
675*8226594fSRick McNeal 
676*8226594fSRick McNeal /*
677*8226594fSRick McNeal  * These messages come from pqi2r01 spec section 5.6 table 18.
678*8226594fSRick McNeal  */
679*8226594fSRick McNeal static qual_t pair0[] = { {0, "No error"}, {0, NULL} };
680*8226594fSRick McNeal static qual_t pair1[] = { {0, "Error detected during initialization"},
681*8226594fSRick McNeal 	{ 0, NULL } };
682*8226594fSRick McNeal static qual_t pair2[] = { {1, "Invalid PD Function"},
683*8226594fSRick McNeal 	{2, "Invalid paramter for PD function"},
684*8226594fSRick McNeal 	{0, NULL } };
685*8226594fSRick McNeal static qual_t pair3[] = { {0, "Error creating admin queue pair"},
686*8226594fSRick McNeal 	{ 1, "Error deleting admin queue pair"},
687*8226594fSRick McNeal 	{ 0, NULL} };
688*8226594fSRick McNeal static qual_t pair4[] = { {1, "Invalid IU type in general" },
689*8226594fSRick McNeal 	{2, "Invalid IU length in general admin request"},
690*8226594fSRick McNeal 	{0, NULL} };
691*8226594fSRick McNeal static qual_t pair5[] = { {1, "Internal error" },
692*8226594fSRick McNeal 	{2, "OQ spanning conflict"},
693*8226594fSRick McNeal 	{0, NULL} };
694*8226594fSRick McNeal static qual_t pair6[] = { {1, "Error completing PQI soft reset"},
695*8226594fSRick McNeal 	{2, "Error completing PQI firmware reset"},
696*8226594fSRick McNeal 	{3, "Error completing PQI hardware reset"},
697*8226594fSRick McNeal 	{0, NULL} };
698*8226594fSRick McNeal static code_qual_t cq_table[] = {
699*8226594fSRick McNeal 	{ 0, pair0 },
700*8226594fSRick McNeal 	{ 1, pair1 },
701*8226594fSRick McNeal 	{ 2, pair2 },
702*8226594fSRick McNeal 	{ 3, pair3 },
703*8226594fSRick McNeal 	{ 4, pair4 },
704*8226594fSRick McNeal 	{ 5, pair5 },
705*8226594fSRick McNeal 	{ 6, pair6 },
706*8226594fSRick McNeal 	{ 0, NULL },
707*8226594fSRick McNeal };
708*8226594fSRick McNeal 
709*8226594fSRick McNeal /*
710*8226594fSRick McNeal  * cmd_finish_task -- taskq to complete command processing
711*8226594fSRick McNeal  *
712*8226594fSRick McNeal  * Under high load the driver will run out of IO slots which causes command
713*8226594fSRick McNeal  * requests to pause until a slot is free. Calls to pkt_comp below can circle
714*8226594fSRick McNeal  * through the SCSI layer and back into the driver to start another command
715*8226594fSRick McNeal  * request and therefore possibly pause. If cmd_finish_task() was called on
716*8226594fSRick McNeal  * the interrupt thread a hang condition could occur because IO slots wouldn't
717*8226594fSRick McNeal  * be processed and then freed. So, this portion of the command completion
718*8226594fSRick McNeal  * is run on a taskq.
719*8226594fSRick McNeal  */
720*8226594fSRick McNeal static void
cmd_finish_task(void * v)721*8226594fSRick McNeal cmd_finish_task(void *v)
722*8226594fSRick McNeal {
723*8226594fSRick McNeal 	pqi_cmd_t	*c = v;
724*8226594fSRick McNeal 	struct scsi_pkt	*pkt = CMD2PKT(c);
725*8226594fSRick McNeal 
726*8226594fSRick McNeal 	if (c->pc_poll)
727*8226594fSRick McNeal 		sema_v(c->pc_poll);
728*8226594fSRick McNeal 
729*8226594fSRick McNeal 	if (pkt != NULL && (pkt->pkt_flags & FLAG_NOINTR) == 0 &&
730*8226594fSRick McNeal 	    (pkt->pkt_comp != NULL))
731*8226594fSRick McNeal 		(*pkt->pkt_comp)(pkt);
732*8226594fSRick McNeal }
733*8226594fSRick McNeal 
734*8226594fSRick McNeal static void
cmd_start_time(pqi_cmd_t * c)735*8226594fSRick McNeal cmd_start_time(pqi_cmd_t *c)
736*8226594fSRick McNeal {
737*8226594fSRick McNeal 	c->pc_start_time = gethrtime();
738*8226594fSRick McNeal 	if (CMD2PKT(c) != NULL) {
739*8226594fSRick McNeal 		c->pc_expiration = c->pc_start_time +
740*8226594fSRick McNeal 		    ((hrtime_t)c->pc_pkt->pkt_time * NANOSEC);
741*8226594fSRick McNeal 	} else {
742*8226594fSRick McNeal 		c->pc_expiration = c->pc_start_time + 5 * NANOSEC;
743*8226594fSRick McNeal 	}
744*8226594fSRick McNeal }
745*8226594fSRick McNeal 
746*8226594fSRick McNeal static void
show_error_detail(pqi_state_t * s)747*8226594fSRick McNeal show_error_detail(pqi_state_t *s)
748*8226594fSRick McNeal {
749*8226594fSRick McNeal 	uint32_t error_reg = G32(s, pqi_registers.device_error);
750*8226594fSRick McNeal 	uint8_t		code, qualifier;
751*8226594fSRick McNeal 	qual_t		*p;
752*8226594fSRick McNeal 	code_qual_t	*cq;
753*8226594fSRick McNeal 
754*8226594fSRick McNeal 	code = error_reg & 0xff;
755*8226594fSRick McNeal 	qualifier = (error_reg >> 8) & 0xff;
756*8226594fSRick McNeal 
757*8226594fSRick McNeal 	for (cq = cq_table; cq->cq_list != NULL; cq++) {
758*8226594fSRick McNeal 		if (cq->cq_code == code) {
759*8226594fSRick McNeal 			for (p = cq->cq_list; p->q_str != NULL; p++) {
760*8226594fSRick McNeal 				if (p->q_val == qualifier) {
761*8226594fSRick McNeal 					cmn_err(CE_NOTE,
762*8226594fSRick McNeal 					    "[code=%x,qual=%x]: %s",
763*8226594fSRick McNeal 					    code, qualifier, p->q_str);
764*8226594fSRick McNeal 					return;
765*8226594fSRick McNeal 				}
766*8226594fSRick McNeal 			}
767*8226594fSRick McNeal 		}
768*8226594fSRick McNeal 	}
769*8226594fSRick McNeal 	cmn_err(CE_NOTE, "Undefined code(%x)/qualifier(%x)",
770*8226594fSRick McNeal 	    code, qualifier);
771*8226594fSRick McNeal }
772*8226594fSRick McNeal 
773*8226594fSRick McNeal static void
pqi_catch_release(pqi_io_request_t * io __unused,void * v __unused)774*8226594fSRick McNeal pqi_catch_release(pqi_io_request_t *io __unused, void *v __unused)
775*8226594fSRick McNeal {
776*8226594fSRick McNeal 	/*
777*8226594fSRick McNeal 	 * This call can occur if the software times out a command because
778*8226594fSRick McNeal 	 * the HBA hasn't responded in the default amount of time, 10 seconds,
779*8226594fSRick McNeal 	 * and then the HBA responds. It's occurred a few times during testing
780*8226594fSRick McNeal 	 * so catch and ignore.
781*8226594fSRick McNeal 	 */
782*8226594fSRick McNeal 	cmn_err(CE_NOTE, "%s: caught", __func__);
783*8226594fSRick McNeal }
784*8226594fSRick McNeal 
785*8226594fSRick McNeal static void
reinit_io(pqi_io_request_t * io)786*8226594fSRick McNeal reinit_io(pqi_io_request_t *io)
787*8226594fSRick McNeal {
788*8226594fSRick McNeal 	io->io_cb = pqi_catch_release;
789*8226594fSRick McNeal 	io->io_status = 0;
790*8226594fSRick McNeal 	io->io_serviced = B_FALSE;
791*8226594fSRick McNeal 	io->io_error_info = NULL;
792*8226594fSRick McNeal 	io->io_raid_bypass = B_FALSE;
793*8226594fSRick McNeal 	io->io_context = NULL;
794*8226594fSRick McNeal 	io->io_cmd = NULL;
795*8226594fSRick McNeal }
796*8226594fSRick McNeal 
797*8226594fSRick McNeal mem_len_pair_t
build_cdb_str(uint8_t * cdb)798*8226594fSRick McNeal build_cdb_str(uint8_t *cdb)
799*8226594fSRick McNeal {
800*8226594fSRick McNeal 	mem_len_pair_t m = pqi_alloc_mem_len(64);
801*8226594fSRick McNeal 
802*8226594fSRick McNeal 	m.mem[0] = '\0';
803*8226594fSRick McNeal 
804*8226594fSRick McNeal 	switch (cdb[0]) {
805*8226594fSRick McNeal 	case SCMD_INQUIRY:
806*8226594fSRick McNeal 		MEMP("%s", cdb_to_str(cdb[0]));
807*8226594fSRick McNeal 		if ((cdb[1] & 0x1) != 0)
808*8226594fSRick McNeal 			MEMP(".vpd=%x", cdb[2]);
809*8226594fSRick McNeal 		else if (cdb[2])
810*8226594fSRick McNeal 			MEMP("Illegal CDB");
811*8226594fSRick McNeal 		MEMP(".len=%x", cdb[3] << 8 | cdb[4]);
812*8226594fSRick McNeal 		break;
813*8226594fSRick McNeal 
814*8226594fSRick McNeal 	case SCMD_READ:
815*8226594fSRick McNeal 		MEMP("%s.lba=%x.len=%x", cdb_to_str(cdb[0]),
816*8226594fSRick McNeal 		    (cdb[1] & 0x1f) << 16 | cdb[2] << 8 | cdb[3],
817*8226594fSRick McNeal 		    cdb[4]);
818*8226594fSRick McNeal 		break;
819*8226594fSRick McNeal 
820*8226594fSRick McNeal 	case SCMD_MODE_SENSE:
821*8226594fSRick McNeal 		MEMP("%s.dbd=%s.pc=%x.page_code=%x.subpage=%x."
822*8226594fSRick McNeal 		    "len=%x", cdb_to_str(cdb[0]),
823*8226594fSRick McNeal 		    bool_to_str(cdb[1] & 8), cdb[2] >> 6 & 0x3,
824*8226594fSRick McNeal 		    cdb[2] & 0x3f, cdb[3], cdb[4]);
825*8226594fSRick McNeal 		break;
826*8226594fSRick McNeal 
827*8226594fSRick McNeal 	case SCMD_START_STOP:
828*8226594fSRick McNeal 		MEMP("%s.immed=%s.power=%x.start=%s",
829*8226594fSRick McNeal 		    cdb_to_str(cdb[0]), bool_to_str(cdb[1] & 1),
830*8226594fSRick McNeal 		    (cdb[4] >> 4) & 0xf, bool_to_str(cdb[4] & 1));
831*8226594fSRick McNeal 		break;
832*8226594fSRick McNeal 
833*8226594fSRick McNeal 	case SCMD_SVC_ACTION_IN_G4:
834*8226594fSRick McNeal 	case SCMD_READ_CAPACITY:
835*8226594fSRick McNeal 	case SCMD_TEST_UNIT_READY:
836*8226594fSRick McNeal 	default:
837*8226594fSRick McNeal 		MEMP("%s (%x)", cdb_to_str(cdb[0]), cdb[0]);
838*8226594fSRick McNeal 		break;
839*8226594fSRick McNeal 	}
840*8226594fSRick McNeal 	return (m);
841*8226594fSRick McNeal }
842*8226594fSRick McNeal 
843*8226594fSRick McNeal mem_len_pair_t
mem_to_arraystr(uint8_t * ptr,size_t len)844*8226594fSRick McNeal mem_to_arraystr(uint8_t *ptr, size_t len)
845*8226594fSRick McNeal {
846*8226594fSRick McNeal 	mem_len_pair_t	m	= pqi_alloc_mem_len(len * 3 + 20);
847*8226594fSRick McNeal 	int		i;
848*8226594fSRick McNeal 
849*8226594fSRick McNeal 	m.mem[0] = '\0';
850*8226594fSRick McNeal 	MEMP("{ ");
851*8226594fSRick McNeal 	for (i = 0; i < len; i++) {
852*8226594fSRick McNeal 		MEMP("%02x ", *ptr++ & 0xff);
853*8226594fSRick McNeal 	}
854*8226594fSRick McNeal 	MEMP(" }");
855*8226594fSRick McNeal 
856*8226594fSRick McNeal 	return (m);
857*8226594fSRick McNeal }
858*8226594fSRick McNeal 
859*8226594fSRick McNeal static char lun_str[64];
860*8226594fSRick McNeal static char *
lun_to_str(uint8_t * lun)861*8226594fSRick McNeal lun_to_str(uint8_t *lun)
862*8226594fSRick McNeal {
863*8226594fSRick McNeal 	int	i;
864*8226594fSRick McNeal 	lun_str[0] = '\0';
865*8226594fSRick McNeal 	for (i = 0; i < 8; i++)
866*8226594fSRick McNeal 		(void) snprintf(lun_str + strlen(lun_str),
867*8226594fSRick McNeal 		    sizeof (lun_str) - strlen(lun_str), "%02x.", *lun++);
868*8226594fSRick McNeal 	return (lun_str);
869*8226594fSRick McNeal }
870*8226594fSRick McNeal 
871*8226594fSRick McNeal static char *
dir_to_str(int dir)872*8226594fSRick McNeal dir_to_str(int dir)
873*8226594fSRick McNeal {
874*8226594fSRick McNeal 	switch (dir) {
875*8226594fSRick McNeal 	case SOP_NO_DIRECTION_FLAG: return ("NoDir");
876*8226594fSRick McNeal 	case SOP_WRITE_FLAG: return ("Write");
877*8226594fSRick McNeal 	case SOP_READ_FLAG: return ("Read");
878*8226594fSRick McNeal 	case SOP_BIDIRECTIONAL: return ("RW");
879*8226594fSRick McNeal 	default: return ("Oops");
880*8226594fSRick McNeal 	}
881*8226594fSRick McNeal }
882*8226594fSRick McNeal 
883*8226594fSRick McNeal static char *
flags_to_str(uint32_t flag)884*8226594fSRick McNeal flags_to_str(uint32_t flag)
885*8226594fSRick McNeal {
886*8226594fSRick McNeal 	switch (flag) {
887*8226594fSRick McNeal 	case CISS_SG_LAST: return ("Last");
888*8226594fSRick McNeal 	case CISS_SG_CHAIN: return ("Chain");
889*8226594fSRick McNeal 	case CISS_SG_NORMAL: return ("Norm");
890*8226594fSRick McNeal 	default: return ("Ooops");
891*8226594fSRick McNeal 	}
892*8226594fSRick McNeal }
893*8226594fSRick McNeal 
894*8226594fSRick McNeal /* ---- Only for use in dump_raid and dump_aio ---- */
895*8226594fSRick McNeal #define	SCRATCH_PRINT(args...) (void)snprintf(scratch + strlen(scratch), \
896*8226594fSRick McNeal     len - strlen(scratch), args)
897*8226594fSRick McNeal 
898*8226594fSRick McNeal static void
dump_raid(pqi_state_t * s,void * v,pqi_index_t idx)899*8226594fSRick McNeal dump_raid(pqi_state_t *s, void *v, pqi_index_t idx)
900*8226594fSRick McNeal {
901*8226594fSRick McNeal 	int			i;
902*8226594fSRick McNeal 	int			len	= 512;
903*8226594fSRick McNeal 	caddr_t			scratch;
904*8226594fSRick McNeal 	pqi_raid_path_request_t	*rqst = v;
905*8226594fSRick McNeal 	mem_len_pair_t		cdb_data;
906*8226594fSRick McNeal 	caddr_t			raw = v;
907*8226594fSRick McNeal 
908*8226594fSRick McNeal 	scratch = kmem_alloc(len, KM_SLEEP);
909*8226594fSRick McNeal 	scratch[0] = '\0';
910*8226594fSRick McNeal 
911*8226594fSRick McNeal 	if (s->s_debug_level & DBG_LVL_RAW_RQST) {
912*8226594fSRick McNeal 		SCRATCH_PRINT("RAW RQST: ");
913*8226594fSRick McNeal 		for (i = 0; i < sizeof (*rqst); i++)
914*8226594fSRick McNeal 			SCRATCH_PRINT("%02x:", *raw++ & 0xff);
915*8226594fSRick McNeal 		cmn_err(CE_NOTE, "%s", scratch);
916*8226594fSRick McNeal 		scratch[0] = '\0';
917*8226594fSRick McNeal 	}
918*8226594fSRick McNeal 
919*8226594fSRick McNeal 	if (s->s_debug_level & DBG_LVL_CDB) {
920*8226594fSRick McNeal 		cdb_data = build_cdb_str(rqst->rp_cdb);
921*8226594fSRick McNeal 		SCRATCH_PRINT("cdb(%s),", cdb_data.mem);
922*8226594fSRick McNeal 		pqi_free_mem_len(&cdb_data);
923*8226594fSRick McNeal 	}
924*8226594fSRick McNeal 
925*8226594fSRick McNeal 	ASSERT0(rqst->header.reserved);
926*8226594fSRick McNeal 	ASSERT0(rqst->reserved1);
927*8226594fSRick McNeal 	ASSERT0(rqst->reserved2);
928*8226594fSRick McNeal 	ASSERT0(rqst->reserved3);
929*8226594fSRick McNeal 	ASSERT0(rqst->reserved4);
930*8226594fSRick McNeal 	ASSERT0(rqst->reserved5);
931*8226594fSRick McNeal 
932*8226594fSRick McNeal 	if (s->s_debug_level & DBG_LVL_RQST) {
933*8226594fSRick McNeal 		SCRATCH_PRINT("pi=%x,h(type=%x,len=%x,id=%x)", idx,
934*8226594fSRick McNeal 		    rqst->header.iu_type, rqst->header.iu_length,
935*8226594fSRick McNeal 		    rqst->header.iu_id);
936*8226594fSRick McNeal 		SCRATCH_PRINT("rqst_id=%x,nexus_id=%x,len=%x,lun=(%s),"
937*8226594fSRick McNeal 		    "proto=%x,dir=%s,partial=%s,",
938*8226594fSRick McNeal 		    rqst->rp_id, rqst->rp_nexus_id, rqst->rp_data_len,
939*8226594fSRick McNeal 		    lun_to_str(rqst->rp_lun), rqst->protocol_specific,
940*8226594fSRick McNeal 		    dir_to_str(rqst->rp_data_dir),
941*8226594fSRick McNeal 		    bool_to_str(rqst->rp_partial));
942*8226594fSRick McNeal 		SCRATCH_PRINT("fence=%s,error_idx=%x,task_attr=%x,"
943*8226594fSRick McNeal 		    "priority=%x,additional=%x,sg=(",
944*8226594fSRick McNeal 		    bool_to_str(rqst->rp_fence), rqst->rp_error_index,
945*8226594fSRick McNeal 		    rqst->rp_task_attr,
946*8226594fSRick McNeal 		    rqst->rp_pri, rqst->rp_additional_cdb);
947*8226594fSRick McNeal 		for (i = 0; i < PQI_MAX_EMBEDDED_SG_DESCRIPTORS; i++) {
948*8226594fSRick McNeal 			SCRATCH_PRINT("%lx:%x:%s,",
949*8226594fSRick McNeal 			    (long unsigned int)rqst->rp_sglist[i].sg_addr,
950*8226594fSRick McNeal 			    rqst->rp_sglist[i].sg_len,
951*8226594fSRick McNeal 			    flags_to_str(rqst->rp_sglist[i].sg_flags));
952*8226594fSRick McNeal 		}
953*8226594fSRick McNeal 		SCRATCH_PRINT(")");
954*8226594fSRick McNeal 	}
955*8226594fSRick McNeal 
956*8226594fSRick McNeal 	cmn_err(CE_NOTE, "%s", scratch);
957*8226594fSRick McNeal 	kmem_free(scratch, len);
958*8226594fSRick McNeal }
959*8226594fSRick McNeal 
960*8226594fSRick McNeal static void
dump_aio(void * v)961*8226594fSRick McNeal dump_aio(void *v)
962*8226594fSRick McNeal {
963*8226594fSRick McNeal 	pqi_aio_path_request_t	*rqst	= v;
964*8226594fSRick McNeal 	int			i;
965*8226594fSRick McNeal 	int			len	= 512;
966*8226594fSRick McNeal 	caddr_t			scratch;
967*8226594fSRick McNeal 	mem_len_pair_t		cdb_data;
968*8226594fSRick McNeal 
969*8226594fSRick McNeal 	scratch = kmem_alloc(len, KM_SLEEP);
970*8226594fSRick McNeal 	scratch[0] = '\0';
971*8226594fSRick McNeal 
972*8226594fSRick McNeal 	cdb_data = build_cdb_str(rqst->cdb);
973*8226594fSRick McNeal 	SCRATCH_PRINT("cdb(%s)", cdb_data.mem);
974*8226594fSRick McNeal 	pqi_free_mem_len(&cdb_data);
975*8226594fSRick McNeal 
976*8226594fSRick McNeal 	SCRATCH_PRINT("h(type=%x,len=%x,id=%x)",
977*8226594fSRick McNeal 	    rqst->header.iu_type, rqst->header.iu_length,
978*8226594fSRick McNeal 	    rqst->header.iu_id);
979*8226594fSRick McNeal 	SCRATCH_PRINT("rqst_id=%x,nexus_id=%x,len=%x,lun=(%s),dir=%s,"
980*8226594fSRick McNeal 	    "partial=%s,",
981*8226594fSRick McNeal 	    rqst->request_id, rqst->nexus_id, rqst->buffer_length,
982*8226594fSRick McNeal 	    lun_to_str(rqst->lun_number),
983*8226594fSRick McNeal 	    dir_to_str(rqst->data_direction), bool_to_str(rqst->partial));
984*8226594fSRick McNeal 	SCRATCH_PRINT("fence=%s,error_idx=%x,task_attr=%x,priority=%x,"
985*8226594fSRick McNeal 	    "num_sg=%x,cdb_len=%x,sg=(",
986*8226594fSRick McNeal 	    bool_to_str(rqst->fence), rqst->error_index, rqst->task_attribute,
987*8226594fSRick McNeal 	    rqst->command_priority, rqst->num_sg_descriptors, rqst->cdb_length);
988*8226594fSRick McNeal 	for (i = 0; i < PQI_MAX_EMBEDDED_SG_DESCRIPTORS; i++) {
989*8226594fSRick McNeal 		SCRATCH_PRINT("%lx:%x:%s,",
990*8226594fSRick McNeal 		    (long unsigned int)rqst->ap_sglist[i].sg_addr,
991*8226594fSRick McNeal 		    rqst->ap_sglist[i].sg_len,
992*8226594fSRick McNeal 		    flags_to_str(rqst->ap_sglist[i].sg_flags));
993*8226594fSRick McNeal 	}
994*8226594fSRick McNeal 	SCRATCH_PRINT(")");
995*8226594fSRick McNeal 
996*8226594fSRick McNeal 	cmn_err(CE_NOTE, "%s", scratch);
997*8226594fSRick McNeal 	kmem_free(scratch, len);
998*8226594fSRick McNeal }
999