1 /* $NetBSD: wdc.c,v 1.13 2010/01/19 15:28:52 tsutsui 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 * 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. 30 */ 31 32 #include <sys/types.h> 33 #include <sys/disklabel.h> 34 #include <sys/bootblock.h> 35 36 #include <lib/libsa/stand.h> 37 #include <lib/libkern/libkern.h> 38 #include <machine/param.h> 39 40 #include "boot.h" 41 #include "wdvar.h" 42 43 #define WDCDELAY 100 44 #define WDCNDELAY_RST 31000 * 10 45 46 static int wdcprobe(struct wdc_channel *chp); 47 static int wdc_wait_for_ready(struct wdc_channel *chp); 48 static int wdc_read_block(struct wd_softc *sc, struct wdc_command *wd_c); 49 static int __wdcwait_reset(struct wdc_channel *chp, int drv_mask); 50 51 /* 52 * Reset the controller. 53 */ 54 static int 55 __wdcwait_reset(struct wdc_channel *chp, int drv_mask) 56 { 57 int timeout; 58 uint8_t st0, st1; 59 60 /* wait for BSY to deassert */ 61 for (timeout = 0; timeout < WDCNDELAY_RST; timeout++) { 62 WDC_WRITE_REG(chp, wd_sdh, WDSD_IBM); /* master */ 63 delay(10); 64 st0 = WDC_READ_REG(chp, wd_status); 65 WDC_WRITE_REG(chp, wd_sdh, WDSD_IBM | 0x10); /* slave */ 66 delay(10); 67 st1 = WDC_READ_REG(chp, wd_status); 68 69 if ((drv_mask & 0x01) == 0) { 70 /* no master */ 71 if ((drv_mask & 0x02) != 0 && (st1 & WDCS_BSY) == 0) { 72 /* No master, slave is ready, it's done */ 73 goto end; 74 } 75 } else if ((drv_mask & 0x02) == 0) { 76 /* no slave */ 77 if ((drv_mask & 0x01) != 0 && (st0 & WDCS_BSY) == 0) { 78 /* No slave, master is ready, it's done */ 79 goto end; 80 } 81 } else { 82 /* Wait for both master and slave to be ready */ 83 if ((st0 & WDCS_BSY) == 0 && (st1 & WDCS_BSY) == 0) { 84 goto end; 85 } 86 } 87 88 delay(WDCDELAY); 89 } 90 91 /* Reset timed out. Maybe it's because drv_mask was not right */ 92 if (st0 & WDCS_BSY) 93 drv_mask &= ~0x01; 94 if (st1 & WDCS_BSY) 95 drv_mask &= ~0x02; 96 97 end: 98 return drv_mask; 99 } 100 101 /* Test to see controller with at last one attached drive is there. 102 * Returns a bit for each possible drive found (0x01 for drive 0, 103 * 0x02 for drive 1). 104 * Logic: 105 * - If a status register is at 0xff, assume there is no drive here 106 * (ISA has pull-up resistors). Similarly if the status register has 107 * the value we last wrote to the bus (for IDE interfaces without pullups). 108 * If no drive at all -> return. 109 * - reset the controller, wait for it to complete (may take up to 31s !). 110 * If timeout -> return. 111 */ 112 static int 113 wdcprobe(struct wdc_channel *chp) 114 { 115 uint8_t st0, st1; 116 uint8_t ret_value = 0x03; 117 uint8_t drive; 118 int found; 119 120 /* 121 * Sanity check to see if the wdc channel responds at all. 122 */ 123 WDC_WRITE_REG(chp, wd_sdh, WDSD_IBM); 124 delay(10); 125 st0 = WDC_READ_REG(chp, wd_status); 126 WDC_WRITE_REG(chp, wd_sdh, WDSD_IBM | 0x10); 127 delay(10); 128 st1 = WDC_READ_REG(chp, wd_status); 129 130 if (st0 == 0xff || st0 == WDSD_IBM) 131 ret_value &= ~0x01; 132 if (st1 == 0xff || st1 == (WDSD_IBM | 0x10)) 133 ret_value &= ~0x02; 134 if (ret_value == 0) 135 return ENXIO; 136 137 /* assert SRST, wait for reset to complete */ 138 WDC_WRITE_REG(chp, wd_sdh, WDSD_IBM); 139 delay(10); 140 WDC_WRITE_CTLREG(chp, wd_aux_ctlr, WDCTL_RST | WDCTL_IDS); 141 delay(1000); 142 WDC_WRITE_CTLREG(chp, wd_aux_ctlr, WDCTL_IDS); 143 delay(1000); 144 (void) WDC_READ_REG(chp, wd_error); 145 WDC_WRITE_CTLREG(chp, wd_aux_ctlr, WDCTL_4BIT); 146 delay(10); 147 148 ret_value = __wdcwait_reset(chp, ret_value); 149 150 /* if reset failed, there's nothing here */ 151 if (ret_value == 0) 152 return ENXIO; 153 154 /* 155 * Test presence of drives. First test register signatures looking for 156 * ATAPI devices. If it's not an ATAPI and reset said there may be 157 * something here assume it's ATA or OLD. Ghost will be killed later in 158 * attach routine. 159 */ 160 found = 0; 161 for (drive = 0; drive < 2; drive++) { 162 if ((ret_value & (0x01 << drive)) == 0) 163 continue; 164 return 0; 165 } 166 return ENXIO; 167 } 168 169 /* 170 * Initialize the device. 171 */ 172 int 173 wdc_init(struct wd_softc *sc, u_int *unit) 174 { 175 176 if (pciide_init(&sc->sc_channel, unit) != 0) 177 return ENXIO; 178 if (wdcprobe(&sc->sc_channel) != 0) 179 return ENXIO; 180 return 0; 181 } 182 183 /* 184 * Wait until the device is ready. 185 */ 186 int 187 wdc_wait_for_ready(struct wdc_channel *chp) 188 { 189 u_int timeout; 190 191 for (timeout = WDC_TIMEOUT; timeout > 0; --timeout) { 192 if ((WDC_READ_REG(chp, wd_status) & (WDCS_BSY | WDCS_DRDY)) 193 == WDCS_DRDY) 194 return 0; 195 } 196 return ENXIO; 197 } 198 199 /* 200 * Read one block off the device. 201 */ 202 int 203 wdc_read_block(struct wd_softc *sc, struct wdc_command *wd_c) 204 { 205 int i; 206 struct wdc_channel *chp = &sc->sc_channel; 207 uint16_t *ptr = (uint16_t *)wd_c->data; 208 209 if (ptr == NULL) 210 return 0; 211 212 for (i = wd_c->bcount; i > 0; i -= sizeof(uint16_t)) 213 *ptr++ = WDC_READ_DATA(chp); 214 215 return 0; 216 } 217 218 /* 219 * Send a command to the device (CHS and LBA addressing). 220 */ 221 int 222 wdccommand(struct wd_softc *sc, struct wdc_command *wd_c) 223 { 224 struct wdc_channel *chp = &sc->sc_channel; 225 226 #if 0 227 DPRINTF(("wdccommand(%d, %d, %d, %d, %d, %d, %d)\n", 228 wd_c->drive, wd_c->r_command, wd_c->r_cyl, 229 wd_c->r_head, wd_c->r_sector, wd_c->bcount, 230 wd_c->r_precomp)); 231 #endif 232 233 WDC_WRITE_REG(chp, wd_features, wd_c->r_features); 234 WDC_WRITE_REG(chp, wd_seccnt, wd_c->r_count); 235 WDC_WRITE_REG(chp, wd_sector, wd_c->r_sector); 236 WDC_WRITE_REG(chp, wd_cyl_lo, wd_c->r_cyl); 237 WDC_WRITE_REG(chp, wd_cyl_hi, wd_c->r_cyl >> 8); 238 WDC_WRITE_REG(chp, wd_sdh, 239 WDSD_IBM | (wd_c->drive << 4) | wd_c->r_head); 240 WDC_WRITE_REG(chp, wd_command, wd_c->r_command); 241 242 if (wdc_wait_for_ready(chp) != 0) 243 return ENXIO; 244 245 if (WDC_READ_REG(chp, wd_status) & WDCS_ERR) { 246 printf("wd%d: error %x\n", chp->compatchan, 247 WDC_READ_REG(chp, wd_error)); 248 return ENXIO; 249 } 250 251 return 0; 252 } 253 254 /* 255 * Send a command to the device (LBA48 addressing). 256 */ 257 int 258 wdccommandext(struct wd_softc *wd, struct wdc_command *wd_c) 259 { 260 struct wdc_channel *chp = &wd->sc_channel; 261 262 #if 0 263 DPRINTF(("%s(%d, %x, %" PRId64 ", %d)\n", __func__, 264 wd_c->drive, wd_c->r_command, 265 wd_c->r_blkno, wd_c->r_count)); 266 #endif 267 268 /* Select drive, head, and addressing mode. */ 269 WDC_WRITE_REG(chp, wd_sdh, (wd_c->drive << 4) | WDSD_LBA); 270 271 /* previous */ 272 WDC_WRITE_REG(chp, wd_features, 0); 273 WDC_WRITE_REG(chp, wd_seccnt, wd_c->r_count >> 8); 274 WDC_WRITE_REG(chp, wd_lba_hi, wd_c->r_blkno >> 40); 275 WDC_WRITE_REG(chp, wd_lba_mi, wd_c->r_blkno >> 32); 276 WDC_WRITE_REG(chp, wd_lba_lo, wd_c->r_blkno >> 24); 277 278 /* current */ 279 WDC_WRITE_REG(chp, wd_features, 0); 280 WDC_WRITE_REG(chp, wd_seccnt, wd_c->r_count); 281 WDC_WRITE_REG(chp, wd_lba_hi, wd_c->r_blkno >> 16); 282 WDC_WRITE_REG(chp, wd_lba_mi, wd_c->r_blkno >> 8); 283 WDC_WRITE_REG(chp, wd_lba_lo, wd_c->r_blkno); 284 285 /* Send command. */ 286 WDC_WRITE_REG(chp, wd_command, wd_c->r_command); 287 288 if (wdc_wait_for_ready(chp) != 0) 289 return ENXIO; 290 291 if (WDC_READ_REG(chp, wd_status) & WDCS_ERR) { 292 printf("wd%d: error %x\n", chp->compatchan, 293 WDC_READ_REG(chp, wd_error)); 294 return ENXIO; 295 } 296 297 return 0; 298 } 299 300 /* 301 * Issue 'device identify' command. 302 */ 303 int 304 wdc_exec_identify(struct wd_softc *wd, void *data) 305 { 306 int error; 307 struct wdc_command wd_c; 308 309 memset(&wd_c, 0, sizeof(wd_c)); 310 311 wd_c.drive = wd->sc_unit; 312 wd_c.r_command = WDCC_IDENTIFY; 313 wd_c.bcount = DEV_BSIZE; 314 wd_c.data = data; 315 316 if ((error = wdccommand(wd, &wd_c)) != 0) 317 return error; 318 319 return wdc_read_block(wd, &wd_c); 320 } 321 322 /* 323 * Issue 'read' command. 324 */ 325 int 326 wdc_exec_read(struct wd_softc *wd, uint8_t cmd, daddr_t blkno, void *data) 327 { 328 int error; 329 struct wdc_command wd_c; 330 bool lba, lba48; 331 332 memset(&wd_c, 0, sizeof(wd_c)); 333 lba = false; 334 lba48 = false; 335 336 wd_c.data = data; 337 wd_c.r_count = 1; 338 wd_c.r_features = 0; 339 wd_c.drive = wd->sc_unit; 340 wd_c.bcount = wd->sc_label.d_secsize; 341 342 if ((wd->sc_flags & WDF_LBA48) != 0 && blkno > wd->sc_capacity28) 343 lba48 = true; 344 else if ((wd->sc_flags & WDF_LBA) != 0) 345 lba = true; 346 347 if (lba48) { 348 /* LBA48 */ 349 wd_c.r_command = atacmd_to48(cmd); 350 wd_c.r_blkno = blkno; 351 } else if (lba) { 352 /* LBA */ 353 wd_c.r_command = cmd; 354 wd_c.r_sector = (blkno >> 0) & 0xff; 355 wd_c.r_cyl = (blkno >> 8) & 0xffff; 356 wd_c.r_head = (blkno >> 24) & 0x0f; 357 wd_c.r_head |= WDSD_LBA; 358 } else { 359 /* CHS */ 360 wd_c.r_command = cmd; 361 wd_c.r_sector = blkno % wd->sc_label.d_nsectors; 362 wd_c.r_sector++; /* Sectors begin with 1, not 0. */ 363 blkno /= wd->sc_label.d_nsectors; 364 wd_c.r_head = blkno % wd->sc_label.d_ntracks; 365 blkno /= wd->sc_label.d_ntracks; 366 wd_c.r_cyl = blkno; 367 wd_c.r_head |= WDSD_CHS; 368 } 369 370 if (lba48) 371 error = wdccommandext(wd, &wd_c); 372 else 373 error = wdccommand(wd, &wd_c); 374 375 if (error != 0) 376 return error; 377 378 return wdc_read_block(wd, &wd_c); 379 } 380