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