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