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 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <sys/types.h> 28 #include <sys/debug.h> 29 30 #include "ata_common.h" 31 #include "ata_disk.h" 32 #include "atapi.h" 33 #include "pciide.h" 34 35 /* 36 * grap the PCI-IDE status byte 37 */ 38 #define PCIIDE_STATUS_GET(hdl, addr) \ 39 ddi_get8((hdl), ((uchar_t *)(addr) + PCIIDE_BMISX_REG)) 40 41 /* 42 * DMA attributes for device I/O 43 */ 44 45 ddi_dma_attr_t ata_pciide_dma_attr = { 46 DMA_ATTR_V0, /* dma_attr_version */ 47 0, /* dma_attr_addr_lo */ 48 0xffffffffU, /* dma_attr_addr_hi */ 49 0xffff, /* dma_attr_count_max */ 50 sizeof (int), /* dma_attr_align */ 51 1, /* dma_attr_burstsizes */ 52 1, /* dma_attr_minxfer */ 53 0x100 << SCTRSHFT, /* dma_attr_maxxfer */ 54 /* note that this value can change */ 55 /* based on max_transfer property */ 56 0xffff, /* dma_attr_seg */ 57 ATA_DMA_NSEGS, /* dma_attr_sgllen */ 58 512, /* dma_attr_granular */ 59 0 /* dma_attr_flags */ 60 }; 61 62 /* 63 * DMA attributes for the Bus Mastering PRD table 64 * 65 * PRD table Must not cross 4k boundary. 66 * 67 * NOTE: the SFF-8038i spec says don't cross a 64k boundary but 68 * some chip specs seem to think the spec says 4k boundary, Intel 69 * 82371AB, section 5.2.3. I don't know whether the 4k restriction 70 * is for real or just a typo. I've specified 4k just to be safe. 71 * The same Intel spec says the buffer must be 64K aligned, I don't 72 * believe that and have specified 4 byte alignment. 73 * 74 */ 75 76 #define PCIIDE_BOUNDARY (0x1000) 77 78 ddi_dma_attr_t ata_prd_dma_attr = { 79 DMA_ATTR_V0, /* dma_attr_version */ 80 0, /* dma_attr_addr_lo */ 81 0xffffffffU, /* dma_attr_addr_hi */ 82 PCIIDE_BOUNDARY - 1, /* dma_attr_count_max */ 83 sizeof (int), /* dma_attr_align */ 84 1, /* dma_attr_burstsizes */ 85 1, /* dma_attr_minxfer */ 86 PCIIDE_BOUNDARY, /* dma_attr_maxxfer */ 87 PCIIDE_BOUNDARY - 1, /* dma_attr_seg */ 88 1, /* dma_attr_sgllen */ 89 1, /* dma_attr_granular */ 90 0 /* dma_attr_flags */ 91 }; 92 93 94 95 size_t prd_size = sizeof (prde_t) * ATA_DMA_NSEGS; 96 97 int 98 ata_pciide_alloc( 99 dev_info_t *dip, 100 ata_ctl_t *ata_ctlp) 101 { 102 ddi_device_acc_attr_t dev_attr; 103 ddi_dma_cookie_t cookie; 104 size_t buf_size; 105 uint_t count; 106 int rc; 107 108 dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 109 dev_attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC; 110 dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 111 112 113 rc = ddi_dma_alloc_handle(dip, &ata_prd_dma_attr, DDI_DMA_SLEEP, NULL, 114 &ata_ctlp->ac_sg_handle); 115 if (rc != DDI_SUCCESS) { 116 ADBG_ERROR(("ata_pciide_alloc 0x%p handle %d\n", 117 (void *)ata_ctlp, rc)); 118 goto err3; 119 } 120 121 rc = ddi_dma_mem_alloc(ata_ctlp->ac_sg_handle, prd_size, &dev_attr, 122 DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, 123 &ata_ctlp->ac_sg_list, &buf_size, &ata_ctlp->ac_sg_acc_handle); 124 if (rc != DDI_SUCCESS) { 125 ADBG_ERROR(("ata_pciide_alloc 0x%p mem %d\n", 126 (void *)ata_ctlp, rc)); 127 goto err2; 128 } 129 130 rc = ddi_dma_addr_bind_handle(ata_ctlp->ac_sg_handle, NULL, 131 ata_ctlp->ac_sg_list, buf_size, 132 DDI_DMA_WRITE | DDI_DMA_CONSISTENT, 133 DDI_DMA_SLEEP, NULL, &cookie, &count); 134 if (rc != DDI_DMA_MAPPED) { 135 ADBG_ERROR(("ata_pciide_alloc 0x%p bind %d\n", 136 (void *)ata_ctlp, rc)); 137 goto err1; 138 } 139 140 ASSERT(count == 1); 141 ASSERT((cookie.dmac_address & (sizeof (int) - 1)) == 0); 142 #define Mask4K 0xfffff000 143 ASSERT((cookie.dmac_address & Mask4K) 144 == ((cookie.dmac_address + cookie.dmac_size - 1) & Mask4K)); 145 146 ata_ctlp->ac_sg_paddr = cookie.dmac_address; 147 return (TRUE); 148 err1: 149 ddi_dma_mem_free(&ata_ctlp->ac_sg_acc_handle); 150 ata_ctlp->ac_sg_acc_handle = NULL; 151 err2: 152 ddi_dma_free_handle(&ata_ctlp->ac_sg_handle); 153 ata_ctlp->ac_sg_handle = NULL; 154 err3: 155 return (FALSE); 156 } 157 158 159 void 160 ata_pciide_free(ata_ctl_t *ata_ctlp) 161 { 162 if (ata_ctlp->ac_sg_handle == NULL) 163 return; 164 165 (void) ddi_dma_unbind_handle(ata_ctlp->ac_sg_handle); 166 ddi_dma_mem_free(&ata_ctlp->ac_sg_acc_handle); 167 ddi_dma_free_handle(&ata_ctlp->ac_sg_handle); 168 ata_ctlp->ac_sg_handle = NULL; 169 ata_ctlp->ac_sg_acc_handle = NULL; 170 } 171 172 173 174 void 175 ata_pciide_dma_setup( 176 ata_ctl_t *ata_ctlp, 177 prde_t *srcp, 178 int sg_cnt) 179 { 180 ddi_acc_handle_t bmhandle = ata_ctlp->ac_bmhandle; 181 caddr_t bmaddr = ata_ctlp->ac_bmaddr; 182 ddi_acc_handle_t sg_acc_handle = ata_ctlp->ac_sg_acc_handle; 183 uint_t *dstp = (uint_t *)ata_ctlp->ac_sg_list; 184 int idx; 185 186 ASSERT(dstp != 0); 187 ASSERT(sg_cnt != 0); 188 189 ADBG_DMA(("ata dma_setup 0x%p 0x%p %d\n", ata_ctlp, srcp, sg_cnt)); 190 /* 191 * Copy the PRD list to controller's phys buffer. 192 * Copying to a fixed location avoids having to check 193 * every ata_pkt for alignment and page boundaries. 194 */ 195 for (idx = 0; idx < sg_cnt - 1; idx++, srcp++) { 196 ddi_put32(sg_acc_handle, dstp++, srcp->p_address); 197 ddi_put32(sg_acc_handle, dstp++, srcp->p_count); 198 } 199 200 /* 201 * set the end of table flag in the last entry 202 */ 203 srcp->p_count |= PCIIDE_PRDE_EOT; 204 ddi_put32(sg_acc_handle, dstp++, srcp->p_address); 205 ddi_put32(sg_acc_handle, dstp++, srcp->p_count); 206 207 /* 208 * give the pciide chip the physical address of the PRDE table 209 */ 210 ddi_put32(bmhandle, (uint_t *)(bmaddr + PCIIDE_BMIDTPX_REG), 211 ata_ctlp->ac_sg_paddr); 212 213 ADBG_DMA(("ata dma_setup 0x%p 0x%llx\n", 214 bmaddr, (unsigned long long)ata_ctlp->ac_sg_paddr)); 215 } 216 217 218 219 void 220 ata_pciide_dma_start( 221 ata_ctl_t *ata_ctlp, 222 uchar_t direction) 223 { 224 ddi_acc_handle_t bmhandle = ata_ctlp->ac_bmhandle; 225 caddr_t bmaddr = ata_ctlp->ac_bmaddr; 226 uchar_t tmp; 227 228 ASSERT((ata_ctlp->ac_sg_paddr & PCIIDE_BMIDTPX_MASK) == 0); 229 ASSERT((direction == PCIIDE_BMICX_RWCON_WRITE_TO_MEMORY) || 230 (direction == PCIIDE_BMICX_RWCON_READ_FROM_MEMORY)); 231 232 /* 233 * Set the direction control and start the PCIIDE DMA controller 234 */ 235 tmp = ddi_get8(bmhandle, (uchar_t *)bmaddr + PCIIDE_BMICX_REG); 236 tmp &= PCIIDE_BMICX_MASK; 237 ddi_put8(bmhandle, (uchar_t *)bmaddr + PCIIDE_BMICX_REG, 238 (tmp | direction)); 239 240 ddi_put8(bmhandle, (uchar_t *)bmaddr + PCIIDE_BMICX_REG, 241 (tmp | PCIIDE_BMICX_SSBM_E | direction)); 242 243 return; 244 245 } 246 247 248 void 249 ata_pciide_dma_stop( 250 ata_ctl_t *ata_ctlp) 251 { 252 ddi_acc_handle_t bmhandle = ata_ctlp->ac_bmhandle; 253 caddr_t bmaddr = ata_ctlp->ac_bmaddr; 254 uchar_t tmp; 255 256 /* 257 * Stop the PCIIDE DMA controller 258 */ 259 tmp = ddi_get8(bmhandle, (uchar_t *)bmaddr + PCIIDE_BMICX_REG); 260 tmp &= (PCIIDE_BMICX_MASK & (~PCIIDE_BMICX_SSBM)); 261 262 ADBG_DMA(("ata_pciide_dma_stop 0x%p 0x%x\n", bmaddr, tmp)); 263 264 ddi_put8(bmhandle, (uchar_t *)bmaddr + PCIIDE_BMICX_REG, tmp); 265 } 266 267 /* ARGSUSED */ 268 void 269 ata_pciide_dma_sg_func( 270 gcmd_t *gcmdp, 271 ddi_dma_cookie_t *dmackp, 272 int single_segment, 273 int seg_index) 274 { 275 ata_pkt_t *ata_pktp = GCMD2APKT(gcmdp); 276 prde_t *dmap; 277 278 ASSERT(seg_index < ATA_DMA_NSEGS); 279 ASSERT(((uint_t)dmackp->dmac_address & PCIIDE_PRDE_ADDR_MASK) == 0); 280 ASSERT((dmackp->dmac_size & PCIIDE_PRDE_CNT_MASK) == 0); 281 ASSERT(dmackp->dmac_size <= PCIIDE_PRDE_CNT_MAX); 282 283 ADBG_TRACE(("adp_dma_sg_func: gcmdp 0x%p dmackp 0x%p s %d idx %d\n", 284 gcmdp, dmackp, single_segment, seg_index)); 285 286 /* set address of current entry in scatter/gather list */ 287 dmap = ata_pktp->ap_sg_list + seg_index; 288 289 /* store the phys addr and count from the cookie */ 290 dmap->p_address = (uint_t)dmackp->dmac_address; 291 dmap->p_count = (uint_t)dmackp->dmac_size; 292 293 /* save the count of scatter/gather segments */ 294 ata_pktp->ap_sg_cnt = seg_index + 1; 295 296 /* compute the total bytes in this request */ 297 if (seg_index == 0) 298 ata_pktp->ap_bcount = 0; 299 ata_pktp->ap_bcount += dmackp->dmac_size; 300 } 301 302 303 304 int 305 ata_pciide_status_clear( 306 ata_ctl_t *ata_ctlp) 307 { 308 ddi_acc_handle_t bmhandle = ata_ctlp->ac_bmhandle; 309 caddr_t bmaddr = ata_ctlp->ac_bmaddr; 310 uchar_t status; 311 uchar_t tmp; 312 313 /* 314 * Get the current PCIIDE status 315 */ 316 status = PCIIDE_STATUS_GET(ata_ctlp->ac_bmhandle, ata_ctlp->ac_bmaddr); 317 tmp = status & PCIIDE_BMISX_MASK; 318 tmp |= (PCIIDE_BMISX_IDERR | PCIIDE_BMISX_IDEINTS); 319 320 ADBG_DMA(("ata_pciide_status_clear 0x%p 0x%x\n", 321 bmaddr, status)); 322 323 /* 324 * Clear the latches (and preserve the other bits) 325 */ 326 ddi_put8(bmhandle, (uchar_t *)bmaddr + PCIIDE_BMISX_REG, tmp); 327 328 #ifdef NAT_SEMI_PC87415_BUG 329 /* ??? chip errata ??? */ 330 if (ata_ctlp->ac_nat_semi_bug) { 331 tmp = ddi_get8(bmhandle, bmaddr + PCIIDE_BMICX_REG); 332 tmp &= PCIIDE_BMICX_MASK; 333 ddi_put8(bmhandle, bmaddr + PCIIDE_BMICX_REG, 334 (tmp | PCIIDE_BMISX_IDERR | PCIIDE_BMISX_IDEINTS)); 335 } 336 #endif 337 return (status); 338 } 339 340 int 341 ata_pciide_status_dmacheck_clear( 342 ata_ctl_t *ata_ctlp) 343 { 344 uchar_t status; 345 346 /* 347 * Get the PCIIDE DMA controller's current status 348 */ 349 status = ata_pciide_status_clear(ata_ctlp); 350 351 ADBG_DMA(("ata_pciide_status_dmacheck_clear 0x%p 0x%x\n", 352 ata_ctlp->ac_bmaddr, status)); 353 /* 354 * check for errors 355 */ 356 if (status & PCIIDE_BMISX_IDERR) { 357 ADBG_WARN(("ata_pciide_status: 0x%x\n", status)); 358 return (TRUE); 359 } 360 return (FALSE); 361 } 362 363 364 365 /* 366 * Check for a pending PCI-IDE interrupt 367 */ 368 369 int 370 ata_pciide_status_pending( 371 ata_ctl_t *ata_ctlp) 372 { 373 uchar_t status; 374 375 status = PCIIDE_STATUS_GET(ata_ctlp->ac_bmhandle, ata_ctlp->ac_bmaddr); 376 ADBG_DMA(("ata_pciide_status_pending 0x%p 0x%x\n", 377 ata_ctlp->ac_bmaddr, status)); 378 if (status & PCIIDE_BMISX_IDEINTS) 379 return (TRUE); 380 return (FALSE); 381 } 382