xref: /illumos-gate/usr/src/uts/common/io/cpqary3/cpqary3_transport.c (revision bd0ce624be4492bab2f6c53383a40618647aba28)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright (C) 2013 Hewlett-Packard Development Company, L.P.
14  */
15 
16 #include <sys/sdt.h>
17 #include "cpqary3.h"
18 
19 /*
20  * Local Functions Definitions
21  */
22 
23 static int cpqary3_tgt_init(dev_info_t *, dev_info_t *, scsi_hba_tran_t *,
24     struct scsi_device *);
25 static int cpqary3_tgt_probe(struct scsi_device *, int (*)());
26 static int cpqary3_transport(struct scsi_address *, struct scsi_pkt *);
27 static int cpqary3_reset(struct scsi_address *, int);
28 static int cpqary3_abort(struct scsi_address *, struct scsi_pkt *);
29 static int cpqary3_getcap(struct scsi_address *, char *, int);
30 static int cpqary3_setcap(struct scsi_address *, char *, int, int);
31 static int cpqary3_dma_alloc(cpqary3_t *, struct scsi_pkt *,
32     struct buf *, int, int (*)());
33 static int cpqary3_dma_move(struct scsi_pkt *, struct buf *, cpqary3_t *);
34 static int cpqary3_handle_flag_nointr(cpqary3_cmdpvt_t *, struct scsi_pkt *);
35 static int cpqary3_poll(cpqary3_t *, uint32_t);
36 static void cpqary3_dmafree(struct scsi_address *, struct scsi_pkt *);
37 static void cpqary3_dma_sync(struct scsi_address *, struct scsi_pkt *);
38 static void cpqary3_destroy_pkt(struct scsi_address *, struct scsi_pkt *);
39 static struct scsi_pkt *cpqary3_init_pkt(struct scsi_address *,
40     struct scsi_pkt *, struct buf *, int, int, int, int, int (*callback)(),
41     caddr_t);
42 static int cpqary3_additional_cmd(struct scsi_pkt *scsi_pktp, cpqary3_t *);
43 void cpqary3_oscmd_complete(cpqary3_cmdpvt_t *);
44 static uint8_t cpqary3_is_scsi_read_write(struct scsi_pkt *scsi_pktp);
45 
46 /*
47  * External Variable Declarations
48  */
49 
50 extern ddi_dma_attr_t cpqary3_dma_attr;
51 
52 /*
53  * Function	: 	cpqary3_init_hbatran
54  * Description	: 	This routine initializes the transport vector in the
55  *			SCSA architecture for entry ponts in this driver.
56  * Called By	: 	cpqary3_attach()
57  * Parameters	: 	per_controller
58  * Calls	: 	None
59  * Return Values: 	None
60  */
61 void
62 cpqary3_init_hbatran(cpqary3_t *ctlr)
63 {
64 	scsi_hba_tran_t	*hba_tran;
65 
66 	ASSERT(ctlr != NULL);
67 
68 	hba_tran = ctlr->hba_tran;
69 
70 	/*
71 	 * Memory for the transport vector has been allocated by now.
72 	 * initialize all the entry points in this vector
73 	 */
74 
75 	hba_tran->tran_hba_private = (void *)ctlr;
76 
77 	/* Target Driver Instance Initialization */
78 	hba_tran->tran_tgt_init = cpqary3_tgt_init;
79 	hba_tran->tran_tgt_probe = cpqary3_tgt_probe;
80 
81 	/* Resource Allocation */
82 	hba_tran->tran_init_pkt = cpqary3_init_pkt;
83 	hba_tran->tran_destroy_pkt = cpqary3_destroy_pkt;
84 	hba_tran->tran_sync_pkt = cpqary3_dma_sync;
85 	hba_tran->tran_dmafree = cpqary3_dmafree;
86 
87 	/* Command Transport */
88 	hba_tran->tran_start = cpqary3_transport;
89 
90 	/* Capability Management */
91 	hba_tran->tran_getcap = cpqary3_getcap;
92 	hba_tran->tran_setcap = cpqary3_setcap;
93 
94 	/* Abort and Reset */
95 	hba_tran->tran_reset = cpqary3_reset;
96 	hba_tran->tran_abort = cpqary3_abort;
97 }
98 
99 /*
100  * Function	:	cpqary3_tgt_init ()
101  * Description	: 	This routine validates the target ID.
102  * Called By	:  	cpqary3_init_hbatran()
103  * Parameters	: 	HBA-instance, target instance, transport vector,
104  *			scsi-device structure
105  * Calls	:  	cpqary3_detect_target_geometry(),
106  *			cpqary3_probe4targets()
107  * Return Values: 	DDI_SUCCESS : A Target exists at this ID.
108  *			DDI_FAILURE : No such target exists.
109  */
110 /* ARGSUSED */
111 static int
112 cpqary3_tgt_init(dev_info_t *hba_dip, dev_info_t *tgt_dip,
113     scsi_hba_tran_t *hba_tran, struct scsi_device *sd)
114 {
115 	uint32_t	tid = SD2TGT(sd);
116 	uint32_t	lun = SD2LUN(sd);
117 	cpqary3_t	*ctlr;
118 
119 	ctlr = (cpqary3_t *)hba_tran->tran_hba_private;
120 
121 	/* HPQacucli Changes */
122 
123 	extern int8_t	cpqary3_detect_target_geometry(cpqary3_t *);
124 	if ((CPQARY3_SUCCESS == cpqary3_probe4targets(ctlr)) &&
125 	    (ctlr->num_of_targets > 0)) {
126 		(void) cpqary3_detect_target_geometry(ctlr);
127 	}
128 
129 	/* HPQacucli Changes */
130 	/*
131 	 * Validate the Target ID
132 	 * Validate Lun --Ver1.10--
133 	 * If not a valid target id, return FAILURE.
134 	 * Derieve the per-controller
135 	 */
136 
137 	if ((tid >= CPQARY3_MAX_TGT) || (lun != 0)) {
138 		DTRACE_PROBE2(tgt_init_notsup,
139 		    cpqary3_t *, ctlr, uint32_t, tid);
140 		return (DDI_FAILURE);
141 	}
142 
143 	/*
144 	 * Check to see if a target structure corrresponding to this
145 	 * target Id exists.(support only for Logical Drives and Controller)
146 	 * if target exists, update target flags, return SUCCESS
147 	 * is target does not exist, return FAILURE
148 	 */
149 
150 	mutex_enter(&ctlr->sw_mutex);
151 
152 	if (!(ctlr->cpqary3_tgtp[tid])) {
153 		mutex_exit(&ctlr->sw_mutex);
154 		return (DDI_FAILURE);
155 	}
156 
157 	ctlr->cpqary3_tgtp[tid]->tgt_dip = tgt_dip;
158 	ctlr->cpqary3_tgtp[tid]->ctlr_flags = CPQARY3_CAP_DISCON_ENABLED |
159 	    CPQARY3_CAP_SYNC_ENABLED | CPQARY3_CAP_WIDE_XFER_ENABLED |
160 	    CPQARY3_CAP_ARQ_ENABLED;
161 
162 	mutex_exit(&ctlr->sw_mutex);
163 
164 	DTRACE_PROBE1(tgt_init_done, uint32_t, tid);
165 
166 	return (DDI_SUCCESS);
167 }
168 
169 /*
170  * Function	:	cpqary3_tgt_probe()
171  * Description	: 	This routine probes into the Target Details.
172  * Called By	:  	cpqary3_init_hbatran()
173  * Parameters	: 	scsi-device structure, calling function if any
174  * Calls	: 	None
175  * Return Values: 	value returned by scsi_hba_probe()
176  */
177 static int
178 cpqary3_tgt_probe(struct scsi_device *sd, int (*waitfunc)())
179 {
180 #ifdef CPQARY3_DEBUG
181 	int	status;
182 #endif
183 
184 	/*
185 	 * Probe for the presence of the target, using the scsi_hba_probe().
186 	 * It inturn issues the SCSI inquiry command that is serviced by our
187 	 * driver
188 	 */
189 
190 	/* HPQacucli Changes */
191 	extern int8_t		cpqary3_detect_target_geometry(cpqary3_t *);
192 	struct scsi_hba_tran	*hba_tran = sd->sd_address.a_hba_tran;
193 	cpqary3_t		*ctlr = hba_tran->tran_hba_private;
194 
195 	if ((CPQARY3_SUCCESS == cpqary3_probe4targets(ctlr)) &&
196 	    (ctlr->num_of_targets > 0)) {
197 		(void) cpqary3_detect_target_geometry(ctlr);
198 	}
199 	/* HPQacucli Changes */
200 
201 	return (scsi_hba_probe(sd, waitfunc));
202 
203 #ifdef CPQARY3_DEBUG
204 
205 	/* Comment the previous line of code */
206 	status = scsi_hba_probe(sd, waitfunc);
207 	cmn_err(CE_CONT, "CPQary3 : _tgt_probe : target = %d \n", SD2TGT(sd));
208 	cmn_err(CE_CONT, "CPQary3 : _tgt_probe : scsi_hba_probe returned %d \n",
209 	    status);
210 	cmn_err(CE_CONT, "CPQary3 : _tgt_probe : Leaving \n");
211 	return (status);
212 
213 #endif
214 }
215 
216 /*
217  * Function	:	cpqary3_init_pkt
218  * Description	: 	This routine allocates resources for a SCSI packet.
219  * Called By	:  	cpqary3_init_pkt()
220  * Parameters	: 	SCSI address, SCSI packet, buffer, CDB length,
221  *			SCB length, driver private length, flags modifier,
222  *			callback function, arguement for the callback function
223  * Calls	: 	cpqary3_dma_alloc(), cpqary3_dma_move()
224  * Return Values: 	allocated SCSI packet / NULL
225  */
226 /* ARGSUSED */
227 static struct scsi_pkt *
228 cpqary3_init_pkt(struct scsi_address *sa, struct scsi_pkt *scsi_pktp,
229     struct buf *bp, int cmdlen, int statuslen, int tgtlen,
230     int flags, int (*callback)(), caddr_t arg)
231 {
232 	cpqary3_t	*cpqary3p;
233 	dev_info_t	*dip;
234 	cpqary3_pkt_t	*cpqary3_pktp;
235 	struct scsi_pkt	*new_scsi_pktp;
236 
237 	ASSERT(callback == NULL_FUNC || callback == SLEEP_FUNC);
238 
239 	cpqary3p = SA2CTLR(sa);
240 	dip = cpqary3p->dip;
241 
242 	/*
243 	 * If the SCSI packet is NULL, allocate frresh resources to it.
244 	 * Else, get the next available resources for the same
245 	 */
246 
247 	if (!scsi_pktp) {
248 		scsi_pktp = scsi_hba_pkt_alloc(dip, sa, cmdlen, statuslen,
249 		    tgtlen, sizeof (cpqary3_pkt_t), callback, NULL);
250 		if (!scsi_pktp)
251 			return (NULL);
252 
253 		cpqary3_pktp = (cpqary3_pkt_t *)scsi_pktp->pkt_ha_private;
254 		bzero(cpqary3_pktp, sizeof (cpqary3_pkt_t));
255 
256 		cpqary3_pktp->scsi_cmd_pkt = scsi_pktp;
257 
258 		/*
259 		 * Store the CDB length and sense data length in the
260 		 * pkt private
261 		 */
262 		cpqary3_pktp->cdb_len = cmdlen;
263 		cpqary3_pktp->scb_len = statuslen;
264 		cpqary3_pktp->cmd_dmahandle = NULL;
265 		cpqary3_pktp->memp = (cpqary3_cmdpvt_t *)NULL;
266 
267 		/*
268 		 * Initialize to NULL all the fields of scsi_pktp, except
269 		 * pkt_scbp, pkt_cdbp, pkt_ha_private and pkt_private members.
270 		 */
271 		scsi_pktp->pkt_address = *sa;
272 		scsi_pktp->pkt_comp = (void (*) ())NULL;
273 		scsi_pktp->pkt_flags = 0;
274 		scsi_pktp->pkt_time = 0;
275 		scsi_pktp->pkt_resid = 0;
276 		scsi_pktp->pkt_statistics = 0;
277 		scsi_pktp->pkt_state = 0;
278 		scsi_pktp->pkt_reason = 0;
279 
280 		if (flags & PKT_CONSISTENT)
281 			cpqary3_pktp->cmd_flags |=  DDI_DMA_CONSISTENT;
282 
283 		if (flags & PKT_DMA_PARTIAL)
284 			cpqary3_pktp->cmd_flags |= DDI_DMA_PARTIAL;
285 
286 		new_scsi_pktp = scsi_pktp;
287 	} else {
288 		new_scsi_pktp = NULL;
289 		cpqary3_pktp = (cpqary3_pkt_t *)scsi_pktp->pkt_ha_private;
290 	}
291 
292 	cpqary3_pktp->bf = bp;
293 
294 	/*
295 	 * If any I/O is desired, Allocate/Move DMA resources for the SCSI
296 	 * packet
297 	 * If first time allocation for this SCSI packet, allocate fresh DMA
298 	 * Else, move the already allocated DMA resources
299 	 */
300 	if (bp && bp->b_bcount != 0) { /* I/O is desired */
301 		if (!cpqary3_pktp->cmd_dmahandle) { /* First time allocation */
302 			if (cpqary3_dma_alloc(cpqary3p, scsi_pktp,
303 			    bp, flags, callback) == CPQARY3_FAILURE) {
304 				if (new_scsi_pktp)
305 					scsi_hba_pkt_free(sa, new_scsi_pktp);
306 				return ((struct scsi_pkt *)NULL);
307 			}
308 		} else {
309 			ASSERT(new_scsi_pktp == NULL);
310 			if (CPQARY3_FAILURE ==
311 			    cpqary3_dma_move(scsi_pktp, bp, cpqary3p)) {
312 				return ((struct scsi_pkt *)NULL);
313 			}
314 		}
315 	}
316 
317 	return (scsi_pktp);
318 }
319 
320 /*
321  * Function	:	cpqary3_dma_alloc()
322  * Description	: 	This routine services requests for memory (dynamic)
323  *			as and when required by the OS.
324  * Called By	: 	cpqary3_init_pkt()
325  * Parameters	: 	per-controller, SCSI packet, buffer, flag modifier,
326  *			callback function
327  * Calls	: 	None
328  * Return Values: 	SUCCESS / FAILURE
329  */
330 static int
331 cpqary3_dma_alloc(cpqary3_t *cpqary3p, struct scsi_pkt *scsi_pktp,
332     struct buf *bp, int flags, int (*callback)())
333 {
334 	int32_t		(*cb)(caddr_t);
335 	int32_t		retvalue;
336 	uint32_t	i = 0;
337 	uint32_t	dma_flags;
338 	cpqary3_pkt_t	*cpqary3_pktp;
339 	ddi_dma_attr_t	tmp_dma_attr;
340 
341 	cpqary3_pktp = (cpqary3_pkt_t *)scsi_pktp->pkt_ha_private;
342 
343 	ASSERT(callback == NULL_FUNC || callback == SLEEP_FUNC);
344 	/*
345 	 * Record the direction of the data transfer, so that it
346 	 * can be used in appropriate synchronization during cpqary3_sync_pkt()
347 	 */
348 	if (bp->b_flags & B_READ) {
349 		cpqary3_pktp->cmd_flags &= ~CFLAG_DMASEND;
350 		dma_flags = DDI_DMA_READ;
351 	} else {
352 		cpqary3_pktp->cmd_flags |= CFLAG_DMASEND;
353 		dma_flags = DDI_DMA_WRITE;
354 	}
355 
356 	if (flags & PKT_CONSISTENT) {
357 		cpqary3_pktp->cmd_flags |= CFLAG_CMDIOPB;
358 		dma_flags |= DDI_DMA_CONSISTENT;
359 	}
360 
361 	if (flags & PKT_DMA_PARTIAL) {
362 		dma_flags |= DDI_DMA_PARTIAL;
363 	}
364 
365 	tmp_dma_attr = cpqary3_dma_attr;
366 
367 	/* SG */
368 	tmp_dma_attr.dma_attr_sgllen = cpqary3p->sg_cnt;
369 	/* SG */
370 
371 	cb = (callback == NULL_FUNC) ? DDI_DMA_DONTWAIT : DDI_DMA_SLEEP;
372 
373 	/*
374 	 * DMA resources are allocated thru a 2 step protocol :
375 	 * - allocate a DMA handle
376 	 * - bind the buffer to the handle
377 	 * If both the steps succeed, we have succeeded in allocating resources
378 	 */
379 
380 	if (DDI_SUCCESS != (retvalue = ddi_dma_alloc_handle(cpqary3p->dip,
381 	    &tmp_dma_attr, cb, CPQARY3_DMA_NO_CALLBACK,
382 	    &cpqary3_pktp->cmd_dmahandle))) {
383 		switch (retvalue) {
384 		case DDI_DMA_NORESOURCES:
385 			/*
386 			 * No Resources are available to be allocated
387 			 */
388 			bioerror(bp, CPQARY3_BUFFER_ERROR_CLEAR);
389 			break;
390 
391 		case DDI_DMA_BADATTR:
392 			/*
393 			 * The attributes stated in our DMA attribute
394 			 * structure is such that potential DMA resources can
395 			 * not be allocated.
396 			 */
397 			cmn_err(CE_CONT, "CPQary3: DmaAlloc: "
398 			    "AllocHandle Failed BadAttr\n");
399 			bioerror(bp, EFAULT);
400 			break;
401 
402 		default:
403 			/*
404 			 * There is no other possible return value
405 			 */
406 			cmn_err(CE_WARN,
407 			    "CPQary3: dma_alloc: Unexpected Return Value %x "
408 			    "From call to Allocate DMA Handle \n", retvalue);
409 			break;
410 		}
411 		return (CPQARY3_FAILURE);
412 	}
413 
414 	retvalue = ddi_dma_buf_bind_handle(cpqary3_pktp->cmd_dmahandle, bp,
415 	    dma_flags, cb, CPQARY3_DMA_NO_CALLBACK,
416 	    &cpqary3_pktp->cmd_dmacookies[0], &cpqary3_pktp->cmd_ncookies);
417 
418 	switch (retvalue) {
419 	case DDI_DMA_PARTIAL_MAP :
420 	case DDI_DMA_MAPPED :
421 		if (DDI_DMA_PARTIAL_MAP == retvalue) {
422 			if (ddi_dma_numwin(cpqary3_pktp->cmd_dmahandle,
423 			    &cpqary3_pktp->cmd_nwin) == DDI_FAILURE) {
424 				cmn_err(CE_PANIC, "CPQary3: Retrieval of DMA "
425 				    "windows number failed");
426 			}
427 
428 			if (ddi_dma_getwin(cpqary3_pktp->cmd_dmahandle,
429 			    cpqary3_pktp->cmd_curwin,
430 			    &cpqary3_pktp->cmd_dma_offset,
431 			    &cpqary3_pktp->cmd_dma_len,
432 			    &cpqary3_pktp->cmd_dmacookies[0],
433 			    &cpqary3_pktp->cmd_ncookies) == DDI_FAILURE) {
434 				cmn_err(CE_PANIC, "CPQary3: Activation of New "
435 				    "DMA Window Failed");
436 			}
437 		} else {
438 			cpqary3_pktp->cmd_nwin = 1;
439 			cpqary3_pktp->cmd_dma_len = 0;
440 			cpqary3_pktp->cmd_dma_offset = 0;
441 		}
442 
443 		cpqary3_pktp->cmd_dmacount = 0;
444 		i = 0;
445 		for (;;) {
446 			cpqary3_pktp->cmd_dmacount +=
447 			    cpqary3_pktp->cmd_dmacookies[i++].dmac_size;
448 			/* SG */
449 			/* Check Out for Limits */
450 			if (i == cpqary3p->sg_cnt ||
451 			    i == cpqary3_pktp->cmd_ncookies)
452 				break;
453 			/* SG */
454 
455 			ddi_dma_nextcookie(cpqary3_pktp->cmd_dmahandle,
456 			    &cpqary3_pktp->cmd_dmacookies[i]);
457 		}
458 
459 		cpqary3_pktp->cmd_cookie = i;
460 		cpqary3_pktp->cmd_cookiecnt = i;
461 		cpqary3_pktp->cmd_flags |= CFLAG_DMAVALID;
462 
463 		scsi_pktp->pkt_resid =
464 		    bp->b_bcount - cpqary3_pktp->cmd_dmacount;
465 
466 		return (CPQARY3_SUCCESS);
467 
468 	case DDI_DMA_NORESOURCES:
469 		bioerror(bp, CPQARY3_BUFFER_ERROR_CLEAR);
470 		break;
471 
472 	case DDI_DMA_NOMAPPING:
473 		bioerror(bp, EFAULT);
474 		break;
475 
476 	case DDI_DMA_TOOBIG:
477 		bioerror(bp, EINVAL);
478 		break;
479 
480 	case DDI_DMA_INUSE:
481 		cmn_err(CE_PANIC, "CPQary3: Another I/O transaction "
482 		    "is using the DMA handle");
483 
484 	default:
485 		cmn_err(CE_PANIC, "CPQary3: Unexpected ERROR "
486 		    "returned from Call to Bind Buffer "
487 		    "to Handle : 0x%X", i);
488 	}
489 
490 	ddi_dma_free_handle(&cpqary3_pktp->cmd_dmahandle);
491 	cpqary3_pktp->cmd_dmahandle = NULL;
492 	cpqary3_pktp->cmd_flags &= ~CFLAG_DMAVALID;
493 
494 	return (CPQARY3_FAILURE);
495 
496 }
497 
498 /*
499  * Function	:	cpqary3_dma_move()
500  * Description	: 	This routine gets the next DMA window.
501  * Called By	: 	cpqary3_init_pkt()
502  * Parameters	: 	per-controller, SCSI packet, buffer
503  * Calls	: 	None
504  * Return Values: 	SUCCESS / FAILURE
505  */
506 static int
507 cpqary3_dma_move(struct scsi_pkt *scsi_pktp, struct buf *bp,
508     cpqary3_t *cpqary3p)
509 {
510 	uint32_t		i = 0;
511 	cpqary3_pkt_t	*cpqary3_pktp;
512 
513 	cpqary3_pktp = PKT2PVTPKT(scsi_pktp);
514 
515 	/*
516 	 * If there are no more cookies remaining in this window,
517 	 * must move to the next window first.
518 	 */
519 	if (cpqary3_pktp->cmd_cookie == cpqary3_pktp->cmd_ncookies) {
520 		/* For small pkts, leave things where they are */
521 		if ((cpqary3_pktp->cmd_curwin == cpqary3_pktp->cmd_nwin) &&
522 		    (cpqary3_pktp->cmd_nwin == 1))
523 			return (CPQARY3_SUCCESS);
524 
525 		/* Shall not be able to move if last window */
526 		if (++cpqary3_pktp->cmd_curwin >= cpqary3_pktp->cmd_nwin)
527 			return (CPQARY3_FAILURE);
528 
529 		if (ddi_dma_getwin(cpqary3_pktp->cmd_dmahandle,
530 		    cpqary3_pktp->cmd_curwin, &cpqary3_pktp->cmd_dma_offset,
531 		    &cpqary3_pktp->cmd_dma_len,
532 		    &cpqary3_pktp->cmd_dmacookies[0],
533 		    &cpqary3_pktp->cmd_ncookies) == DDI_FAILURE)
534 			return (CPQARY3_FAILURE);
535 
536 		cpqary3_pktp->cmd_cookie = 0;
537 	} else {
538 		/* Still more cookies in this window - get the next one */
539 		ddi_dma_nextcookie(cpqary3_pktp->cmd_dmahandle,
540 		    &cpqary3_pktp->cmd_dmacookies[0]);
541 	}
542 
543 	/* Get remaining cookies in this window, up to our maximum */
544 	for (;;) {
545 		cpqary3_pktp->cmd_dmacount +=
546 		    cpqary3_pktp->cmd_dmacookies[i++].dmac_size;
547 		cpqary3_pktp->cmd_cookie++;
548 		/* SG */
549 		/* no. of DATA SEGMENTS */
550 		if (i == cpqary3p->sg_cnt ||
551 		    cpqary3_pktp->cmd_cookie == cpqary3_pktp->cmd_ncookies)
552 			break;
553 		/* SG */
554 
555 		ddi_dma_nextcookie(cpqary3_pktp->cmd_dmahandle,
556 		    &cpqary3_pktp->cmd_dmacookies[i]);
557 	}
558 
559 	cpqary3_pktp->cmd_cookiecnt = i;
560 	scsi_pktp->pkt_resid = bp->b_bcount - cpqary3_pktp->cmd_dmacount;
561 
562 	return (CPQARY3_SUCCESS);
563 
564 }
565 
566 /*
567  * Function	:	cpqary3_transport()
568  * Description	: 	This routine services requests from the OS that are
569  *			directed towards the targets.(any SCSI command)
570  * Called By	: 	kernel
571  * Parameters	: 	SCSI address, SCSI packet, buffer
572  * Calls	: 	cpqary3_build_iop, cpqary3_add2submitted
573  * Return Values: 	TRAN_ACCEPT	: The driver accepts the command.
574  *			TRAN_BUSY	: Required resources not available
575  *					at the moment.
576  *			TRAN_FATAL_ERROR: A target no longer exists.
577  */
578 static int
579 cpqary3_transport(struct scsi_address *sa, struct scsi_pkt *scsi_pktp)
580 {
581 	cpqary3_t		*ctlr;
582 	cpqary3_pkt_t		*cpqary3_pktp;
583 	cpqary3_tgt_t		*tgtp;
584 	cpqary3_cmdpvt_t	*memp;
585 
586 	ASSERT(sa != NULL);
587 	ctlr = SA2CTLR(sa);
588 	cpqary3_pktp = PKT2PVTPKT(scsi_pktp);
589 	tgtp = ctlr->cpqary3_tgtp[SA2TGT(sa)];
590 
591 	if (!tgtp)
592 		return (TRAN_FATAL_ERROR);
593 
594 	if (tgtp->type == CPQARY3_TARGET_NONE)
595 		return (TRAN_FATAL_ERROR);
596 
597 	if (cpqary3_additional_cmd(scsi_pktp, ctlr))
598 		return (TRAN_ACCEPT);
599 
600 	/*
601 	 * Attempt to occupy a free command memory block
602 	 * If not successful, return TRAN_BUSY
603 	 * Else, build the Command
604 	 * Submit it to the controller
605 	 * If NO_INTR flag is set, wait for the completion of the command and
606 	 * when the command completes, update packet values appropriately and
607 	 * return TRAN_ACCEPT.
608 	 * Make an entry in the submitted Q
609 	 * return TRAN_ACCEPT
610 	 */
611 
612 	if (NULL == (memp = cpqary3_cmdlist_occupy(ctlr)))
613 		return (TRAN_BUSY);
614 
615 	cpqary3_pktp->memp = memp;
616 	memp->pvt_pkt = cpqary3_pktp;
617 
618 	if ((cpqary3_pktp->cmd_flags & DDI_DMA_CONSISTENT) &&
619 	    cpqary3_pktp->cmd_dmahandle) {
620 		(void) ddi_dma_sync(cpqary3_pktp->cmd_dmahandle, 0, 0,
621 		    DDI_DMA_SYNC_FORDEV);
622 	}
623 	/* SG */
624 	ASSERT(cpqary3_pktp->cmd_cookiecnt <= ctlr->sg_cnt);
625 	/* SG */
626 
627 	/* PERF */
628 	memp->complete = cpqary3_oscmd_complete;
629 	/* PERF */
630 
631 	switch (cpqary3_build_cmdlist(memp, SA2TGT(sa))) {
632 	case CPQARY3_SUCCESS :
633 		if (scsi_pktp->pkt_flags & FLAG_NOINTR) {
634 			return (cpqary3_handle_flag_nointr(memp, scsi_pktp));
635 		}
636 		cpqary3_pktp->cmd_start_time = ddi_get_lbolt();
637 		mutex_enter(&ctlr->hw_mutex);
638 		/* CONTROLLER_LOCKUP */
639 		if (EIO == cpqary3_submit(ctlr, memp->cmdlist_phyaddr)) {
640 			mutex_exit(&ctlr->hw_mutex);
641 			cpqary3_cmdlist_release(memp, CPQARY3_HOLD_SW_MUTEX);
642 			return (TRAN_FATAL_ERROR);
643 		}
644 		/* CONTROLLER_LOCKUP */
645 		mutex_exit(&ctlr->hw_mutex);
646 		break;
647 	case CPQARY3_FAILURE :
648 		cpqary3_cmdlist_release(memp, CPQARY3_HOLD_SW_MUTEX);
649 		return (TRAN_FATAL_ERROR);
650 	default: /* Never occurs */
651 		cmn_err(CE_NOTE, "CPQary3 : Transport : Unexpected Error");
652 		return (TRAN_FATAL_ERROR);
653 	}
654 
655 	return (TRAN_ACCEPT);
656 }
657 
658 /*
659  * Function	:	cpqary3_dmafree
660  * Description	: 	This routine de-allocates previously allocated
661  *			DMA resources.
662  * Called By	: 	kernel
663  * Parameters	: 	SCSI address, SCSI packet
664  * Calls	: 	None
665  * Return Values: 	None
666  */
667 /* ARGSUSED */
668 static void
669 cpqary3_dmafree(struct scsi_address *sa, struct scsi_pkt *scsi_pktp)
670 {
671 	cpqary3_pkt_t	*cpqary3_pktp;
672 
673 	cpqary3_pktp = PKT2PVTPKT(scsi_pktp);
674 
675 	/*
676 	 * If any DMA was succesfully attempted earlier, free all allocated
677 	 * resources
678 	 */
679 
680 	if (cpqary3_pktp->cmd_flags & CFLAG_DMAVALID) {
681 		if (!cpqary3_pktp->cmd_dmahandle) {
682 			DTRACE_PROBE(dmafree_null);
683 			return;
684 		}
685 		cpqary3_pktp->cmd_flags &= ~CFLAG_DMAVALID;
686 		(void) ddi_dma_unbind_handle(cpqary3_pktp->cmd_dmahandle);
687 		ddi_dma_free_handle(&cpqary3_pktp->cmd_dmahandle);
688 		cpqary3_pktp->cmd_dmahandle = NULL;
689 	}
690 }
691 
692 /*
693  * Function	:	cpqary3_dma_sync
694  * Description	: 	This routine synchronizes the CPU's / HBA's view of
695  *			the data associated with the pkt, typically by calling
696  *			ddi_dma_sync().
697  * Called By	: 	kernel
698  * Parameters	: 	SCSI address, SCSI packet
699  * Calls	: 	None
700  * Return Values: 	None
701  */
702 /* ARGSUSED */
703 static void
704 cpqary3_dma_sync(struct scsi_address *sa, struct scsi_pkt *scsi_pktp)
705 {
706 	cpqary3_pkt_t	*cpqary3_pktp = PKT2PVTPKT(scsi_pktp);
707 
708 	/*
709 	 * Check whether DMA was attempted successfully earlier
710 	 * If yes and
711 	 * if the command flags is write, then synchronise the device else
712 	 * synchronise the CPU
713 	 */
714 
715 	if (cpqary3_pktp->cmd_flags & CFLAG_DMAVALID) {
716 		(void) ddi_dma_sync(cpqary3_pktp->cmd_dmahandle,
717 		    cpqary3_pktp->cmd_dma_offset, cpqary3_pktp->cmd_dma_len,
718 		    (cpqary3_pktp->cmd_flags & CFLAG_DMASEND) ?
719 		    DDI_DMA_SYNC_FORDEV : DDI_DMA_SYNC_FORCPU);
720 	}
721 }
722 
723 /*
724  * Function	:	cpqary3_destroy_pkt
725  * Description	: 	This routine de-allocates previously allocated
726  *			resources for the SCSI packet.
727  * Called By	: 	kernel
728  * Parameters	: 	SCSI address, SCSI packet
729  * Calls	: 	None
730  * Return Values: 	None
731  */
732 static void
733 cpqary3_destroy_pkt(struct scsi_address *sa, struct scsi_pkt *scsi_pktp)
734 {
735 	cpqary3_pkt_t	*cpqary3_pktp;
736 
737 	cpqary3_pktp = PKT2PVTPKT(scsi_pktp);
738 
739 	/*
740 	 * Deallocate DMA Resources, if allocated.
741 	 * Free the SCSI Packet.
742 	 */
743 
744 	if (cpqary3_pktp->cmd_flags & CFLAG_DMAVALID) {
745 		if (!cpqary3_pktp->cmd_dmahandle) {
746 			DTRACE_PROBE(dmafree_null);
747 		} else {
748 			cpqary3_pktp->cmd_flags &= ~CFLAG_DMAVALID;
749 
750 			(void) ddi_dma_unbind_handle(
751 			    cpqary3_pktp->cmd_dmahandle);
752 			ddi_dma_free_handle(&cpqary3_pktp->cmd_dmahandle);
753 
754 			cpqary3_pktp->cmd_dmahandle = NULL;
755 		}
756 	}
757 
758 	scsi_hba_pkt_free(sa, scsi_pktp);
759 }
760 
761 /*
762  * Function	:	cpqary3_reset
763  * Description	: 	This routine resets a SCSI bus/target.
764  * Called By	: 	kernel
765  * Parameters	: 	SCSI address, reset level required
766  * Calls	: 	None
767  * Return Values: 	SUCCESS
768  */
769 /* ARGSUSED */
770 static int
771 cpqary3_reset(struct scsi_address *sa, int level)
772 {
773 	/*
774 	 * Fix for Crash seen during RAID 0 Drive removal -
775 	 * just return CPQARY3_SUCCESS on reset request
776 	 */
777 	return (CPQARY3_SUCCESS);
778 }
779 
780 /*
781  * Function	:	cpqary3_abort()
782  * Description	: 	This routine aborts a particular command or all commands
783  *			directed towards a target.
784  * Called By	: 	kernel
785  * Parameters	: 	SCSI address, SCSI packet
786  * Calls	: 	None
787  * Return Values: 	SUCCESS / FAILURE
788  *			[ abort of concernd command(s) was a success or
789  *			a failure. ]
790  */
791 static int
792 cpqary3_abort(struct scsi_address *sa, struct scsi_pkt *scsi_pktp)
793 {
794 	uint32_t	tid;
795 	cpqary3_t	*ctlr;
796 
797 	ASSERT(sa != NULL);
798 	tid  = SA2TGT(sa);
799 	ctlr = SA2CTLR(sa);
800 
801 	/*
802 	 * If SCSI packet exists, abort that particular command.
803 	 * Else, abort all existing commands to the target
804 	 * In either of the cases, we shall have to wait after the abort
805 	 * functions are called to return the status.
806 	 */
807 
808 	if (!scsi_pktp) {
809 		return (cpqary3_send_abortcmd(ctlr, tid,
810 		    (CommandList_t *)NULL));
811 	} else {
812 		return (cpqary3_send_abortcmd(ctlr, tid, SP2CMD(scsi_pktp)));
813 	}
814 }
815 
816 /*
817  * Function	:	cpqary3_getcap
818  * Description	: 	This routine is called to get the current value of a
819  *			capability.(SCSI transport capability)
820  * Called By	: 	kernel
821  * Parameters	: 	SCSI address, capability identifier, target(s) affected
822  * Calls	: 	None
823  * Return Values: 	current value of capability / -1 (if unsupported)
824  */
825 static int
826 cpqary3_getcap(struct scsi_address *sa, char *capstr, int tgtonly)
827 {
828 	int		index;
829 	cpqary3_t	*ctlr = SA2CTLR(sa);
830 	cpqary3_tgt_t	*tgtp = ctlr->cpqary3_tgtp[SA2TGT(sa)];
831 
832 	/*
833 	 * If requested Capability is not supported, return -1.
834 	 */
835 	if (DDI_FAILURE == (index = scsi_hba_lookup_capstr(capstr)))
836 		return (CAP_NOT_DEFINED);
837 
838 	/*
839 	 * Getting capability for a particulat target is supported
840 	 * the generic form of tran_getcap() is unsupported(for all targets)
841 	 * If directed towards a particular target, return current capability.
842 	 */
843 	if (tgtonly == 0) {	/* all targets */
844 		DTRACE_PROBE1(getcap_alltgt, int, index);
845 		return (CAP_NOT_DEFINED);
846 	}
847 
848 	DTRACE_PROBE1(getcap_index, int, index);
849 
850 	switch (index) {
851 	case SCSI_CAP_DMA_MAX:
852 		return ((int)cpqary3_dma_attr.dma_attr_maxxfer);
853 	case SCSI_CAP_DISCONNECT:
854 		return (tgtp->ctlr_flags & CPQARY3_CAP_DISCON_ENABLED);
855 	case SCSI_CAP_SYNCHRONOUS:
856 		return (tgtp->ctlr_flags & CPQARY3_CAP_SYNC_ENABLED);
857 	case SCSI_CAP_WIDE_XFER:
858 		return (tgtp->ctlr_flags & CPQARY3_CAP_WIDE_XFER_ENABLED);
859 	case SCSI_CAP_ARQ:
860 		return ((tgtp->ctlr_flags & CPQARY3_CAP_ARQ_ENABLED) ? 1 : 0);
861 	case SCSI_CAP_INITIATOR_ID:
862 		return (CTLR_SCSI_ID);
863 	case SCSI_CAP_UNTAGGED_QING:
864 		return (1);
865 	case SCSI_CAP_TAGGED_QING:
866 		return (1);
867 	case SCSI_CAP_SECTOR_SIZE:
868 		return (cpqary3_dma_attr.dma_attr_granular);
869 	case SCSI_CAP_TOTAL_SECTORS:
870 		return (CAP_NOT_DEFINED);
871 	case SCSI_CAP_GEOMETRY:
872 		return (cpqary3_target_geometry(sa));
873 	case SCSI_CAP_RESET_NOTIFICATION:
874 		return (0);
875 	default:
876 		return (CAP_NOT_DEFINED);
877 	}
878 }
879 
880 /*
881  * Function	:	cpqary3_setcap
882  * Description	: 	This routine is called to set the current value of a
883  *			capability.(SCSI transport capability)
884  * Called By	: 	kernel
885  * Parameters	: 	SCSI address, capability identifier,
886  *			new capability value, target(s) affected
887  * Calls	: 	None
888  * Return Values: 	SUCCESS / FAILURE / -1 (if capability is unsupported)
889  */
890 /* ARGSUSED */
891 static int
892 cpqary3_setcap(struct scsi_address *sa, char *capstr, int value, int tgtonly)
893 {
894 	int	index;
895 	int	retstatus = CAP_NOT_DEFINED;
896 
897 	/*
898 	 * If requested Capability is not supported, return -1.
899 	 */
900 	if ((index = scsi_hba_lookup_capstr(capstr)) == DDI_FAILURE)
901 		return (retstatus);
902 
903 	/*
904 	 * Setting capability for a particulat target is supported
905 	 * the generic form of tran_setcap() is unsupported(for all targets)
906 	 * If directed towards a particular target, set & return current
907 	 * capability.
908 	 */
909 	if (!tgtonly) {
910 		DTRACE_PROBE1(setcap_alltgt, int, index);
911 		return (retstatus);
912 	}
913 
914 	DTRACE_PROBE1(setcap_index, int, index);
915 
916 	switch (index) {
917 	case SCSI_CAP_DMA_MAX:
918 		return (CAP_CHG_NOT_ALLOWED);
919 	case SCSI_CAP_DISCONNECT:
920 		return (CAP_CHG_NOT_ALLOWED);
921 	case SCSI_CAP_SYNCHRONOUS:
922 		return (CAP_CHG_NOT_ALLOWED);
923 	case SCSI_CAP_WIDE_XFER:
924 		return (CAP_CHG_NOT_ALLOWED);
925 	case SCSI_CAP_ARQ:
926 		return (1);
927 	case SCSI_CAP_INITIATOR_ID:
928 		return (CAP_CHG_NOT_ALLOWED);
929 	case SCSI_CAP_UNTAGGED_QING:
930 		return (1);
931 	case SCSI_CAP_TAGGED_QING:
932 		return (1);
933 	case SCSI_CAP_SECTOR_SIZE:
934 		return (CAP_CHG_NOT_ALLOWED);
935 	case SCSI_CAP_TOTAL_SECTORS:
936 		return (CAP_CHG_NOT_ALLOWED);
937 	case SCSI_CAP_GEOMETRY:
938 		return (CAP_CHG_NOT_ALLOWED);
939 	case SCSI_CAP_RESET_NOTIFICATION:
940 		return (CAP_CHG_NOT_ALLOWED);
941 	default:
942 		return (CAP_NOT_DEFINED);
943 	}
944 }
945 
946 /*
947  * Function	:	cpqary3_handle_flag_nointr
948  * Description	: 	This routine is called to handle submission and
949  *			subsequently poll for the completion of a command,
950  *			when its FLAG_NOINTR bit is set.
951  * Called By	: 	cpqary3_transport()
952  * Parameters	: 	command private structure, SCSI packet
953  * Calls	: 	cpqary3_intr_onoff, cpqary3_retrieve,
954  *			cpqary3_submit, cpqary3_poll
955  * Return Values: 	TRAN_ACCEPT
956  */
957 static int
958 cpqary3_handle_flag_nointr(cpqary3_cmdpvt_t *memp, struct scsi_pkt *scsi_pktp)
959 {
960 	uint32_t		tag;
961 	uint32_t		simple_tag;
962 	uint32_t		i;
963 	cpqary3_t		*ctlr;
964 	cpqary3_cmdpvt_t	*cpqary3_cmdpvtp;
965 	uint32_t		CmdsOutMax;
966 	uint32_t		no_cmds;
967 
968 	RETURN_FAILURE_IF_NULL(memp);
969 	tag = memp->tag.tag_value;
970 	ctlr = memp->ctlr;
971 	ctlr->poll_flag = CPQARY3_FALSE;
972 
973 	/*
974 	 * Before sumitting this command, ensure all commands pending
975 	 * with the controller are completed.
976 	 */
977 
978 	cpqary3_intr_onoff(ctlr, CPQARY3_INTR_DISABLE);
979 	if (ctlr->host_support & 0x4)
980 		cpqary3_lockup_intr_onoff(ctlr, CPQARY3_LOCKUP_INTR_DISABLE);
981 
982 	no_cmds = (uint32_t)((ctlr->ctlr_maxcmds / 3) * NO_OF_CMDLIST_IN_A_BLK);
983 	mutex_enter(&ctlr->sw_mutex);
984 
985 	for (;;) {
986 		ctlr->poll_flag = CPQARY3_FALSE;
987 		for (i = 0; i < no_cmds; i++) {
988 			cpqary3_cmdpvtp = &ctlr->cmdmemlistp->pool[i];
989 			ASSERT(cpqary3_cmdpvtp != NULL);
990 
991 			if ((tag != cpqary3_cmdpvtp->tag.tag_value) &&
992 			    (cpqary3_cmdpvtp->occupied == CPQARY3_OCCUPIED)) {
993 				if (ctlr->noe_support == 1) {
994 					if ((cpqary3_cmdpvtp->cmdlist_memaddr->
995 					    Header.Tag.drvinfo_n_err ==
996 					    CPQARY3_NOECMD_SUCCESS) ||
997 					    (cpqary3_cmdpvtp->cmdpvt_flag ==
998 					    CPQARY3_TIMEOUT))  {
999 						continue;
1000 					}
1001 				} else {
1002 					if (cpqary3_cmdpvtp->cmdpvt_flag ==
1003 					    CPQARY3_TIMEOUT)  {
1004 						continue;
1005 					}
1006 				}
1007 				ctlr->poll_flag = CPQARY3_TRUE;
1008 			}
1009 			/* NOE */
1010 
1011 			if (ctlr->poll_flag == CPQARY3_TRUE) {
1012 				break;
1013 			}
1014 		}
1015 
1016 		if (ctlr->poll_flag == CPQARY3_TRUE) {
1017 			if (!(ctlr->bddef->bd_flags & SA_BD_SAS)) {
1018 				while ((simple_tag =
1019 				    ddi_get32(ctlr->opq_handle,
1020 				    (uint32_t *)ctlr->opq)) != 0xFFFFFFFF) {
1021 					CmdsOutMax = ctlr->ctlr_maxcmds;
1022 					if ((simple_tag >>
1023 					    CPQARY3_GET_MEM_TAG) >=
1024 					    ((CmdsOutMax / 3) * 3)) {
1025 						cmn_err(CE_WARN,
1026 						    "CPQary3 : HBA returned "
1027 						    "Spurious Tag");
1028 						return (CPQARY3_FAILURE);
1029 					}
1030 
1031 					cpqary3_cmdpvtp =
1032 					    &ctlr->cmdmemlistp->pool[
1033 					    simple_tag >> CPQARY3_GET_MEM_TAG];
1034 					cpqary3_cmdpvtp->cmdlist_memaddr->
1035 					    Header.Tag.drvinfo_n_err =
1036 					    (simple_tag & 0xF) >> 1;
1037 					cpqary3_cmdpvtp->complete(
1038 					    cpqary3_cmdpvtp);
1039 				}
1040 			} else {
1041 				mutex_exit(&ctlr->sw_mutex);
1042 				if (CPQARY3_SUCCESS != cpqary3_retrieve(ctlr)) {
1043 					drv_usecwait(1000);
1044 				}
1045 				mutex_enter(&ctlr->sw_mutex); /* Changes */
1046 			}
1047 		} else {
1048 			break;
1049 		}
1050 	}
1051 
1052 	mutex_enter(&ctlr->hw_mutex);
1053 	if (EIO == cpqary3_submit(ctlr, memp->cmdlist_phyaddr)) {
1054 		mutex_exit(&ctlr->hw_mutex);
1055 		mutex_exit(&ctlr->sw_mutex);
1056 		cpqary3_cmdlist_release(memp, CPQARY3_HOLD_SW_MUTEX);
1057 		return (TRAN_FATAL_ERROR);
1058 	}
1059 
1060 	if (CPQARY3_FAILURE == cpqary3_poll(ctlr, tag)) {
1061 		scsi_pktp->pkt_reason = CMD_TIMEOUT;
1062 		scsi_pktp->pkt_statistics = STAT_TIMEOUT;
1063 		scsi_pktp->pkt_state = 0;
1064 		mutex_exit(&ctlr->hw_mutex);
1065 		mutex_exit(&ctlr->sw_mutex);
1066 		cpqary3_cmdlist_release(memp, CPQARY3_HOLD_SW_MUTEX);
1067 		cpqary3_intr_onoff(ctlr, CPQARY3_INTR_ENABLE);
1068 		if (ctlr->host_support & 0x4)
1069 			cpqary3_lockup_intr_onoff(ctlr,
1070 			    CPQARY3_LOCKUP_INTR_ENABLE);
1071 		return (TRAN_ACCEPT);
1072 	} else {
1073 		mutex_exit(&ctlr->hw_mutex);
1074 		mutex_exit(&ctlr->sw_mutex);
1075 		cpqary3_intr_onoff(ctlr, CPQARY3_INTR_ENABLE);
1076 		if (ctlr->host_support & 0x4) {
1077 			cpqary3_lockup_intr_onoff(ctlr,
1078 			    CPQARY3_LOCKUP_INTR_ENABLE);
1079 		}
1080 		return (TRAN_ACCEPT);
1081 	}
1082 }
1083 
1084 /*
1085  * Function	:	cpqary3_poll
1086  * Description	: 	This routine polls for the completion of a command.
1087  * Called By	: 	cpqary3_handle_flag_nointr
1088  * Parameters	: 	per controller, tag of the command to be polled
1089  * Calls	: 	cpqary3_poll_retrieve
1090  * Return Values: 	TRAN_ACCEPT
1091  */
1092 static int
1093 cpqary3_poll(cpqary3_t *ctlr, uint32_t tag)
1094 {
1095 	uint32_t		ii = 0;
1096 
1097 	RETURN_FAILURE_IF_NULL(ctlr);
1098 
1099 	/*
1100 	 * POLL for the completion of the said command
1101 	 * Since, we had ensured that controller is empty, we need not
1102 	 * check for the complete Retrieved Q.
1103 	 * However, we just check the Retrieved Q and complete all
1104 	 * commands in it, inclusive of the polled command.
1105 	 * if the polled command is completed, send back a success.
1106 	 */
1107 
1108 	for (;;) {	/* this function is called with both the locks held */
1109 		if (CPQARY3_SUCCESS != cpqary3_poll_retrieve(ctlr, tag)) {
1110 			ii++;
1111 			if (ii > 120000)
1112 				return (CPQARY3_FAILURE);
1113 			drv_usecwait(500);
1114 			continue;
1115 		}
1116 		break;
1117 	}
1118 
1119 	return (CPQARY3_SUCCESS);
1120 }
1121 
1122 static int
1123 cpqary3_additional_cmd(struct scsi_pkt *scsi_pktp, cpqary3_t *ctlr)
1124 {
1125 	struct scsi_arq_status *arqstat;
1126 	/* LINTED: alignment */
1127 	arqstat = (struct scsi_arq_status *)(scsi_pktp->pkt_scbp);
1128 
1129 	switch (scsi_pktp->pkt_cdbp[0]) {
1130 	case 0x35: /* Synchronize Cache */
1131 
1132 		cpqary3_flush_cache(ctlr);
1133 
1134 		scsi_pktp->pkt_reason = CMD_CMPLT;
1135 		scsi_pktp->pkt_statistics = 0;
1136 		scsi_pktp->pkt_state = STATE_GOT_BUS | STATE_GOT_TARGET |
1137 		    STATE_SENT_CMD | STATE_XFERRED_DATA | STATE_GOT_STATUS;
1138 
1139 		if (scsi_pktp->pkt_comp) {
1140 			(*scsi_pktp->pkt_comp)(scsi_pktp);
1141 		}
1142 
1143 		return (1);
1144 
1145 	case 0x04: /* Format Unit */
1146 		cmn_err(CE_NOTE, "The FORMAT UNIT is not supported by this "
1147 		    "device If this option is selected from the format utility "
1148 		    "do not continue further.  Please refer to cpqary3 driver "
1149 		    "man pages for details.");
1150 
1151 		return (0);
1152 	case SCSI_LOG_SENSE:
1153 	case SCSI_MODE_SELECT:
1154 	case SCSI_PERSISTENT_RESERVE_IN:
1155 		arqstat->sts_status.sts_chk = 1; /* CHECK CONDITION */
1156 		arqstat->sts_rqpkt_reason = CMD_CMPLT;
1157 		arqstat->sts_rqpkt_resid = 0;
1158 		arqstat->sts_rqpkt_state = STATE_GOT_BUS | STATE_GOT_TARGET |
1159 		    STATE_SENT_CMD | STATE_XFERRED_DATA;
1160 		arqstat->sts_rqpkt_statistics = 0;
1161 		arqstat->sts_sensedata.es_valid = 1;
1162 		arqstat->sts_sensedata.es_class = CLASS_EXTENDED_SENSE;
1163 		arqstat->sts_sensedata.es_key = KEY_ILLEGAL_REQUEST;
1164 		scsi_pktp->pkt_state = STATE_GOT_BUS | STATE_GOT_TARGET |
1165 		    STATE_SENT_CMD | STATE_XFERRED_DATA;
1166 
1167 		if (scsi_pktp->pkt_comp) {
1168 			(*scsi_pktp->pkt_comp)(scsi_pktp);
1169 		}
1170 		return (1);
1171 	}
1172 
1173 	return (0);
1174 }
1175 
1176 /* PERF */
1177 /*
1178  * Function	:      	cpqary3_oscmd_complete
1179  * Description	:      	This routine processes the
1180  *			completed OS commands and
1181  *			initiates any callback that is needed.
1182  * Called By	:      	cpqary3_transport
1183  * Parameters	:      	per-command
1184  * Calls	:      	cpqary3_ioctl_send_bmiccmd,
1185  *			cpqary3_ioctl_send_scsicmd,
1186  *			cpqary3_send_abortcmd, cpqary3_flush_cache,
1187  *			cpqary3_probe4LVs,
1188  *			cpqary3_probe4Tapes, cpqary3_synccmd_complete,
1189  *			cpqary3_detect_target_geometry,
1190  *			cpqary3_detect_target_geometry
1191  * Return Values:      	None
1192  */
1193 void
1194 cpqary3_oscmd_complete(cpqary3_cmdpvt_t *cpqary3_cmdpvtp)
1195 {
1196 	cpqary3_t	*cpqary3p;
1197 	ErrorInfo_t	*errorinfop;
1198 	CommandList_t	*cmdlistp;
1199 	struct scsi_pkt	*scsi_pktp;
1200 
1201 	ASSERT(cpqary3_cmdpvtp != NULL);
1202 
1203 	if (CPQARY3_TIMEOUT == cpqary3_cmdpvtp->cmdpvt_flag) {
1204 		cpqary3_cmdlist_release(cpqary3_cmdpvtp,
1205 		    CPQARY3_NO_MUTEX);
1206 		return;
1207 	}
1208 
1209 	cpqary3p = cpqary3_cmdpvtp->ctlr;
1210 	cmdlistp = cpqary3_cmdpvtp->cmdlist_memaddr;
1211 	errorinfop = cpqary3_cmdpvtp->errorinfop;
1212 
1213 	if (cmdlistp->Header.Tag.drvinfo_n_err == CPQARY3_OSCMD_SUCCESS) {
1214 		scsi_pktp = cpqary3_cmdpvtp->pvt_pkt->scsi_cmd_pkt;
1215 		scsi_pktp->pkt_reason = CMD_CMPLT;
1216 		scsi_pktp->pkt_statistics = 0;
1217 		scsi_pktp->pkt_state = STATE_GOT_BUS |
1218 		    STATE_GOT_TARGET | STATE_SENT_CMD |
1219 		    STATE_XFERRED_DATA | STATE_GOT_STATUS;
1220 
1221 		if (cpqary3_cmdpvtp->pvt_pkt->scsi_cmd_pkt->pkt_flags &
1222 		    FLAG_NOINTR) {
1223 			cpqary3_cmdlist_release(cpqary3_cmdpvtp,
1224 			    CPQARY3_NO_MUTEX);
1225 		} else {
1226 			cpqary3_cmdlist_release(cpqary3_cmdpvtp,
1227 			    CPQARY3_NO_MUTEX);
1228 
1229 			if (scsi_pktp->pkt_comp) {
1230 				mutex_exit(&cpqary3p->sw_mutex);
1231 				(*scsi_pktp->pkt_comp)(scsi_pktp);
1232 				mutex_enter(&cpqary3p->sw_mutex);
1233 			}
1234 		}
1235 		return;
1236 	} else {
1237 		scsi_pktp = cpqary3_cmdpvtp->pvt_pkt->scsi_cmd_pkt;
1238 	}
1239 
1240 	switch (errorinfop->CommandStatus) {
1241 	case CISS_CMD_DATA_OVERRUN :
1242 		scsi_pktp->pkt_reason = CMD_DATA_OVR;
1243 		scsi_pktp->pkt_state = STATE_GOT_BUS | STATE_GOT_TARGET |
1244 		    STATE_SENT_CMD | STATE_XFERRED_DATA | STATE_GOT_STATUS;
1245 		break;
1246 
1247 	case CISS_CMD_INVALID :
1248 		DTRACE_PROBE1(invalid_cmd, struct scsi_pkt *, scsi_pktp);
1249 		scsi_pktp->pkt_reason = CMD_BADMSG;
1250 		scsi_pktp->pkt_state = STATE_GOT_BUS |STATE_GOT_TARGET |
1251 		    STATE_SENT_CMD | STATE_GOT_STATUS;
1252 		break;
1253 
1254 	case CISS_CMD_PROTOCOL_ERR :
1255 		scsi_pktp->pkt_reason = CMD_BADMSG;
1256 		scsi_pktp->pkt_state = STATE_GOT_BUS | STATE_GOT_TARGET |
1257 		    STATE_SENT_CMD | STATE_GOT_STATUS;
1258 		break;
1259 
1260 	case CISS_CMD_HARDWARE_ERR:
1261 	case CISS_CMD_CONNECTION_LOST:
1262 		scsi_pktp->pkt_reason = CMD_INCOMPLETE;
1263 		scsi_pktp->pkt_state = 0;
1264 		break;
1265 
1266 	case CISS_CMD_ABORTED:
1267 	case CISS_CMD_UNSOLICITED_ABORT:
1268 		scsi_pktp->pkt_reason = CMD_ABORTED;
1269 		scsi_pktp->pkt_statistics = STAT_ABORTED;
1270 		scsi_pktp->pkt_state = STATE_GOT_BUS | STATE_GOT_TARGET |
1271 		    STATE_SENT_CMD | STATE_XFERRED_DATA | STATE_GOT_STATUS;
1272 		break;
1273 
1274 	case CISS_CMD_ABORT_FAILED:
1275 		break;
1276 
1277 	case CISS_CMD_TIMEOUT:
1278 		scsi_pktp->pkt_reason = CMD_TIMEOUT;
1279 		scsi_pktp->pkt_statistics = STAT_TIMEOUT;
1280 		scsi_pktp->pkt_state = 0;
1281 		break;
1282 
1283 	case CISS_CMD_DATA_UNDERRUN:	/* Significant ONLY for Read & Write */
1284 		if (cpqary3_is_scsi_read_write(scsi_pktp)) {
1285 			scsi_pktp->pkt_reason = CMD_CMPLT;
1286 			scsi_pktp->pkt_statistics = 0;
1287 			scsi_pktp->pkt_state =
1288 			    STATE_GOT_BUS | STATE_GOT_TARGET | STATE_SENT_CMD |
1289 			    STATE_XFERRED_DATA | STATE_GOT_STATUS;
1290 			break;
1291 		}
1292 		/* FALLTHROUGH */
1293 	case CISS_CMD_SUCCESS:
1294 	case CISS_CMD_TARGET_STATUS:
1295 		scsi_pktp->pkt_reason = CMD_CMPLT;
1296 		scsi_pktp->pkt_statistics = 0;
1297 		scsi_pktp->pkt_state = STATE_GOT_BUS | STATE_GOT_TARGET |
1298 		    STATE_SENT_CMD | STATE_XFERRED_DATA | STATE_GOT_STATUS;
1299 		break;
1300 
1301 	default:	/* Should never Occur !!! */
1302 		scsi_pktp->pkt_reason = CMD_TRAN_ERR;
1303 		break;
1304 	}
1305 
1306 
1307 	/*
1308 	 * if ever a command completes with a CHECK CONDITION or a
1309 	 * COMMAND_TERMINATED SCSI status, Update the sense data.
1310 	 * NOTE : The CISS_CMD_INVALID command status would always result in a
1311 	 * CHECK CONDITION and hence reach this part of the code.
1312 	 */
1313 
1314 	if ((errorinfop->ScsiStatus == SCSI_CHECK_CONDITION) ||
1315 	    (errorinfop->ScsiStatus == SCSI_COMMAND_TERMINATED)) {
1316 		if (errorinfop->SenseLen) {
1317 			struct scsi_arq_status	*arq_statusp;
1318 			arq_statusp =
1319 			    /* LINTED: alignment */
1320 			    (struct scsi_arq_status *)scsi_pktp->pkt_scbp;
1321 
1322 			if ((errorinfop->ScsiStatus == SCSI_CHECK_CONDITION)) {
1323 				arq_statusp->sts_status.sts_chk = (uint8_t)1;
1324 			} else {
1325 				arq_statusp->sts_status.sts_chk = (uint8_t)1;
1326 				arq_statusp->sts_status.sts_scsi2 = (uint8_t)1;
1327 			}
1328 			bzero((void *)&(arq_statusp->sts_rqpkt_status),
1329 			    sizeof (struct scsi_status));
1330 			arq_statusp->sts_rqpkt_reason = CMD_CMPLT;
1331 			arq_statusp->sts_rqpkt_resid = 0;
1332 			arq_statusp->sts_rqpkt_state = scsi_pktp->pkt_state;
1333 			arq_statusp->sts_rqpkt_statistics =
1334 			    scsi_pktp->pkt_statistics;
1335 			bcopy((caddr_t)&errorinfop->SenseInfo[0],
1336 			    (caddr_t)(&arq_statusp->sts_sensedata),
1337 			    CPQARY3_MIN(errorinfop->SenseLen,
1338 			    cpqary3_cmdpvtp->pvt_pkt->scb_len));
1339 			scsi_pktp->pkt_state |= STATE_ARQ_DONE;
1340 		}
1341 	}
1342 
1343 	if (cpqary3_cmdpvtp->pvt_pkt->scsi_cmd_pkt->pkt_flags & FLAG_NOINTR) {
1344 		cpqary3_cmdlist_release(cpqary3_cmdpvtp, CPQARY3_NO_MUTEX);
1345 	} else {
1346 		cpqary3_cmdlist_release(cpqary3_cmdpvtp, CPQARY3_NO_MUTEX);
1347 
1348 		if (scsi_pktp->pkt_comp) {
1349 			mutex_exit(&cpqary3p->sw_mutex);
1350 			(*scsi_pktp->pkt_comp)(scsi_pktp);
1351 			mutex_enter(&cpqary3p->sw_mutex);
1352 		}
1353 	}
1354 }
1355 
1356 static uint8_t
1357 cpqary3_is_scsi_read_write(struct scsi_pkt *scsi_pktp)
1358 {
1359 	/*
1360 	 * In the scsi packet structure, the first byte is the SCSI Command
1361 	 * OpCode.  We check to see if it is any one of the SCSI Read or Write
1362 	 * opcodes.
1363 	 */
1364 
1365 	switch (scsi_pktp->pkt_cdbp[0]) {
1366 	case SCSI_READ_6:
1367 	case SCSI_READ_10:
1368 	case SCSI_READ_12:
1369 	case SCSI_WRITE_6:
1370 	case SCSI_WRITE_10:
1371 	case SCSI_WRITE_12:
1372 		return (1);
1373 
1374 	default:
1375 		return (0);
1376 	}
1377 }
1378