xref: /illumos-gate/usr/src/uts/common/io/cpqary3/cpqary3_transport.c (revision bde334a8dbd66dfa70ce4d7fc9dcad6e1ae45fe4)
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 		break;
484 
485 	default:
486 		cmn_err(CE_PANIC, "CPQary3: Unexpected ERROR "
487 		    "returned from Call to Bind Buffer "
488 		    "to Handle : 0x%X", retvalue);
489 	}
490 
491 	ddi_dma_free_handle(&cpqary3_pktp->cmd_dmahandle);
492 	cpqary3_pktp->cmd_dmahandle = NULL;
493 	cpqary3_pktp->cmd_flags &= ~CFLAG_DMAVALID;
494 
495 	return (CPQARY3_FAILURE);
496 
497 }
498 
499 /*
500  * Function	:	cpqary3_dma_move()
501  * Description	: 	This routine gets the next DMA window.
502  * Called By	: 	cpqary3_init_pkt()
503  * Parameters	: 	per-controller, SCSI packet, buffer
504  * Calls	: 	None
505  * Return Values: 	SUCCESS / FAILURE
506  */
507 static int
508 cpqary3_dma_move(struct scsi_pkt *scsi_pktp, struct buf *bp,
509     cpqary3_t *cpqary3p)
510 {
511 	uint32_t		i = 0;
512 	cpqary3_pkt_t	*cpqary3_pktp;
513 
514 	cpqary3_pktp = PKT2PVTPKT(scsi_pktp);
515 
516 	/*
517 	 * If there are no more cookies remaining in this window,
518 	 * must move to the next window first.
519 	 */
520 	if (cpqary3_pktp->cmd_cookie == cpqary3_pktp->cmd_ncookies) {
521 		/* For small pkts, leave things where they are */
522 		if ((cpqary3_pktp->cmd_curwin == cpqary3_pktp->cmd_nwin) &&
523 		    (cpqary3_pktp->cmd_nwin == 1))
524 			return (CPQARY3_SUCCESS);
525 
526 		/* Shall not be able to move if last window */
527 		if (++cpqary3_pktp->cmd_curwin >= cpqary3_pktp->cmd_nwin)
528 			return (CPQARY3_FAILURE);
529 
530 		if (ddi_dma_getwin(cpqary3_pktp->cmd_dmahandle,
531 		    cpqary3_pktp->cmd_curwin, &cpqary3_pktp->cmd_dma_offset,
532 		    &cpqary3_pktp->cmd_dma_len,
533 		    &cpqary3_pktp->cmd_dmacookies[0],
534 		    &cpqary3_pktp->cmd_ncookies) == DDI_FAILURE)
535 			return (CPQARY3_FAILURE);
536 
537 		cpqary3_pktp->cmd_cookie = 0;
538 	} else {
539 		/* Still more cookies in this window - get the next one */
540 		ddi_dma_nextcookie(cpqary3_pktp->cmd_dmahandle,
541 		    &cpqary3_pktp->cmd_dmacookies[0]);
542 	}
543 
544 	/* Get remaining cookies in this window, up to our maximum */
545 	for (;;) {
546 		cpqary3_pktp->cmd_dmacount +=
547 		    cpqary3_pktp->cmd_dmacookies[i++].dmac_size;
548 		cpqary3_pktp->cmd_cookie++;
549 		/* SG */
550 		/* no. of DATA SEGMENTS */
551 		if (i == cpqary3p->sg_cnt ||
552 		    cpqary3_pktp->cmd_cookie == cpqary3_pktp->cmd_ncookies)
553 			break;
554 		/* SG */
555 
556 		ddi_dma_nextcookie(cpqary3_pktp->cmd_dmahandle,
557 		    &cpqary3_pktp->cmd_dmacookies[i]);
558 	}
559 
560 	cpqary3_pktp->cmd_cookiecnt = i;
561 	scsi_pktp->pkt_resid = bp->b_bcount - cpqary3_pktp->cmd_dmacount;
562 
563 	return (CPQARY3_SUCCESS);
564 
565 }
566 
567 /*
568  * Function	:	cpqary3_transport()
569  * Description	: 	This routine services requests from the OS that are
570  *			directed towards the targets.(any SCSI command)
571  * Called By	: 	kernel
572  * Parameters	: 	SCSI address, SCSI packet, buffer
573  * Calls	: 	cpqary3_build_iop, cpqary3_add2submitted
574  * Return Values: 	TRAN_ACCEPT	: The driver accepts the command.
575  *			TRAN_BUSY	: Required resources not available
576  *					at the moment.
577  *			TRAN_FATAL_ERROR: A target no longer exists.
578  */
579 static int
580 cpqary3_transport(struct scsi_address *sa, struct scsi_pkt *scsi_pktp)
581 {
582 	cpqary3_t		*ctlr;
583 	cpqary3_pkt_t		*cpqary3_pktp;
584 	cpqary3_tgt_t		*tgtp;
585 	cpqary3_cmdpvt_t	*memp;
586 
587 	ASSERT(sa != NULL);
588 	ctlr = SA2CTLR(sa);
589 	cpqary3_pktp = PKT2PVTPKT(scsi_pktp);
590 	tgtp = ctlr->cpqary3_tgtp[SA2TGT(sa)];
591 
592 	if (!tgtp)
593 		return (TRAN_FATAL_ERROR);
594 
595 	if (tgtp->type == CPQARY3_TARGET_NONE)
596 		return (TRAN_FATAL_ERROR);
597 
598 	if (cpqary3_additional_cmd(scsi_pktp, ctlr))
599 		return (TRAN_ACCEPT);
600 
601 	/*
602 	 * Attempt to occupy a free command memory block
603 	 * If not successful, return TRAN_BUSY
604 	 * Else, build the Command
605 	 * Submit it to the controller
606 	 * If NO_INTR flag is set, wait for the completion of the command and
607 	 * when the command completes, update packet values appropriately and
608 	 * return TRAN_ACCEPT.
609 	 * Make an entry in the submitted Q
610 	 * return TRAN_ACCEPT
611 	 */
612 
613 	if (NULL == (memp = cpqary3_cmdlist_occupy(ctlr)))
614 		return (TRAN_BUSY);
615 
616 	cpqary3_pktp->memp = memp;
617 	memp->pvt_pkt = cpqary3_pktp;
618 
619 	if ((cpqary3_pktp->cmd_flags & DDI_DMA_CONSISTENT) &&
620 	    cpqary3_pktp->cmd_dmahandle) {
621 		(void) ddi_dma_sync(cpqary3_pktp->cmd_dmahandle, 0, 0,
622 		    DDI_DMA_SYNC_FORDEV);
623 	}
624 	/* SG */
625 	ASSERT(cpqary3_pktp->cmd_cookiecnt <= ctlr->sg_cnt);
626 	/* SG */
627 
628 	/* PERF */
629 	memp->complete = cpqary3_oscmd_complete;
630 	/* PERF */
631 
632 	switch (cpqary3_build_cmdlist(memp, SA2TGT(sa))) {
633 	case CPQARY3_SUCCESS :
634 		if (scsi_pktp->pkt_flags & FLAG_NOINTR) {
635 			return (cpqary3_handle_flag_nointr(memp, scsi_pktp));
636 		}
637 		cpqary3_pktp->cmd_start_time = ddi_get_lbolt();
638 		mutex_enter(&ctlr->hw_mutex);
639 		/* CONTROLLER_LOCKUP */
640 		if (EIO == cpqary3_submit(ctlr, memp->cmdlist_phyaddr)) {
641 			mutex_exit(&ctlr->hw_mutex);
642 			cpqary3_cmdlist_release(memp, CPQARY3_HOLD_SW_MUTEX);
643 			return (TRAN_FATAL_ERROR);
644 		}
645 		/* CONTROLLER_LOCKUP */
646 		mutex_exit(&ctlr->hw_mutex);
647 		break;
648 	case CPQARY3_FAILURE :
649 		cpqary3_cmdlist_release(memp, CPQARY3_HOLD_SW_MUTEX);
650 		return (TRAN_FATAL_ERROR);
651 	default: /* Never occurs */
652 		cmn_err(CE_NOTE, "CPQary3 : Transport : Unexpected Error");
653 		return (TRAN_FATAL_ERROR);
654 	}
655 
656 	return (TRAN_ACCEPT);
657 }
658 
659 /*
660  * Function	:	cpqary3_dmafree
661  * Description	: 	This routine de-allocates previously allocated
662  *			DMA resources.
663  * Called By	: 	kernel
664  * Parameters	: 	SCSI address, SCSI packet
665  * Calls	: 	None
666  * Return Values: 	None
667  */
668 /* ARGSUSED */
669 static void
670 cpqary3_dmafree(struct scsi_address *sa, struct scsi_pkt *scsi_pktp)
671 {
672 	cpqary3_pkt_t	*cpqary3_pktp;
673 
674 	cpqary3_pktp = PKT2PVTPKT(scsi_pktp);
675 
676 	/*
677 	 * If any DMA was succesfully attempted earlier, free all allocated
678 	 * resources
679 	 */
680 
681 	if (cpqary3_pktp->cmd_flags & CFLAG_DMAVALID) {
682 		if (!cpqary3_pktp->cmd_dmahandle) {
683 			DTRACE_PROBE(dmafree_null);
684 			return;
685 		}
686 		cpqary3_pktp->cmd_flags &= ~CFLAG_DMAVALID;
687 		(void) ddi_dma_unbind_handle(cpqary3_pktp->cmd_dmahandle);
688 		ddi_dma_free_handle(&cpqary3_pktp->cmd_dmahandle);
689 		cpqary3_pktp->cmd_dmahandle = NULL;
690 	}
691 }
692 
693 /*
694  * Function	:	cpqary3_dma_sync
695  * Description	: 	This routine synchronizes the CPU's / HBA's view of
696  *			the data associated with the pkt, typically by calling
697  *			ddi_dma_sync().
698  * Called By	: 	kernel
699  * Parameters	: 	SCSI address, SCSI packet
700  * Calls	: 	None
701  * Return Values: 	None
702  */
703 /* ARGSUSED */
704 static void
705 cpqary3_dma_sync(struct scsi_address *sa, struct scsi_pkt *scsi_pktp)
706 {
707 	cpqary3_pkt_t	*cpqary3_pktp = PKT2PVTPKT(scsi_pktp);
708 
709 	/*
710 	 * Check whether DMA was attempted successfully earlier
711 	 * If yes and
712 	 * if the command flags is write, then synchronise the device else
713 	 * synchronise the CPU
714 	 */
715 
716 	if (cpqary3_pktp->cmd_flags & CFLAG_DMAVALID) {
717 		(void) ddi_dma_sync(cpqary3_pktp->cmd_dmahandle,
718 		    cpqary3_pktp->cmd_dma_offset, cpqary3_pktp->cmd_dma_len,
719 		    (cpqary3_pktp->cmd_flags & CFLAG_DMASEND) ?
720 		    DDI_DMA_SYNC_FORDEV : DDI_DMA_SYNC_FORCPU);
721 	}
722 }
723 
724 /*
725  * Function	:	cpqary3_destroy_pkt
726  * Description	: 	This routine de-allocates previously allocated
727  *			resources for the SCSI packet.
728  * Called By	: 	kernel
729  * Parameters	: 	SCSI address, SCSI packet
730  * Calls	: 	None
731  * Return Values: 	None
732  */
733 static void
734 cpqary3_destroy_pkt(struct scsi_address *sa, struct scsi_pkt *scsi_pktp)
735 {
736 	cpqary3_pkt_t	*cpqary3_pktp;
737 
738 	cpqary3_pktp = PKT2PVTPKT(scsi_pktp);
739 
740 	/*
741 	 * Deallocate DMA Resources, if allocated.
742 	 * Free the SCSI Packet.
743 	 */
744 
745 	if (cpqary3_pktp->cmd_flags & CFLAG_DMAVALID) {
746 		if (!cpqary3_pktp->cmd_dmahandle) {
747 			DTRACE_PROBE(dmafree_null);
748 		} else {
749 			cpqary3_pktp->cmd_flags &= ~CFLAG_DMAVALID;
750 
751 			(void) ddi_dma_unbind_handle(
752 			    cpqary3_pktp->cmd_dmahandle);
753 			ddi_dma_free_handle(&cpqary3_pktp->cmd_dmahandle);
754 
755 			cpqary3_pktp->cmd_dmahandle = NULL;
756 		}
757 	}
758 
759 	scsi_hba_pkt_free(sa, scsi_pktp);
760 }
761 
762 /*
763  * Function	:	cpqary3_reset
764  * Description	: 	This routine resets a SCSI bus/target.
765  * Called By	: 	kernel
766  * Parameters	: 	SCSI address, reset level required
767  * Calls	: 	None
768  * Return Values: 	SUCCESS
769  */
770 /* ARGSUSED */
771 static int
772 cpqary3_reset(struct scsi_address *sa, int level)
773 {
774 	/*
775 	 * Fix for Crash seen during RAID 0 Drive removal -
776 	 * just return CPQARY3_SUCCESS on reset request
777 	 */
778 	return (CPQARY3_SUCCESS);
779 }
780 
781 /*
782  * Function	:	cpqary3_abort()
783  * Description	: 	This routine aborts a particular command or all commands
784  *			directed towards a target.
785  * Called By	: 	kernel
786  * Parameters	: 	SCSI address, SCSI packet
787  * Calls	: 	None
788  * Return Values: 	SUCCESS / FAILURE
789  *			[ abort of concernd command(s) was a success or
790  *			a failure. ]
791  */
792 static int
793 cpqary3_abort(struct scsi_address *sa, struct scsi_pkt *scsi_pktp)
794 {
795 	uint32_t	tid;
796 	cpqary3_t	*ctlr;
797 
798 	ASSERT(sa != NULL);
799 	tid  = SA2TGT(sa);
800 	ctlr = SA2CTLR(sa);
801 
802 	/*
803 	 * If SCSI packet exists, abort that particular command.
804 	 * Else, abort all existing commands to the target
805 	 * In either of the cases, we shall have to wait after the abort
806 	 * functions are called to return the status.
807 	 */
808 
809 	if (!scsi_pktp) {
810 		return (cpqary3_send_abortcmd(ctlr, tid,
811 		    (CommandList_t *)NULL));
812 	} else {
813 		return (cpqary3_send_abortcmd(ctlr, tid, SP2CMD(scsi_pktp)));
814 	}
815 }
816 
817 /*
818  * Function	:	cpqary3_getcap
819  * Description	: 	This routine is called to get the current value of a
820  *			capability.(SCSI transport capability)
821  * Called By	: 	kernel
822  * Parameters	: 	SCSI address, capability identifier, target(s) affected
823  * Calls	: 	None
824  * Return Values: 	current value of capability / -1 (if unsupported)
825  */
826 static int
827 cpqary3_getcap(struct scsi_address *sa, char *capstr, int tgtonly)
828 {
829 	int		index;
830 	cpqary3_t	*ctlr = SA2CTLR(sa);
831 	cpqary3_tgt_t	*tgtp = ctlr->cpqary3_tgtp[SA2TGT(sa)];
832 
833 	/*
834 	 * If requested Capability is not supported, return -1.
835 	 */
836 	if (DDI_FAILURE == (index = scsi_hba_lookup_capstr(capstr)))
837 		return (CAP_NOT_DEFINED);
838 
839 	/*
840 	 * Getting capability for a particulat target is supported
841 	 * the generic form of tran_getcap() is unsupported(for all targets)
842 	 * If directed towards a particular target, return current capability.
843 	 */
844 	if (tgtonly == 0) {	/* all targets */
845 		DTRACE_PROBE1(getcap_alltgt, int, index);
846 		return (CAP_NOT_DEFINED);
847 	}
848 
849 	DTRACE_PROBE1(getcap_index, int, index);
850 
851 	switch (index) {
852 	case SCSI_CAP_DMA_MAX:
853 		return ((int)cpqary3_dma_attr.dma_attr_maxxfer);
854 	case SCSI_CAP_DISCONNECT:
855 		return (tgtp->ctlr_flags & CPQARY3_CAP_DISCON_ENABLED);
856 	case SCSI_CAP_SYNCHRONOUS:
857 		return (tgtp->ctlr_flags & CPQARY3_CAP_SYNC_ENABLED);
858 	case SCSI_CAP_WIDE_XFER:
859 		return (tgtp->ctlr_flags & CPQARY3_CAP_WIDE_XFER_ENABLED);
860 	case SCSI_CAP_ARQ:
861 		return ((tgtp->ctlr_flags & CPQARY3_CAP_ARQ_ENABLED) ? 1 : 0);
862 	case SCSI_CAP_INITIATOR_ID:
863 		return (CTLR_SCSI_ID);
864 	case SCSI_CAP_UNTAGGED_QING:
865 		return (1);
866 	case SCSI_CAP_TAGGED_QING:
867 		return (1);
868 	case SCSI_CAP_SECTOR_SIZE:
869 		return (cpqary3_dma_attr.dma_attr_granular);
870 	case SCSI_CAP_TOTAL_SECTORS:
871 		return (CAP_NOT_DEFINED);
872 	case SCSI_CAP_GEOMETRY:
873 		return (cpqary3_target_geometry(sa));
874 	case SCSI_CAP_RESET_NOTIFICATION:
875 		return (0);
876 	default:
877 		return (CAP_NOT_DEFINED);
878 	}
879 }
880 
881 /*
882  * Function	:	cpqary3_setcap
883  * Description	: 	This routine is called to set the current value of a
884  *			capability.(SCSI transport capability)
885  * Called By	: 	kernel
886  * Parameters	: 	SCSI address, capability identifier,
887  *			new capability value, target(s) affected
888  * Calls	: 	None
889  * Return Values: 	SUCCESS / FAILURE / -1 (if capability is unsupported)
890  */
891 /* ARGSUSED */
892 static int
893 cpqary3_setcap(struct scsi_address *sa, char *capstr, int value, int tgtonly)
894 {
895 	int	index;
896 	int	retstatus = CAP_NOT_DEFINED;
897 
898 	/*
899 	 * If requested Capability is not supported, return -1.
900 	 */
901 	if ((index = scsi_hba_lookup_capstr(capstr)) == DDI_FAILURE)
902 		return (retstatus);
903 
904 	/*
905 	 * Setting capability for a particulat target is supported
906 	 * the generic form of tran_setcap() is unsupported(for all targets)
907 	 * If directed towards a particular target, set & return current
908 	 * capability.
909 	 */
910 	if (!tgtonly) {
911 		DTRACE_PROBE1(setcap_alltgt, int, index);
912 		return (retstatus);
913 	}
914 
915 	DTRACE_PROBE1(setcap_index, int, index);
916 
917 	switch (index) {
918 	case SCSI_CAP_DMA_MAX:
919 		return (CAP_CHG_NOT_ALLOWED);
920 	case SCSI_CAP_DISCONNECT:
921 		return (CAP_CHG_NOT_ALLOWED);
922 	case SCSI_CAP_SYNCHRONOUS:
923 		return (CAP_CHG_NOT_ALLOWED);
924 	case SCSI_CAP_WIDE_XFER:
925 		return (CAP_CHG_NOT_ALLOWED);
926 	case SCSI_CAP_ARQ:
927 		return (1);
928 	case SCSI_CAP_INITIATOR_ID:
929 		return (CAP_CHG_NOT_ALLOWED);
930 	case SCSI_CAP_UNTAGGED_QING:
931 		return (1);
932 	case SCSI_CAP_TAGGED_QING:
933 		return (1);
934 	case SCSI_CAP_SECTOR_SIZE:
935 		return (CAP_CHG_NOT_ALLOWED);
936 	case SCSI_CAP_TOTAL_SECTORS:
937 		return (CAP_CHG_NOT_ALLOWED);
938 	case SCSI_CAP_GEOMETRY:
939 		return (CAP_CHG_NOT_ALLOWED);
940 	case SCSI_CAP_RESET_NOTIFICATION:
941 		return (CAP_CHG_NOT_ALLOWED);
942 	default:
943 		return (CAP_NOT_DEFINED);
944 	}
945 }
946 
947 /*
948  * Function	:	cpqary3_handle_flag_nointr
949  * Description	: 	This routine is called to handle submission and
950  *			subsequently poll for the completion of a command,
951  *			when its FLAG_NOINTR bit is set.
952  * Called By	: 	cpqary3_transport()
953  * Parameters	: 	command private structure, SCSI packet
954  * Calls	: 	cpqary3_intr_onoff, cpqary3_retrieve,
955  *			cpqary3_submit, cpqary3_poll
956  * Return Values: 	TRAN_ACCEPT
957  */
958 static int
959 cpqary3_handle_flag_nointr(cpqary3_cmdpvt_t *memp, struct scsi_pkt *scsi_pktp)
960 {
961 	uint32_t		tag;
962 	uint32_t		simple_tag;
963 	uint32_t		i;
964 	cpqary3_t		*ctlr;
965 	cpqary3_cmdpvt_t	*cpqary3_cmdpvtp;
966 	uint32_t		CmdsOutMax;
967 	uint32_t		no_cmds;
968 
969 	RETURN_FAILURE_IF_NULL(memp);
970 	tag = memp->tag.tag_value;
971 	ctlr = memp->ctlr;
972 	ctlr->poll_flag = CPQARY3_FALSE;
973 
974 	/*
975 	 * Before sumitting this command, ensure all commands pending
976 	 * with the controller are completed.
977 	 */
978 
979 	cpqary3_intr_onoff(ctlr, CPQARY3_INTR_DISABLE);
980 	if (ctlr->host_support & 0x4)
981 		cpqary3_lockup_intr_onoff(ctlr, CPQARY3_LOCKUP_INTR_DISABLE);
982 
983 	no_cmds = (uint32_t)((ctlr->ctlr_maxcmds / 3) * NO_OF_CMDLIST_IN_A_BLK);
984 	mutex_enter(&ctlr->sw_mutex);
985 
986 	for (;;) {
987 		ctlr->poll_flag = CPQARY3_FALSE;
988 		for (i = 0; i < no_cmds; i++) {
989 			cpqary3_cmdpvtp = &ctlr->cmdmemlistp->pool[i];
990 			ASSERT(cpqary3_cmdpvtp != NULL);
991 
992 			if ((tag != cpqary3_cmdpvtp->tag.tag_value) &&
993 			    (cpqary3_cmdpvtp->occupied == CPQARY3_OCCUPIED)) {
994 				if (ctlr->noe_support == 1) {
995 					if ((cpqary3_cmdpvtp->cmdlist_memaddr->
996 					    Header.Tag.drvinfo_n_err ==
997 					    CPQARY3_NOECMD_SUCCESS) ||
998 					    (cpqary3_cmdpvtp->cmdpvt_flag ==
999 					    CPQARY3_TIMEOUT))  {
1000 						continue;
1001 					}
1002 				} else {
1003 					if (cpqary3_cmdpvtp->cmdpvt_flag ==
1004 					    CPQARY3_TIMEOUT)  {
1005 						continue;
1006 					}
1007 				}
1008 				ctlr->poll_flag = CPQARY3_TRUE;
1009 			}
1010 			/* NOE */
1011 
1012 			if (ctlr->poll_flag == CPQARY3_TRUE) {
1013 				break;
1014 			}
1015 		}
1016 
1017 		if (ctlr->poll_flag == CPQARY3_TRUE) {
1018 			if (!(ctlr->bddef->bd_flags & SA_BD_SAS)) {
1019 				while ((simple_tag =
1020 				    ddi_get32(ctlr->opq_handle,
1021 				    (uint32_t *)ctlr->opq)) != 0xFFFFFFFF) {
1022 					CmdsOutMax = ctlr->ctlr_maxcmds;
1023 					if ((simple_tag >>
1024 					    CPQARY3_GET_MEM_TAG) >=
1025 					    ((CmdsOutMax / 3) * 3)) {
1026 						cmn_err(CE_WARN,
1027 						    "CPQary3 : HBA returned "
1028 						    "Spurious Tag");
1029 						return (CPQARY3_FAILURE);
1030 					}
1031 
1032 					cpqary3_cmdpvtp =
1033 					    &ctlr->cmdmemlistp->pool[
1034 					    simple_tag >> CPQARY3_GET_MEM_TAG];
1035 					cpqary3_cmdpvtp->cmdlist_memaddr->
1036 					    Header.Tag.drvinfo_n_err =
1037 					    (simple_tag & 0xF) >> 1;
1038 					cpqary3_cmdpvtp->complete(
1039 					    cpqary3_cmdpvtp);
1040 				}
1041 			} else {
1042 				mutex_exit(&ctlr->sw_mutex);
1043 				if (CPQARY3_SUCCESS != cpqary3_retrieve(ctlr)) {
1044 					drv_usecwait(1000);
1045 				}
1046 				mutex_enter(&ctlr->sw_mutex); /* Changes */
1047 			}
1048 		} else {
1049 			break;
1050 		}
1051 	}
1052 
1053 	mutex_enter(&ctlr->hw_mutex);
1054 	if (EIO == cpqary3_submit(ctlr, memp->cmdlist_phyaddr)) {
1055 		mutex_exit(&ctlr->hw_mutex);
1056 		mutex_exit(&ctlr->sw_mutex);
1057 		cpqary3_cmdlist_release(memp, CPQARY3_HOLD_SW_MUTEX);
1058 		return (TRAN_FATAL_ERROR);
1059 	}
1060 
1061 	if (CPQARY3_FAILURE == cpqary3_poll(ctlr, tag)) {
1062 		scsi_pktp->pkt_reason = CMD_TIMEOUT;
1063 		scsi_pktp->pkt_statistics = STAT_TIMEOUT;
1064 		scsi_pktp->pkt_state = 0;
1065 		mutex_exit(&ctlr->hw_mutex);
1066 		mutex_exit(&ctlr->sw_mutex);
1067 		cpqary3_cmdlist_release(memp, CPQARY3_HOLD_SW_MUTEX);
1068 		cpqary3_intr_onoff(ctlr, CPQARY3_INTR_ENABLE);
1069 		if (ctlr->host_support & 0x4)
1070 			cpqary3_lockup_intr_onoff(ctlr,
1071 			    CPQARY3_LOCKUP_INTR_ENABLE);
1072 		return (TRAN_ACCEPT);
1073 	} else {
1074 		mutex_exit(&ctlr->hw_mutex);
1075 		mutex_exit(&ctlr->sw_mutex);
1076 		cpqary3_intr_onoff(ctlr, CPQARY3_INTR_ENABLE);
1077 		if (ctlr->host_support & 0x4) {
1078 			cpqary3_lockup_intr_onoff(ctlr,
1079 			    CPQARY3_LOCKUP_INTR_ENABLE);
1080 		}
1081 		return (TRAN_ACCEPT);
1082 	}
1083 }
1084 
1085 /*
1086  * Function	:	cpqary3_poll
1087  * Description	: 	This routine polls for the completion of a command.
1088  * Called By	: 	cpqary3_handle_flag_nointr
1089  * Parameters	: 	per controller, tag of the command to be polled
1090  * Calls	: 	cpqary3_poll_retrieve
1091  * Return Values: 	TRAN_ACCEPT
1092  */
1093 static int
1094 cpqary3_poll(cpqary3_t *ctlr, uint32_t tag)
1095 {
1096 	uint32_t		ii = 0;
1097 
1098 	RETURN_FAILURE_IF_NULL(ctlr);
1099 
1100 	/*
1101 	 * POLL for the completion of the said command
1102 	 * Since, we had ensured that controller is empty, we need not
1103 	 * check for the complete Retrieved Q.
1104 	 * However, we just check the Retrieved Q and complete all
1105 	 * commands in it, inclusive of the polled command.
1106 	 * if the polled command is completed, send back a success.
1107 	 */
1108 
1109 	for (;;) {	/* this function is called with both the locks held */
1110 		if (CPQARY3_SUCCESS != cpqary3_poll_retrieve(ctlr, tag)) {
1111 			ii++;
1112 			if (ii > 120000)
1113 				return (CPQARY3_FAILURE);
1114 			drv_usecwait(500);
1115 			continue;
1116 		}
1117 		break;
1118 	}
1119 
1120 	return (CPQARY3_SUCCESS);
1121 }
1122 
1123 static int
1124 cpqary3_additional_cmd(struct scsi_pkt *scsi_pktp, cpqary3_t *ctlr)
1125 {
1126 	struct scsi_arq_status *arqstat;
1127 	/* LINTED: alignment */
1128 	arqstat = (struct scsi_arq_status *)(scsi_pktp->pkt_scbp);
1129 
1130 	switch (scsi_pktp->pkt_cdbp[0]) {
1131 	case 0x35: /* Synchronize Cache */
1132 
1133 		cpqary3_flush_cache(ctlr);
1134 
1135 		scsi_pktp->pkt_reason = CMD_CMPLT;
1136 		scsi_pktp->pkt_statistics = 0;
1137 		scsi_pktp->pkt_state = STATE_GOT_BUS | STATE_GOT_TARGET |
1138 		    STATE_SENT_CMD | STATE_XFERRED_DATA | STATE_GOT_STATUS;
1139 
1140 		if (scsi_pktp->pkt_comp) {
1141 			(*scsi_pktp->pkt_comp)(scsi_pktp);
1142 		}
1143 
1144 		return (1);
1145 
1146 	case 0x04: /* Format Unit */
1147 		cmn_err(CE_NOTE, "The FORMAT UNIT is not supported by this "
1148 		    "device If this option is selected from the format utility "
1149 		    "do not continue further.  Please refer to cpqary3 driver "
1150 		    "man pages for details.");
1151 
1152 		return (0);
1153 	case SCSI_LOG_SENSE:
1154 	case SCSI_MODE_SELECT:
1155 	case SCSI_PERSISTENT_RESERVE_IN:
1156 		arqstat->sts_status.sts_chk = 1; /* CHECK CONDITION */
1157 		arqstat->sts_rqpkt_reason = CMD_CMPLT;
1158 		arqstat->sts_rqpkt_resid = 0;
1159 		arqstat->sts_rqpkt_state = STATE_GOT_BUS | STATE_GOT_TARGET |
1160 		    STATE_SENT_CMD | STATE_XFERRED_DATA;
1161 		arqstat->sts_rqpkt_statistics = 0;
1162 		arqstat->sts_sensedata.es_valid = 1;
1163 		arqstat->sts_sensedata.es_class = CLASS_EXTENDED_SENSE;
1164 		arqstat->sts_sensedata.es_key = KEY_ILLEGAL_REQUEST;
1165 		scsi_pktp->pkt_state = STATE_GOT_BUS | STATE_GOT_TARGET |
1166 		    STATE_SENT_CMD | STATE_XFERRED_DATA;
1167 
1168 		if (scsi_pktp->pkt_comp) {
1169 			(*scsi_pktp->pkt_comp)(scsi_pktp);
1170 		}
1171 		return (1);
1172 	}
1173 
1174 	return (0);
1175 }
1176 
1177 /* PERF */
1178 /*
1179  * Function	:      	cpqary3_oscmd_complete
1180  * Description	:      	This routine processes the
1181  *			completed OS commands and
1182  *			initiates any callback that is needed.
1183  * Called By	:      	cpqary3_transport
1184  * Parameters	:      	per-command
1185  * Calls	:      	cpqary3_ioctl_send_bmiccmd,
1186  *			cpqary3_ioctl_send_scsicmd,
1187  *			cpqary3_send_abortcmd, cpqary3_flush_cache,
1188  *			cpqary3_probe4LVs,
1189  *			cpqary3_probe4Tapes, cpqary3_synccmd_complete,
1190  *			cpqary3_detect_target_geometry,
1191  *			cpqary3_detect_target_geometry
1192  * Return Values:      	None
1193  */
1194 void
1195 cpqary3_oscmd_complete(cpqary3_cmdpvt_t *cpqary3_cmdpvtp)
1196 {
1197 	cpqary3_t	*cpqary3p;
1198 	ErrorInfo_t	*errorinfop;
1199 	CommandList_t	*cmdlistp;
1200 	struct scsi_pkt	*scsi_pktp;
1201 
1202 	ASSERT(cpqary3_cmdpvtp != NULL);
1203 
1204 	if (CPQARY3_TIMEOUT == cpqary3_cmdpvtp->cmdpvt_flag) {
1205 		cpqary3_cmdlist_release(cpqary3_cmdpvtp,
1206 		    CPQARY3_NO_MUTEX);
1207 		return;
1208 	}
1209 
1210 	cpqary3p = cpqary3_cmdpvtp->ctlr;
1211 	cmdlistp = cpqary3_cmdpvtp->cmdlist_memaddr;
1212 	errorinfop = cpqary3_cmdpvtp->errorinfop;
1213 
1214 	if (cmdlistp->Header.Tag.drvinfo_n_err == CPQARY3_OSCMD_SUCCESS) {
1215 		scsi_pktp = cpqary3_cmdpvtp->pvt_pkt->scsi_cmd_pkt;
1216 		scsi_pktp->pkt_reason = CMD_CMPLT;
1217 		scsi_pktp->pkt_statistics = 0;
1218 		scsi_pktp->pkt_state = STATE_GOT_BUS |
1219 		    STATE_GOT_TARGET | STATE_SENT_CMD |
1220 		    STATE_XFERRED_DATA | STATE_GOT_STATUS;
1221 
1222 		if (cpqary3_cmdpvtp->pvt_pkt->scsi_cmd_pkt->pkt_flags &
1223 		    FLAG_NOINTR) {
1224 			cpqary3_cmdlist_release(cpqary3_cmdpvtp,
1225 			    CPQARY3_NO_MUTEX);
1226 		} else {
1227 			cpqary3_cmdlist_release(cpqary3_cmdpvtp,
1228 			    CPQARY3_NO_MUTEX);
1229 
1230 			if (scsi_pktp->pkt_comp) {
1231 				mutex_exit(&cpqary3p->sw_mutex);
1232 				(*scsi_pktp->pkt_comp)(scsi_pktp);
1233 				mutex_enter(&cpqary3p->sw_mutex);
1234 			}
1235 		}
1236 		return;
1237 	} else {
1238 		scsi_pktp = cpqary3_cmdpvtp->pvt_pkt->scsi_cmd_pkt;
1239 	}
1240 
1241 	switch (errorinfop->CommandStatus) {
1242 	case CISS_CMD_DATA_OVERRUN :
1243 		scsi_pktp->pkt_reason = CMD_DATA_OVR;
1244 		scsi_pktp->pkt_state = STATE_GOT_BUS | STATE_GOT_TARGET |
1245 		    STATE_SENT_CMD | STATE_XFERRED_DATA | STATE_GOT_STATUS;
1246 		break;
1247 
1248 	case CISS_CMD_INVALID :
1249 		DTRACE_PROBE1(invalid_cmd, struct scsi_pkt *, scsi_pktp);
1250 		scsi_pktp->pkt_reason = CMD_BADMSG;
1251 		scsi_pktp->pkt_state = STATE_GOT_BUS |STATE_GOT_TARGET |
1252 		    STATE_SENT_CMD | STATE_GOT_STATUS;
1253 		break;
1254 
1255 	case CISS_CMD_PROTOCOL_ERR :
1256 		scsi_pktp->pkt_reason = CMD_BADMSG;
1257 		scsi_pktp->pkt_state = STATE_GOT_BUS | STATE_GOT_TARGET |
1258 		    STATE_SENT_CMD | STATE_GOT_STATUS;
1259 		break;
1260 
1261 	case CISS_CMD_HARDWARE_ERR:
1262 	case CISS_CMD_CONNECTION_LOST:
1263 		scsi_pktp->pkt_reason = CMD_INCOMPLETE;
1264 		scsi_pktp->pkt_state = 0;
1265 		break;
1266 
1267 	case CISS_CMD_ABORTED:
1268 	case CISS_CMD_UNSOLICITED_ABORT:
1269 		scsi_pktp->pkt_reason = CMD_ABORTED;
1270 		scsi_pktp->pkt_statistics = STAT_ABORTED;
1271 		scsi_pktp->pkt_state = STATE_GOT_BUS | STATE_GOT_TARGET |
1272 		    STATE_SENT_CMD | STATE_XFERRED_DATA | STATE_GOT_STATUS;
1273 		break;
1274 
1275 	case CISS_CMD_ABORT_FAILED:
1276 		break;
1277 
1278 	case CISS_CMD_TIMEOUT:
1279 		scsi_pktp->pkt_reason = CMD_TIMEOUT;
1280 		scsi_pktp->pkt_statistics = STAT_TIMEOUT;
1281 		scsi_pktp->pkt_state = 0;
1282 		break;
1283 
1284 	case CISS_CMD_DATA_UNDERRUN:	/* Significant ONLY for Read & Write */
1285 		if (cpqary3_is_scsi_read_write(scsi_pktp)) {
1286 			scsi_pktp->pkt_reason = CMD_CMPLT;
1287 			scsi_pktp->pkt_statistics = 0;
1288 			scsi_pktp->pkt_state =
1289 			    STATE_GOT_BUS | STATE_GOT_TARGET | STATE_SENT_CMD |
1290 			    STATE_XFERRED_DATA | STATE_GOT_STATUS;
1291 			break;
1292 		}
1293 		/* FALLTHROUGH */
1294 	case CISS_CMD_SUCCESS:
1295 	case CISS_CMD_TARGET_STATUS:
1296 		scsi_pktp->pkt_reason = CMD_CMPLT;
1297 		scsi_pktp->pkt_statistics = 0;
1298 		scsi_pktp->pkt_state = STATE_GOT_BUS | STATE_GOT_TARGET |
1299 		    STATE_SENT_CMD | STATE_XFERRED_DATA | STATE_GOT_STATUS;
1300 		break;
1301 
1302 	default:	/* Should never Occur !!! */
1303 		scsi_pktp->pkt_reason = CMD_TRAN_ERR;
1304 		break;
1305 	}
1306 
1307 
1308 	/*
1309 	 * if ever a command completes with a CHECK CONDITION or a
1310 	 * COMMAND_TERMINATED SCSI status, Update the sense data.
1311 	 * NOTE : The CISS_CMD_INVALID command status would always result in a
1312 	 * CHECK CONDITION and hence reach this part of the code.
1313 	 */
1314 
1315 	if ((errorinfop->ScsiStatus == SCSI_CHECK_CONDITION) ||
1316 	    (errorinfop->ScsiStatus == SCSI_COMMAND_TERMINATED)) {
1317 		if (errorinfop->SenseLen) {
1318 			struct scsi_arq_status	*arq_statusp;
1319 			arq_statusp =
1320 			    /* LINTED: alignment */
1321 			    (struct scsi_arq_status *)scsi_pktp->pkt_scbp;
1322 
1323 			if ((errorinfop->ScsiStatus == SCSI_CHECK_CONDITION)) {
1324 				arq_statusp->sts_status.sts_chk = (uint8_t)1;
1325 			} else {
1326 				arq_statusp->sts_status.sts_chk = (uint8_t)1;
1327 				arq_statusp->sts_status.sts_scsi2 = (uint8_t)1;
1328 			}
1329 			bzero((void *)&(arq_statusp->sts_rqpkt_status),
1330 			    sizeof (struct scsi_status));
1331 			arq_statusp->sts_rqpkt_reason = CMD_CMPLT;
1332 			arq_statusp->sts_rqpkt_resid = 0;
1333 			arq_statusp->sts_rqpkt_state = scsi_pktp->pkt_state;
1334 			arq_statusp->sts_rqpkt_statistics =
1335 			    scsi_pktp->pkt_statistics;
1336 			bcopy((caddr_t)&errorinfop->SenseInfo[0],
1337 			    (caddr_t)(&arq_statusp->sts_sensedata),
1338 			    CPQARY3_MIN(errorinfop->SenseLen,
1339 			    cpqary3_cmdpvtp->pvt_pkt->scb_len));
1340 			scsi_pktp->pkt_state |= STATE_ARQ_DONE;
1341 		}
1342 	}
1343 
1344 	if (cpqary3_cmdpvtp->pvt_pkt->scsi_cmd_pkt->pkt_flags & FLAG_NOINTR) {
1345 		cpqary3_cmdlist_release(cpqary3_cmdpvtp, CPQARY3_NO_MUTEX);
1346 	} else {
1347 		cpqary3_cmdlist_release(cpqary3_cmdpvtp, CPQARY3_NO_MUTEX);
1348 
1349 		if (scsi_pktp->pkt_comp) {
1350 			mutex_exit(&cpqary3p->sw_mutex);
1351 			(*scsi_pktp->pkt_comp)(scsi_pktp);
1352 			mutex_enter(&cpqary3p->sw_mutex);
1353 		}
1354 	}
1355 }
1356 
1357 static uint8_t
1358 cpqary3_is_scsi_read_write(struct scsi_pkt *scsi_pktp)
1359 {
1360 	/*
1361 	 * In the scsi packet structure, the first byte is the SCSI Command
1362 	 * OpCode.  We check to see if it is any one of the SCSI Read or Write
1363 	 * opcodes.
1364 	 */
1365 
1366 	switch (scsi_pktp->pkt_cdbp[0]) {
1367 	case SCSI_READ_6:
1368 	case SCSI_READ_10:
1369 	case SCSI_READ_12:
1370 	case SCSI_WRITE_6:
1371 	case SCSI_WRITE_10:
1372 	case SCSI_WRITE_12:
1373 		return (1);
1374 
1375 	default:
1376 		return (0);
1377 	}
1378 }
1379