132529Sbostic /* 236193Sbostic * Copyright (c) 1988 The Regents of the University of California. 336193Sbostic * All rights reserved. 432557Sbostic * 536193Sbostic * This code is derived from software contributed to Berkeley by 636193Sbostic * Harris Corp. 736193Sbostic * 8*44532Sbostic * %sccs.include.redist.c% 936193Sbostic * 10*44532Sbostic * @(#)hd.c 7.8 (Berkeley) 06/28/90 1132529Sbostic */ 1232529Sbostic 1343457Sroot #include "sys/param.h" 1443457Sroot #include "sys/time.h" 1543457Sroot #include "sys/vnode.h" 1643457Sroot #include "ufs/inode.h" 1743457Sroot #include "ufs/fs.h" 1843457Sroot #include "sys/buf.h" 1943457Sroot #include "sys/ioctl.h" 2043457Sroot #include "sys/disklabel.h" 2132557Sbostic #include "saio.h" 2243457Sroot #include "tahoe/mtpr.h" 2343457Sroot #include "tahoevba/hdreg.h" 2432529Sbostic 2536193Sbostic static struct registers *hdc_regs[HDC_MAXCTLR][HDC_MAXBUS]; 2636193Sbostic static struct disklabel dklabel[HDC_MAXDRIVE][HDC_MAXCTLR][HDC_MAXBUS]; 2733164Sbostic 2832529Sbostic hdopen(io) 2936193Sbostic register struct iob *io; 3032529Sbostic { 3136193Sbostic register struct disklabel *dlp; 3236193Sbostic struct status status; 3336193Sbostic struct module_id id; 3436193Sbostic struct registers *hr; 3536193Sbostic struct mcb mcb; 3636193Sbostic long junk, dlbuf[DEV_BSIZE/sizeof(long)]; 3732529Sbostic 3833164Sbostic /* validate the device specification */ 3936193Sbostic if ((u_int)io->i_bus >= HDC_MAXBUS) 4036193Sbostic return(EADAPT); 4136193Sbostic if ((u_int)io->i_ctlr >= HDC_MAXCTLR) 4236193Sbostic return(ECTLR); 4336193Sbostic if ((u_int)io->i_unit >= HDC_MAXDRIVE) 4432560Sbostic return(EUNIT); 4536193Sbostic if ((u_int)io->i_part > 7) 4636193Sbostic return(EPART); 4732529Sbostic 4833164Sbostic /* init drive structure. */ 4936193Sbostic hdc_regs[io->i_ctlr][io->i_bus] = hr = (struct registers *)(io->i_bus ? 5036193Sbostic 0x80000000 | io->i_ctlr << 24 | HDC_MID << 16 : 5136193Sbostic 0xC0000000 | io->i_ctlr << 24 | HDC_MID << 16); 5232529Sbostic 5333164Sbostic /* insure that this is an hdc, then reset the hdc. */ 5436193Sbostic if (wbadaddr(&hr->module_id, 4, &junk)) { 5536193Sbostic printf("hd%d: %x: invalid csr\n", io->i_ctlr, (u_int)hr); 5632560Sbostic return(ENXIO); 5732557Sbostic } 5836193Sbostic hr->soft_reset = 0; 5932529Sbostic DELAY(1000000); 6032529Sbostic 6132529Sbostic /* 6236193Sbostic * read in the hdc module id word. The controller is bad if the 6332560Sbostic * hdc's writeable control store is not loaded or if the hdc failed 6432560Sbostic * the functional integrity test for any reason. 6532529Sbostic */ 6636193Sbostic hr->module_id = (u_long)&id; 6732529Sbostic DELAY(10000); 6832557Sbostic mtpr(PADC, 0); 6936193Sbostic if (id.module_id != (u_char)HDC_MID) { 7036193Sbostic printf("hdc: controller bad module id: id = %x\n", 7136193Sbostic id.module_id); 7233164Sbostic return(ENXIO); 7332529Sbostic } 7436193Sbostic if (id.code_rev == (u_char)0xff) { 7536193Sbostic printf("hdc: controller micro-code is not loaded.\n"); 7632560Sbostic return(ENXIO); 7732529Sbostic } 7836193Sbostic if (id.fit != (u_char)0xff) { 7936193Sbostic printf("hdc: controller FIT test failed: error= %x\n", 8036193Sbostic id.fit); 8132560Sbostic return(ENXIO); 8232529Sbostic } 8332529Sbostic 8436193Sbostic /* read the drive status */ 8536193Sbostic mcb.command = HCMD_STATUS; 8636193Sbostic mcb.drive = io->i_unit; 8736193Sbostic mcb.cyl = 0; 8836193Sbostic mcb.head = 0; 8936193Sbostic mcb.sector = 0; 9036193Sbostic mcb.chain[0].wcount = (long)(sizeof(struct status) / sizeof(long)); 9136193Sbostic mcb.chain[0].memadr = (long)&status; 9236193Sbostic if (hdimcb(&mcb, io)) 9332560Sbostic return(EIO); 9433164Sbostic 9533164Sbostic /* 9633164Sbostic * Report drive down if anything in the drive status is bad. 9733164Sbostic * If fault condition, reading will try to clear the fault. 9833164Sbostic */ 9936193Sbostic if (status.drs&DRS_FAULT) 10033164Sbostic printf("hdc: clearing drive fault.\n"); 10136193Sbostic if (!(status.drs&DRS_ONLINE)) { 10233164Sbostic printf("hdc: drive is not online.\n"); 10333164Sbostic return(EIO); 10433164Sbostic } 10533164Sbostic 10636193Sbostic /* read in the pack label */ 10736193Sbostic mcb.command = HCMD_READ; 10836193Sbostic mcb.drive = io->i_unit; 10936193Sbostic mcb.cyl = 0; 11036193Sbostic mcb.head = 0; 11136193Sbostic mcb.sector = LABELSECTOR; 11236193Sbostic mcb.chain[0].wcount = (long)(DEV_BSIZE / sizeof(long)); 11336193Sbostic mcb.chain[0].memadr = (long)dlbuf; 11436193Sbostic if (hdimcb(&mcb, io)) 11536193Sbostic return(ERDLAB); 11637566Sbostic dlp = (struct disklabel *)(dlbuf + (LABELOFFSET / sizeof(long))); 11736193Sbostic if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) 11836193Sbostic #ifdef COMPAT_42 11936193Sbostic { 12036193Sbostic int error; 12132529Sbostic 12236193Sbostic if (error = hdmaptype(io, dlp, &status, io->i_unit)) 12336193Sbostic return(error); 12432529Sbostic } 12536193Sbostic #else 12636193Sbostic return(EUNLAB); 12736193Sbostic #endif 12836193Sbostic dklabel[io->i_unit][io->i_ctlr][io->i_bus] = *dlp; 12936193Sbostic if (io->i_part >= dlp->d_npartitions || 13036193Sbostic dlp->d_partitions[io->i_part].p_size == 0) 13136193Sbostic return(EPART); 13236193Sbostic io->i_boff = (dlp->d_partitions[io->i_part].p_offset * 13336193Sbostic dlp->d_secsize) / DEV_BSIZE; 13432560Sbostic return(0); 13532529Sbostic } 13632529Sbostic 13732560Sbostic hdstrategy(io, cmd) 13836193Sbostic register struct iob *io; 13936193Sbostic int cmd; 14032529Sbostic { 14136193Sbostic register struct disklabel *dlp; 14236193Sbostic struct mcb mcb; 14336193Sbostic long sector; 14432529Sbostic 14536193Sbostic if (io->i_cc&3) { 14636193Sbostic printf("hd%d: i/o not a longword multiple.\n", io->i_unit); 14732560Sbostic return(0); 14832560Sbostic } 14936193Sbostic dlp = &dklabel[io->i_unit][io->i_ctlr][io->i_bus]; 15032529Sbostic sector = io->i_bn * HDC_SPB; 15136193Sbostic mcb.command = (cmd == READ) ? HCMD_READ : HCMD_WRITE; 15236193Sbostic mcb.drive = io->i_unit; 15336193Sbostic mcb.cyl = sector / dlp->d_secpercyl; 15436193Sbostic mcb.head = (sector / dlp->d_nsectors) % dlp->d_ntracks; 15536193Sbostic mcb.sector = sector % dlp->d_nsectors; 15636193Sbostic mcb.chain[0].wcount = io->i_cc / sizeof(long); 15736193Sbostic mcb.chain[0].memadr = (u_long)io->i_ma; 15836193Sbostic return(hdimcb(&mcb, io) ? -1 : io->i_cc); 15932529Sbostic } 16032529Sbostic 16136193Sbostic hdimcb(mcb, io) 16236193Sbostic register struct mcb *mcb; 16336193Sbostic register struct iob *io; 16432529Sbostic { 16536193Sbostic struct master_mcb master; 16636193Sbostic int timeout; 16732529Sbostic 16836193Sbostic /* fill in mcb */ 16936193Sbostic mcb->interrupt = 0; 17036193Sbostic mcb->forw_phaddr = 0; 17132529Sbostic 17236193Sbostic /* fill in master mcb */ 17336193Sbostic master.mcw = MCL_IMMEDIATE; 17436193Sbostic master.forw_phaddr = (u_long)mcb; 17536193Sbostic master.mcs = 0; 17632529Sbostic 17736193Sbostic hdc_regs[io->i_ctlr][io->i_bus]->master_mcb = (u_long)&master; 17836193Sbostic for (timeout = 15000; timeout; --timeout) { 17936193Sbostic DELAY(1000); 18036193Sbostic mtpr(PADC, 0); 18136193Sbostic if (master.mcs&MCS_FATALERROR) { 18236193Sbostic printf("hdc%d: fatal error.\n", io->i_ctlr); 18332529Sbostic return(1); 18432529Sbostic } 18536193Sbostic if (master.mcs&MCS_DONE) 18636193Sbostic return(0); 18732529Sbostic } 18837566Sbostic printf("hdc%d: timed out.\n", io->i_ctlr); 18936193Sbostic return(1); 19036193Sbostic } 19132529Sbostic 19236193Sbostic #ifdef COMPAT_42 19336193Sbostic hdmaptype(io, dlp, status, unit) 19436193Sbostic register struct iob *io; 19536193Sbostic register struct disklabel *dlp; 19636193Sbostic struct status *status; 19736193Sbostic int unit; 19836193Sbostic { 19936193Sbostic geometry_sector geometry; 20036193Sbostic geometry_block *geo; 20136193Sbostic struct mcb mcb; 20236193Sbostic int cnt; 20336193Sbostic char *strcpy(); 20432529Sbostic 20536193Sbostic printf("hd%d: unlabeled\n", unit); 20636193Sbostic /* 20736193Sbostic * Read the geometry block (at head = 0 sector = 0 of the drive 20836193Sbostic * definition cylinder), validate it (must have the correct version 20936193Sbostic * number, header, and checksum). 21036193Sbostic */ 21136193Sbostic mcb.command = HCMD_READ; 21236193Sbostic mcb.drive = unit; 21336193Sbostic mcb.cyl = status->def_cyl; 21436193Sbostic mcb.head = 0; 21536193Sbostic mcb.sector = 0; 21636193Sbostic mcb.chain[0].wcount = (long)(sizeof(geometry_sector) / sizeof(long)); 21736193Sbostic mcb.chain[0].memadr = (long)&geometry; 21836193Sbostic if (hdimcb(&mcb, io)) { 21936193Sbostic printf("hd%d: can't read default geometry.\n", io->i_unit); 22036193Sbostic return(ERDLAB); 22132529Sbostic } 22236193Sbostic geo = &geometry.geometry_block; 22336193Sbostic if (geo->version > 64000 || geo->version < 0) { 22436193Sbostic printf("hd%d: bad default geometry version#.\n", io->i_unit); 22536193Sbostic return(ENXIO); 22632529Sbostic } 22736193Sbostic if (strcmp(&geo->id[0], GB_ID)) { 22836193Sbostic printf("hd%d: bad default geometry header.\n", io->i_unit); 22936193Sbostic return(ENXIO); 23032529Sbostic } 23136193Sbostic GB_CHECKSUM(geo, cnt); 23236193Sbostic if (geometry.checksum != cnt) { 23336193Sbostic printf("hd%d: bad default geometry checksum.\n", io->i_unit); 23436193Sbostic return(ENXIO); 23532529Sbostic } 23636193Sbostic for (cnt = 0; cnt < GB_MAXPART; cnt++) { 23736193Sbostic dlp->d_partitions[cnt].p_offset = geo->partition[cnt].start; 23836193Sbostic dlp->d_partitions[cnt].p_size = geo->partition[cnt].length; 23932529Sbostic } 24036193Sbostic #ifdef RAW_SIZE 24136193Sbostic dlp->d_secsize = status->bytes_per_sec; 24236193Sbostic #else 24336193Sbostic dlp->d_secsize = 512; 24436193Sbostic #endif 24536193Sbostic dlp->d_nsectors = status->max_sector + 1; 24636193Sbostic dlp->d_ncylinders = status->max_cyl + 1; 24736193Sbostic dlp->d_ntracks = status->max_head + 1; 24836193Sbostic dlp->d_secpercyl = dlp->d_ntracks * dlp->d_nsectors; 24936193Sbostic dlp->d_npartitions = GB_MAXPART; 25036193Sbostic dlp->d_rpm = status->rpm; 25136193Sbostic (void)strcpy(dlp->d_typename, "hdc (prom)"); 25232560Sbostic return(0); 25332529Sbostic } 25436193Sbostic #endif /* COMPAT_42 */ 255