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
ata_pciide_alloc(dev_info_t * dip,ata_ctl_t * ata_ctlp)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
ata_pciide_free(ata_ctl_t * ata_ctlp)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
ata_pciide_dma_setup(ata_ctl_t * ata_ctlp,prde_t * srcp,int sg_cnt)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
ata_pciide_dma_start(ata_ctl_t * ata_ctlp,uchar_t direction)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
ata_pciide_dma_stop(ata_ctl_t * ata_ctlp)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
ata_pciide_dma_sg_func(gcmd_t * gcmdp,ddi_dma_cookie_t * dmackp,int single_segment,int seg_index)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
ata_pciide_status_clear(ata_ctl_t * ata_ctlp)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
ata_pciide_status_dmacheck_clear(ata_ctl_t * ata_ctlp)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
ata_pciide_status_pending(ata_ctl_t * ata_ctlp)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