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 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 #include "ghd.h"
30
31
32 /*
33 * Local Function Prototypes
34 */
35
36 static struct scsi_pkt *ghd_pktalloc(ccc_t *cccp, struct scsi_address *ap,
37 int cmdlen, int statuslen, int tgtlen,
38 int (*callback)(), caddr_t arg, int ccblen);
39
40 /*
41 * Round up all allocations so that we can guarantee
42 * long-long alignment. This is the same alignment
43 * provided by kmem_alloc().
44 */
45 #define ROUNDUP(x) (((x) + 0x07) & ~0x07)
46
47 /*
48 * Private wrapper for gcmd_t
49 */
50
51 /*
52 * round up the size so the HBA private area is on a 8 byte boundary
53 */
54 #define GW_PADDED_LENGTH ROUNDUP(sizeof (gcmd_t))
55
56 typedef struct gcmd_padded_wrapper {
57 union {
58 gcmd_t gw_gcmd;
59 char gw_pad[GW_PADDED_LENGTH];
60
61 } gwrap;
62 } gwrap_t;
63
64
65
66
67 /*ARGSUSED*/
68 void
ghd_tran_sync_pkt(struct scsi_address * ap,struct scsi_pkt * pktp)69 ghd_tran_sync_pkt(struct scsi_address *ap, struct scsi_pkt *pktp)
70 {
71 gcmd_t *gcmdp = PKTP2GCMDP(pktp);
72 int status;
73
74 if (gcmdp->cmd_dma_handle) {
75 status = ddi_dma_sync(gcmdp->cmd_dma_handle, 0, 0,
76 (gcmdp->cmd_dma_flags & DDI_DMA_READ) ?
77 DDI_DMA_SYNC_FORCPU : DDI_DMA_SYNC_FORDEV);
78 if (status != DDI_SUCCESS) {
79 cmn_err(CE_WARN, "ghd_tran_sync_pkt() fail\n");
80 }
81 }
82 }
83
84
85 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)86 ghd_pktalloc(ccc_t *cccp,
87 struct scsi_address *ap,
88 int cmdlen,
89 int statuslen,
90 int tgtlen,
91 int (*callback)(),
92 caddr_t arg,
93 int ccblen)
94 {
95 gtgt_t *gtgtp = ADDR2GTGTP(ap);
96 struct scsi_pkt *pktp;
97 gcmd_t *gcmdp;
98 gwrap_t *gwp;
99 int gwrap_len;
100
101 gwrap_len = sizeof (gwrap_t) + ROUNDUP(ccblen);
102
103 /* allocate everything from kmem pool */
104 pktp = scsi_hba_pkt_alloc(cccp->ccc_hba_dip, ap, cmdlen, statuslen,
105 tgtlen, gwrap_len, callback, arg);
106 if (pktp == NULL) {
107 return (NULL);
108 }
109
110 /* get the ptr to the HBA specific buffer */
111 gwp = (gwrap_t *)(pktp->pkt_ha_private);
112
113 /* get the ptr to the GHD specific buffer */
114 gcmdp = &gwp->gwrap.gw_gcmd;
115
116 ASSERT((caddr_t)gwp == (caddr_t)gcmdp);
117
118 /*
119 * save the ptr to HBA private area and initialize the rest
120 * of the gcmd_t members
121 */
122 GHD_GCMD_INIT(gcmdp, (void *)(gwp + 1), gtgtp);
123
124 /*
125 * save the the scsi_pkt ptr in gcmd_t.
126 */
127 gcmdp->cmd_pktp = pktp;
128
129 /*
130 * callback to the HBA driver so it can initalize its
131 * buffer and return the ptr to my cmd_t structure which is
132 * probably embedded in its buffer.
133 */
134
135 if (!(*cccp->ccc_ccballoc)(gtgtp, gcmdp, cmdlen, statuslen, tgtlen,
136 ccblen)) {
137 scsi_hba_pkt_free(ap, pktp);
138 return (NULL);
139 }
140
141 return (pktp);
142 }
143
144
145
146 /*
147 * packet free
148 */
149 /*ARGSUSED*/
150 void
ghd_pktfree(ccc_t * cccp,struct scsi_address * ap,struct scsi_pkt * pktp)151 ghd_pktfree(ccc_t *cccp,
152 struct scsi_address *ap,
153 struct scsi_pkt *pktp)
154 {
155 GDBG_PKT(("ghd_pktfree: cccp 0x%p ap 0x%p pktp 0x%p\n",
156 (void *)cccp, (void *)ap, (void *)pktp));
157
158 /* free any extra resources allocated by the HBA */
159 (*cccp->ccc_ccbfree)(PKTP2GCMDP(pktp));
160
161 /* free the scsi_pkt and the GHD and HBA private areas */
162 scsi_hba_pkt_free(ap, pktp);
163 }
164
165
166 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)167 ghd_tran_init_pkt_attr(ccc_t *cccp,
168 struct scsi_address *ap,
169 struct scsi_pkt *pktp,
170 struct buf *bp,
171 int cmdlen,
172 int statuslen,
173 int tgtlen,
174 int flags,
175 int (*callback)(),
176 caddr_t arg,
177 int ccblen,
178 ddi_dma_attr_t *sg_attrp)
179 {
180 gcmd_t *gcmdp;
181 int new_pkt;
182 uint_t xfercount;
183
184 ASSERT(callback == NULL_FUNC || callback == SLEEP_FUNC);
185
186 /*
187 * Allocate a pkt
188 */
189 if (pktp == NULL) {
190 pktp = ghd_pktalloc(cccp, ap, cmdlen, statuslen, tgtlen,
191 callback, arg, ccblen);
192 if (pktp == NULL)
193 return (NULL);
194 new_pkt = TRUE;
195
196 } else {
197 new_pkt = FALSE;
198
199 }
200
201 gcmdp = PKTP2GCMDP(pktp);
202
203 GDBG_PKT(("ghd_tran_init_pkt_attr: gcmdp 0x%p dma_handle 0x%p\n",
204 (void *)gcmdp, (void *)gcmdp->cmd_dma_handle));
205
206 /*
207 * free stale DMA window if necessary.
208 */
209
210 if (cmdlen && gcmdp->cmd_dma_handle) {
211 /* release the old DMA resources */
212 ghd_dmafree_attr(gcmdp);
213 }
214
215 /*
216 * Set up dma info if there's any data and
217 * if the device supports DMA.
218 */
219
220 GDBG_PKT(("ghd_tran_init_pkt: gcmdp 0x%p bp 0x%p limp 0x%p\n",
221 (void *)gcmdp, (void *)bp, (void *)sg_attrp));
222
223 if (bp && bp->b_bcount && sg_attrp) {
224 int dma_flags;
225
226 /* check direction for data transfer */
227 if (bp->b_flags & B_READ)
228 dma_flags = DDI_DMA_READ;
229 else
230 dma_flags = DDI_DMA_WRITE;
231
232 /* check dma option flags */
233 if (flags & PKT_CONSISTENT)
234 dma_flags |= DDI_DMA_CONSISTENT;
235 if (flags & PKT_DMA_PARTIAL)
236 dma_flags |= DDI_DMA_PARTIAL;
237
238 if (gcmdp->cmd_dma_handle == NULL) {
239 if (!ghd_dma_buf_bind_attr(cccp, gcmdp, bp, dma_flags,
240 callback, arg, sg_attrp)) {
241 if (new_pkt)
242 ghd_pktfree(cccp, ap, pktp);
243 return (NULL);
244 }
245 }
246
247 /* map the buffer and/or create the scatter/gather list */
248 if (!ghd_dmaget_attr(cccp, gcmdp,
249 bp->b_bcount - gcmdp->cmd_totxfer,
250 sg_attrp->dma_attr_sgllen, &xfercount)) {
251 if (new_pkt)
252 ghd_pktfree(cccp, ap, pktp);
253 return (NULL);
254 }
255 pktp->pkt_resid = bp->b_bcount - gcmdp->cmd_totxfer;
256 } else {
257 pktp->pkt_resid = 0;
258 }
259
260 return (pktp);
261 }
262