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