xref: /illumos-gate/usr/src/uts/intel/io/dktp/hba/ghd/ghd_scsa.c (revision 2d6eb4a5e0a47d30189497241345dc5466bb68ab)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include "ghd.h"
28 
29 
30 /*
31  * Local Function Prototypes
32  */
33 
34 static	struct scsi_pkt	*ghd_pktalloc(ccc_t *cccp, struct scsi_address *ap,
35 				int cmdlen, int statuslen, int tgtlen,
36 				int (*callback)(), caddr_t arg, int ccblen);
37 
38 /*
39  * Round up all allocations so that we can guarantee
40  * long-long alignment.  This is the same alignment
41  * provided by kmem_alloc().
42  */
43 #define	ROUNDUP(x)	(((x) + 0x07) & ~0x07)
44 
45 /*
46  * Private wrapper for gcmd_t
47  */
48 
49 /*
50  * round up the size so the HBA private area is on a 8 byte boundary
51  */
52 #define	GW_PADDED_LENGTH	ROUNDUP(sizeof (gcmd_t))
53 
54 typedef struct gcmd_padded_wrapper {
55 	union {
56 		gcmd_t	gw_gcmd;
57 		char	gw_pad[GW_PADDED_LENGTH];
58 
59 	} gwrap;
60 } gwrap_t;
61 
62 
63 
64 
65 /*ARGSUSED*/
66 void
ghd_tran_sync_pkt(struct scsi_address * ap,struct scsi_pkt * pktp)67 ghd_tran_sync_pkt(struct scsi_address *ap, struct scsi_pkt *pktp)
68 {
69 	gcmd_t *gcmdp = PKTP2GCMDP(pktp);
70 	int	status;
71 
72 	if (gcmdp->cmd_dma_handle) {
73 		status = ddi_dma_sync(gcmdp->cmd_dma_handle, 0, 0,
74 		    (gcmdp->cmd_dma_flags & DDI_DMA_READ) ?
75 		    DDI_DMA_SYNC_FORCPU : DDI_DMA_SYNC_FORDEV);
76 		if (status != DDI_SUCCESS) {
77 			cmn_err(CE_WARN, "ghd_tran_sync_pkt() fail\n");
78 		}
79 	}
80 }
81 
82 
83 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)84 ghd_pktalloc(ccc_t	*cccp,
85 	struct scsi_address *ap,
86 	int	 cmdlen,
87 	int	 statuslen,
88 	int	 tgtlen,
89 	int	(*callback)(),
90 	caddr_t	 arg,
91 	int	ccblen)
92 {
93 	gtgt_t		*gtgtp =  ADDR2GTGTP(ap);
94 	struct scsi_pkt	*pktp;
95 	gcmd_t		*gcmdp;
96 	gwrap_t		*gwp;
97 	int		 gwrap_len;
98 
99 	gwrap_len = sizeof (gwrap_t) + ROUNDUP(ccblen);
100 
101 	/* allocate everything from kmem pool */
102 	pktp = scsi_hba_pkt_alloc(cccp->ccc_hba_dip, ap, cmdlen, statuslen,
103 	    tgtlen, gwrap_len, callback, arg);
104 	if (pktp == NULL) {
105 		return (NULL);
106 	}
107 
108 	/* get the ptr to the HBA specific buffer */
109 	gwp = (gwrap_t *)(pktp->pkt_ha_private);
110 
111 	/* get the ptr to the GHD specific buffer */
112 	gcmdp = &gwp->gwrap.gw_gcmd;
113 
114 	ASSERT((caddr_t)gwp == (caddr_t)gcmdp);
115 
116 	/*
117 	 * save the ptr to HBA private area and initialize the rest
118 	 * of the gcmd_t members
119 	 */
120 	GHD_GCMD_INIT(gcmdp, (void *)(gwp + 1), gtgtp);
121 
122 	/*
123 	 * save the the scsi_pkt ptr in gcmd_t.
124 	 */
125 	gcmdp->cmd_pktp = pktp;
126 
127 	/*
128 	 * callback to the HBA driver so it can initalize its
129 	 * buffer and return the ptr to my cmd_t structure which is
130 	 * probably embedded in its buffer.
131 	 */
132 
133 	if (!(*cccp->ccc_ccballoc)(gtgtp, gcmdp, cmdlen, statuslen, tgtlen,
134 	    ccblen)) {
135 		scsi_hba_pkt_free(ap, pktp);
136 		return (NULL);
137 	}
138 
139 	return (pktp);
140 }
141 
142 
143 
144 /*
145  * packet free
146  */
147 /*ARGSUSED*/
148 void
ghd_pktfree(ccc_t * cccp,struct scsi_address * ap,struct scsi_pkt * pktp)149 ghd_pktfree(ccc_t		*cccp,
150 	struct scsi_address	*ap,
151 	struct scsi_pkt		*pktp)
152 {
153 	GDBG_PKT(("ghd_pktfree: cccp 0x%p ap 0x%p pktp 0x%p\n",
154 	    (void *)cccp, (void *)ap, (void *)pktp));
155 
156 	/* free any extra resources allocated by the HBA */
157 	(*cccp->ccc_ccbfree)(PKTP2GCMDP(pktp));
158 
159 	/* free the scsi_pkt and the GHD and HBA private areas */
160 	scsi_hba_pkt_free(ap, pktp);
161 }
162 
163 
164 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)165 ghd_tran_init_pkt_attr(ccc_t	*cccp,
166 			struct scsi_address *ap,
167 			struct scsi_pkt	*pktp,
168 			struct buf	*bp,
169 			int	 cmdlen,
170 			int	 statuslen,
171 			int	 tgtlen,
172 			int	 flags,
173 			int	(*callback)(),
174 			caddr_t	 arg,
175 			int	 ccblen,
176 			ddi_dma_attr_t	*sg_attrp)
177 {
178 	gcmd_t	*gcmdp;
179 	int	 new_pkt;
180 	uint_t	xfercount;
181 
182 	ASSERT(callback == NULL_FUNC || callback == SLEEP_FUNC);
183 
184 	/*
185 	 * Allocate a pkt
186 	 */
187 	if (pktp == NULL) {
188 		pktp = ghd_pktalloc(cccp, ap, cmdlen, statuslen, tgtlen,
189 		    callback, arg, ccblen);
190 		if (pktp == NULL)
191 			return (NULL);
192 		new_pkt = TRUE;
193 
194 	} else {
195 		new_pkt = FALSE;
196 
197 	}
198 
199 	gcmdp = PKTP2GCMDP(pktp);
200 
201 	GDBG_PKT(("ghd_tran_init_pkt_attr: gcmdp 0x%p dma_handle 0x%p\n",
202 	    (void *)gcmdp, (void *)gcmdp->cmd_dma_handle));
203 
204 	/*
205 	 * free stale DMA window if necessary.
206 	 */
207 
208 	if (cmdlen && gcmdp->cmd_dma_handle) {
209 		/* release the old DMA resources */
210 		ghd_dmafree_attr(gcmdp);
211 	}
212 
213 	/*
214 	 * Set up dma info if there's any data and
215 	 * if the device supports DMA.
216 	 */
217 
218 	GDBG_PKT(("ghd_tran_init_pkt: gcmdp 0x%p bp 0x%p limp 0x%p\n",
219 	    (void *)gcmdp, (void *)bp, (void *)sg_attrp));
220 
221 	if (bp && bp->b_bcount && sg_attrp) {
222 		int	dma_flags;
223 
224 		/* check direction for data transfer */
225 		if (bp->b_flags & B_READ)
226 			dma_flags = DDI_DMA_READ;
227 		else
228 			dma_flags = DDI_DMA_WRITE;
229 
230 		/* check dma option flags */
231 		if (flags & PKT_CONSISTENT)
232 			dma_flags |= DDI_DMA_CONSISTENT;
233 		if (flags & PKT_DMA_PARTIAL)
234 			dma_flags |= DDI_DMA_PARTIAL;
235 
236 		if (gcmdp->cmd_dma_handle == NULL) {
237 			if (!ghd_dma_buf_bind_attr(cccp, gcmdp, bp, dma_flags,
238 			    callback, arg, sg_attrp)) {
239 				if (new_pkt)
240 					ghd_pktfree(cccp, ap, pktp);
241 				return (NULL);
242 			}
243 		}
244 
245 		/* map the buffer and/or create the scatter/gather list */
246 		if (!ghd_dmaget_attr(cccp, gcmdp,
247 		    bp->b_bcount - gcmdp->cmd_totxfer,
248 		    sg_attrp->dma_attr_sgllen, &xfercount)) {
249 			if (new_pkt)
250 				ghd_pktfree(cccp, ap, pktp);
251 			return (NULL);
252 		}
253 		pktp->pkt_resid = bp->b_bcount - gcmdp->cmd_totxfer;
254 	} else {
255 		pktp->pkt_resid = 0;
256 	}
257 
258 	return (pktp);
259 }
260