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 * 844532Sbostic * %sccs.include.redist.c% 936193Sbostic * 10*45796Sbostic * @(#)hd.c 7.10 (Berkeley) 12/16/90 1132529Sbostic */ 1232529Sbostic 1343457Sroot #include "sys/param.h" 1443457Sroot #include "sys/time.h" 1543457Sroot #include "sys/buf.h" 1643457Sroot #include "sys/ioctl.h" 1743457Sroot #include "sys/disklabel.h" 18*45796Sbostic #include "stand/saio.h" 19*45796Sbostic #include "../include/mtpr.h" 20*45796Sbostic #include "../vba/hdreg.h" 2132529Sbostic 2236193Sbostic static struct registers *hdc_regs[HDC_MAXCTLR][HDC_MAXBUS]; 2336193Sbostic static struct disklabel dklabel[HDC_MAXDRIVE][HDC_MAXCTLR][HDC_MAXBUS]; 2433164Sbostic 2532529Sbostic hdopen(io) 2636193Sbostic register struct iob *io; 2732529Sbostic { 2836193Sbostic register struct disklabel *dlp; 2936193Sbostic struct status status; 3036193Sbostic struct module_id id; 3136193Sbostic struct registers *hr; 3236193Sbostic struct mcb mcb; 3336193Sbostic long junk, dlbuf[DEV_BSIZE/sizeof(long)]; 3432529Sbostic 3533164Sbostic /* validate the device specification */ 3636193Sbostic if ((u_int)io->i_bus >= HDC_MAXBUS) 3736193Sbostic return(EADAPT); 3836193Sbostic if ((u_int)io->i_ctlr >= HDC_MAXCTLR) 3936193Sbostic return(ECTLR); 4036193Sbostic if ((u_int)io->i_unit >= HDC_MAXDRIVE) 4132560Sbostic return(EUNIT); 4236193Sbostic if ((u_int)io->i_part > 7) 4336193Sbostic return(EPART); 4432529Sbostic 4533164Sbostic /* init drive structure. */ 4636193Sbostic hdc_regs[io->i_ctlr][io->i_bus] = hr = (struct registers *)(io->i_bus ? 4736193Sbostic 0x80000000 | io->i_ctlr << 24 | HDC_MID << 16 : 4836193Sbostic 0xC0000000 | io->i_ctlr << 24 | HDC_MID << 16); 4932529Sbostic 5033164Sbostic /* insure that this is an hdc, then reset the hdc. */ 5136193Sbostic if (wbadaddr(&hr->module_id, 4, &junk)) { 5236193Sbostic printf("hd%d: %x: invalid csr\n", io->i_ctlr, (u_int)hr); 5332560Sbostic return(ENXIO); 5432557Sbostic } 5536193Sbostic hr->soft_reset = 0; 5632529Sbostic DELAY(1000000); 5732529Sbostic 5832529Sbostic /* 5936193Sbostic * read in the hdc module id word. The controller is bad if the 6032560Sbostic * hdc's writeable control store is not loaded or if the hdc failed 6132560Sbostic * the functional integrity test for any reason. 6232529Sbostic */ 6336193Sbostic hr->module_id = (u_long)&id; 6432529Sbostic DELAY(10000); 6532557Sbostic mtpr(PADC, 0); 6636193Sbostic if (id.module_id != (u_char)HDC_MID) { 6736193Sbostic printf("hdc: controller bad module id: id = %x\n", 6836193Sbostic id.module_id); 6933164Sbostic return(ENXIO); 7032529Sbostic } 7136193Sbostic if (id.code_rev == (u_char)0xff) { 7236193Sbostic printf("hdc: controller micro-code is not loaded.\n"); 7332560Sbostic return(ENXIO); 7432529Sbostic } 7536193Sbostic if (id.fit != (u_char)0xff) { 7636193Sbostic printf("hdc: controller FIT test failed: error= %x\n", 7736193Sbostic id.fit); 7832560Sbostic return(ENXIO); 7932529Sbostic } 8032529Sbostic 8136193Sbostic /* read the drive status */ 8236193Sbostic mcb.command = HCMD_STATUS; 8336193Sbostic mcb.drive = io->i_unit; 8436193Sbostic mcb.cyl = 0; 8536193Sbostic mcb.head = 0; 8636193Sbostic mcb.sector = 0; 8736193Sbostic mcb.chain[0].wcount = (long)(sizeof(struct status) / sizeof(long)); 8836193Sbostic mcb.chain[0].memadr = (long)&status; 8936193Sbostic if (hdimcb(&mcb, io)) 9032560Sbostic return(EIO); 9133164Sbostic 9233164Sbostic /* 9333164Sbostic * Report drive down if anything in the drive status is bad. 9433164Sbostic * If fault condition, reading will try to clear the fault. 9533164Sbostic */ 9636193Sbostic if (status.drs&DRS_FAULT) 9733164Sbostic printf("hdc: clearing drive fault.\n"); 9836193Sbostic if (!(status.drs&DRS_ONLINE)) { 9933164Sbostic printf("hdc: drive is not online.\n"); 10033164Sbostic return(EIO); 10133164Sbostic } 10233164Sbostic 10336193Sbostic /* read in the pack label */ 10436193Sbostic mcb.command = HCMD_READ; 10536193Sbostic mcb.drive = io->i_unit; 10636193Sbostic mcb.cyl = 0; 10736193Sbostic mcb.head = 0; 10836193Sbostic mcb.sector = LABELSECTOR; 10936193Sbostic mcb.chain[0].wcount = (long)(DEV_BSIZE / sizeof(long)); 11036193Sbostic mcb.chain[0].memadr = (long)dlbuf; 11136193Sbostic if (hdimcb(&mcb, io)) 11236193Sbostic return(ERDLAB); 11337566Sbostic dlp = (struct disklabel *)(dlbuf + (LABELOFFSET / sizeof(long))); 11436193Sbostic if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) 11536193Sbostic #ifdef COMPAT_42 11636193Sbostic { 11736193Sbostic int error; 11832529Sbostic 11936193Sbostic if (error = hdmaptype(io, dlp, &status, io->i_unit)) 12036193Sbostic return(error); 12132529Sbostic } 12236193Sbostic #else 12336193Sbostic return(EUNLAB); 12436193Sbostic #endif 12536193Sbostic dklabel[io->i_unit][io->i_ctlr][io->i_bus] = *dlp; 12636193Sbostic if (io->i_part >= dlp->d_npartitions || 12736193Sbostic dlp->d_partitions[io->i_part].p_size == 0) 12836193Sbostic return(EPART); 12936193Sbostic io->i_boff = (dlp->d_partitions[io->i_part].p_offset * 13036193Sbostic dlp->d_secsize) / DEV_BSIZE; 13132560Sbostic return(0); 13232529Sbostic } 13332529Sbostic 13432560Sbostic hdstrategy(io, cmd) 13536193Sbostic register struct iob *io; 13636193Sbostic int cmd; 13732529Sbostic { 13836193Sbostic register struct disklabel *dlp; 13936193Sbostic struct mcb mcb; 14036193Sbostic long sector; 14132529Sbostic 14236193Sbostic if (io->i_cc&3) { 14336193Sbostic printf("hd%d: i/o not a longword multiple.\n", io->i_unit); 14432560Sbostic return(0); 14532560Sbostic } 14636193Sbostic dlp = &dklabel[io->i_unit][io->i_ctlr][io->i_bus]; 14732529Sbostic sector = io->i_bn * HDC_SPB; 14836193Sbostic mcb.command = (cmd == READ) ? HCMD_READ : HCMD_WRITE; 14936193Sbostic mcb.drive = io->i_unit; 15036193Sbostic mcb.cyl = sector / dlp->d_secpercyl; 15136193Sbostic mcb.head = (sector / dlp->d_nsectors) % dlp->d_ntracks; 15236193Sbostic mcb.sector = sector % dlp->d_nsectors; 15336193Sbostic mcb.chain[0].wcount = io->i_cc / sizeof(long); 15436193Sbostic mcb.chain[0].memadr = (u_long)io->i_ma; 15536193Sbostic return(hdimcb(&mcb, io) ? -1 : io->i_cc); 15632529Sbostic } 15732529Sbostic 15836193Sbostic hdimcb(mcb, io) 15936193Sbostic register struct mcb *mcb; 16036193Sbostic register struct iob *io; 16132529Sbostic { 16236193Sbostic struct master_mcb master; 16336193Sbostic int timeout; 16432529Sbostic 16536193Sbostic /* fill in mcb */ 16636193Sbostic mcb->interrupt = 0; 16736193Sbostic mcb->forw_phaddr = 0; 16832529Sbostic 16936193Sbostic /* fill in master mcb */ 17036193Sbostic master.mcw = MCL_IMMEDIATE; 17136193Sbostic master.forw_phaddr = (u_long)mcb; 17236193Sbostic master.mcs = 0; 17332529Sbostic 17436193Sbostic hdc_regs[io->i_ctlr][io->i_bus]->master_mcb = (u_long)&master; 17536193Sbostic for (timeout = 15000; timeout; --timeout) { 17636193Sbostic DELAY(1000); 17736193Sbostic mtpr(PADC, 0); 17836193Sbostic if (master.mcs&MCS_FATALERROR) { 17936193Sbostic printf("hdc%d: fatal error.\n", io->i_ctlr); 18032529Sbostic return(1); 18132529Sbostic } 18236193Sbostic if (master.mcs&MCS_DONE) 18336193Sbostic return(0); 18432529Sbostic } 18537566Sbostic printf("hdc%d: timed out.\n", io->i_ctlr); 18636193Sbostic return(1); 18736193Sbostic } 18832529Sbostic 18936193Sbostic #ifdef COMPAT_42 19036193Sbostic hdmaptype(io, dlp, status, unit) 19136193Sbostic register struct iob *io; 19236193Sbostic register struct disklabel *dlp; 19336193Sbostic struct status *status; 19436193Sbostic int unit; 19536193Sbostic { 19636193Sbostic geometry_sector geometry; 19736193Sbostic geometry_block *geo; 19836193Sbostic struct mcb mcb; 19936193Sbostic int cnt; 20036193Sbostic char *strcpy(); 20132529Sbostic 20236193Sbostic printf("hd%d: unlabeled\n", unit); 20336193Sbostic /* 20436193Sbostic * Read the geometry block (at head = 0 sector = 0 of the drive 20536193Sbostic * definition cylinder), validate it (must have the correct version 20636193Sbostic * number, header, and checksum). 20736193Sbostic */ 20836193Sbostic mcb.command = HCMD_READ; 20936193Sbostic mcb.drive = unit; 21036193Sbostic mcb.cyl = status->def_cyl; 21136193Sbostic mcb.head = 0; 21236193Sbostic mcb.sector = 0; 21336193Sbostic mcb.chain[0].wcount = (long)(sizeof(geometry_sector) / sizeof(long)); 21436193Sbostic mcb.chain[0].memadr = (long)&geometry; 21536193Sbostic if (hdimcb(&mcb, io)) { 21636193Sbostic printf("hd%d: can't read default geometry.\n", io->i_unit); 21736193Sbostic return(ERDLAB); 21832529Sbostic } 21936193Sbostic geo = &geometry.geometry_block; 22036193Sbostic if (geo->version > 64000 || geo->version < 0) { 22136193Sbostic printf("hd%d: bad default geometry version#.\n", io->i_unit); 22236193Sbostic return(ENXIO); 22332529Sbostic } 22436193Sbostic if (strcmp(&geo->id[0], GB_ID)) { 22536193Sbostic printf("hd%d: bad default geometry header.\n", io->i_unit); 22636193Sbostic return(ENXIO); 22732529Sbostic } 22836193Sbostic GB_CHECKSUM(geo, cnt); 22936193Sbostic if (geometry.checksum != cnt) { 23036193Sbostic printf("hd%d: bad default geometry checksum.\n", io->i_unit); 23136193Sbostic return(ENXIO); 23232529Sbostic } 23336193Sbostic for (cnt = 0; cnt < GB_MAXPART; cnt++) { 23436193Sbostic dlp->d_partitions[cnt].p_offset = geo->partition[cnt].start; 23536193Sbostic dlp->d_partitions[cnt].p_size = geo->partition[cnt].length; 23632529Sbostic } 23736193Sbostic #ifdef RAW_SIZE 23836193Sbostic dlp->d_secsize = status->bytes_per_sec; 23936193Sbostic #else 24036193Sbostic dlp->d_secsize = 512; 24136193Sbostic #endif 24236193Sbostic dlp->d_nsectors = status->max_sector + 1; 24336193Sbostic dlp->d_ncylinders = status->max_cyl + 1; 24436193Sbostic dlp->d_ntracks = status->max_head + 1; 24536193Sbostic dlp->d_secpercyl = dlp->d_ntracks * dlp->d_nsectors; 24636193Sbostic dlp->d_npartitions = GB_MAXPART; 24736193Sbostic dlp->d_rpm = status->rpm; 24836193Sbostic (void)strcpy(dlp->d_typename, "hdc (prom)"); 24932560Sbostic return(0); 25032529Sbostic } 25136193Sbostic #endif /* COMPAT_42 */ 252