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 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 * 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 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 * 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