1507c3241Smlf /*
2507c3241Smlf  * CDDL HEADER START
3507c3241Smlf  *
4507c3241Smlf  * The contents of this file are subject to the terms of the
5507c3241Smlf  * Common Development and Distribution License (the "License").
6507c3241Smlf  * You may not use this file except in compliance with the License.
7507c3241Smlf  *
8507c3241Smlf  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9507c3241Smlf  * or http://www.opensolaris.org/os/licensing.
10507c3241Smlf  * See the License for the specific language governing permissions
11507c3241Smlf  * and limitations under the License.
12507c3241Smlf  *
13507c3241Smlf  * When distributing Covered Code, include this CDDL HEADER in each
14507c3241Smlf  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15507c3241Smlf  * If applicable, add the following below this CDDL HEADER, with the
16507c3241Smlf  * fields enclosed by brackets "[]" replaced with your own identifying
17507c3241Smlf  * information: Portions Copyright [yyyy] [name of copyright owner]
18507c3241Smlf  *
19507c3241Smlf  * CDDL HEADER END
20507c3241Smlf  */
21507c3241Smlf 
22507c3241Smlf /*
23*903a11ebSrh  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24507c3241Smlf  * Use is subject to license terms.
25507c3241Smlf  */
26507c3241Smlf 
27507c3241Smlf #include "ghd.h"
28507c3241Smlf 
29507c3241Smlf 
30507c3241Smlf /*
31507c3241Smlf  * Local Function Prototypes
32507c3241Smlf  */
33507c3241Smlf 
34507c3241Smlf static	struct scsi_pkt	*ghd_pktalloc(ccc_t *cccp, struct scsi_address *ap,
35507c3241Smlf 				int cmdlen, int statuslen, int tgtlen,
36507c3241Smlf 				int (*callback)(), caddr_t arg, int ccblen);
37507c3241Smlf 
38507c3241Smlf /*
39507c3241Smlf  * Round up all allocations so that we can guarantee
40507c3241Smlf  * long-long alignment.  This is the same alignment
41507c3241Smlf  * provided by kmem_alloc().
42507c3241Smlf  */
43507c3241Smlf #define	ROUNDUP(x)	(((x) + 0x07) & ~0x07)
44507c3241Smlf 
45507c3241Smlf /*
46507c3241Smlf  * Private wrapper for gcmd_t
47507c3241Smlf  */
48507c3241Smlf 
49507c3241Smlf /*
50507c3241Smlf  * round up the size so the HBA private area is on a 8 byte boundary
51507c3241Smlf  */
52507c3241Smlf #define	GW_PADDED_LENGTH	ROUNDUP(sizeof (gcmd_t))
53507c3241Smlf 
54507c3241Smlf typedef struct gcmd_padded_wrapper {
55507c3241Smlf 	union {
56507c3241Smlf 		gcmd_t	gw_gcmd;
57507c3241Smlf 		char	gw_pad[GW_PADDED_LENGTH];
58507c3241Smlf 
59507c3241Smlf 	} gwrap;
60507c3241Smlf } gwrap_t;
61507c3241Smlf 
62507c3241Smlf 
63507c3241Smlf 
64507c3241Smlf 
65507c3241Smlf /*ARGSUSED*/
66507c3241Smlf void
ghd_tran_sync_pkt(struct scsi_address * ap,struct scsi_pkt * pktp)67507c3241Smlf ghd_tran_sync_pkt(struct scsi_address *ap, struct scsi_pkt *pktp)
68507c3241Smlf {
69507c3241Smlf 	gcmd_t *gcmdp = PKTP2GCMDP(pktp);
70507c3241Smlf 	int	status;
71507c3241Smlf 
72507c3241Smlf 	if (gcmdp->cmd_dma_handle) {
73507c3241Smlf 		status = ddi_dma_sync(gcmdp->cmd_dma_handle, 0, 0,
74*903a11ebSrh 		    (gcmdp->cmd_dma_flags & DDI_DMA_READ) ?
75*903a11ebSrh 		    DDI_DMA_SYNC_FORCPU : DDI_DMA_SYNC_FORDEV);
76507c3241Smlf 		if (status != DDI_SUCCESS) {
77507c3241Smlf 			cmn_err(CE_WARN, "ghd_tran_sync_pkt() fail\n");
78507c3241Smlf 		}
79507c3241Smlf 	}
80507c3241Smlf }
81507c3241Smlf 
82507c3241Smlf 
83507c3241Smlf static struct scsi_pkt *
ghd_pktalloc(ccc_t * cccp,struct scsi_address * ap,int cmdlen,int statuslen,int tgtlen,int (* callback)(),caddr_t arg,int ccblen)84507c3241Smlf ghd_pktalloc(ccc_t	*cccp,
85507c3241Smlf 	struct scsi_address *ap,
86507c3241Smlf 	int	 cmdlen,
87507c3241Smlf 	int	 statuslen,
88507c3241Smlf 	int	 tgtlen,
89507c3241Smlf 	int	(*callback)(),
90507c3241Smlf 	caddr_t	 arg,
91507c3241Smlf 	int	ccblen)
92507c3241Smlf {
93507c3241Smlf 	gtgt_t		*gtgtp =  ADDR2GTGTP(ap);
94507c3241Smlf 	struct scsi_pkt	*pktp;
95507c3241Smlf 	gcmd_t		*gcmdp;
96507c3241Smlf 	gwrap_t		*gwp;
97507c3241Smlf 	int		 gwrap_len;
98507c3241Smlf 
99507c3241Smlf 	gwrap_len = sizeof (gwrap_t) + ROUNDUP(ccblen);
100507c3241Smlf 
101507c3241Smlf 	/* allocate everything from kmem pool */
102507c3241Smlf 	pktp = scsi_hba_pkt_alloc(cccp->ccc_hba_dip, ap, cmdlen, statuslen,
103507c3241Smlf 	    tgtlen, gwrap_len, callback, arg);
104507c3241Smlf 	if (pktp == NULL) {
105507c3241Smlf 		return (NULL);
106507c3241Smlf 	}
107507c3241Smlf 
108507c3241Smlf 	/* get the ptr to the HBA specific buffer */
109507c3241Smlf 	gwp = (gwrap_t *)(pktp->pkt_ha_private);
110507c3241Smlf 
111507c3241Smlf 	/* get the ptr to the GHD specific buffer */
112507c3241Smlf 	gcmdp = &gwp->gwrap.gw_gcmd;
113507c3241Smlf 
114507c3241Smlf 	ASSERT((caddr_t)gwp == (caddr_t)gcmdp);
115507c3241Smlf 
116507c3241Smlf 	/*
117507c3241Smlf 	 * save the ptr to HBA private area and initialize the rest
118507c3241Smlf 	 * of the gcmd_t members
119507c3241Smlf 	 */
120507c3241Smlf 	GHD_GCMD_INIT(gcmdp, (void *)(gwp + 1), gtgtp);
121507c3241Smlf 
122507c3241Smlf 	/*
123507c3241Smlf 	 * save the the scsi_pkt ptr in gcmd_t.
124507c3241Smlf 	 */
125507c3241Smlf 	gcmdp->cmd_pktp = pktp;
126507c3241Smlf 
127507c3241Smlf 	/*
128507c3241Smlf 	 * callback to the HBA driver so it can initalize its
129507c3241Smlf 	 * buffer and return the ptr to my cmd_t structure which is
130507c3241Smlf 	 * probably embedded in its buffer.
131507c3241Smlf 	 */
132507c3241Smlf 
133507c3241Smlf 	if (!(*cccp->ccc_ccballoc)(gtgtp, gcmdp, cmdlen, statuslen, tgtlen,
134507c3241Smlf 	    ccblen)) {
135507c3241Smlf 		scsi_hba_pkt_free(ap, pktp);
136507c3241Smlf 		return (NULL);
137507c3241Smlf 	}
138507c3241Smlf 
139507c3241Smlf 	return (pktp);
140507c3241Smlf }
141507c3241Smlf 
142507c3241Smlf 
143507c3241Smlf 
144507c3241Smlf /*
145507c3241Smlf  * packet free
146507c3241Smlf  */
147507c3241Smlf /*ARGSUSED*/
148507c3241Smlf void
ghd_pktfree(ccc_t * cccp,struct scsi_address * ap,struct scsi_pkt * pktp)149507c3241Smlf ghd_pktfree(ccc_t		*cccp,
150507c3241Smlf 	struct scsi_address	*ap,
151507c3241Smlf 	struct scsi_pkt		*pktp)
152507c3241Smlf {
153507c3241Smlf 	GDBG_PKT(("ghd_pktfree: cccp 0x%p ap 0x%p pktp 0x%p\n",
154*903a11ebSrh 	    (void *)cccp, (void *)ap, (void *)pktp));
155507c3241Smlf 
156507c3241Smlf 	/* free any extra resources allocated by the HBA */
157507c3241Smlf 	(*cccp->ccc_ccbfree)(PKTP2GCMDP(pktp));
158507c3241Smlf 
159507c3241Smlf 	/* free the scsi_pkt and the GHD and HBA private areas */
160507c3241Smlf 	scsi_hba_pkt_free(ap, pktp);
161507c3241Smlf }
162507c3241Smlf 
163507c3241Smlf 
164507c3241Smlf struct scsi_pkt *
ghd_tran_init_pkt_attr(ccc_t * cccp,struct scsi_address * ap,struct scsi_pkt * pktp,struct buf * bp,int cmdlen,int statuslen,int tgtlen,int flags,int (* callback)(),caddr_t arg,int ccblen,ddi_dma_attr_t * sg_attrp)165507c3241Smlf ghd_tran_init_pkt_attr(ccc_t	*cccp,
166507c3241Smlf 			struct scsi_address *ap,
167507c3241Smlf 			struct scsi_pkt	*pktp,
168507c3241Smlf 			struct buf	*bp,
169507c3241Smlf 			int	 cmdlen,
170507c3241Smlf 			int	 statuslen,
171507c3241Smlf 			int	 tgtlen,
172507c3241Smlf 			int	 flags,
173507c3241Smlf 			int	(*callback)(),
174507c3241Smlf 			caddr_t	 arg,
175507c3241Smlf 			int	 ccblen,
176507c3241Smlf 			ddi_dma_attr_t	*sg_attrp)
177507c3241Smlf {
178507c3241Smlf 	gcmd_t	*gcmdp;
179507c3241Smlf 	int	 new_pkt;
180507c3241Smlf 	uint_t	xfercount;
181507c3241Smlf 
182507c3241Smlf 	ASSERT(callback == NULL_FUNC || callback == SLEEP_FUNC);
183507c3241Smlf 
184507c3241Smlf 	/*
185507c3241Smlf 	 * Allocate a pkt
186507c3241Smlf 	 */
187507c3241Smlf 	if (pktp == NULL) {
188507c3241Smlf 		pktp = ghd_pktalloc(cccp, ap, cmdlen, statuslen, tgtlen,
189507c3241Smlf 		    callback, arg, ccblen);
190507c3241Smlf 		if (pktp == NULL)
191507c3241Smlf 			return (NULL);
192507c3241Smlf 		new_pkt = TRUE;
193507c3241Smlf 
194507c3241Smlf 	} else {
195507c3241Smlf 		new_pkt = FALSE;
196507c3241Smlf 
197507c3241Smlf 	}
198507c3241Smlf 
199507c3241Smlf 	gcmdp = PKTP2GCMDP(pktp);
200507c3241Smlf 
201507c3241Smlf 	GDBG_PKT(("ghd_tran_init_pkt_attr: gcmdp 0x%p dma_handle 0x%p\n",
202*903a11ebSrh 	    (void *)gcmdp, (void *)gcmdp->cmd_dma_handle));
203507c3241Smlf 
204507c3241Smlf 	/*
205507c3241Smlf 	 * free stale DMA window if necessary.
206507c3241Smlf 	 */
207507c3241Smlf 
208507c3241Smlf 	if (cmdlen && gcmdp->cmd_dma_handle) {
209507c3241Smlf 		/* release the old DMA resources */
210507c3241Smlf 		ghd_dmafree_attr(gcmdp);
211507c3241Smlf 	}
212507c3241Smlf 
213507c3241Smlf 	/*
214507c3241Smlf 	 * Set up dma info if there's any data and
215507c3241Smlf 	 * if the device supports DMA.
216507c3241Smlf 	 */
217507c3241Smlf 
218507c3241Smlf 	GDBG_PKT(("ghd_tran_init_pkt: gcmdp 0x%p bp 0x%p limp 0x%p\n",
219*903a11ebSrh 	    (void *)gcmdp, (void *)bp, (void *)sg_attrp));
220507c3241Smlf 
221507c3241Smlf 	if (bp && bp->b_bcount && sg_attrp) {
222507c3241Smlf 		int	dma_flags;
223507c3241Smlf 
224507c3241Smlf 		/* check direction for data transfer */
225507c3241Smlf 		if (bp->b_flags & B_READ)
226507c3241Smlf 			dma_flags = DDI_DMA_READ;
227507c3241Smlf 		else
228507c3241Smlf 			dma_flags = DDI_DMA_WRITE;
229507c3241Smlf 
230507c3241Smlf 		/* check dma option flags */
231507c3241Smlf 		if (flags & PKT_CONSISTENT)
232507c3241Smlf 			dma_flags |= DDI_DMA_CONSISTENT;
233507c3241Smlf 		if (flags & PKT_DMA_PARTIAL)
234507c3241Smlf 			dma_flags |= DDI_DMA_PARTIAL;
235507c3241Smlf 
236507c3241Smlf 		if (gcmdp->cmd_dma_handle == NULL) {
237507c3241Smlf 			if (!ghd_dma_buf_bind_attr(cccp, gcmdp, bp, dma_flags,
238*903a11ebSrh 			    callback, arg, sg_attrp)) {
239507c3241Smlf 				if (new_pkt)
240507c3241Smlf 					ghd_pktfree(cccp, ap, pktp);
241507c3241Smlf 				return (NULL);
242507c3241Smlf 			}
243507c3241Smlf 		}
244507c3241Smlf 
245507c3241Smlf 		/* map the buffer and/or create the scatter/gather list */
246507c3241Smlf 		if (!ghd_dmaget_attr(cccp, gcmdp,
247*903a11ebSrh 		    bp->b_bcount - gcmdp->cmd_totxfer,
248*903a11ebSrh 		    sg_attrp->dma_attr_sgllen, &xfercount)) {
249507c3241Smlf 			if (new_pkt)
250507c3241Smlf 				ghd_pktfree(cccp, ap, pktp);
251507c3241Smlf 			return (NULL);
252507c3241Smlf 		}
253507c3241Smlf 		pktp->pkt_resid = bp->b_bcount - gcmdp->cmd_totxfer;
254507c3241Smlf 	} else {
255507c3241Smlf 		pktp->pkt_resid = 0;
256507c3241Smlf 	}
257507c3241Smlf 
258507c3241Smlf 	return (pktp);
259507c3241Smlf }
260