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