132529Sbostic /* 2*36193Sbostic * Copyright (c) 1988 The Regents of the University of California. 3*36193Sbostic * All rights reserved. 432557Sbostic * 5*36193Sbostic * This code is derived from software contributed to Berkeley by 6*36193Sbostic * Harris Corp. 7*36193Sbostic * 8*36193Sbostic * Redistribution and use in source and binary forms are permitted 9*36193Sbostic * provided that the above copyright notice and this paragraph are 10*36193Sbostic * duplicated in all such forms and that any documentation, 11*36193Sbostic * advertising materials, and other materials related to such 12*36193Sbostic * distribution and use acknowledge that the software was developed 13*36193Sbostic * by the University of California, Berkeley. The name of the 14*36193Sbostic * University may not be used to endorse or promote products derived 15*36193Sbostic * from this software without specific prior written permission. 16*36193Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17*36193Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18*36193Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19*36193Sbostic * 20*36193Sbostic * @(#)hd.c 7.5 (Berkeley) 11/01/88 2132529Sbostic */ 2232529Sbostic 2332557Sbostic #include "param.h" 2432557Sbostic #include "inode.h" 2532557Sbostic #include "fs.h" 2633164Sbostic #include "buf.h" 2732557Sbostic #include "ioctl.h" 2833164Sbostic #include "disklabel.h" 2932557Sbostic #include "saio.h" 30*36193Sbostic #include "../tahoe/mtpr.h" 31*36193Sbostic #include "../tahoevba/hdreg.h" 3232529Sbostic 33*36193Sbostic static struct registers *hdc_regs[HDC_MAXCTLR][HDC_MAXBUS]; 34*36193Sbostic static struct disklabel dklabel[HDC_MAXDRIVE][HDC_MAXCTLR][HDC_MAXBUS]; 3533164Sbostic 3632529Sbostic hdopen(io) 37*36193Sbostic register struct iob *io; 3832529Sbostic { 39*36193Sbostic register struct disklabel *dlp; 40*36193Sbostic struct status status; 41*36193Sbostic struct module_id id; 42*36193Sbostic struct registers *hr; 43*36193Sbostic struct mcb mcb; 44*36193Sbostic long junk, dlbuf[DEV_BSIZE/sizeof(long)]; 4532529Sbostic 4633164Sbostic /* validate the device specification */ 47*36193Sbostic if ((u_int)io->i_bus >= HDC_MAXBUS) 48*36193Sbostic return(EADAPT); 49*36193Sbostic if ((u_int)io->i_ctlr >= HDC_MAXCTLR) 50*36193Sbostic return(ECTLR); 51*36193Sbostic if ((u_int)io->i_unit >= HDC_MAXDRIVE) 5232560Sbostic return(EUNIT); 53*36193Sbostic if ((u_int)io->i_part > 7) 54*36193Sbostic return(EPART); 5532529Sbostic 5633164Sbostic /* init drive structure. */ 57*36193Sbostic hdc_regs[io->i_ctlr][io->i_bus] = hr = (struct registers *)(io->i_bus ? 58*36193Sbostic 0x80000000 | io->i_ctlr << 24 | HDC_MID << 16 : 59*36193Sbostic 0xC0000000 | io->i_ctlr << 24 | HDC_MID << 16); 6032529Sbostic 6133164Sbostic /* insure that this is an hdc, then reset the hdc. */ 62*36193Sbostic if (wbadaddr(&hr->module_id, 4, &junk)) { 63*36193Sbostic printf("hd%d: %x: invalid csr\n", io->i_ctlr, (u_int)hr); 6432560Sbostic return(ENXIO); 6532557Sbostic } 66*36193Sbostic hr->soft_reset = 0; 6732529Sbostic DELAY(1000000); 6832529Sbostic 6932529Sbostic /* 70*36193Sbostic * read in the hdc module id word. The controller is bad if the 7132560Sbostic * hdc's writeable control store is not loaded or if the hdc failed 7232560Sbostic * the functional integrity test for any reason. 7332529Sbostic */ 74*36193Sbostic hr->module_id = (u_long)&id; 7532529Sbostic DELAY(10000); 7632557Sbostic mtpr(PADC, 0); 77*36193Sbostic if (id.module_id != (u_char)HDC_MID) { 78*36193Sbostic printf("hdc: controller bad module id: id = %x\n", 79*36193Sbostic id.module_id); 8033164Sbostic return(ENXIO); 8132529Sbostic } 82*36193Sbostic if (id.code_rev == (u_char)0xff) { 83*36193Sbostic printf("hdc: controller micro-code is not loaded.\n"); 8432560Sbostic return(ENXIO); 8532529Sbostic } 86*36193Sbostic if (id.fit != (u_char)0xff) { 87*36193Sbostic printf("hdc: controller FIT test failed: error= %x\n", 88*36193Sbostic id.fit); 8932560Sbostic return(ENXIO); 9032529Sbostic } 9132529Sbostic 92*36193Sbostic /* read the drive status */ 93*36193Sbostic mcb.command = HCMD_STATUS; 94*36193Sbostic mcb.drive = io->i_unit; 95*36193Sbostic mcb.cyl = 0; 96*36193Sbostic mcb.head = 0; 97*36193Sbostic mcb.sector = 0; 98*36193Sbostic mcb.chain[0].wcount = (long)(sizeof(struct status) / sizeof(long)); 99*36193Sbostic mcb.chain[0].memadr = (long)&status; 100*36193Sbostic if (hdimcb(&mcb, io)) 10132560Sbostic return(EIO); 10233164Sbostic 10333164Sbostic /* 10433164Sbostic * Report drive down if anything in the drive status is bad. 10533164Sbostic * If fault condition, reading will try to clear the fault. 10633164Sbostic */ 107*36193Sbostic if (status.drs&DRS_FAULT) 10833164Sbostic printf("hdc: clearing drive fault.\n"); 109*36193Sbostic if (!(status.drs&DRS_ONLINE)) { 11033164Sbostic printf("hdc: drive is not online.\n"); 11133164Sbostic return(EIO); 11233164Sbostic } 11333164Sbostic 114*36193Sbostic /* read in the pack label */ 115*36193Sbostic mcb.command = HCMD_READ; 116*36193Sbostic mcb.drive = io->i_unit; 117*36193Sbostic mcb.cyl = 0; 118*36193Sbostic mcb.head = 0; 119*36193Sbostic mcb.sector = LABELSECTOR; 120*36193Sbostic mcb.chain[0].wcount = (long)(DEV_BSIZE / sizeof(long)); 121*36193Sbostic mcb.chain[0].memadr = (long)dlbuf; 122*36193Sbostic if (hdimcb(&mcb, io)) 123*36193Sbostic return(ERDLAB); 124*36193Sbostic dlp = (struct disklabel *)(dlbuf + LABELOFFSET); 125*36193Sbostic if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) 126*36193Sbostic #ifdef COMPAT_42 127*36193Sbostic { 128*36193Sbostic int error; 12932529Sbostic 130*36193Sbostic if (error = hdmaptype(io, dlp, &status, io->i_unit)) 131*36193Sbostic return(error); 13232529Sbostic } 133*36193Sbostic #else 134*36193Sbostic return(EUNLAB); 135*36193Sbostic #endif 136*36193Sbostic dklabel[io->i_unit][io->i_ctlr][io->i_bus] = *dlp; 137*36193Sbostic if (io->i_part >= dlp->d_npartitions || 138*36193Sbostic dlp->d_partitions[io->i_part].p_size == 0) 139*36193Sbostic return(EPART); 140*36193Sbostic io->i_boff = (dlp->d_partitions[io->i_part].p_offset * 141*36193Sbostic dlp->d_secsize) / DEV_BSIZE; 14232560Sbostic return(0); 14332529Sbostic } 14432529Sbostic 14532560Sbostic hdstrategy(io, cmd) 146*36193Sbostic register struct iob *io; 147*36193Sbostic int cmd; 14832529Sbostic { 149*36193Sbostic register struct disklabel *dlp; 150*36193Sbostic struct mcb mcb; 151*36193Sbostic long sector; 15232529Sbostic 153*36193Sbostic if (io->i_cc&3) { 154*36193Sbostic printf("hd%d: i/o not a longword multiple.\n", io->i_unit); 15532560Sbostic return(0); 15632560Sbostic } 157*36193Sbostic dlp = &dklabel[io->i_unit][io->i_ctlr][io->i_bus]; 15832529Sbostic sector = io->i_bn * HDC_SPB; 159*36193Sbostic mcb.command = (cmd == READ) ? HCMD_READ : HCMD_WRITE; 160*36193Sbostic mcb.drive = io->i_unit; 161*36193Sbostic mcb.cyl = sector / dlp->d_secpercyl; 162*36193Sbostic mcb.head = (sector / dlp->d_nsectors) % dlp->d_ntracks; 163*36193Sbostic mcb.sector = sector % dlp->d_nsectors; 164*36193Sbostic mcb.chain[0].wcount = io->i_cc / sizeof(long); 165*36193Sbostic mcb.chain[0].memadr = (u_long)io->i_ma; 166*36193Sbostic return(hdimcb(&mcb, io) ? -1 : io->i_cc); 16732529Sbostic } 16832529Sbostic 169*36193Sbostic hdimcb(mcb, io) 170*36193Sbostic register struct mcb *mcb; 171*36193Sbostic register struct iob *io; 17232529Sbostic { 173*36193Sbostic struct master_mcb master; 174*36193Sbostic int timeout; 17532529Sbostic 176*36193Sbostic /* fill in mcb */ 177*36193Sbostic mcb->interrupt = 0; 178*36193Sbostic mcb->forw_phaddr = 0; 17932529Sbostic 180*36193Sbostic /* fill in master mcb */ 181*36193Sbostic master.mcw = MCL_IMMEDIATE; 182*36193Sbostic master.forw_phaddr = (u_long)mcb; 183*36193Sbostic master.mcs = 0; 18432529Sbostic 185*36193Sbostic hdc_regs[io->i_ctlr][io->i_bus]->master_mcb = (u_long)&master; 186*36193Sbostic for (timeout = 15000; timeout; --timeout) { 187*36193Sbostic DELAY(1000); 188*36193Sbostic mtpr(PADC, 0); 189*36193Sbostic if (master.mcs&MCS_FATALERROR) { 190*36193Sbostic printf("hdc%d: fatal error.\n", io->i_ctlr); 19132529Sbostic return(1); 19232529Sbostic } 193*36193Sbostic if (master.mcs&MCS_DONE) 194*36193Sbostic return(0); 19532529Sbostic } 196*36193Sbostic printf("hdc: controller timed out.\n"); 197*36193Sbostic return(1); 198*36193Sbostic } 19932529Sbostic 200*36193Sbostic #ifdef COMPAT_42 201*36193Sbostic hdmaptype(io, dlp, status, unit) 202*36193Sbostic register struct iob *io; 203*36193Sbostic register struct disklabel *dlp; 204*36193Sbostic struct status *status; 205*36193Sbostic int unit; 206*36193Sbostic { 207*36193Sbostic geometry_sector geometry; 208*36193Sbostic geometry_block *geo; 209*36193Sbostic struct mcb mcb; 210*36193Sbostic int cnt; 211*36193Sbostic char *strcpy(); 21232529Sbostic 213*36193Sbostic printf("hd%d: unlabeled\n", unit); 214*36193Sbostic /* 215*36193Sbostic * Read the geometry block (at head = 0 sector = 0 of the drive 216*36193Sbostic * definition cylinder), validate it (must have the correct version 217*36193Sbostic * number, header, and checksum). 218*36193Sbostic */ 219*36193Sbostic mcb.command = HCMD_READ; 220*36193Sbostic mcb.drive = unit; 221*36193Sbostic mcb.cyl = status->def_cyl; 222*36193Sbostic mcb.head = 0; 223*36193Sbostic mcb.sector = 0; 224*36193Sbostic mcb.chain[0].wcount = (long)(sizeof(geometry_sector) / sizeof(long)); 225*36193Sbostic mcb.chain[0].memadr = (long)&geometry; 226*36193Sbostic if (hdimcb(&mcb, io)) { 227*36193Sbostic printf("hd%d: can't read default geometry.\n", io->i_unit); 228*36193Sbostic return(ERDLAB); 22932529Sbostic } 230*36193Sbostic geo = &geometry.geometry_block; 231*36193Sbostic if (geo->version > 64000 || geo->version < 0) { 232*36193Sbostic printf("hd%d: bad default geometry version#.\n", io->i_unit); 233*36193Sbostic return(ENXIO); 23432529Sbostic } 235*36193Sbostic if (strcmp(&geo->id[0], GB_ID)) { 236*36193Sbostic printf("hd%d: bad default geometry header.\n", io->i_unit); 237*36193Sbostic return(ENXIO); 23832529Sbostic } 239*36193Sbostic GB_CHECKSUM(geo, cnt); 240*36193Sbostic if (geometry.checksum != cnt) { 241*36193Sbostic printf("hd%d: bad default geometry checksum.\n", io->i_unit); 242*36193Sbostic return(ENXIO); 24332529Sbostic } 244*36193Sbostic for (cnt = 0; cnt < GB_MAXPART; cnt++) { 245*36193Sbostic dlp->d_partitions[cnt].p_offset = geo->partition[cnt].start; 246*36193Sbostic dlp->d_partitions[cnt].p_size = geo->partition[cnt].length; 24732529Sbostic } 248*36193Sbostic #ifdef RAW_SIZE 249*36193Sbostic dlp->d_secsize = status->bytes_per_sec; 250*36193Sbostic #else 251*36193Sbostic dlp->d_secsize = 512; 252*36193Sbostic #endif 253*36193Sbostic dlp->d_nsectors = status->max_sector + 1; 254*36193Sbostic dlp->d_ncylinders = status->max_cyl + 1; 255*36193Sbostic dlp->d_ntracks = status->max_head + 1; 256*36193Sbostic dlp->d_secpercyl = dlp->d_ntracks * dlp->d_nsectors; 257*36193Sbostic dlp->d_npartitions = GB_MAXPART; 258*36193Sbostic dlp->d_rpm = status->rpm; 259*36193Sbostic (void)strcpy(dlp->d_typename, "hdc (prom)"); 26032560Sbostic return(0); 26132529Sbostic } 262*36193Sbostic #endif /* COMPAT_42 */ 263