1 /* $NetBSD: hdc9224.c,v 1.2 1996/08/27 21:58:43 cgd Exp $ */ 2 /* 3 * Copyright (c) 1996 Ludd, University of Lule}, Sweden. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to Ludd by Bertram Barth. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed at Ludd, University of 19 * Lule}, Sweden and its contributors. 20 * 4. The name of the author may not be used to endorse or promote products 21 * derived from this software without specific prior written permission 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 /* 36 * with much help from (in alphabetical order): 37 * Jeremy 38 * Roger Ivie 39 * Rick Macklem 40 * Mike Young 41 */ 42 43 /* #define DEBUG /* */ 44 /* #define TRACE /* */ 45 static int haveLock = 0; 46 static int keepLock = 0; 47 48 #define F_READ 11 49 #define F_WRITE 12 50 51 #define trace(x) 52 #define debug(x) 53 54 #include "hdc.h" 55 #if NHDC > 0 56 57 #include <sys/param.h> 58 #include <sys/systm.h> 59 #include <sys/kernel.h> 60 #include <sys/conf.h> 61 #include <sys/file.h> 62 #include <sys/stat.h> 63 #include <sys/ioctl.h> 64 #include <sys/buf.h> 65 #include <sys/proc.h> 66 #include <sys/user.h> 67 #include <sys/map.h> 68 #include <sys/device.h> 69 #include <sys/dkstat.h> 70 #include <sys/disklabel.h> 71 #include <sys/disk.h> 72 #include <sys/syslog.h> 73 74 #include <machine/pte.h> 75 #include <machine/sid.h> 76 #include <machine/cpu.h> 77 #include <machine/uvax.h> 78 #include <machine/ka410.h> 79 #include <machine/vsbus.h> 80 81 #include <vax/vsa/hdc9224.h> 82 83 84 /* 85 * some definitions 86 */ 87 #define CTLRNAME "hdc" 88 #define UNITNAME "rd" 89 #define HDC_PRI LOG_INFO 90 91 /* Bits in minor device */ 92 #define HDCUNIT(dev) DISKUNIT(dev) 93 #define HDCPART(dev) DISKPART(dev) 94 #define HDCCTLR(dev) 0 95 #define HDCLABELDEV(dev) (MAKEDISKDEV(major(dev),HDCUNIT(dev),RAW_PART)) 96 97 #define MAX_WAIT (1000*1000) /* # of loop-instructions in seconds */ 98 99 100 /* 101 * on-disk geometry block 102 */ 103 #define _aP __attribute__ ((packed)) /* force byte-alignment */ 104 struct rdgeom { 105 char mbz[10]; /* 10 bytes of zero */ 106 long xbn_count _aP; /* number of XBNs */ 107 long dbn_count _aP; /* number of DBNs */ 108 long lbn_count _aP; /* number of LBNs (Logical-Block-Numbers) */ 109 long rbn_count _aP; /* number of RBNs (Replacement-Block-Numbers) */ 110 short nspt; /* number of sectors per track */ 111 short ntracks; /* number of tracks */ 112 short ncylinders; /* number of cylinders */ 113 short precomp; /* first cylinder for write precompensation */ 114 short reduced; /* first cylinder for reduced write current */ 115 short seek_rate; /* seek rate or zero for buffered seeks */ 116 short crc_eec; /* 0 if CRC is being used or 1 if ECC is being used */ 117 short rct; /* "replacement control table" (RCT) */ 118 short rct_ncopies; /* number of copies of the RCT */ 119 long media_id _aP; /* media identifier */ 120 short interleave; /* sector-to-sector interleave */ 121 short headskew; /* head-to-head skew */ 122 short cylskew; /* cylinder-to-cylinder skew */ 123 short gap0_size; /* size of GAP 0 in the MFM format */ 124 short gap1_size; /* size of GAP 1 in the MFM format */ 125 short gap2_size; /* size of GAP 2 in the MFM format */ 126 short gap3_size; /* size of GAP 3 in the MFM format */ 127 short sync_value; /* sync value used to start a track when formatting */ 128 char reserved[32]; /* reserved for use by the RQDX1/2/3 formatter */ 129 short serial_number; /* serial number */ 130 #if 0 /* we don't need these 412 useless bytes ... */ 131 char fill[412-2]; /* Filler bytes to the end of the block */ 132 short checksum; /* checksum over the XBN */ 133 #endif 134 }; 135 136 /* 137 * Software status 138 */ 139 struct rdsoftc { 140 struct device sc_dev; /* must be here! (pseudo-OOP:) */ 141 struct disk sc_dk; /* disklabel etc. */ 142 struct rdgeom sc_xbn; /* on-disk geometry information */ 143 struct rdparams { 144 u_short cylinders; /* number of cylinders */ 145 u_char heads; /* number of heads (tracks) */ 146 u_char sectors; /* number of sectors/track */ 147 u_long diskblks; /* number of sectors/disk */ 148 u_long disklbns; /* number of available sectors */ 149 u_long blksize; /* number of bytes/sector */ 150 u_long diskbytes; /* number of bytes/disk */ 151 char diskname[8]; 152 } sc_param; 153 int sc_drive; /* physical unit number */ 154 int sc_flags; 155 int sc_state; 156 int sc_mode; 157 }; 158 159 struct hdcsoftc { 160 struct device sc_dev; /* must be here (pseudo-OOP:) */ 161 struct hdc9224_DKCreg *sc_dkc; /* I/O address of the controller */ 162 struct hdc9224_UDCreg sc_creg; /* (command) registers to be written */ 163 struct hdc9224_UDCreg sc_sreg; /* (status) registers being read */ 164 struct confargs *sc_cfargs; /* remember args being probed with */ 165 char *sc_dmabase; /* */ 166 long sc_dmasize; /* */ 167 long sc_ioaddr; /* unmapped I/O address */ 168 long sc_ivec; /* interrupt vector address */ 169 short sc_ibit; /* bit-value in interrupt register */ 170 short sc_status; /* copy of status register */ 171 short sc_state; 172 short sc_flags; 173 short sc_errors; 174 }; 175 176 /* 177 * Device definition for (new) autoconfiguration. 178 */ 179 int hdcmatch __P((struct device *parent, void *cfdata, void *aux)); 180 void hdcattach __P((struct device *parent, struct device *self, void *aux)); 181 int hdcprint __P((void *aux, const char *name)); 182 183 struct cfdriver hdc_cd = { 184 NULL, "hdc", DV_DULL 185 }; 186 struct cfattach hdc_ca = { 187 sizeof(struct hdcsoftc), hdcmatch, hdcattach 188 }; 189 190 int rdmatch __P((struct device *parent, void *cfdata, void *aux)); 191 void rdattach __P((struct device *parent, struct device *self, void *aux)); 192 int rdprint __P((void *aux, const char *name)); 193 void rdstrategy __P((struct buf *bp)); 194 195 struct cfdriver rd_cd = { 196 NULL, "rd", DV_DISK 197 }; 198 struct cfattach rd_ca = { 199 sizeof(struct rdsoftc), rdmatch, rdattach 200 }; 201 202 struct dkdriver rddkdriver = { rdstrategy }; 203 204 /* 205 * prototypes for (almost) all the internal routines 206 */ 207 int hdc_reset __P((struct hdcsoftc *sc)); 208 int hdc_select __P((struct hdcsoftc *sc, int drive)); 209 int hdc_command __P((struct hdcsoftc *sc, int cmd)); 210 211 int hdc_getdata __P((struct hdcsoftc *hdc, struct rdsoftc *rd, int drive)); 212 int hdc_getlabel __P((struct hdcsoftc *hdc, struct rdsoftc *rd, int drive)); 213 214 void rdgetlabel __P((struct rdsoftc *sc)); 215 216 /* 217 * new-config's hdcmatch() is similiar to old-config's hdcprobe(), 218 * thus we probe for the existence of the controller and reset it. 219 * NB: we can't initialize the controller yet, since space for hdcsoftc 220 * is not yet allocated. Thus we do this in hdcattach()... 221 */ 222 int 223 hdcmatch(parent, match, aux) 224 struct device *parent; 225 void *match, *aux; 226 { 227 struct cfdata *cf = match; 228 struct confargs *ca = aux; 229 230 trace(("hdcmatch(0x%x, %d, %s)\n", parent, cf->cf_unit, ca->ca_name)); 231 232 if (strcmp(ca->ca_name, "hdc") && 233 strcmp(ca->ca_name, "hdc9224") && 234 strcmp(ca->ca_name, "HDC9224")) 235 return (0); 236 237 /* 238 * only(?) VS2000/KA410 has exactly one HDC9224 controller 239 */ 240 if (vax_boardtype != VAX_BTYP_410) { 241 printf ("unexpected boardtype 0x%x in hdcmatch()\n", 242 vax_boardtype); 243 return (0); 244 } 245 if (cf->cf_unit != 0) 246 return (0); 247 248 return (1); 249 } 250 251 struct hdc_attach_args { 252 int ha_drive; 253 }; 254 255 int 256 rdprint(aux, name) 257 void *aux; 258 const char *name; 259 { 260 struct hdc_attach_args *ha = aux; 261 262 trace(("rdprint(%d, %s)\n", ha->ha_drive, name)); 263 264 if (!name) 265 printf (" drive %d", ha->ha_drive); 266 return (QUIET); 267 } 268 269 /* 270 * hdc_attach() probes for all possible devices 271 */ 272 void 273 hdcattach(parent, self, aux) 274 struct device *parent, *self; 275 void *aux; 276 { 277 struct hdcsoftc *sc = (void*)self; 278 struct confargs *ca = aux; 279 struct hdc_attach_args ha; 280 281 trace(("hdcattach(0x%x, 0x%x, %s)\n", parent, self, ca->ca_name)); 282 283 printf ("\n"); 284 /* 285 * first reset/initialize the controller 286 */ 287 sc->sc_cfargs = ca; 288 289 sc->sc_ioaddr = ca->ca_ioaddr; 290 sc->sc_dkc = (void*)uvax_phys2virt(sc->sc_ioaddr); 291 sc->sc_ibit = ca->ca_intbit; 292 sc->sc_ivec = ca->ca_intvec; 293 sc->sc_status = 0; 294 sc->sc_state = 0; 295 sc->sc_flags = 0; 296 sc->sc_errors = 0; 297 298 sc->sc_dkc = (void*)uvax_phys2virt(KA410_DKC_BASE); 299 sc->sc_dmabase = (void*)uvax_phys2virt(KA410_DMA_BASE); 300 sc->sc_dmasize = KA410_DMA_SIZE; 301 302 if (hdc_reset(sc) != 0) { 303 delay(500*1000); /* wait .5 seconds */ 304 if (hdc_reset(sc) != 0) 305 printf ("problems with hdc_reset()...\n"); 306 } 307 308 /* 309 * now probe for all possible disks 310 */ 311 for (ha.ha_drive=0; ha.ha_drive<3; ha.ha_drive++) 312 (void)config_found(self, (void*)&ha, rdprint); 313 314 #ifdef notyet 315 /* 316 * now that probing is done, we can register and enable interrupts 317 */ 318 vsbus_intr_register(XXX); 319 vsbus_intr_enable(XXX); 320 #endif 321 } 322 323 /* 324 * rdmatch() probes for the existence of a RD-type disk/floppy 325 */ 326 int 327 rdmatch(parent, match, aux) 328 struct device *parent; 329 void *match, *aux; 330 { 331 struct hdcsoftc *hdc = (void*)parent; 332 struct cfdata *cf = match; 333 struct hdc_attach_args *ha = aux; 334 int drive = ha->ha_drive; 335 int res; 336 337 trace(("rdmatch(%d, %d)\n", cf->cf_unit, drive)); 338 339 if (cf->cf_unit != ha->ha_drive) 340 return (0); 341 342 switch (drive) { 343 case 0: 344 case 1: 345 case 2: 346 res = hdc_select(hdc, drive); 347 break; 348 default: 349 printf ("rdmatch: invalid unit-number %d\n", drive); 350 return (0); 351 } 352 353 debug (("cstat: %x dstat: %x\n", hdc->sc_sreg.udc_cstat, 354 hdc->sc_sreg.udc_dstat)); 355 if (drive == 1) 356 return (0); /* XXX */ 357 358 return (1); 359 } 360 361 void 362 rdattach(parent, self, aux) 363 struct device *parent, *self; 364 void *aux; 365 { 366 struct hdcsoftc *hdc = (void*)parent; 367 struct rdsoftc *rd = (void*)self; 368 struct hdc_attach_args *ha = aux; 369 struct rdparams *rp = &rd->sc_param; 370 371 trace(("rdattach(%d)\n", ha->ha_drive)); 372 373 rd->sc_drive = ha->ha_drive; 374 /* 375 * Initialize and attach the disk structure. 376 */ 377 rd->sc_dk.dk_driver = &rddkdriver; 378 rd->sc_dk.dk_name = rd->sc_dev.dv_xname; 379 disk_attach(&rd->sc_dk); 380 /* 381 * if it's not a floppy then evaluate the on-disk geometry. 382 * if neccessary correct the label... 383 */ 384 printf("\n%s: ", rd->sc_dev.dv_xname); 385 if (rd->sc_drive == 2) { 386 printf("floppy (RX33)\n"); 387 } 388 else { 389 hdc_getdata(hdc, rd, rd->sc_drive); 390 printf("%s, %d MB, %d LBN, %d cyl, %d head, %d sect/track\n", 391 rp->diskname, rp->diskblks/2048, rp->disklbns, 392 rp->cylinders, rp->heads, rp->sectors); 393 } 394 } 395 396 /* 397 * Read/write routine for a buffer. For now we poll the controller, 398 * thus this routine waits for the transfer to complete. 399 */ 400 void 401 rdstrategy(bp) 402 struct buf *bp; 403 { 404 struct rdsoftc *rd = rd_cd.cd_devs[HDCUNIT(bp->b_dev)]; 405 struct hdcsoftc *hdc = (void *)rd->sc_dev.dv_parent; 406 struct partition *p; 407 int blkno, i, s; 408 409 trace (("rdstrategy(#%d/%d)\n", bp->b_blkno, bp->b_bcount)); 410 411 /* XXX should make some checks... */ 412 413 /* 414 * If it's a null transfer, return immediatly 415 */ 416 if (bp->b_bcount == 0) 417 goto done; 418 419 /* 420 * what follows now should not be here but in rdstart... 421 */ 422 /*------------------------------*/ 423 blkno = bp->b_blkno / (rd->sc_dk.dk_label->d_secsize / DEV_BSIZE); 424 if (HDCPART(bp->b_dev) != RAW_PART) { 425 p = &rd->sc_dk.dk_label->d_partitions[HDCPART(bp->b_dev)]; 426 blkno += p->p_offset; 427 } 428 /* nblks = howmany(bp->b_bcount, sd->sc_dk.dk_label->d_secsize); */ 429 430 if (hdc_strategy(hdc, rd, HDCUNIT(bp->b_dev), 431 ((bp->b_flags & B_READ) ? F_READ : F_WRITE), 432 blkno, bp->b_bcount, bp->b_data) == 0) 433 goto done; 434 /*------------------------------*/ 435 bad: 436 bp->b_flags |= B_ERROR; 437 done: 438 /* 439 * Correctly set the buf to indicate a completed xfer 440 */ 441 bp->b_resid = 0; /* ??? bertram */ 442 biodone(bp); 443 } 444 445 int 446 hdc_strategy(hdc, rd, unit, func, dblk, size, buf) 447 struct hdcsoftc *hdc; 448 struct rdsoftc *rd; 449 int unit; 450 int func; 451 int dblk; 452 int size; 453 char *buf; 454 { 455 struct hdc9224_UDCreg *p = &hdc->sc_creg; 456 struct disklabel *lp = rd->sc_dk.dk_label; 457 int sect, head, cyl; 458 int scount; 459 int cmd, res = 0; 460 461 trace (("hdc_strategy(%d, %d, %d, %d, 0x%x)\n", 462 unit, func, dblk, size, buf)); 463 464 hdc_select(hdc, unit); /* select drive right now */ 465 466 if (unit != 2 && dblk == -1) { /* read the on-disk geometry */ 467 468 p->udc_dma7 = 0; 469 p->udc_dma15 = 0; 470 p->udc_dma23 = 0; 471 472 p->udc_dsect = 0; 473 p->udc_dhead = 0; 474 p->udc_dcyl = 0; 475 476 p->udc_scnt = size/512; 477 p->udc_rtcnt = 0xF0; 478 p->udc_mode = 0xC0; 479 p->udc_term = 0xB4; 480 481 vsbus_lockDMA(hdc->sc_cfargs); /* bertram XXX */ 482 haveLock = 1; 483 keepLock = 1; 484 485 #ifdef PARANOID 486 bzero (hdc->sc_dmabase, size); /* clear disk buffer */ 487 #endif 488 cmd = 0x5C | 0x03; /* bypass bad sectors */ 489 cmd = 0x5C | 0x01; /* terminate if bad sector */ 490 491 res = hdc_command (hdc, cmd); 492 /* hold the locking ! */ 493 bcopy (hdc->sc_dmabase, buf, size); /* copy to buf */ 494 /* now release the locking */ 495 496 vsbus_unlockDMA(hdc->sc_cfargs); 497 haveLock = 0; 498 keepLock = 0; 499 500 return (res); 501 } 502 503 scount = size / 512; 504 while (scount) { 505 /* 506 * prepare drive/operation parameter 507 */ 508 cyl = dblk / lp->d_secpercyl; 509 sect = dblk % lp->d_secpercyl; 510 head = sect / lp->d_nsectors; 511 sect = sect % lp->d_nsectors; 512 if (unit == 2) 513 sect++; 514 else 515 cyl++; /* first cylinder is reserved */ 516 517 size = 512 * min(scount, lp->d_nsectors - sect); 518 519 debug (("hdc_strategy: block #%d ==> s/t/c=%d/%d/%d (%d/%d)\n", 520 dblk, sect, head, cyl, scount, size)); 521 522 /* 523 * now initialize the register values ... 524 */ 525 p->udc_dma7 = 0; 526 p->udc_dma15 = 0; 527 p->udc_dma23 = 0; 528 529 p->udc_dsect = sect; 530 head |= (cyl >> 4) & 0x70; 531 p->udc_dhead = head; 532 p->udc_dcyl = cyl; 533 534 p->udc_scnt = size/512; 535 536 if (unit == 2) { /* floppy */ 537 p->udc_rtcnt = 0xF2; 538 p->udc_mode = 0x81; /* RX33 with RX50 media */ 539 p->udc_mode = 0x82; /* RX33 with RX33 media */ 540 p->udc_term = 0xB4; 541 } else { /* disk */ 542 p->udc_rtcnt = 0xF0; 543 p->udc_mode = 0xC0; 544 p->udc_term = 0xB4; 545 } 546 547 vsbus_lockDMA(hdc->sc_cfargs); 548 haveLock = 1; 549 keepLock = 1; 550 551 if (func == F_WRITE) { 552 bcopy (buf, hdc->sc_dmabase, size); /* copy from buf */ 553 cmd = 0xA0 | (unit==2 ? 1 : 0); 554 res = hdc_command (hdc, cmd); 555 } 556 else { 557 #ifdef PARANOID 558 bzero (hdc->sc_dmabase, size); /* clear disk buffer */ 559 #endif 560 cmd = 0x5C | 0x03; /* bypass bad sectors */ 561 cmd = 0x5C | 0x01; /* terminate if bad sector */ 562 res = hdc_command (hdc, cmd); 563 bcopy (hdc->sc_dmabase, buf, size); /* copy to buf */ 564 } 565 566 vsbus_unlockDMA(hdc->sc_cfargs); 567 haveLock = 0; 568 keepLock = 0; 569 570 scount -= size/512; 571 dblk += size/512; 572 buf += size; 573 } 574 575 if (unit != 2) /* deselect drive, if not floppy */ 576 hdc_command (hdc, DKC_CMD_DRDESELECT); 577 578 return 0; 579 } 580 581 char hdc_iobuf[17*512]; /* we won't need more */ 582 583 #ifdef DEBUG 584 /* 585 * display the contents of the on-disk geometry structure 586 */ 587 int 588 hdc_printgeom(p) 589 struct rdgeom *p; 590 { 591 char dname[8]; 592 hdc_mid2str(p->media_id, dname); 593 594 printf ("**DiskData** XBNs: %d, DBNs: %d, LBNs: %d, RBNs: %d\n", 595 p->xbn_count, p->dbn_count, p->lbn_count, p->rbn_count); 596 printf ("sec/track: %d, tracks: %d, cyl: %d, precomp/reduced: %d/%d\n", 597 p->nspt, p->ntracks, p->ncylinders, p->precomp, p->reduced); 598 printf ("seek-rate: %d, crc/eec: %s, RCT: %d, RCT-copies: %d\n", 599 p->seek_rate, p->crc_eec?"EEC":"CRC", p->rct, p->rct_ncopies); 600 printf ("media-ID: %s, interleave: %d, headskew: %d, cylskew: %d\n", 601 dname, p->interleave, p->headskew, p->cylskew); 602 printf ("gap0: %d, gap1: %d, gap2: %d, gap3: %d, sync-value: %d\n", 603 p->gap0_size, p->gap1_size, p->gap2_size, p->gap3_size, 604 p->sync_value); 605 } 606 #endif 607 608 /* 609 * Convert media_id to string/name (encoding is documented in mscp.h) 610 */ 611 int 612 hdc_mid2str(media_id, name) 613 long media_id; 614 char *name; 615 { 616 struct { /* For RD32 this struct holds: */ 617 u_long mt:7; /* number in name: 0x20 == 32 */ 618 u_long a2:5; /* ' ' encoded as 0x0 */ 619 u_long a1:5; /* 'D' encoded with base '@' */ 620 u_long a0:5; /* 'R' encoded with base '@' */ 621 u_long d1:5; /* 'U' encoded with base '@' */ 622 u_long d0:5; /* 'D' encoded with base '@' */ 623 } *p = (void*)&media_id; 624 625 #define MIDCHR(x) (x ? x + '@' : ' ') 626 627 sprintf (name, "%c%c%d", MIDCHR(p->a0), MIDCHR(p->a1), p->mt); 628 } 629 630 int 631 hdc_getdata(hdc, rd, unit) 632 struct hdcsoftc *hdc; 633 struct rdsoftc *rd; 634 int unit; 635 { 636 struct disklabel *lp = rd->sc_dk.dk_label; 637 struct rdparams *rp = &rd->sc_param; 638 int res; 639 640 trace (("hdc_getdata(%d)\n", unit)); 641 642 bzero(rd->sc_dk.dk_label, sizeof(struct disklabel)); 643 bzero(rd->sc_dk.dk_cpulabel, sizeof(struct cpu_disklabel)); 644 645 if (unit == 2) { 646 lp->d_secsize = DEV_BSIZE; 647 lp->d_ntracks = 2; 648 lp->d_nsectors = 15; 649 lp->d_ncylinders = 80; 650 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 651 652 return (0); 653 } 654 655 res = hdc_strategy(hdc, rd, unit, F_READ, -1, 4096, hdc_iobuf); 656 bcopy (hdc_iobuf, &rd->sc_xbn, sizeof(struct rdgeom)); 657 #ifdef DEBUG 658 hdc_printgeom(&rd->sc_xbn); 659 #endif 660 lp->d_secsize = DEV_BSIZE; 661 lp->d_ntracks = rd->sc_xbn.ntracks; 662 lp->d_nsectors = rd->sc_xbn.nspt; 663 lp->d_ncylinders = rd->sc_xbn.ncylinders; 664 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 665 666 rp->cylinders = rd->sc_xbn.ncylinders; 667 rp->heads = rd->sc_xbn.ntracks; 668 rp->sectors = rd->sc_xbn.nspt; 669 rp->diskblks = rp->cylinders * rp->heads * rp->sectors; 670 rp->disklbns = rd->sc_xbn.lbn_count; 671 rp->blksize = DEV_BSIZE; 672 rp->diskbytes = rp->disklbns * rp->blksize; 673 hdc_mid2str(rd->sc_xbn.media_id, rp->diskname); 674 675 return (0); 676 } 677 678 int 679 hdc_getlabel(hdc, rd, unit) 680 struct hdcsoftc *hdc; 681 struct rdsoftc *rd; 682 int unit; 683 { 684 struct disklabel *lp = rd->sc_dk.dk_label; 685 struct disklabel *xp = (void*)(hdc_iobuf + 64); 686 int res; 687 688 trace (("hdc_getlabel(%d)\n", unit)); 689 690 #define LBL_CHECK(x) if (xp->x != lp->x) { \ 691 printf ("%d-->%d\n", xp->x, lp->x); \ 692 xp->x = lp->x; \ 693 } 694 res = hdc_strategy(hdc, rd, unit, F_READ, 0, DEV_BSIZE, hdc_iobuf); 695 LBL_CHECK(d_secsize); 696 LBL_CHECK(d_ntracks); 697 LBL_CHECK(d_nsectors); 698 LBL_CHECK(d_ncylinders); 699 LBL_CHECK(d_secpercyl); 700 bcopy(xp, lp, sizeof(struct disklabel)); 701 702 return (0); 703 } 704 705 /* 706 * Return the size of a partition, if known, or -1 if not. 707 */ 708 hdcsize(dev) 709 dev_t dev; 710 { 711 int unit = HDCUNIT(dev); 712 int part = HDCPART(dev); 713 struct rdsoftc *rd = rd_cd.cd_devs[unit]; 714 int size; 715 716 trace (("hdcsize(%x == %d/%d)\n", dev, unit, part)); 717 718 if (hdcopen(dev, 0, S_IFBLK) != 0) 719 return (-1); 720 #if 0 721 if (rd->sc_dk.dk_label->d_partitions[part].p_fstype != FS_SWAP) 722 size = -1; 723 else 724 #endif 725 size = rd->sc_dk.dk_label->d_partitions[part].p_size; 726 if (hdcclose(dev, 0, S_IFBLK) != 0) 727 return (-1); 728 debug (("hdcsize: size=%d\n", size)); 729 return (size); 730 } 731 732 /* 733 * 734 */ 735 int 736 hdcopen (dev, flag, fmt) 737 dev_t dev; 738 int flag; 739 int fmt; 740 { 741 int unit = HDCUNIT(dev); 742 int part = HDCPART(dev); 743 struct hdcsoftc *hdc; 744 struct rdsoftc *rd; 745 int res, error; 746 747 trace (("hdcopen(0x%x = %d/%d)\n", dev, unit, part)); 748 749 if (unit >= rd_cd.cd_ndevs) { 750 printf ("hdcopen: invalid unit %d\n", unit); 751 return ENXIO; 752 } 753 rd = rd_cd.cd_devs[unit]; 754 if (!rd) { 755 printf("hdcopen: null-pointer in rdsoftc.\n"); 756 return (ENXIO); 757 } 758 hdc = (void *)rd->sc_dev.dv_parent; 759 760 /* XXX here's much more to do! XXX */ 761 762 hdc_getdata (hdc, rd, unit); 763 hdc_getlabel (hdc, rd, unit); 764 765 return (0); 766 } 767 768 /* 769 * 770 */ 771 int 772 hdcclose (dev, flag) 773 dev_t dev; 774 int flag; 775 { 776 trace (("hdcclose()\n")); 777 return (0); 778 } 779 780 /* 781 * 782 */ 783 void 784 hdcstrategy(bp) 785 register struct buf *bp; 786 { 787 trace (("hdcstrategy()\n")); 788 rdstrategy(bp); 789 debug (("hdcstrategy done.\n")); 790 } 791 792 /* 793 * 794 */ 795 int 796 hdcioctl(dev, cmd, data, flag, p) 797 dev_t dev; 798 int cmd; 799 caddr_t data; /* aka: addr */ 800 int flag; 801 struct proc *p; 802 { 803 struct rdsoftc *rd = rd_cd.cd_devs[HDCUNIT(dev)]; 804 struct hdcsoftc *hdc = (void *)rd->sc_dev.dv_parent; 805 int error; 806 807 trace (("hdcioctl(%x, %x)\n", dev, cmd)); 808 809 /* 810 * If the device is not valid.. abandon ship 811 */ 812 /* XXX */ 813 814 switch (cmd) { 815 case DIOCGDINFO: 816 *(struct disklabel *)data = *(rd->sc_dk.dk_label); 817 return (0); 818 819 case DIOCGPART: 820 ((struct partinfo *)data)->disklab = rd->sc_dk.dk_label; 821 ((struct partinfo *)data)->part = 822 &rd->sc_dk.dk_label->d_partitions[HDCPART(dev)]; 823 return (0); 824 825 case DIOCWDINFO: 826 case DIOCSDINFO: 827 /* XXX 828 if ((flag & FWRITE) == 0) 829 return EBADF; 830 831 if ((error = sdlock(sd)) != 0) 832 return error; 833 sd->flags |= SDF_LABELLING; 834 */ 835 error = setdisklabel(rd->sc_dk.dk_label, 836 (struct disklabel *)data, 0, rd->sc_dk.dk_cpulabel); 837 if (error == 0) { 838 if (cmd == DIOCWDINFO) 839 error = writedisklabel(HDCLABELDEV(dev), 840 rdstrategy, rd->sc_dk.dk_label, 841 rd->sc_dk.dk_cpulabel); 842 } 843 /* XXX 844 sd->flags &= ~SDF_LABELLING; 845 sdunlock(sd); 846 */ 847 return (error); 848 849 case DIOCWLABEL: 850 if ((flag & FWRITE) == 0) 851 return (EBADF); 852 /* XXX 853 if (*(int *)data) 854 sd->flags |= SDF_WLABEL; 855 else 856 sd->flags &= ~SDF_WLABEL; 857 */ 858 return (0); 859 860 default: 861 if (HDCPART(dev) != RAW_PART) 862 return ENOTTY; 863 printf ("IOCTL %x not implemented.\n", cmd); 864 return (-1); 865 } 866 } 867 868 /* 869 * 870 */ 871 int 872 hdcintr() 873 { 874 trace (("hdcintr()\n")); 875 } 876 877 /* 878 * 879 */ 880 int 881 hdcread (dev, uio) 882 dev_t dev; 883 struct uio *uio; 884 { 885 trace (("hdcread()\n")); 886 return (physio (hdcstrategy, NULL, dev, B_READ, minphys, uio)); 887 } 888 889 /* 890 * 891 */ 892 int 893 hdcwrite (dev, uio) 894 dev_t dev; 895 struct uio *uio; 896 { 897 trace (("hdcwrite()\n")); 898 return (physio (hdcstrategy, NULL, dev, B_WRITE, minphys, uio)); 899 } 900 901 /* 902 * 903 */ 904 int 905 hdcdump(dev) 906 dev_t dev; 907 { 908 trace (("hdcdump (%x)\n", dev)); 909 } 910 911 /* 912 * we have to wait 0.7 usec between two accesses to any of the 913 * dkc-registers, on a VS2000 with 1 MIPS, this is roughly one 914 * instruction. Thus the loop-overhead will be enough... 915 */ 916 void 917 hdc_readregs(sc) 918 struct hdcsoftc *sc; 919 { 920 int i; 921 char *p; 922 923 trace(("hdc_readregs()\n")); 924 925 sc->sc_dkc->dkc_cmd = 0x40; /* set internal counter to zero */ 926 p = (void*)&sc->sc_sreg; 927 for (i=0; i<10; i++) 928 *p++ = sc->sc_dkc->dkc_reg; /* dkc_reg auto-increments */ 929 } 930 931 void 932 hdc_writeregs(sc) 933 struct hdcsoftc *sc; 934 { 935 int i; 936 char *p; 937 938 trace(("hdc_writeregs()\n")); 939 940 sc->sc_dkc->dkc_cmd = 0x40; /* set internal counter to zero */ 941 p = (void*)&sc->sc_creg; 942 for (i=0; i<10; i++) 943 sc->sc_dkc->dkc_reg = *p++; /* dkc_reg auto-increments */ 944 } 945 946 /* 947 * hdc_command() issues a command and polls the intreq-register 948 * to find when command has completed 949 */ 950 int 951 hdc_command(sc, cmd) 952 struct hdcsoftc *sc; 953 int cmd; 954 { 955 volatile u_char *intreq = (void*)uvax_phys2virt(KA410_INTREQ); 956 volatile u_char *intclr = (void*)uvax_phys2virt(KA410_INTCLR); 957 volatile u_char *intmsk = (void*)uvax_phys2virt(KA410_INTMSK); 958 int i, c; 959 960 trace (("hdc_command(%x)\n", cmd)); 961 debug (("intr-state: %x %x %x\n", *intreq, *intclr, *intmsk)); 962 963 if (!haveLock) { 964 vsbus_lockDMA(sc->sc_cfargs); 965 haveLock = 1; 966 } 967 968 hdc_writeregs(sc); /* write the prepared registers */ 969 *intclr = INTR_DC; /* clear any old interrupt */ 970 sc->sc_dkc->dkc_cmd = cmd; /* issue the command */ 971 for (i=0; i<MAX_WAIT; i++) { 972 if ((c = *intreq) & INTR_DC) 973 break; 974 } 975 if ((c & INTR_DC) == 0) { 976 printf ("hdc_command: timeout in command 0x%x\n", cmd); 977 } 978 hdc_readregs(sc); /* read the status registers */ 979 sc->sc_status = sc->sc_dkc->dkc_stat; 980 981 if (!keepLock) { 982 vsbus_unlockDMA(sc->sc_cfargs); 983 haveLock = 0; 984 } 985 986 if (sc->sc_status != DKC_ST_DONE|DKC_TC_SUCCESS) { 987 printf ("command 0x%x completed with status 0x%x\n", 988 cmd, sc->sc_status); 989 return (-1); 990 } 991 return (0); 992 } 993 994 /* 995 * writing zero into the command-register will reset the controller. 996 * This will not interrupt data-transfer commands! 997 * Also no interrupt is generated, thus we don't use hdc_command() 998 */ 999 int 1000 hdc_reset(sc) 1001 struct hdcsoftc *sc; 1002 { 1003 trace (("hdc_reset()\n")); 1004 1005 sc->sc_dkc->dkc_cmd = DKC_CMD_RESET; /* issue RESET command */ 1006 hdc_readregs(sc); /* read the status registers */ 1007 sc->sc_status = sc->sc_dkc->dkc_stat; 1008 if (sc->sc_status != DKC_ST_DONE|DKC_TC_SUCCESS) { 1009 printf ("RESET command completed with status 0x%x\n", 1010 sc->sc_status); 1011 return (-1); 1012 } 1013 return (0); 1014 } 1015 1016 int 1017 hdc_rxselect(sc, unit) 1018 struct hdcsoftc *sc; 1019 int unit; 1020 { 1021 register struct hdc9224_UDCreg *p = &sc->sc_creg; 1022 register struct hdc9224_UDCreg *q = &sc->sc_sreg; 1023 int error; 1024 1025 /* 1026 * bring command-regs in some known-to-work state and 1027 * select the drive with the DRIVE SELECT command. 1028 */ 1029 p->udc_dma7 = 0; 1030 p->udc_dma15 = 0; 1031 p->udc_dma23 = 0; 1032 p->udc_dsect = 1; /* sectors are numbered 1..15 !!! */ 1033 p->udc_dhead = 0; 1034 p->udc_dcyl = 0; 1035 p->udc_scnt = 0; 1036 1037 p->udc_rtcnt = UDC_RC_RX33READ; 1038 p->udc_mode = UDC_MD_RX33; 1039 p->udc_term = UDC_TC_FDD; 1040 1041 /* 1042 * this is ... 1043 */ 1044 error = hdc_command (sc, DKC_CMD_DRSEL_RX33 | unit); 1045 1046 if ((error != 0) || (q->udc_dstat & UDC_DS_READY == 0)) { 1047 printf("\nfloppy-drive not ready (new floppy inserted?)\n\n"); 1048 p->udc_rtcnt &= ~UDC_RC_INVRDY; /* clear INVRDY-flag */ 1049 error = hdc_command(sc, DKC_CMD_DRSEL_RX33 | unit); 1050 if ((error != 0) || (q->udc_dstat & UDC_DS_READY == 0)) { 1051 printf("diskette not ready(1): %x/%x\n", error, q->udc_dstat); 1052 printf("floppy-drive offline?\n"); 1053 return (-1); 1054 } 1055 1056 if (q->udc_dstat & UDC_DS_TRK00) /* if track-0 */ 1057 error = hdc_command(sc, DKC_CMD_STEPIN_FDD); /* step inwards */ 1058 else /* else */ 1059 error = hdc_command(sc, DKC_CMD_STEPOUT_FDD); /* step outwards */ 1060 1061 if ((error != 0) || (q->udc_dstat & UDC_DS_READY == 1)) { 1062 printf("diskette not ready(2): %x/%x\n", error, q->udc_dstat); 1063 printf("No floppy inserted or drive offline\n"); 1064 /* return (-1); */ 1065 } 1066 1067 p->udc_rtcnt |= UDC_RC_INVRDY; 1068 error = hdc_command(sc, DKC_CMD_DRSEL_RX33 | unit); 1069 if ((error != 0) || (q->udc_dstat & UDC_DS_READY == 0)) { 1070 printf("diskette not ready(3): %x/%x\n", error, q->udc_dstat); 1071 printf("no floppy inserted or floppy-door open\n"); 1072 return(-1); 1073 } 1074 printf("floppy-drive reselected.\n"); 1075 } 1076 if (error) 1077 error = hdc_command (sc, DKC_CMD_DRSEL_RX33 | unit); 1078 1079 return (error); 1080 } 1081 1082 int 1083 hdc_rdselect(sc, unit) 1084 struct hdcsoftc *sc; 1085 int unit; 1086 { 1087 register struct hdc9224_UDCreg *p = &sc->sc_creg; 1088 register struct hdc9224_UDCreg *q = &sc->sc_sreg; 1089 int error; 1090 1091 /* 1092 * bring "creg" in some known-to-work state and 1093 * select the drive with the DRIVE SELECT command. 1094 */ 1095 p->udc_dma7 = 0; 1096 p->udc_dma15 = 0; 1097 p->udc_dma23 = 0; 1098 p->udc_dsect = 0; /* sectors are numbered 0..16 */ 1099 p->udc_dhead = 0; 1100 p->udc_dcyl = 0; 1101 p->udc_scnt = 0; 1102 1103 p->udc_rtcnt = UDC_RC_HDD_READ; 1104 p->udc_mode = UDC_MD_HDD; 1105 p->udc_term = UDC_TC_HDD; 1106 1107 error = hdc_command (sc, DKC_CMD_DRSEL_HDD | unit); 1108 if (error) 1109 error = hdc_command (sc, DKC_CMD_DRSEL_HDD | unit); 1110 1111 return (error); 1112 } 1113 1114 /* 1115 * bring command-regs into some known-to-work state and select 1116 * the drive with the DRIVE SELECT command. 1117 */ 1118 int 1119 hdc_select(sc, unit) 1120 struct hdcsoftc *sc; 1121 int unit; 1122 { 1123 int error; 1124 1125 trace (("hdc_select(%x,%d)\n", sc, unit)); 1126 1127 switch (unit) { 1128 case 0: 1129 case 1: 1130 error = hdc_rdselect(sc, unit); 1131 break; 1132 case 2: 1133 error = hdc_rxselect(sc, unit); 1134 /* bertram: delay ??? XXX */ 1135 break; 1136 default: 1137 printf("invalid unit %d in hdc_select()\n", unit); 1138 error = -1; 1139 } 1140 1141 return (error); 1142 } 1143 1144 #endif /* NHDC > 0 */ 1145