1 /* $NetBSD: wdc.c,v 1.10 2008/03/02 06:17:41 tsutsui Exp $ */
4 * Copyright (c) 2003 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/types.h>
33 #include <sys/disklabel.h>
34 #include <sys/bootblock.h>
36 #include <lib/libsa/stand.h>
37 #include <machine/param.h>
43 #define WDCNDELAY_RST 31000 * 10
45 static int wdcprobe(struct wdc_channel
*chp
);
46 static int wdc_wait_for_ready(struct wdc_channel
*chp
);
47 static int wdc_read_block(struct wd_softc
*sc
, struct wdc_command
*wd_c
);
48 static int __wdcwait_reset(struct wdc_channel
*chp
, int drv_mask
);
51 * Reset the controller.
54 __wdcwait_reset(struct wdc_channel
*chp
, int drv_mask
)
59 /* wait for BSY to deassert */
60 for (timeout
= 0; timeout
< WDCNDELAY_RST
; timeout
++) {
61 WDC_WRITE_REG(chp
, wd_sdh
, WDSD_IBM
); /* master */
63 st0
= WDC_READ_REG(chp
, wd_status
);
64 WDC_WRITE_REG(chp
, wd_sdh
, WDSD_IBM
| 0x10); /* slave */
66 st1
= WDC_READ_REG(chp
, wd_status
);
68 if ((drv_mask
& 0x01) == 0) {
70 if ((drv_mask
& 0x02) != 0 && (st1
& WDCS_BSY
) == 0) {
71 /* No master, slave is ready, it's done */
74 } else if ((drv_mask
& 0x02) == 0) {
76 if ((drv_mask
& 0x01) != 0 && (st0
& WDCS_BSY
) == 0) {
77 /* No slave, master is ready, it's done */
81 /* Wait for both master and slave to be ready */
82 if ((st0
& WDCS_BSY
) == 0 && (st1
& WDCS_BSY
) == 0) {
90 /* Reset timed out. Maybe it's because drv_mask was not right */
100 /* Test to see controller with at last one attached drive is there.
101 * Returns a bit for each possible drive found (0x01 for drive 0,
104 * - If a status register is at 0xff, assume there is no drive here
105 * (ISA has pull-up resistors). Similarly if the status register has
106 * the value we last wrote to the bus (for IDE interfaces without pullups).
107 * If no drive at all -> return.
108 * - reset the controller, wait for it to complete (may take up to 31s !).
109 * If timeout -> return.
112 wdcprobe(struct wdc_channel
*chp
)
115 uint8_t ret_value
= 0x03;
120 * Sanity check to see if the wdc channel responds at all.
122 WDC_WRITE_REG(chp
, wd_sdh
, WDSD_IBM
);
124 st0
= WDC_READ_REG(chp
, wd_status
);
125 WDC_WRITE_REG(chp
, wd_sdh
, WDSD_IBM
| 0x10);
127 st1
= WDC_READ_REG(chp
, wd_status
);
129 if (st0
== 0xff || st0
== WDSD_IBM
)
131 if (st1
== 0xff || st1
== (WDSD_IBM
| 0x10))
136 /* assert SRST, wait for reset to complete */
137 WDC_WRITE_REG(chp
, wd_sdh
, WDSD_IBM
);
139 WDC_WRITE_CTLREG(chp
, wd_aux_ctlr
, WDCTL_RST
| WDCTL_IDS
);
141 WDC_WRITE_CTLREG(chp
, wd_aux_ctlr
, WDCTL_IDS
);
143 (void) WDC_READ_REG(chp
, wd_error
);
144 WDC_WRITE_CTLREG(chp
, wd_aux_ctlr
, WDCTL_4BIT
);
147 ret_value
= __wdcwait_reset(chp
, ret_value
);
149 /* if reset failed, there's nothing here */
154 * Test presence of drives. First test register signatures looking for
155 * ATAPI devices. If it's not an ATAPI and reset said there may be
156 * something here assume it's ATA or OLD. Ghost will be killed later in
160 for (drive
= 0; drive
< 2; drive
++) {
161 if ((ret_value
& (0x01 << drive
)) == 0)
169 * Initialize the device.
172 wdc_init(struct wd_softc
*sc
, u_int
*unit
)
175 if (pciide_init(&sc
->sc_channel
, unit
) != 0)
177 if (wdcprobe(&sc
->sc_channel
) != 0)
183 * Wait until the device is ready.
186 wdc_wait_for_ready(struct wdc_channel
*chp
)
190 for (timeout
= WDC_TIMEOUT
; timeout
> 0; --timeout
) {
191 if ((WDC_READ_REG(chp
, wd_status
) & (WDCS_BSY
| WDCS_DRDY
))
199 * Read one block off the device.
202 wdc_read_block(struct wd_softc
*sc
, struct wdc_command
*wd_c
)
205 struct wdc_channel
*chp
= &sc
->sc_channel
;
206 uint16_t *ptr
= (uint16_t *)wd_c
->data
;
211 for (i
= wd_c
->bcount
; i
> 0; i
-= sizeof(uint16_t))
212 *ptr
++ = WDC_READ_DATA(chp
);
218 * Send a command to the device (CHS and LBA addressing).
221 wdccommand(struct wd_softc
*sc
, struct wdc_command
*wd_c
)
223 struct wdc_channel
*chp
= &sc
->sc_channel
;
226 DPRINTF(("wdccommand(%d, %d, %d, %d, %d, %d, %d)\n",
227 wd_c
->drive
, wd_c
->r_command
, wd_c
->r_cyl
,
228 wd_c
->r_head
, wd_c
->r_sector
, wd_c
->bcount
,
232 WDC_WRITE_REG(chp
, wd_precomp
, wd_c
->r_precomp
);
233 WDC_WRITE_REG(chp
, wd_seccnt
, wd_c
->r_count
);
234 WDC_WRITE_REG(chp
, wd_sector
, wd_c
->r_sector
);
235 WDC_WRITE_REG(chp
, wd_cyl_lo
, wd_c
->r_cyl
);
236 WDC_WRITE_REG(chp
, wd_cyl_hi
, wd_c
->r_cyl
>> 8);
237 WDC_WRITE_REG(chp
, wd_sdh
,
238 WDSD_IBM
| (wd_c
->drive
<< 4) | wd_c
->r_head
);
239 WDC_WRITE_REG(chp
, wd_command
, wd_c
->r_command
);
241 if (wdc_wait_for_ready(chp
) != 0)
244 if (WDC_READ_REG(chp
, wd_status
) & WDCS_ERR
) {
245 printf("wd%d: error %x\n", chp
->compatchan
,
246 WDC_READ_REG(chp
, wd_error
));
254 * Send a command to the device (LBA48 addressing).
257 wdccommandext(struct wd_softc
*wd
, struct wdc_command
*wd_c
)
259 struct wdc_channel
*chp
= &wd
->sc_channel
;
261 /* Select drive, head, and addressing mode. */
262 WDC_WRITE_REG(chp
, wd_sdh
, (wd_c
->drive
<< 4) | WDSD_LBA
);
265 WDC_WRITE_REG(chp
, wd_features
, 0);
266 WDC_WRITE_REG(chp
, wd_seccnt
, wd_c
->r_count
>> 8);
267 WDC_WRITE_REG(chp
, wd_lba_hi
, wd_c
->r_blkno
>> 40);
268 WDC_WRITE_REG(chp
, wd_lba_mi
, wd_c
->r_blkno
>> 32);
269 WDC_WRITE_REG(chp
, wd_lba_lo
, wd_c
->r_blkno
>> 24);
272 WDC_WRITE_REG(chp
, wd_features
, 0);
273 WDC_WRITE_REG(chp
, wd_seccnt
, wd_c
->r_count
);
274 WDC_WRITE_REG(chp
, wd_lba_hi
, wd_c
->r_blkno
>> 16);
275 WDC_WRITE_REG(chp
, wd_lba_mi
, wd_c
->r_blkno
>> 8);
276 WDC_WRITE_REG(chp
, wd_lba_lo
, wd_c
->r_blkno
);
279 WDC_WRITE_REG(chp
, wd_command
, wd_c
->r_command
);
281 if (wdc_wait_for_ready(chp
) != 0)
284 if (WDC_READ_REG(chp
, wd_status
) & WDCS_ERR
) {
285 printf("wd%d: error %x\n", chp
->compatchan
,
286 WDC_READ_REG(chp
, wd_error
));
294 * Issue 'device identify' command.
297 wdc_exec_identify(struct wd_softc
*wd
, void *data
)
300 struct wdc_command wd_c
;
302 memset(&wd_c
, 0, sizeof(wd_c
));
304 wd_c
.drive
= wd
->sc_unit
;
305 wd_c
.r_command
= WDCC_IDENTIFY
;
306 wd_c
.bcount
= DEV_BSIZE
;
309 if ((error
= wdccommand(wd
, &wd_c
)) != 0)
312 return wdc_read_block(wd
, &wd_c
);
316 * Issue 'read' command.
319 wdc_exec_read(struct wd_softc
*wd
, uint8_t cmd
, daddr_t blkno
, void *data
)
322 struct wdc_command wd_c
;
324 memset(&wd_c
, 0, sizeof(wd_c
));
326 if (wd
->sc_flags
& WDF_LBA48
) {
328 wd_c
.r_blkno
= blkno
;
329 } else if (wd
->sc_flags
& WDF_LBA
) {
331 wd_c
.r_sector
= (blkno
>> 0) & 0xff;
332 wd_c
.r_cyl
= (blkno
>> 8) & 0xffff;
333 wd_c
.r_head
= (blkno
>> 24) & 0x0f;
334 wd_c
.r_head
|= WDSD_LBA
;
337 wd_c
.r_sector
= blkno
% wd
->sc_label
.d_nsectors
;
338 wd_c
.r_sector
++; /* Sectors begin with 1, not 0. */
339 blkno
/= wd
->sc_label
.d_nsectors
;
340 wd_c
.r_head
= blkno
% wd
->sc_label
.d_ntracks
;
341 blkno
/= wd
->sc_label
.d_ntracks
;
343 wd_c
.r_head
|= WDSD_CHS
;
348 wd_c
.drive
= wd
->sc_unit
;
349 wd_c
.r_command
= cmd
;
350 wd_c
.bcount
= wd
->sc_label
.d_secsize
;
352 if (wd
->sc_flags
& WDF_LBA48
)
353 error
= wdccommandext(wd
, &wd_c
);
355 error
= wdccommand(wd
, &wd_c
);
360 return wdc_read_block(wd
, &wd_c
);