1 /* $NetBSD: wdc.c,v 1.1 2010/10/14 06:50:43 kiyohara 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 __wdcwait_reset(struct wdc_channel *, int); 47 static char *mkident(uint8_t *, int); 48 static int wdcprobe(struct wdc_channel *); 49 static int wdc_wait_for_ready(struct wdc_channel *); 50 static int wdc_read_block(struct wdc_channel *, struct wdc_command *); 51 static int wdccommand(struct wdc_channel *, struct wdc_command *); 52 static int wdccommandext(struct wdc_channel *, struct wdc_command *); 53 static int _wdc_exec_identify(struct wdc_channel *, int, void *); 54 55 static struct wdc_channel ch; 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 static char * 108 mkident(uint8_t *src, int len) 109 { 110 static char local[40]; 111 uint8_t *end; 112 char *dst, *last; 113 114 if (len > sizeof(local)) 115 len = sizeof(local); 116 dst = last = local; 117 end = src + len - 1; 118 119 /* reserve space for '\0' */ 120 if (len < 2) 121 goto out; 122 /* skip leading white space */ 123 while (*src != '\0' && src < end && *src == ' ') 124 ++src; 125 /* copy string, omitting trailing white space */ 126 while (*src != '\0' && src < end) { 127 *dst++ = *src; 128 if (*src++ != ' ') 129 last = dst; 130 } 131 out: 132 *last = '\0'; 133 return local; 134 } 135 136 /* Test to see controller with at last one attached drive is there. 137 * Returns a bit for each possible drive found (0x01 for drive 0, 138 * 0x02 for drive 1). 139 * Logic: 140 * - If a status register is at 0xff, assume there is no drive here 141 * (ISA has pull-up resistors). Similarly if the status register has 142 * the value we last wrote to the bus (for IDE interfaces without pullups). 143 * If no drive at all -> return. 144 * - reset the controller, wait for it to complete (may take up to 31s !). 145 * If timeout -> return. 146 */ 147 static int 148 wdcprobe(struct wdc_channel *chp) 149 { 150 uint8_t st0, st1; 151 uint8_t drives = 0x03; 152 uint8_t drive, cl, ch; 153 uint8_t ident[DEV_BSIZE]; 154 155 /* 156 * Sanity check to see if the wdc channel responds at all. 157 */ 158 WDC_WRITE_REG(chp, wd_sdh, WDSD_IBM); 159 delay(10); 160 st0 = WDC_READ_REG(chp, wd_status); 161 WDC_WRITE_REG(chp, wd_sdh, WDSD_IBM | 0x10); 162 delay(10); 163 st1 = WDC_READ_REG(chp, wd_status); 164 165 if (st0 == 0xff || st0 == WDSD_IBM) 166 drives &= ~0x01; 167 if (st1 == 0xff || st1 == (WDSD_IBM | 0x10)) 168 drives &= ~0x02; 169 if (drives == 0) 170 return 0; 171 172 if (!(st0 & WDCS_DRDY)) 173 drives &= ~0x01; 174 if (!(st1 & WDCS_DRDY)) 175 drives &= ~0x02; 176 if (drives == 0) 177 return 0; 178 179 /* assert SRST, wait for reset to complete */ 180 WDC_WRITE_REG(chp, wd_sdh, WDSD_IBM); 181 delay(10); 182 WDC_WRITE_CTLREG(chp, wd_aux_ctlr, WDCTL_RST | WDCTL_IDS); 183 delay(1000); 184 WDC_WRITE_CTLREG(chp, wd_aux_ctlr, WDCTL_IDS); 185 delay(1000); 186 (void) WDC_READ_REG(chp, wd_error); 187 WDC_WRITE_CTLREG(chp, wd_aux_ctlr, WDCTL_4BIT); 188 delay(10); 189 190 drives = __wdcwait_reset(chp, drives); 191 192 /* if reset failed, there's nothing here */ 193 if (drives == 0) 194 return 0; 195 196 /* 197 * Test presence of drives. First test register signatures looking for 198 * ATAPI devices. If it's not an ATAPI and reset said there may be 199 * something here assume it's ATA or OLD. Ghost will be killed later in 200 * attach routine. 201 */ 202 for (drive = 0; drive < 2; drive++) { 203 if ((drives & (1 << drive)) == 0) 204 continue; 205 206 /* 207 * ATAPI device not support... 208 */ 209 WDC_WRITE_REG(chp, wd_sdh, WDSD_IBM | (drive << 4)); 210 cl = WDC_READ_REG(chp, wd_cyl_lo); 211 ch = WDC_READ_REG(chp, wd_cyl_hi); 212 if (cl == 0x14 && ch == 0xeb) { 213 drives &= ~(1 << drive); 214 continue; 215 } 216 217 if (_wdc_exec_identify(chp, drive, ident) == 0) { 218 struct ataparams *prms = (struct ataparams *)ident; 219 char *model; 220 221 model = 222 mkident(prms->atap_model, sizeof(prms->atap_model)); 223 printf("/dev/disk/ide/0/%s/0: <%s>\n", 224 (drive == 0) ? "master" : "slave", model); 225 } else 226 printf("/dev/disk/ide/0/%s/0: identify failed\n", 227 (drive == 0) ? "master" : "slave"); 228 } 229 return drives; 230 } 231 232 /* 233 * Wait until the device is ready. 234 */ 235 int 236 wdc_wait_for_ready(struct wdc_channel *chp) 237 { 238 u_int timeout; 239 240 for (timeout = WDC_TIMEOUT; timeout > 0; --timeout) { 241 if ((WDC_READ_REG(chp, wd_status) & (WDCS_BSY | WDCS_DRDY)) 242 == WDCS_DRDY) 243 return 0; 244 } 245 return ENXIO; 246 } 247 248 /* 249 * Read one block off the device. 250 */ 251 int 252 wdc_read_block(struct wdc_channel *chp, struct wdc_command *wd_c) 253 { 254 int i; 255 uint16_t *ptr = (uint16_t *)wd_c->data; 256 257 if (ptr == NULL) 258 return EIO; 259 260 if (wd_c->r_command == WDCC_IDENTIFY) 261 for (i = wd_c->bcount; i > 0; i -= sizeof(uint16_t)) 262 *ptr++ = WDC_READ_DATA(chp); 263 else 264 for (i = wd_c->bcount; i > 0; i -= sizeof(uint16_t)) 265 *ptr++ = WDC_READ_DATA_STREAM(chp); 266 267 return 0; 268 } 269 270 /* 271 * Send a command to the device (CHS and LBA addressing). 272 */ 273 int 274 wdccommand(struct wdc_channel *chp, struct wdc_command *wd_c) 275 { 276 277 #if 0 278 DPRINTF(("wdccommand(%d, %d, %d, %d, %d, %d)\n", 279 wd_c->drive, wd_c->r_command, wd_c->r_cyl, 280 wd_c->r_head, wd_c->r_sector, wd_c->bcount)); 281 #endif 282 283 WDC_WRITE_REG(chp, wd_features, wd_c->r_features); 284 WDC_WRITE_REG(chp, wd_seccnt, wd_c->r_count); 285 WDC_WRITE_REG(chp, wd_sector, wd_c->r_sector); 286 WDC_WRITE_REG(chp, wd_cyl_lo, wd_c->r_cyl); 287 WDC_WRITE_REG(chp, wd_cyl_hi, wd_c->r_cyl >> 8); 288 WDC_WRITE_REG(chp, wd_sdh, 289 WDSD_IBM | (wd_c->drive << 4) | wd_c->r_head); 290 WDC_WRITE_REG(chp, wd_command, wd_c->r_command); 291 292 if (wdc_wait_for_ready(chp) != 0) 293 return ENXIO; 294 295 if (WDC_READ_REG(chp, wd_status) & WDCS_ERR) { 296 printf("/dev/disk/ide/0/%s/0: error %x\n", 297 (wd_c->drive == 0) ? "master" : "slave", 298 WDC_READ_REG(chp, wd_error)); 299 return ENXIO; 300 } 301 302 return 0; 303 } 304 305 /* 306 * Send a command to the device (LBA48 addressing). 307 */ 308 int 309 wdccommandext(struct wdc_channel *chp, struct wdc_command *wd_c) 310 { 311 312 #if 0 313 DPRINTF(("%s(%d, %x, %" PRId64 ", %d)\n", __func__, 314 wd_c->drive, wd_c->r_command, 315 wd_c->r_blkno, wd_c->r_count)); 316 #endif 317 318 /* Select drive, head, and addressing mode. */ 319 WDC_WRITE_REG(chp, wd_sdh, (wd_c->drive << 4) | WDSD_LBA); 320 321 /* previous */ 322 WDC_WRITE_REG(chp, wd_features, 0); 323 WDC_WRITE_REG(chp, wd_seccnt, wd_c->r_count >> 8); 324 WDC_WRITE_REG(chp, wd_lba_hi, wd_c->r_blkno >> 40); 325 WDC_WRITE_REG(chp, wd_lba_mi, wd_c->r_blkno >> 32); 326 WDC_WRITE_REG(chp, wd_lba_lo, wd_c->r_blkno >> 24); 327 328 /* current */ 329 WDC_WRITE_REG(chp, wd_features, 0); 330 WDC_WRITE_REG(chp, wd_seccnt, wd_c->r_count); 331 WDC_WRITE_REG(chp, wd_lba_hi, wd_c->r_blkno >> 16); 332 WDC_WRITE_REG(chp, wd_lba_mi, wd_c->r_blkno >> 8); 333 WDC_WRITE_REG(chp, wd_lba_lo, wd_c->r_blkno); 334 335 /* Send command. */ 336 WDC_WRITE_REG(chp, wd_command, wd_c->r_command); 337 338 if (wdc_wait_for_ready(chp) != 0) 339 return ENXIO; 340 341 if (WDC_READ_REG(chp, wd_status) & WDCS_ERR) { 342 printf("/dev/disk/ide/0/%s/0: error %x\n", 343 (wd_c->drive == 0) ? "master" : "slave", 344 WDC_READ_REG(chp, wd_error)); 345 return ENXIO; 346 } 347 348 return 0; 349 } 350 351 static int 352 _wdc_exec_identify(struct wdc_channel *chp, int drive, void *data) 353 { 354 struct wdc_command wd_c; 355 int error; 356 357 memset(&wd_c, 0, sizeof(wd_c)); 358 359 wd_c.drive = drive; 360 wd_c.r_command = WDCC_IDENTIFY; 361 wd_c.bcount = DEV_BSIZE; 362 wd_c.data = data; 363 364 if ((error = wdccommand(chp, &wd_c)) != 0) 365 return error; 366 367 return wdc_read_block(chp, &wd_c); 368 } 369 370 /* 371 * Initialize the device. 372 */ 373 int 374 wdc_init(int addr) 375 { 376 struct wdc_channel tmp; 377 int i; 378 379 memset(&ch, 0, sizeof(ch)); 380 381 /* set up cmd/ctl regsiters */ 382 tmp.c_cmdbase = addr; 383 #define WDC_ISA_AUXREG_OFFSET 0x206 384 tmp.c_ctlbase = addr + WDC_ISA_AUXREG_OFFSET; 385 tmp.c_data = addr + wd_data; 386 for (i = 0; i < WDC_NPORTS; i++) 387 tmp.c_cmdreg[i] = tmp.c_cmdbase + i; 388 /* set up shadow registers */ 389 tmp.c_cmdreg[wd_status] = tmp.c_cmdreg[wd_command]; 390 tmp.c_cmdreg[wd_features] = tmp.c_cmdreg[wd_precomp]; 391 392 if (wdcprobe(&tmp) == 0) 393 return ENXIO; 394 ch = tmp; 395 return 0; 396 } 397 398 /* 399 * Issue 'device identify' command. 400 */ 401 int 402 wdc_exec_identify(struct wd_softc *wd, void *data) 403 { 404 struct wdc_channel *chp; 405 406 if (wd->sc_ctlr != 0) 407 return ENOTSUP; 408 if (ch.c_cmdbase == 0) 409 return ENOENT; 410 chp = &ch; 411 412 return _wdc_exec_identify(chp, wd->sc_unit, data); 413 } 414 415 /* 416 * Issue 'read' command. 417 */ 418 int 419 wdc_exec_read(struct wd_softc *wd, uint8_t cmd, daddr_t blkno, void *data) 420 { 421 struct wdc_command wd_c; 422 struct wdc_channel *chp; 423 int error; 424 bool lba, lba48; 425 426 if (wd->sc_ctlr != 0) 427 return ENOTSUP; 428 if (ch.c_cmdbase == 0) 429 return ENOENT; 430 chp = &ch; 431 432 memset(&wd_c, 0, sizeof(wd_c)); 433 lba = false; 434 lba48 = false; 435 436 wd_c.data = data; 437 wd_c.r_count = 1; 438 wd_c.r_features = 0; 439 wd_c.drive = wd->sc_unit; 440 wd_c.bcount = wd->sc_label.d_secsize; 441 442 if ((wd->sc_flags & WDF_LBA48) != 0 && blkno > wd->sc_capacity28) 443 lba48 = true; 444 else if ((wd->sc_flags & WDF_LBA) != 0) 445 lba = true; 446 447 if (lba48) { 448 /* LBA48 */ 449 wd_c.r_command = atacmd_to48(cmd); 450 wd_c.r_blkno = blkno; 451 } else if (lba) { 452 /* LBA */ 453 wd_c.r_command = cmd; 454 wd_c.r_sector = (blkno >> 0) & 0xff; 455 wd_c.r_cyl = (blkno >> 8) & 0xffff; 456 wd_c.r_head = (blkno >> 24) & 0x0f; 457 wd_c.r_head |= WDSD_LBA; 458 } else { 459 /* CHS */ 460 wd_c.r_command = cmd; 461 wd_c.r_sector = blkno % wd->sc_label.d_nsectors; 462 wd_c.r_sector++; /* Sectors begin with 1, not 0. */ 463 blkno /= wd->sc_label.d_nsectors; 464 wd_c.r_head = blkno % wd->sc_label.d_ntracks; 465 blkno /= wd->sc_label.d_ntracks; 466 wd_c.r_cyl = blkno; 467 wd_c.r_head |= WDSD_CHS; 468 } 469 470 if (lba48) 471 error = wdccommandext(chp, &wd_c); 472 else 473 error = wdccommand(chp, &wd_c); 474 475 if (error != 0) 476 return error; 477 478 return wdc_read_block(chp, &wd_c); 479 } 480