Annotation of sys/arch/armish/stand/boot/wdc.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: wdc.c,v 1.2 2006/07/29 15:01:49 kettenis Exp $ */
2: /* $NetBSD: wdc.c,v 1.7 2005/12/11 12:17:06 christos Exp $ */
3:
4: /*-
5: * Copyright (c) 2003 The NetBSD Foundation, Inc.
6: * All rights reserved.
7: *
8: * This code is derived from software contributed to The NetBSD Foundation
9: * by Manuel Bouyer.
10: *
11: * Redistribution and use in source and binary forms, with or without
12: * modification, are permitted provided that the following conditions
13: * are met:
14: * 1. Redistributions of source code must retain the above copyright
15: * notice, this list of conditions and the following disclaimer.
16: * 2. Redistributions in binary form must reproduce the above copyright
17: * notice, this list of conditions and the following disclaimer in the
18: * documentation and/or other materials provided with the distribution.
19: * 3. All advertising materials mentioning features or use of this software
20: * must display the following acknowledgement:
21: * This product includes software developed by the NetBSD
22: * Foundation, Inc. and its contributors.
23: * 4. Neither the name of The NetBSD Foundation nor the names of its
24: * contributors may be used to endorse or promote products derived
25: * from this software without specific prior written permission.
26: *
27: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37: * POSSIBILITY OF SUCH DAMAGE.
38: */
39:
40: #include <sys/types.h>
41: #include <machine/param.h>
42:
43: #include "libsa.h"
44: #include "wdvar.h"
45:
46: #define WDCDELAY 100
47: #define WDCNDELAY_RST 31000 * 10
48:
49: static int wdcprobe(struct wdc_channel *chp);
50: static int wdc_wait_for_ready(struct wdc_channel *chp);
51: static int wdc_read_block(struct wd_softc *sc, struct wdc_command *wd_c);
52: static int __wdcwait_reset(struct wdc_channel *chp, int drv_mask);
53:
54: /*
55: * Reset the controller.
56: */
57: static int
58: __wdcwait_reset(chp, drv_mask)
59: struct wdc_channel *chp;
60: int drv_mask;
61: {
62: int timeout;
63: u_int8_t st0, st1;
64:
65: /* wait for BSY to deassert */
66: for (timeout = 0; timeout < WDCNDELAY_RST; timeout++) {
67: WDC_WRITE_REG(chp, wd_sdh, WDSD_IBM); /* master */
68: delay(10);
69: st0 = WDC_READ_REG(chp, wd_status);
70: WDC_WRITE_REG(chp, wd_sdh, WDSD_IBM | 0x10); /* slave */
71: delay(10);
72: st1 = WDC_READ_REG(chp, wd_status);
73:
74: if ((drv_mask & 0x01) == 0) {
75: /* no master */
76: if ((drv_mask & 0x02) != 0 && (st1 & WDCS_BSY) == 0) {
77: /* No master, slave is ready, it's done */
78: goto end;
79: }
80: } else if ((drv_mask & 0x02) == 0) {
81: /* no slave */
82: if ((drv_mask & 0x01) != 0 && (st0 & WDCS_BSY) == 0) {
83: /* No slave, master is ready, it's done */
84: goto end;
85: }
86: } else {
87: /* Wait for both master and slave to be ready */
88: if ((st0 & WDCS_BSY) == 0 && (st1 & WDCS_BSY) == 0) {
89: goto end;
90: }
91: }
92:
93: delay(WDCDELAY);
94: }
95:
96: /* Reset timed out. Maybe it's because drv_mask was not right */
97: if (st0 & WDCS_BSY)
98: drv_mask &= ~0x01;
99: if (st1 & WDCS_BSY)
100: drv_mask &= ~0x02;
101:
102: end:
103: return (drv_mask);
104: }
105:
106: /* Test to see controller with at last one attached drive is there.
107: * Returns a bit for each possible drive found (0x01 for drive 0,
108: * 0x02 for drive 1).
109: * Logic:
110: * - If a status register is at 0xff, assume there is no drive here
111: * (ISA has pull-up resistors). Similarly if the status register has
112: * the value we last wrote to the bus (for IDE interfaces without pullups).
113: * If no drive at all -> return.
114: * - reset the controller, wait for it to complete (may take up to 31s !).
115: * If timeout -> return.
116: */
117: static int
118: wdcprobe(chp)
119: struct wdc_channel *chp;
120: {
121: u_int8_t st0, st1, sc, sn, cl, ch;
122: u_int8_t ret_value = 0x03;
123: u_int8_t drive;
124: int found;
125:
126: /*
127: * Sanity check to see if the wdc channel responds at all.
128: */
129: WDC_WRITE_REG(chp, wd_sdh, WDSD_IBM);
130: delay(10);
131: st0 = WDC_READ_REG(chp, wd_status);
132: WDC_WRITE_REG(chp, wd_sdh, WDSD_IBM | 0x10);
133: delay(10);
134: st1 = WDC_READ_REG(chp, wd_status);
135:
136: if (st0 == 0xff || st0 == WDSD_IBM)
137: ret_value &= ~0x01;
138: if (st1 == 0xff || st1 == (WDSD_IBM | 0x10))
139: ret_value &= ~0x02;
140: if (ret_value == 0)
141: return (ENXIO);
142:
143: /* assert SRST, wait for reset to complete */
144: WDC_WRITE_REG(chp, wd_sdh, WDSD_IBM);
145: delay(10);
146: WDC_WRITE_CTLREG(chp, wd_aux_ctlr, WDCTL_RST | WDCTL_IDS);
147: delay(1000);
148: WDC_WRITE_CTLREG(chp, wd_aux_ctlr, WDCTL_IDS);
149: delay(1000);
150: (void) WDC_READ_REG(chp, wd_error);
151: WDC_WRITE_CTLREG(chp, wd_aux_ctlr, WDCTL_4BIT);
152: delay(10);
153:
154: ret_value = __wdcwait_reset(chp, ret_value);
155:
156: /* if reset failed, there's nothing here */
157: if (ret_value == 0)
158: return (ENXIO);
159:
160: /*
161: * Test presence of drives. First test register signatures looking for
162: * ATAPI devices. If it's not an ATAPI and reset said there may be
163: * something here assume it's ATA or OLD. Ghost will be killed later in
164: * attach routine.
165: */
166: found = 0;
167: for (drive = 0; drive < 2; drive++) {
168: if ((ret_value & (0x01 << drive)) == 0)
169: continue;
170: return (0);
171: }
172: return (ENXIO);
173: }
174:
175: /*
176: * Initialize the device.
177: */
178: int
179: wdc_init(sc, unit)
180: struct wd_softc *sc;
181: u_int unit;
182: {
183: if (pciide_init(&sc->sc_channel, unit) != 0)
184: return (ENXIO);
185: if (wdcprobe(&sc->sc_channel) != 0)
186: return (ENXIO);
187: return (0);
188: }
189:
190: /*
191: * Wait until the device is ready.
192: */
193: int
194: wdc_wait_for_ready(chp)
195: struct wdc_channel *chp;
196: {
197: u_int timeout;
198: for (timeout = WDC_TIMEOUT; timeout > 0; --timeout) {
199: if ((WDC_READ_REG(chp, wd_status) & (WDCS_BSY | WDCS_DRDY))
200: == WDCS_DRDY)
201: return (0);
202: }
203: return (ENXIO);
204: }
205:
206: /*
207: * Read one block off the device.
208: */
209: int
210: wdc_read_block(sc, wd_c)
211: struct wd_softc *sc;
212: struct wdc_command *wd_c;
213: {
214: int i;
215: struct wdc_channel *chp = &sc->sc_channel;
216: u_int16_t *ptr = (u_int16_t*)wd_c->data;
217:
218: if (ptr == NULL)
219: return (0);
220:
221: for (i = wd_c->bcount; i > 0; i -= sizeof(u_int16_t))
222: *ptr++ = WDC_READ_DATA(chp);
223:
224: return (0);
225: }
226:
227: /*
228: * Send a command to the device (CHS and LBA addressing).
229: */
230: int
231: wdccommand(wd, wd_c)
232: struct wd_softc *wd;
233: struct wdc_command *wd_c;
234: {
235: u_int8_t err;
236: struct wdc_channel *chp = &wd->sc_channel;
237:
238: #if 0
239: DPRINTF(("wdccommand(%d, %d, %d, %d, %d, %d, %d)\n",
240: wd_c->drive, wd_c->r_command, wd_c->r_cyl,
241: wd_c->r_head, wd_c->r_sector, wd_c->bcount,
242: wd_c->r_precomp));
243: #endif
244:
245: WDC_WRITE_REG(chp, wd_precomp, wd_c->r_precomp);
246: WDC_WRITE_REG(chp, wd_seccnt, wd_c->r_count);
247: WDC_WRITE_REG(chp, wd_sector, wd_c->r_sector);
248: WDC_WRITE_REG(chp, wd_cyl_lo, wd_c->r_cyl);
249: WDC_WRITE_REG(chp, wd_cyl_hi, wd_c->r_cyl >> 8);
250: WDC_WRITE_REG(chp, wd_sdh,
251: WDSD_IBM | (wd_c->drive << 4) | wd_c->r_head);
252: WDC_WRITE_REG(chp, wd_command, wd_c->r_command);
253:
254: if (wdc_wait_for_ready(chp) != 0)
255: return (ENXIO);
256:
257: if (WDC_READ_REG(chp, wd_status) & WDCS_ERR) {
258: DPRINTF(("wd%d: error %x\n", wd->sc_unit,
259: WDC_READ_REG(chp, wd_error)));
260: return (ENXIO);
261: }
262:
263: return (0);
264: }
265:
266: /*
267: * Send a command to the device (LBA48 addressing).
268: */
269: int
270: wdccommandext(wd, wd_c)
271: struct wd_softc *wd;
272: struct wdc_command *wd_c;
273: {
274: u_int8_t err;
275: struct wdc_channel *chp = &wd->sc_channel;
276:
277: /* Select drive, head, and addressing mode. */
278: WDC_WRITE_REG(chp, wd_sdh, (wd_c->drive << 4) | WDSD_LBA);
279:
280: /* previous */
281: WDC_WRITE_REG(chp, wd_features, 0);
282: WDC_WRITE_REG(chp, wd_seccnt, wd_c->r_count >> 8);
283: WDC_WRITE_REG(chp, wd_lba_hi, wd_c->r_blkno >> 40);
284: WDC_WRITE_REG(chp, wd_lba_mi, wd_c->r_blkno >> 32);
285: WDC_WRITE_REG(chp, wd_lba_lo, wd_c->r_blkno >> 24);
286:
287: /* current */
288: WDC_WRITE_REG(chp, wd_features, 0);
289: WDC_WRITE_REG(chp, wd_seccnt, wd_c->r_count);
290: WDC_WRITE_REG(chp, wd_lba_hi, wd_c->r_blkno >> 16);
291: WDC_WRITE_REG(chp, wd_lba_mi, wd_c->r_blkno >> 8);
292: WDC_WRITE_REG(chp, wd_lba_lo, wd_c->r_blkno);
293:
294: /* Send command. */
295: WDC_WRITE_REG(chp, wd_command, wd_c->r_command);
296:
297: if (wdc_wait_for_ready(chp) != 0)
298: return (ENXIO);
299:
300: if (WDC_READ_REG(chp, wd_status) & WDCS_ERR) {
301: DPRINTF(("wd%d: error %x\n", wd->sc_unit,
302: WDC_READ_REG(chp, wd_error)));
303: return (ENXIO);
304: }
305:
306: return (0);
307: }
308:
309: /*
310: * Issue 'device identify' command.
311: */
312: int
313: wdc_exec_identify(wd, data)
314: struct wd_softc *wd;
315: void *data;
316: {
317: int error;
318: struct wdc_command wd_c;
319:
320: memset(&wd_c, 0, sizeof(wd_c));
321:
322: wd_c.drive = wd->sc_drive;
323: wd_c.r_command = WDCC_IDENTIFY;
324: wd_c.bcount = DEV_BSIZE;
325: wd_c.data = data;
326:
327: if ((error = wdccommand(wd, &wd_c)) != 0)
328: return (error);
329:
330: return wdc_read_block(wd, &wd_c);
331: }
332:
333: /*
334: * Issue 'read' command.
335: */
336: int
337: wdc_exec_read(wd, cmd, blkno, data)
338: struct wd_softc *wd;
339: u_int8_t cmd;
340: daddr_t blkno;
341: void *data;
342: {
343: int error;
344: struct wdc_command wd_c;
345:
346: memset(&wd_c, 0, sizeof(wd_c));
347:
348: if (wd->sc_flags & WDF_LBA48) {
349: /* LBA48 */
350: wd_c.r_blkno = blkno;
351: } else if (wd->sc_flags & WDF_LBA) {
352: /* LBA */
353: wd_c.r_sector = (blkno >> 0) & 0xff;
354: wd_c.r_cyl = (blkno >> 8) & 0xffff;
355: wd_c.r_head = (blkno >> 24) & 0x0f;
356: wd_c.r_head |= WDSD_LBA;
357: } else {
358: /* LHS */
359: wd_c.r_sector = blkno % wd->sc_label.d_nsectors;
360: wd_c.r_sector++; /* Sectors begin with 1, not 0. */
361: blkno /= wd->sc_label.d_nsectors;
362: wd_c.r_head = blkno % wd->sc_label.d_ntracks;
363: blkno /= wd->sc_label.d_ntracks;
364: wd_c.r_cyl = blkno;
365: wd_c.r_head |= WDSD_CHS;
366: }
367:
368: wd_c.data = data;
369: wd_c.r_count = 1;
370: wd_c.drive = wd->sc_drive;
371: wd_c.r_command = cmd;
372: wd_c.bcount = wd->sc_label.d_secsize;
373:
374: if (wd->sc_flags & WDF_LBA48)
375: error = wdccommandext(wd, &wd_c);
376: else
377: error = wdccommand(wd, &wd_c);
378:
379: if (error != 0)
380: return (error);
381:
382: return wdc_read_block(wd, &wd_c);
383: }
CVSweb