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