File: | dev/ata/ata_wdc.c |
Warning: | line 333, column 6 Value stored to 'error' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: ata_wdc.c,v 1.52 2018/11/02 09:59:36 fcambus Exp $ */ |
2 | /* $NetBSD: ata_wdc.c,v 1.21 1999/08/09 09:43:11 bouyer Exp $ */ |
3 | |
4 | /* |
5 | * Copyright (c) 1998, 2001 Manuel Bouyer. |
6 | * |
7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions |
9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. |
15 | * |
16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
17 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
19 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
21 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
22 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
23 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | * |
27 | */ |
28 | |
29 | /*- |
30 | * Copyright (c) 1998 The NetBSD Foundation, Inc. |
31 | * All rights reserved. |
32 | * |
33 | * This code is derived from software contributed to The NetBSD Foundation |
34 | * by Charles M. Hannum, by Onno van der Linden and by Manuel Bouyer. |
35 | * |
36 | * Redistribution and use in source and binary forms, with or without |
37 | * modification, are permitted provided that the following conditions |
38 | * are met: |
39 | * 1. Redistributions of source code must retain the above copyright |
40 | * notice, this list of conditions and the following disclaimer. |
41 | * 2. Redistributions in binary form must reproduce the above copyright |
42 | * notice, this list of conditions and the following disclaimer in the |
43 | * documentation and/or other materials provided with the distribution. |
44 | * |
45 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
46 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
47 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
48 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
49 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
50 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
51 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
52 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
53 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
54 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
55 | * POSSIBILITY OF SUCH DAMAGE. |
56 | */ |
57 | |
58 | #include <sys/param.h> |
59 | #include <sys/systm.h> |
60 | #include <sys/kernel.h> |
61 | #include <sys/stat.h> |
62 | #include <sys/buf.h> |
63 | #include <sys/malloc.h> |
64 | #include <sys/device.h> |
65 | #include <sys/disklabel.h> |
66 | #include <sys/disk.h> |
67 | #include <sys/syslog.h> |
68 | |
69 | #include <machine/intr.h> |
70 | #include <machine/bus.h> |
71 | |
72 | #include <dev/ata/atavar.h> |
73 | #include <dev/ic/wdcreg.h> |
74 | #include <dev/ic/wdcvar.h> |
75 | #include <dev/ata/wdvar.h> |
76 | |
77 | #ifdef HIBERNATE1 |
78 | #include <sys/hibernate.h> |
79 | #endif |
80 | |
81 | #define DEBUG_INTR0x01 0x01 |
82 | #define DEBUG_XFERS0x02 0x02 |
83 | #define DEBUG_STATUS0x04 0x04 |
84 | #define DEBUG_FUNCS0x08 0x08 |
85 | #define DEBUG_PROBE0x10 0x10 |
86 | |
87 | #ifdef WDCDEBUG |
88 | #ifndef WDCDEBUG_WD_MASK |
89 | #define WDCDEBUG_WD_MASK 0x00 |
90 | #endif |
91 | int wdcdebug_wd_mask = WDCDEBUG_WD_MASK; |
92 | #define WDCDEBUG_PRINT(args, level) do { \ |
93 | if ((wdcdebug_wd_mask & (level)) != 0) \ |
94 | printf args; \ |
95 | } while (0) |
96 | #else |
97 | #define WDCDEBUG_PRINT(args, level) |
98 | #endif |
99 | |
100 | #define ATA_DELAY45000 45000 /* 45s for a drive I/O */ |
101 | |
102 | void wdc_ata_bio_start(struct channel_softc *, struct wdc_xfer *); |
103 | void _wdc_ata_bio_start(struct channel_softc *, struct wdc_xfer *); |
104 | int wdc_ata_bio_intr(struct channel_softc *, struct wdc_xfer *, int); |
105 | void wdc_ata_bio_kill_xfer(struct channel_softc *, struct wdc_xfer *); |
106 | void wdc_ata_bio_done(struct channel_softc *, struct wdc_xfer *); |
107 | int wdc_ata_ctrl_intr(struct channel_softc *, struct wdc_xfer *, int); |
108 | int wdc_ata_err(struct ata_drive_datas *, struct ata_bio *); |
109 | #define WDC_ATA_NOERR0x00 0x00 /* Drive doesn't report an error */ |
110 | #define WDC_ATA_RECOV0x01 0x01 /* There was a recovered error */ |
111 | #define WDC_ATA_ERR0x02 0x02 /* Drive reports an error */ |
112 | |
113 | #ifdef HIBERNATE1 |
114 | int |
115 | wd_hibernate_io(dev_t dev, daddr_t blkno, vaddr_t addr, size_t size, int op, void *page) |
116 | { |
117 | struct { |
118 | struct wd_softc wd; |
119 | struct wdc_xfer xfer; |
120 | struct channel_softc chp; |
121 | daddr_t poffset; |
122 | size_t psize; |
123 | } *my = page; |
124 | struct wd_softc *real_wd, *wd = &my->wd; |
125 | struct wdc_xfer *xfer = &my->xfer; |
126 | struct channel_softc *chp = &my->chp; |
127 | struct ata_bio *ata_bio; |
128 | extern struct cfdriver wd_cd; |
129 | |
130 | /* early call for initialization */ |
131 | if (op == HIB_INIT-1) { |
132 | my->poffset = blkno; |
133 | my->psize = size; |
134 | return(0); |
135 | } |
136 | |
137 | real_wd = (struct wd_softc *)disk_lookup(&wd_cd, DISKUNIT(dev)(((unsigned)((dev) & 0xff) | (((dev) & 0xffff0000) >> 8)) / 16)); |
138 | if (real_wd == NULL((void *)0)) |
139 | return (ENODEV19); |
140 | |
141 | if (op == HIB_DONE-2) { |
142 | struct wdc_softc *wdc = chp->wdc; |
143 | config_suspend(&wdc->sc_dev, DVACT_RESUME4); |
144 | return (0); |
145 | } |
146 | |
147 | if (blkno > my->psize) |
148 | return (E2BIG7); |
149 | blkno += my->poffset; |
150 | |
151 | /* |
152 | * Craft a fake set of softc and related structures |
153 | * which we think the driver modifies. Some of these will |
154 | * have pointers which reach to unsafe places, but.. |
155 | */ |
156 | bcopy(real_wd->drvp->chnl_softc, &my->chp, sizeof my->chp); |
157 | chp->ch_drive[0].chnl_softc = chp; |
158 | chp->ch_drive[1].chnl_softc = chp; |
159 | |
160 | bcopy(real_wd, &my->wd, sizeof my->wd); |
161 | ata_bio = &wd->sc_wdc_bio; |
162 | ata_bio->wd = wd; /* fixup ata_bio->wd */ |
163 | wd->drvp = &chp->ch_drive[real_wd->drvp->drive]; |
164 | |
165 | /* Fill the request and submit it */ |
166 | wd->sc_wdc_bio.blkno = blkno; |
167 | wd->sc_wdc_bio.flags = ATA_POLL0x0002 | ATA_LBA480x0080; |
168 | if (op == HIB_R0) |
169 | wd->sc_wdc_bio.flags |= ATA_READ0x0020; |
170 | wd->sc_wdc_bio.bcount = size; |
171 | wd->sc_wdc_bio.databuf = (caddr_t)addr; |
172 | wd->sc_wdc_bio.wd = wd; |
173 | |
174 | bzero(&my->xfer, sizeof my->xfer)__builtin_bzero((&my->xfer), (sizeof my->xfer)); |
175 | xfer->c_flags |= C_PRIVATEXFER0x0400; /* Our xfer is totally private */ |
176 | xfer->c_flags |= C_POLL0x0020; |
177 | xfer->drive = wd->drvp->drive; |
178 | xfer->cmd = ata_bio; |
179 | xfer->databuf = ata_bio->databuf; |
180 | xfer->c_bcount = ata_bio->bcount; |
181 | xfer->c_start = wdc_ata_bio_start; |
182 | xfer->c_intr = wdc_ata_bio_intr; |
183 | xfer->c_kill_xfer = wdc_ata_bio_kill_xfer; |
184 | wdc_exec_xfer(chp, xfer); |
185 | return (ata_bio->flags & ATA_ITSDONE0x0004) ? 0 : EIO5; |
186 | } |
187 | #endif /* HIBERNATE */ |
188 | |
189 | /* |
190 | * Handle block I/O operation. Return WDC_COMPLETE, WDC_QUEUED, or |
191 | * WDC_TRY_AGAIN. Must be called at splbio(). |
192 | */ |
193 | int |
194 | wdc_ata_bio(struct ata_drive_datas *drvp, struct ata_bio *ata_bio) |
195 | { |
196 | struct wdc_xfer *xfer; |
197 | struct channel_softc *chp = drvp->chnl_softc; |
198 | |
199 | xfer = wdc_get_xfer(WDC_NOSLEEP0x01); |
200 | if (xfer == NULL((void *)0)) |
201 | return WDC_TRY_AGAIN0x03; |
202 | if (ata_bio->flags & ATA_POLL0x0002) |
203 | xfer->c_flags |= C_POLL0x0020; |
204 | if (!(ata_bio->flags & ATA_POLL0x0002) && |
205 | (drvp->drive_flags & (DRIVE_DMA0x0010 | DRIVE_UDMA0x0020)) && |
206 | (ata_bio->flags & ATA_SINGLE0x0008) == 0 && |
207 | (ata_bio->bcount > 512 || |
208 | (chp->wdc->quirks & WDC_QUIRK_NOSHORTDMA0x0001) == 0)) |
209 | xfer->c_flags |= C_DMA0x0040; |
210 | xfer->drive = drvp->drive; |
211 | xfer->cmd = ata_bio; |
212 | xfer->databuf = ata_bio->databuf; |
213 | xfer->c_bcount = ata_bio->bcount; |
214 | xfer->c_start = wdc_ata_bio_start; |
215 | xfer->c_intr = wdc_ata_bio_intr; |
216 | xfer->c_kill_xfer = wdc_ata_bio_kill_xfer; |
217 | wdc_exec_xfer(chp, xfer); |
218 | return (ata_bio->flags & ATA_ITSDONE0x0004) ? WDC_COMPLETE0x01 : WDC_QUEUED0x02; |
219 | } |
220 | |
221 | void |
222 | wdc_ata_bio_start(struct channel_softc *chp, struct wdc_xfer *xfer) |
223 | { |
224 | struct ata_bio *ata_bio = xfer->cmd; |
225 | WDCDEBUG_PRINT(("wdc_ata_bio_start %s:%d:%d\n", |
226 | chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive), |
227 | DEBUG_XFERS); |
228 | |
229 | /* start timeout machinery */ |
230 | if ((ata_bio->flags & ATA_POLL0x0002) == 0) |
231 | timeout_add_msec(&chp->ch_timo, ATA_DELAY45000); |
232 | _wdc_ata_bio_start(chp, xfer); |
233 | } |
234 | |
235 | void |
236 | _wdc_ata_bio_start(struct channel_softc *chp, struct wdc_xfer *xfer) |
237 | { |
238 | struct ata_bio *ata_bio = xfer->cmd; |
239 | struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive]; |
240 | u_int16_t cyl; |
241 | u_int8_t head, sect, cmd = 0; |
242 | int nblks; |
243 | int error, dma_flags = 0; |
244 | |
245 | WDCDEBUG_PRINT(("_wdc_ata_bio_start %s:%d:%d\n", |
246 | chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive), |
247 | DEBUG_INTR | DEBUG_XFERS); |
248 | /* Do control operations specially. */ |
249 | if (drvp->state < READY10) { |
250 | /* |
251 | * Actually, we want to be careful not to mess with the control |
252 | * state if the device is currently busy, but we can assume |
253 | * that we never get to this point if that's the case. |
254 | */ |
255 | /* at this point, we should only be in RECAL state */ |
256 | if (drvp->state != RECAL0) { |
257 | printf("%s:%d:%d: bad state %d in _wdc_ata_bio_start\n", |
258 | chp->wdc->sc_dev.dv_xname, chp->channel, |
259 | xfer->drive, drvp->state); |
260 | panic("_wdc_ata_bio_start: bad state"); |
261 | } |
262 | xfer->c_intr = wdc_ata_ctrl_intr; |
263 | wdc_set_drive(chp, xfer->drive); |
264 | if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY)((wdc_wait_for_status((chp), (0x40), (0x40), (45000)) >= 0 ) ? 0 : -1) != 0) |
265 | goto timeout; |
266 | wdccommandshort(chp, xfer->drive, WDCC_RECAL0x10); |
267 | drvp->state = RECAL_WAIT1; |
268 | if ((ata_bio->flags & ATA_POLL0x0002) == 0) { |
269 | chp->ch_flags |= WDCF_IRQ_WAIT0x10; |
270 | } else { |
271 | /* Wait for at last 400ns for status bit to be valid */ |
272 | DELAY(1)(*delay_func)(1); |
273 | wdc_ata_ctrl_intr(chp, xfer, 0); |
274 | } |
275 | return; |
276 | } |
277 | |
278 | if (xfer->c_flags & C_DMA0x0040) { |
279 | if (drvp->n_xfers <= NXFER1000) |
280 | drvp->n_xfers++; |
281 | dma_flags = (ata_bio->flags & ATA_READ0x0020) ? WDC_DMA_READ0x01 : 0; |
282 | if (ata_bio->flags & ATA_LBA480x0080) |
283 | dma_flags |= WDC_DMA_LBA480x04; |
284 | } |
285 | again: |
286 | /* |
287 | * |
288 | * When starting a multi-sector transfer, or doing single-sector |
289 | * transfers... |
290 | */ |
291 | if (xfer->c_skip == 0 || (ata_bio->flags & ATA_SINGLE0x0008) != 0) { |
292 | if (ata_bio->flags & ATA_SINGLE0x0008) |
293 | nblks = 1; |
294 | else |
295 | nblks = xfer->c_bcount / ata_bio->lp->d_secsize; |
296 | if (ata_bio->flags & ATA_LBA0x0010) { |
297 | sect = (ata_bio->blkno >> 0) & 0xff; |
298 | cyl = (ata_bio->blkno >> 8) & 0xffff; |
299 | head = (ata_bio->blkno >> 24) & 0x0f; |
300 | head |= WDSD_LBA0x40; |
301 | } else { |
302 | int blkno = ata_bio->blkno; |
303 | sect = blkno % ata_bio->lp->d_nsectors; |
304 | sect++; /* Sectors begin with 1, not 0. */ |
305 | blkno /= ata_bio->lp->d_nsectors; |
306 | head = blkno % ata_bio->lp->d_ntracks; |
307 | blkno /= ata_bio->lp->d_ntracks; |
308 | cyl = blkno; |
309 | head |= WDSD_CHS0x00; |
310 | } |
311 | if (xfer->c_flags & C_DMA0x0040) { |
312 | ata_bio->nblks = nblks; |
313 | ata_bio->nbytes = xfer->c_bcount; |
314 | if (ata_bio->flags & ATA_LBA480x0080) |
315 | cmd = (ata_bio->flags & ATA_READ0x0020) ? |
316 | WDCC_READDMA_EXT0x25 : WDCC_WRITEDMA_EXT0x35; |
317 | else |
318 | cmd = (ata_bio->flags & ATA_READ0x0020) ? |
319 | WDCC_READDMA0xc8 : WDCC_WRITEDMA0xca; |
320 | /* Init the DMA channel. */ |
321 | error = (*chp->wdc->dma_init)(chp->wdc->dma_arg, |
322 | chp->channel, xfer->drive, |
323 | (char *)xfer->databuf + xfer->c_skip, |
324 | ata_bio->nbytes, dma_flags); |
325 | if (error) { |
326 | if (error == EINVAL22) { |
327 | /* |
328 | * We can't do DMA on this transfer |
329 | * for some reason. Fall back to |
330 | * PIO. |
331 | */ |
332 | xfer->c_flags &= ~C_DMA0x0040; |
333 | error = 0; |
Value stored to 'error' is never read | |
334 | goto do_pio; |
335 | } |
336 | ata_bio->error = ERR_DMA3; |
337 | ata_bio->r_error = 0; |
338 | wdc_ata_bio_done(chp, xfer); |
339 | return; |
340 | } |
341 | /* Initiate command */ |
342 | wdc_set_drive(chp, xfer->drive); |
343 | if (wait_for_ready(chp, ATA_DELAY)((wdc_wait_for_status(((chp)), (0x40), (0x40), ((45000))) >= 0) ? 0 : -1) < 0) |
344 | goto timeout; |
345 | |
346 | /* start the DMA channel (before) */ |
347 | if (chp->ch_flags & WDCF_DMA_BEFORE_CMD0x80) |
348 | (*chp->wdc->dma_start)(chp->wdc->dma_arg, |
349 | chp->channel, xfer->drive); |
350 | |
351 | if (ata_bio->flags & ATA_LBA480x0080) { |
352 | wdccommandext(chp, xfer->drive, cmd, |
353 | (u_int64_t)ata_bio->blkno, nblks); |
354 | } else { |
355 | wdccommand(chp, xfer->drive, cmd, cyl, |
356 | head, sect, nblks, 0); |
357 | } |
358 | |
359 | /* start the DMA channel (after) */ |
360 | if ((chp->ch_flags & WDCF_DMA_BEFORE_CMD0x80) == 0) |
361 | (*chp->wdc->dma_start)(chp->wdc->dma_arg, |
362 | chp->channel, xfer->drive); |
363 | |
364 | chp->ch_flags |= WDCF_DMA_WAIT0x20; |
365 | /* wait for irq */ |
366 | goto intr; |
367 | } /* else not DMA */ |
368 | do_pio: |
369 | ata_bio->nblks = min(nblks, ata_bio->multi); |
370 | ata_bio->nbytes = ata_bio->nblks * ata_bio->lp->d_secsize; |
371 | KASSERT(nblks == 1 || (ata_bio->flags & ATA_SINGLE) == 0)((nblks == 1 || (ata_bio->flags & 0x0008) == 0) ? (void )0 : __assert("diagnostic ", "/usr/src/sys/dev/ata/ata_wdc.c" , 371, "nblks == 1 || (ata_bio->flags & ATA_SINGLE) == 0" )); |
372 | if (ata_bio->nblks > 1) { |
373 | if (ata_bio->flags & ATA_LBA480x0080) |
374 | cmd = (ata_bio->flags & ATA_READ0x0020) ? |
375 | WDCC_READMULTI_EXT0x29 : WDCC_WRITEMULTI_EXT0x39; |
376 | else |
377 | cmd = (ata_bio->flags & ATA_READ0x0020) ? |
378 | WDCC_READMULTI0xc4 : WDCC_WRITEMULTI0xc5; |
379 | } else { |
380 | if (ata_bio->flags & ATA_LBA480x0080) |
381 | cmd = (ata_bio->flags & ATA_READ0x0020) ? |
382 | WDCC_READ_EXT0x24 : WDCC_WRITE_EXT0x34; |
383 | else |
384 | cmd = (ata_bio->flags & ATA_READ0x0020) ? |
385 | WDCC_READ0x20 : WDCC_WRITE0x30; |
386 | } |
387 | /* Initiate command! */ |
388 | wdc_set_drive(chp, xfer->drive); |
389 | if (wait_for_ready(chp, ATA_DELAY)((wdc_wait_for_status(((chp)), (0x40), (0x40), ((45000))) >= 0) ? 0 : -1) < 0) |
390 | goto timeout; |
391 | if (ata_bio->flags & ATA_LBA480x0080) { |
392 | wdccommandext(chp, xfer->drive, cmd, |
393 | (u_int64_t)ata_bio->blkno, nblks); |
394 | } else { |
395 | wdccommand(chp, xfer->drive, cmd, cyl, |
396 | head, sect, nblks, 0); |
397 | } |
398 | } else if (ata_bio->nblks > 1) { |
399 | /* The number of blocks in the last stretch may be smaller. */ |
400 | nblks = xfer->c_bcount / ata_bio->lp->d_secsize; |
401 | if (ata_bio->nblks > nblks) { |
402 | ata_bio->nblks = nblks; |
403 | ata_bio->nbytes = xfer->c_bcount; |
404 | } |
405 | } |
406 | /* If this was a write and not using DMA, push the data. */ |
407 | if ((ata_bio->flags & ATA_READ0x0020) == 0) { |
408 | if (wait_for_drq(chp, ATA_DELAY)((wdc_wait_for_status(((chp)), (0x08), (0x08), ((45000))) >= 0) ? 0 : -1) != 0) { |
409 | printf("%s:%d:%d: timeout waiting for DRQ, " |
410 | "st=0x%b, err=0x%02x\n", |
411 | chp->wdc->sc_dev.dv_xname, chp->channel, |
412 | xfer->drive, chp->ch_status, WDCS_BITS"\020\010BSY\007DRDY\006DWF\005DSC\004DRQ\003CORR\002IDX\001ERR", |
413 | chp->ch_error); |
414 | if (wdc_ata_err(drvp, ata_bio) != WDC_ATA_ERR0x02) |
415 | ata_bio->error = TIMEOUT4; |
416 | wdc_ata_bio_done(chp, xfer); |
417 | return; |
418 | } |
419 | if (wdc_ata_err(drvp, ata_bio) == WDC_ATA_ERR0x02) { |
420 | wdc_ata_bio_done(chp, xfer); |
421 | return; |
422 | } |
423 | wdc_output_bytes(drvp, (char *)xfer->databuf + xfer->c_skip, |
424 | ata_bio->nbytes); |
425 | } |
426 | |
427 | intr: /* Wait for IRQ (either real or polled) */ |
428 | if ((ata_bio->flags & ATA_POLL0x0002) == 0) { |
429 | chp->ch_flags |= WDCF_IRQ_WAIT0x10; |
430 | } else { |
431 | /* Wait for at last 400ns for status bit to be valid */ |
432 | delay(1)(*delay_func)(1); |
433 | if (chp->ch_flags & WDCF_DMA_WAIT0x20) { |
434 | wdc_dmawait(chp, xfer, ATA_DELAY45000); |
435 | chp->ch_flags &= ~WDCF_DMA_WAIT0x20; |
436 | } |
437 | wdc_ata_bio_intr(chp, xfer, 0); |
438 | if ((ata_bio->flags & ATA_ITSDONE0x0004) == 0) |
439 | goto again; |
440 | } |
441 | return; |
442 | timeout: |
443 | if (chp->ch_status == 0xff) |
444 | return; |
445 | printf("%s:%d:%d: not ready, st=0x%b, err=0x%02x\n", |
446 | chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive, |
447 | chp->ch_status, WDCS_BITS"\020\010BSY\007DRDY\006DWF\005DSC\004DRQ\003CORR\002IDX\001ERR", chp->ch_error); |
448 | if (wdc_ata_err(drvp, ata_bio) != WDC_ATA_ERR0x02) |
449 | ata_bio->error = TIMEOUT4; |
450 | wdc_ata_bio_done(chp, xfer); |
451 | return; |
452 | } |
453 | |
454 | int |
455 | wdc_ata_bio_intr(struct channel_softc *chp, struct wdc_xfer *xfer, int irq) |
456 | { |
457 | struct ata_bio *ata_bio = xfer->cmd; |
458 | struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive]; |
459 | int drv_err; |
460 | |
461 | WDCDEBUG_PRINT(("wdc_ata_bio_intr %s:%d:%d\n", |
462 | chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive), |
463 | DEBUG_INTR | DEBUG_XFERS); |
464 | |
465 | |
466 | /* Is it not a transfer, but a control operation? */ |
467 | if (drvp->state < READY10) { |
468 | printf("%s:%d:%d: bad state %d in wdc_ata_bio_intr\n", |
469 | chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive, |
470 | drvp->state); |
471 | panic("wdc_ata_bio_intr: bad state"); |
472 | } |
473 | |
474 | /* |
475 | * reset on timeout. This will cause extra resets in the case |
476 | * of occasional lost interrupts |
477 | */ |
478 | if (xfer->c_flags & C_TIMEOU0x0004) |
479 | goto timeout; |
480 | |
481 | /* Ack interrupt done by wait_for_unbusy */ |
482 | if (wait_for_unbusy(chp,((wdc_wait_for_status(((chp)), (0), (0), (((irq == 0) ? 45000 : 0))) >= 0) ? 0 : -1) |
483 | (irq == 0) ? ATA_DELAY : 0)((wdc_wait_for_status(((chp)), (0), (0), (((irq == 0) ? 45000 : 0))) >= 0) ? 0 : -1) < 0) { |
484 | if (irq) |
485 | return 0; /* IRQ was not for us */ |
486 | printf("%s:%d:%d: device timeout, c_bcount=%d, c_skip%d\n", |
487 | chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive, |
488 | xfer->c_bcount, xfer->c_skip); |
489 | |
490 | goto timeout; |
491 | } |
492 | if (chp->wdc->cap & WDC_CAPABILITY_IRQACK0x0400) |
493 | chp->wdc->irqack(chp); |
494 | |
495 | drv_err = wdc_ata_err(drvp, ata_bio); |
496 | |
497 | if (xfer->c_flags & C_DMA0x0040) { |
498 | if (chp->wdc->dma_status != 0) { |
499 | if (drv_err != WDC_ATA_ERR0x02) { |
500 | ata_bio->error = ERR_DMA3; |
501 | drv_err = WDC_ATA_ERR0x02; |
502 | } |
503 | } |
504 | if (chp->ch_status & WDCS_DRQ0x08) { |
505 | if (drv_err != WDC_ATA_ERR0x02) { |
506 | printf("%s:%d:%d: intr with DRQ (st=0x%b)\n", |
507 | chp->wdc->sc_dev.dv_xname, chp->channel, |
508 | xfer->drive, chp->ch_status, WDCS_BITS"\020\010BSY\007DRDY\006DWF\005DSC\004DRQ\003CORR\002IDX\001ERR"); |
509 | ata_bio->error = TIMEOUT4; |
510 | drv_err = WDC_ATA_ERR0x02; |
511 | } |
512 | } |
513 | if (drv_err != WDC_ATA_ERR0x02) |
514 | goto end; |
515 | ata_dmaerr(drvp); |
516 | } |
517 | |
518 | /* if we had an error, end */ |
519 | if (drv_err == WDC_ATA_ERR0x02) { |
520 | wdc_ata_bio_done(chp, xfer); |
521 | return 1; |
522 | } |
523 | |
524 | /* If this was a read and not using DMA, fetch the data. */ |
525 | if ((ata_bio->flags & ATA_READ0x0020) != 0) { |
526 | if ((chp->ch_status & WDCS_DRQ0x08) != WDCS_DRQ0x08) { |
527 | printf("%s:%d:%d: read intr before drq\n", |
528 | chp->wdc->sc_dev.dv_xname, chp->channel, |
529 | xfer->drive); |
530 | ata_bio->error = TIMEOUT4; |
531 | wdc_ata_bio_done(chp, xfer); |
532 | return 1; |
533 | } |
534 | wdc_input_bytes(drvp, (char *)xfer->databuf + xfer->c_skip, |
535 | ata_bio->nbytes); |
536 | } |
537 | end: |
538 | ata_bio->blkno += ata_bio->nblks; |
539 | ata_bio->blkdone += ata_bio->nblks; |
540 | xfer->c_skip += ata_bio->nbytes; |
541 | xfer->c_bcount -= ata_bio->nbytes; |
542 | /* See if this transfer is complete. */ |
543 | if (xfer->c_bcount > 0) { |
544 | if ((ata_bio->flags & ATA_POLL0x0002) == 0) { |
545 | /* Start the next operation */ |
546 | _wdc_ata_bio_start(chp, xfer); |
547 | } else { |
548 | /* Let _wdc_ata_bio_start do the loop */ |
549 | return 1; |
550 | } |
551 | } else { /* Done with this transfer */ |
552 | ata_bio->error = NOERROR0; |
553 | wdc_ata_bio_done(chp, xfer); |
554 | } |
555 | return 1; |
556 | |
557 | timeout: |
558 | if (xfer->c_flags & C_DMA0x0040) |
559 | ata_dmaerr(drvp); |
560 | |
561 | ata_bio->error = TIMEOUT4; |
562 | wdc_ata_bio_done(chp, xfer); |
563 | return 1; |
564 | } |
565 | |
566 | void |
567 | wdc_ata_bio_kill_xfer(struct channel_softc *chp, struct wdc_xfer *xfer) |
568 | { |
569 | struct ata_bio *ata_bio = xfer->cmd; |
570 | |
571 | timeout_del(&chp->ch_timo); |
572 | /* remove this command from xfer queue */ |
573 | wdc_free_xfer(chp, xfer); |
574 | |
575 | ata_bio->flags |= ATA_ITSDONE0x0004; |
576 | ata_bio->error = ERR_NODEV5; |
577 | ata_bio->r_error = WDCE_ABRT0x04; |
578 | if ((ata_bio->flags & ATA_POLL0x0002) == 0) { |
579 | WDCDEBUG_PRINT(("wdc_ata_done: wddone\n"), DEBUG_XFERS); |
580 | wddone(ata_bio->wd); |
581 | } |
582 | } |
583 | |
584 | void |
585 | wdc_ata_bio_done(struct channel_softc *chp, struct wdc_xfer *xfer) |
586 | { |
587 | struct ata_bio *ata_bio = xfer->cmd; |
588 | |
589 | WDCDEBUG_PRINT(("wdc_ata_bio_done %s:%d:%d: flags 0x%x\n", |
590 | chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive, |
591 | (u_int)xfer->c_flags), |
592 | DEBUG_XFERS); |
593 | |
594 | if ((xfer->c_flags & C_PRIVATEXFER0x0400) == 0) |
595 | timeout_del(&chp->ch_timo); |
596 | |
597 | /* feed back residual bcount to our caller */ |
598 | ata_bio->bcount = xfer->c_bcount; |
599 | |
600 | /* remove this command from xfer queue */ |
601 | wdc_free_xfer(chp, xfer); |
602 | |
603 | ata_bio->flags |= ATA_ITSDONE0x0004; |
604 | if ((ata_bio->flags & ATA_POLL0x0002) == 0) { |
605 | WDCDEBUG_PRINT(("wdc_ata_done: wddone\n"), DEBUG_XFERS); |
606 | wddone(ata_bio->wd); |
607 | } |
608 | WDCDEBUG_PRINT(("wdcstart from wdc_ata_done, flags 0x%x\n", |
609 | chp->ch_flags), DEBUG_XFERS); |
610 | wdcstart(chp); |
611 | } |
612 | |
613 | /* |
614 | * Implement operations needed before read/write. |
615 | */ |
616 | int |
617 | wdc_ata_ctrl_intr(struct channel_softc *chp, struct wdc_xfer *xfer, int irq) |
618 | { |
619 | struct ata_bio *ata_bio = xfer->cmd; |
620 | struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive]; |
621 | char *errstring = NULL((void *)0); |
622 | int delay = (irq == 0) ? ATA_DELAY45000 : 0; |
623 | |
624 | WDCDEBUG_PRINT(("wdc_ata_ctrl_intr: state %d\n", drvp->state), |
625 | DEBUG_FUNCS); |
626 | |
627 | again: |
628 | switch (drvp->state) { |
629 | case RECAL0: /* Should not be in this state here */ |
630 | panic("wdc_ata_ctrl_intr: state==RECAL"); |
631 | break; |
632 | |
633 | case RECAL_WAIT1: |
634 | errstring = "recal"; |
635 | if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, delay)((wdc_wait_for_status((chp), (0x40), (0x40), (delay)) >= 0 ) ? 0 : -1)) |
636 | goto timeout; |
637 | if (chp->wdc->cap & WDC_CAPABILITY_IRQACK0x0400) |
638 | chp->wdc->irqack(chp); |
639 | if (chp->ch_status & (WDCS_ERR0x01 | WDCS_DWF0x20)) |
640 | goto error; |
641 | /* FALLTHROUGH */ |
642 | |
643 | case PIOMODE2: |
644 | /* Don't try to set modes if controller can't be adjusted */ |
645 | if ((chp->wdc->cap & WDC_CAPABILITY_MODE0x0004) == 0) |
646 | goto geometry; |
647 | /* Also don't try if the drive didn't report its mode */ |
648 | if ((drvp->drive_flags & DRIVE_MODE0x0040) == 0) |
649 | goto geometry; |
650 | /* SET FEATURES 0x08 is only for PIO mode > 2 */ |
651 | if (drvp->PIO_mode <= 2) |
652 | goto geometry; |
653 | wdccommand(chp, drvp->drive, SET_FEATURES0xef, 0, 0, 0, |
654 | 0x08 | drvp->PIO_mode, WDSF_SET_MODE0x03); |
655 | drvp->state = PIOMODE_WAIT3; |
656 | break; |
657 | |
658 | case PIOMODE_WAIT3: |
659 | errstring = "piomode"; |
660 | if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, delay)((wdc_wait_for_status((chp), (0x40), (0x40), (delay)) >= 0 ) ? 0 : -1)) |
661 | goto timeout; |
662 | if (chp->wdc->cap & WDC_CAPABILITY_IRQACK0x0400) |
663 | chp->wdc->irqack(chp); |
664 | if (chp->ch_status & (WDCS_ERR0x01 | WDCS_DWF0x20)) |
665 | goto error; |
666 | /* FALLTHROUGH */ |
667 | |
668 | case DMAMODE4: |
669 | if (drvp->drive_flags & DRIVE_UDMA0x0020) { |
670 | wdccommand(chp, drvp->drive, SET_FEATURES0xef, 0, 0, 0, |
671 | 0x40 | drvp->UDMA_mode, WDSF_SET_MODE0x03); |
672 | } else if (drvp->drive_flags & DRIVE_DMA0x0010) { |
673 | wdccommand(chp, drvp->drive, SET_FEATURES0xef, 0, 0, 0, |
674 | 0x20 | drvp->DMA_mode, WDSF_SET_MODE0x03); |
675 | } else { |
676 | goto geometry; |
677 | } |
678 | drvp->state = DMAMODE_WAIT5; |
679 | break; |
680 | case DMAMODE_WAIT5: |
681 | errstring = "dmamode"; |
682 | if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, delay)((wdc_wait_for_status((chp), (0x40), (0x40), (delay)) >= 0 ) ? 0 : -1)) |
683 | goto timeout; |
684 | if (chp->wdc->cap & WDC_CAPABILITY_IRQACK0x0400) |
685 | chp->wdc->irqack(chp); |
686 | if (chp->ch_status & (WDCS_ERR0x01 | WDCS_DWF0x20)) |
687 | goto error; |
688 | /* FALLTHROUGH */ |
689 | |
690 | case GEOMETRY6: |
691 | geometry: |
692 | if (ata_bio->flags & ATA_LBA0x0010) |
693 | goto multimode; |
694 | wdccommand(chp, xfer->drive, WDCC_IDP0x91, |
695 | ata_bio->lp->d_ncylinders, |
696 | ata_bio->lp->d_ntracks - 1, 0, ata_bio->lp->d_nsectors, 0); |
697 | drvp->state = GEOMETRY_WAIT7; |
698 | break; |
699 | |
700 | case GEOMETRY_WAIT7: |
701 | errstring = "geometry"; |
702 | if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, delay)((wdc_wait_for_status((chp), (0x40), (0x40), (delay)) >= 0 ) ? 0 : -1)) |
703 | goto timeout; |
704 | if (chp->wdc->cap & WDC_CAPABILITY_IRQACK0x0400) |
705 | chp->wdc->irqack(chp); |
706 | if (chp->ch_status & (WDCS_ERR0x01 | WDCS_DWF0x20)) |
707 | goto error; |
708 | /* FALLTHROUGH */ |
709 | |
710 | case MULTIMODE8: |
711 | multimode: |
712 | if (ata_bio->multi == 1) |
713 | goto ready; |
714 | wdccommand(chp, xfer->drive, WDCC_SETMULTI0xc6, 0, 0, 0, |
715 | ata_bio->multi, 0); |
716 | drvp->state = MULTIMODE_WAIT9; |
717 | break; |
718 | |
719 | case MULTIMODE_WAIT9: |
720 | errstring = "setmulti"; |
721 | if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, delay)((wdc_wait_for_status((chp), (0x40), (0x40), (delay)) >= 0 ) ? 0 : -1)) |
722 | goto timeout; |
723 | if (chp->wdc->cap & WDC_CAPABILITY_IRQACK0x0400) |
724 | chp->wdc->irqack(chp); |
725 | if (chp->ch_status & (WDCS_ERR0x01 | WDCS_DWF0x20)) |
726 | goto error; |
727 | /* FALLTHROUGH */ |
728 | |
729 | case READY10: |
730 | ready: |
731 | drvp->state = READY10; |
732 | /* |
733 | * The drive is usable now |
734 | */ |
735 | xfer->c_intr = wdc_ata_bio_intr; |
736 | _wdc_ata_bio_start(chp, xfer); |
737 | return 1; |
738 | } |
739 | |
740 | if ((ata_bio->flags & ATA_POLL0x0002) == 0) { |
741 | chp->ch_flags |= WDCF_IRQ_WAIT0x10; |
742 | } else { |
743 | goto again; |
744 | } |
745 | return 1; |
746 | |
747 | timeout: |
748 | if (irq && (xfer->c_flags & C_TIMEOU0x0004) == 0) { |
749 | return 0; /* IRQ was not for us */ |
750 | } |
751 | printf("%s:%d:%d: %s timed out\n", |
752 | chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive, errstring); |
753 | ata_bio->error = TIMEOUT4; |
754 | drvp->state = 0; |
755 | wdc_ata_bio_done(chp, xfer); |
756 | return 0; |
757 | error: |
758 | printf("%s:%d:%d: %s ", |
759 | chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive, |
760 | errstring); |
761 | if (chp->ch_status & WDCS_DWF0x20) { |
762 | printf("drive fault\n"); |
763 | ata_bio->error = ERR_DF2; |
764 | } else { |
765 | printf("error (%x)\n", chp->ch_error); |
766 | ata_bio->r_error = chp->ch_error; |
767 | ata_bio->error = ERROR1; |
768 | } |
769 | drvp->state = 0; |
770 | wdc_ata_bio_done(chp, xfer); |
771 | return 1; |
772 | } |
773 | |
774 | int |
775 | wdc_ata_err(struct ata_drive_datas *drvp, struct ata_bio *ata_bio) |
776 | { |
777 | struct channel_softc *chp = drvp->chnl_softc; |
778 | ata_bio->error = 0; |
779 | |
780 | if (chp->ch_status == 0xff) { |
781 | ata_bio->error = ERR_NODEV5; |
782 | return WDC_ATA_ERR0x02; |
783 | } |
784 | if (chp->ch_status & WDCS_BSY0x80) { |
785 | ata_bio->error = TIMEOUT4; |
786 | return WDC_ATA_ERR0x02; |
787 | } |
788 | |
789 | if (chp->ch_status & WDCS_DWF0x20) { |
790 | ata_bio->error = ERR_DF2; |
791 | return WDC_ATA_ERR0x02; |
792 | } |
793 | |
794 | if (chp->ch_status & WDCS_ERR0x01) { |
795 | ata_bio->error = ERROR1; |
796 | ata_bio->r_error = chp->ch_error; |
797 | if (drvp->drive_flags & DRIVE_UDMA0x0020 && |
798 | (ata_bio->r_error & WDCE_CRC0x80)) { |
799 | /* |
800 | * Record the CRC error, to avoid downgrading to |
801 | * multiword DMA |
802 | */ |
803 | drvp->drive_flags |= DRIVE_DMAERR0x0100; |
804 | } |
805 | if (ata_bio->r_error & (WDCE_BBK0x80 | WDCE_UNC0x40 | WDCE_IDNF0x10 | |
806 | WDCE_ABRT0x04 | WDCE_TK0NF0x02 | WDCE_AMNF0x01)) |
807 | return WDC_ATA_ERR0x02; |
808 | return WDC_ATA_NOERR0x00; |
809 | } |
810 | |
811 | if (chp->ch_status & WDCS_CORR0x04) |
812 | ata_bio->flags |= ATA_CORR0x0040; |
813 | return WDC_ATA_NOERR0x00; |
814 | } |
815 | |
816 | #if 0 |
817 | int |
818 | wdc_ata_addref(drvp) |
819 | struct ata_drive_datas *drvp; |
820 | { |
821 | struct channel_softc *chp = drvp->chnl_softc; |
822 | |
823 | return (wdc_addref(chp)); |
824 | } |
825 | |
826 | void |
827 | wdc_ata_delref(drvp) |
828 | struct ata_drive_datas *drvp; |
829 | { |
830 | struct channel_softc *chp = drvp->chnl_softc; |
831 | |
832 | wdc_delref(chp); |
833 | } |
834 | #endif |