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 * 836193Sbostic * Redistribution and use in source and binary forms are permitted 936193Sbostic * provided that the above copyright notice and this paragraph are 1036193Sbostic * duplicated in all such forms and that any documentation, 1136193Sbostic * advertising materials, and other materials related to such 1236193Sbostic * distribution and use acknowledge that the software was developed 1336193Sbostic * by the University of California, Berkeley. The name of the 1436193Sbostic * University may not be used to endorse or promote products derived 1536193Sbostic * from this software without specific prior written permission. 1636193Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1736193Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1836193Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1936193Sbostic * 20*37566Sbostic * @(#)hd.c 7.6 (Berkeley) 05/01/89 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" 3036193Sbostic #include "../tahoe/mtpr.h" 3136193Sbostic #include "../tahoevba/hdreg.h" 3232529Sbostic 3336193Sbostic static struct registers *hdc_regs[HDC_MAXCTLR][HDC_MAXBUS]; 3436193Sbostic static struct disklabel dklabel[HDC_MAXDRIVE][HDC_MAXCTLR][HDC_MAXBUS]; 3533164Sbostic 3632529Sbostic hdopen(io) 3736193Sbostic register struct iob *io; 3832529Sbostic { 3936193Sbostic register struct disklabel *dlp; 4036193Sbostic struct status status; 4136193Sbostic struct module_id id; 4236193Sbostic struct registers *hr; 4336193Sbostic struct mcb mcb; 4436193Sbostic long junk, dlbuf[DEV_BSIZE/sizeof(long)]; 4532529Sbostic 4633164Sbostic /* validate the device specification */ 4736193Sbostic if ((u_int)io->i_bus >= HDC_MAXBUS) 4836193Sbostic return(EADAPT); 4936193Sbostic if ((u_int)io->i_ctlr >= HDC_MAXCTLR) 5036193Sbostic return(ECTLR); 5136193Sbostic if ((u_int)io->i_unit >= HDC_MAXDRIVE) 5232560Sbostic return(EUNIT); 5336193Sbostic if ((u_int)io->i_part > 7) 5436193Sbostic return(EPART); 5532529Sbostic 5633164Sbostic /* init drive structure. */ 5736193Sbostic hdc_regs[io->i_ctlr][io->i_bus] = hr = (struct registers *)(io->i_bus ? 5836193Sbostic 0x80000000 | io->i_ctlr << 24 | HDC_MID << 16 : 5936193Sbostic 0xC0000000 | io->i_ctlr << 24 | HDC_MID << 16); 6032529Sbostic 6133164Sbostic /* insure that this is an hdc, then reset the hdc. */ 6236193Sbostic if (wbadaddr(&hr->module_id, 4, &junk)) { 6336193Sbostic printf("hd%d: %x: invalid csr\n", io->i_ctlr, (u_int)hr); 6432560Sbostic return(ENXIO); 6532557Sbostic } 6636193Sbostic hr->soft_reset = 0; 6732529Sbostic DELAY(1000000); 6832529Sbostic 6932529Sbostic /* 7036193Sbostic * 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 */ 7436193Sbostic hr->module_id = (u_long)&id; 7532529Sbostic DELAY(10000); 7632557Sbostic mtpr(PADC, 0); 7736193Sbostic if (id.module_id != (u_char)HDC_MID) { 7836193Sbostic printf("hdc: controller bad module id: id = %x\n", 7936193Sbostic id.module_id); 8033164Sbostic return(ENXIO); 8132529Sbostic } 8236193Sbostic if (id.code_rev == (u_char)0xff) { 8336193Sbostic printf("hdc: controller micro-code is not loaded.\n"); 8432560Sbostic return(ENXIO); 8532529Sbostic } 8636193Sbostic if (id.fit != (u_char)0xff) { 8736193Sbostic printf("hdc: controller FIT test failed: error= %x\n", 8836193Sbostic id.fit); 8932560Sbostic return(ENXIO); 9032529Sbostic } 9132529Sbostic 9236193Sbostic /* read the drive status */ 9336193Sbostic mcb.command = HCMD_STATUS; 9436193Sbostic mcb.drive = io->i_unit; 9536193Sbostic mcb.cyl = 0; 9636193Sbostic mcb.head = 0; 9736193Sbostic mcb.sector = 0; 9836193Sbostic mcb.chain[0].wcount = (long)(sizeof(struct status) / sizeof(long)); 9936193Sbostic mcb.chain[0].memadr = (long)&status; 10036193Sbostic 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 */ 10736193Sbostic if (status.drs&DRS_FAULT) 10833164Sbostic printf("hdc: clearing drive fault.\n"); 10936193Sbostic if (!(status.drs&DRS_ONLINE)) { 11033164Sbostic printf("hdc: drive is not online.\n"); 11133164Sbostic return(EIO); 11233164Sbostic } 11333164Sbostic 11436193Sbostic /* read in the pack label */ 11536193Sbostic mcb.command = HCMD_READ; 11636193Sbostic mcb.drive = io->i_unit; 11736193Sbostic mcb.cyl = 0; 11836193Sbostic mcb.head = 0; 11936193Sbostic mcb.sector = LABELSECTOR; 12036193Sbostic mcb.chain[0].wcount = (long)(DEV_BSIZE / sizeof(long)); 12136193Sbostic mcb.chain[0].memadr = (long)dlbuf; 12236193Sbostic if (hdimcb(&mcb, io)) 12336193Sbostic return(ERDLAB); 124*37566Sbostic dlp = (struct disklabel *)(dlbuf + (LABELOFFSET / sizeof(long))); 12536193Sbostic if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) 12636193Sbostic #ifdef COMPAT_42 12736193Sbostic { 12836193Sbostic int error; 12932529Sbostic 13036193Sbostic if (error = hdmaptype(io, dlp, &status, io->i_unit)) 13136193Sbostic return(error); 13232529Sbostic } 13336193Sbostic #else 13436193Sbostic return(EUNLAB); 13536193Sbostic #endif 13636193Sbostic dklabel[io->i_unit][io->i_ctlr][io->i_bus] = *dlp; 13736193Sbostic if (io->i_part >= dlp->d_npartitions || 13836193Sbostic dlp->d_partitions[io->i_part].p_size == 0) 13936193Sbostic return(EPART); 14036193Sbostic io->i_boff = (dlp->d_partitions[io->i_part].p_offset * 14136193Sbostic dlp->d_secsize) / DEV_BSIZE; 14232560Sbostic return(0); 14332529Sbostic } 14432529Sbostic 14532560Sbostic hdstrategy(io, cmd) 14636193Sbostic register struct iob *io; 14736193Sbostic int cmd; 14832529Sbostic { 14936193Sbostic register struct disklabel *dlp; 15036193Sbostic struct mcb mcb; 15136193Sbostic long sector; 15232529Sbostic 15336193Sbostic if (io->i_cc&3) { 15436193Sbostic printf("hd%d: i/o not a longword multiple.\n", io->i_unit); 15532560Sbostic return(0); 15632560Sbostic } 15736193Sbostic dlp = &dklabel[io->i_unit][io->i_ctlr][io->i_bus]; 15832529Sbostic sector = io->i_bn * HDC_SPB; 15936193Sbostic mcb.command = (cmd == READ) ? HCMD_READ : HCMD_WRITE; 16036193Sbostic mcb.drive = io->i_unit; 16136193Sbostic mcb.cyl = sector / dlp->d_secpercyl; 16236193Sbostic mcb.head = (sector / dlp->d_nsectors) % dlp->d_ntracks; 16336193Sbostic mcb.sector = sector % dlp->d_nsectors; 16436193Sbostic mcb.chain[0].wcount = io->i_cc / sizeof(long); 16536193Sbostic mcb.chain[0].memadr = (u_long)io->i_ma; 16636193Sbostic return(hdimcb(&mcb, io) ? -1 : io->i_cc); 16732529Sbostic } 16832529Sbostic 16936193Sbostic hdimcb(mcb, io) 17036193Sbostic register struct mcb *mcb; 17136193Sbostic register struct iob *io; 17232529Sbostic { 17336193Sbostic struct master_mcb master; 17436193Sbostic int timeout; 17532529Sbostic 17636193Sbostic /* fill in mcb */ 17736193Sbostic mcb->interrupt = 0; 17836193Sbostic mcb->forw_phaddr = 0; 17932529Sbostic 18036193Sbostic /* fill in master mcb */ 18136193Sbostic master.mcw = MCL_IMMEDIATE; 18236193Sbostic master.forw_phaddr = (u_long)mcb; 18336193Sbostic master.mcs = 0; 18432529Sbostic 18536193Sbostic hdc_regs[io->i_ctlr][io->i_bus]->master_mcb = (u_long)&master; 18636193Sbostic for (timeout = 15000; timeout; --timeout) { 18736193Sbostic DELAY(1000); 18836193Sbostic mtpr(PADC, 0); 18936193Sbostic if (master.mcs&MCS_FATALERROR) { 19036193Sbostic printf("hdc%d: fatal error.\n", io->i_ctlr); 19132529Sbostic return(1); 19232529Sbostic } 19336193Sbostic if (master.mcs&MCS_DONE) 19436193Sbostic return(0); 19532529Sbostic } 196*37566Sbostic printf("hdc%d: timed out.\n", io->i_ctlr); 19736193Sbostic return(1); 19836193Sbostic } 19932529Sbostic 20036193Sbostic #ifdef COMPAT_42 20136193Sbostic hdmaptype(io, dlp, status, unit) 20236193Sbostic register struct iob *io; 20336193Sbostic register struct disklabel *dlp; 20436193Sbostic struct status *status; 20536193Sbostic int unit; 20636193Sbostic { 20736193Sbostic geometry_sector geometry; 20836193Sbostic geometry_block *geo; 20936193Sbostic struct mcb mcb; 21036193Sbostic int cnt; 21136193Sbostic char *strcpy(); 21232529Sbostic 21336193Sbostic printf("hd%d: unlabeled\n", unit); 21436193Sbostic /* 21536193Sbostic * Read the geometry block (at head = 0 sector = 0 of the drive 21636193Sbostic * definition cylinder), validate it (must have the correct version 21736193Sbostic * number, header, and checksum). 21836193Sbostic */ 21936193Sbostic mcb.command = HCMD_READ; 22036193Sbostic mcb.drive = unit; 22136193Sbostic mcb.cyl = status->def_cyl; 22236193Sbostic mcb.head = 0; 22336193Sbostic mcb.sector = 0; 22436193Sbostic mcb.chain[0].wcount = (long)(sizeof(geometry_sector) / sizeof(long)); 22536193Sbostic mcb.chain[0].memadr = (long)&geometry; 22636193Sbostic if (hdimcb(&mcb, io)) { 22736193Sbostic printf("hd%d: can't read default geometry.\n", io->i_unit); 22836193Sbostic return(ERDLAB); 22932529Sbostic } 23036193Sbostic geo = &geometry.geometry_block; 23136193Sbostic if (geo->version > 64000 || geo->version < 0) { 23236193Sbostic printf("hd%d: bad default geometry version#.\n", io->i_unit); 23336193Sbostic return(ENXIO); 23432529Sbostic } 23536193Sbostic if (strcmp(&geo->id[0], GB_ID)) { 23636193Sbostic printf("hd%d: bad default geometry header.\n", io->i_unit); 23736193Sbostic return(ENXIO); 23832529Sbostic } 23936193Sbostic GB_CHECKSUM(geo, cnt); 24036193Sbostic if (geometry.checksum != cnt) { 24136193Sbostic printf("hd%d: bad default geometry checksum.\n", io->i_unit); 24236193Sbostic return(ENXIO); 24332529Sbostic } 24436193Sbostic for (cnt = 0; cnt < GB_MAXPART; cnt++) { 24536193Sbostic dlp->d_partitions[cnt].p_offset = geo->partition[cnt].start; 24636193Sbostic dlp->d_partitions[cnt].p_size = geo->partition[cnt].length; 24732529Sbostic } 24836193Sbostic #ifdef RAW_SIZE 24936193Sbostic dlp->d_secsize = status->bytes_per_sec; 25036193Sbostic #else 25136193Sbostic dlp->d_secsize = 512; 25236193Sbostic #endif 25336193Sbostic dlp->d_nsectors = status->max_sector + 1; 25436193Sbostic dlp->d_ncylinders = status->max_cyl + 1; 25536193Sbostic dlp->d_ntracks = status->max_head + 1; 25636193Sbostic dlp->d_secpercyl = dlp->d_ntracks * dlp->d_nsectors; 25736193Sbostic dlp->d_npartitions = GB_MAXPART; 25836193Sbostic dlp->d_rpm = status->rpm; 25936193Sbostic (void)strcpy(dlp->d_typename, "hdc (prom)"); 26032560Sbostic return(0); 26132529Sbostic } 26236193Sbostic #endif /* COMPAT_42 */ 263