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