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*43457Sroot * @(#)hd.c 7.7 (Berkeley) 06/22/90 2132529Sbostic */ 2232529Sbostic 23*43457Sroot #include "sys/param.h" 24*43457Sroot #include "sys/time.h" 25*43457Sroot #include "sys/vnode.h" 26*43457Sroot #include "ufs/inode.h" 27*43457Sroot #include "ufs/fs.h" 28*43457Sroot #include "sys/buf.h" 29*43457Sroot #include "sys/ioctl.h" 30*43457Sroot #include "sys/disklabel.h" 3132557Sbostic #include "saio.h" 32*43457Sroot #include "tahoe/mtpr.h" 33*43457Sroot #include "tahoevba/hdreg.h" 3432529Sbostic 3536193Sbostic static struct registers *hdc_regs[HDC_MAXCTLR][HDC_MAXBUS]; 3636193Sbostic static struct disklabel dklabel[HDC_MAXDRIVE][HDC_MAXCTLR][HDC_MAXBUS]; 3733164Sbostic 3832529Sbostic hdopen(io) 3936193Sbostic register struct iob *io; 4032529Sbostic { 4136193Sbostic register struct disklabel *dlp; 4236193Sbostic struct status status; 4336193Sbostic struct module_id id; 4436193Sbostic struct registers *hr; 4536193Sbostic struct mcb mcb; 4636193Sbostic long junk, dlbuf[DEV_BSIZE/sizeof(long)]; 4732529Sbostic 4833164Sbostic /* validate the device specification */ 4936193Sbostic if ((u_int)io->i_bus >= HDC_MAXBUS) 5036193Sbostic return(EADAPT); 5136193Sbostic if ((u_int)io->i_ctlr >= HDC_MAXCTLR) 5236193Sbostic return(ECTLR); 5336193Sbostic if ((u_int)io->i_unit >= HDC_MAXDRIVE) 5432560Sbostic return(EUNIT); 5536193Sbostic if ((u_int)io->i_part > 7) 5636193Sbostic return(EPART); 5732529Sbostic 5833164Sbostic /* init drive structure. */ 5936193Sbostic hdc_regs[io->i_ctlr][io->i_bus] = hr = (struct registers *)(io->i_bus ? 6036193Sbostic 0x80000000 | io->i_ctlr << 24 | HDC_MID << 16 : 6136193Sbostic 0xC0000000 | io->i_ctlr << 24 | HDC_MID << 16); 6232529Sbostic 6333164Sbostic /* insure that this is an hdc, then reset the hdc. */ 6436193Sbostic if (wbadaddr(&hr->module_id, 4, &junk)) { 6536193Sbostic printf("hd%d: %x: invalid csr\n", io->i_ctlr, (u_int)hr); 6632560Sbostic return(ENXIO); 6732557Sbostic } 6836193Sbostic hr->soft_reset = 0; 6932529Sbostic DELAY(1000000); 7032529Sbostic 7132529Sbostic /* 7236193Sbostic * read in the hdc module id word. The controller is bad if the 7332560Sbostic * hdc's writeable control store is not loaded or if the hdc failed 7432560Sbostic * the functional integrity test for any reason. 7532529Sbostic */ 7636193Sbostic hr->module_id = (u_long)&id; 7732529Sbostic DELAY(10000); 7832557Sbostic mtpr(PADC, 0); 7936193Sbostic if (id.module_id != (u_char)HDC_MID) { 8036193Sbostic printf("hdc: controller bad module id: id = %x\n", 8136193Sbostic id.module_id); 8233164Sbostic return(ENXIO); 8332529Sbostic } 8436193Sbostic if (id.code_rev == (u_char)0xff) { 8536193Sbostic printf("hdc: controller micro-code is not loaded.\n"); 8632560Sbostic return(ENXIO); 8732529Sbostic } 8836193Sbostic if (id.fit != (u_char)0xff) { 8936193Sbostic printf("hdc: controller FIT test failed: error= %x\n", 9036193Sbostic id.fit); 9132560Sbostic return(ENXIO); 9232529Sbostic } 9332529Sbostic 9436193Sbostic /* read the drive status */ 9536193Sbostic mcb.command = HCMD_STATUS; 9636193Sbostic mcb.drive = io->i_unit; 9736193Sbostic mcb.cyl = 0; 9836193Sbostic mcb.head = 0; 9936193Sbostic mcb.sector = 0; 10036193Sbostic mcb.chain[0].wcount = (long)(sizeof(struct status) / sizeof(long)); 10136193Sbostic mcb.chain[0].memadr = (long)&status; 10236193Sbostic if (hdimcb(&mcb, io)) 10332560Sbostic return(EIO); 10433164Sbostic 10533164Sbostic /* 10633164Sbostic * Report drive down if anything in the drive status is bad. 10733164Sbostic * If fault condition, reading will try to clear the fault. 10833164Sbostic */ 10936193Sbostic if (status.drs&DRS_FAULT) 11033164Sbostic printf("hdc: clearing drive fault.\n"); 11136193Sbostic if (!(status.drs&DRS_ONLINE)) { 11233164Sbostic printf("hdc: drive is not online.\n"); 11333164Sbostic return(EIO); 11433164Sbostic } 11533164Sbostic 11636193Sbostic /* read in the pack label */ 11736193Sbostic mcb.command = HCMD_READ; 11836193Sbostic mcb.drive = io->i_unit; 11936193Sbostic mcb.cyl = 0; 12036193Sbostic mcb.head = 0; 12136193Sbostic mcb.sector = LABELSECTOR; 12236193Sbostic mcb.chain[0].wcount = (long)(DEV_BSIZE / sizeof(long)); 12336193Sbostic mcb.chain[0].memadr = (long)dlbuf; 12436193Sbostic if (hdimcb(&mcb, io)) 12536193Sbostic return(ERDLAB); 12637566Sbostic dlp = (struct disklabel *)(dlbuf + (LABELOFFSET / sizeof(long))); 12736193Sbostic if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) 12836193Sbostic #ifdef COMPAT_42 12936193Sbostic { 13036193Sbostic int error; 13132529Sbostic 13236193Sbostic if (error = hdmaptype(io, dlp, &status, io->i_unit)) 13336193Sbostic return(error); 13432529Sbostic } 13536193Sbostic #else 13636193Sbostic return(EUNLAB); 13736193Sbostic #endif 13836193Sbostic dklabel[io->i_unit][io->i_ctlr][io->i_bus] = *dlp; 13936193Sbostic if (io->i_part >= dlp->d_npartitions || 14036193Sbostic dlp->d_partitions[io->i_part].p_size == 0) 14136193Sbostic return(EPART); 14236193Sbostic io->i_boff = (dlp->d_partitions[io->i_part].p_offset * 14336193Sbostic dlp->d_secsize) / DEV_BSIZE; 14432560Sbostic return(0); 14532529Sbostic } 14632529Sbostic 14732560Sbostic hdstrategy(io, cmd) 14836193Sbostic register struct iob *io; 14936193Sbostic int cmd; 15032529Sbostic { 15136193Sbostic register struct disklabel *dlp; 15236193Sbostic struct mcb mcb; 15336193Sbostic long sector; 15432529Sbostic 15536193Sbostic if (io->i_cc&3) { 15636193Sbostic printf("hd%d: i/o not a longword multiple.\n", io->i_unit); 15732560Sbostic return(0); 15832560Sbostic } 15936193Sbostic dlp = &dklabel[io->i_unit][io->i_ctlr][io->i_bus]; 16032529Sbostic sector = io->i_bn * HDC_SPB; 16136193Sbostic mcb.command = (cmd == READ) ? HCMD_READ : HCMD_WRITE; 16236193Sbostic mcb.drive = io->i_unit; 16336193Sbostic mcb.cyl = sector / dlp->d_secpercyl; 16436193Sbostic mcb.head = (sector / dlp->d_nsectors) % dlp->d_ntracks; 16536193Sbostic mcb.sector = sector % dlp->d_nsectors; 16636193Sbostic mcb.chain[0].wcount = io->i_cc / sizeof(long); 16736193Sbostic mcb.chain[0].memadr = (u_long)io->i_ma; 16836193Sbostic return(hdimcb(&mcb, io) ? -1 : io->i_cc); 16932529Sbostic } 17032529Sbostic 17136193Sbostic hdimcb(mcb, io) 17236193Sbostic register struct mcb *mcb; 17336193Sbostic register struct iob *io; 17432529Sbostic { 17536193Sbostic struct master_mcb master; 17636193Sbostic int timeout; 17732529Sbostic 17836193Sbostic /* fill in mcb */ 17936193Sbostic mcb->interrupt = 0; 18036193Sbostic mcb->forw_phaddr = 0; 18132529Sbostic 18236193Sbostic /* fill in master mcb */ 18336193Sbostic master.mcw = MCL_IMMEDIATE; 18436193Sbostic master.forw_phaddr = (u_long)mcb; 18536193Sbostic master.mcs = 0; 18632529Sbostic 18736193Sbostic hdc_regs[io->i_ctlr][io->i_bus]->master_mcb = (u_long)&master; 18836193Sbostic for (timeout = 15000; timeout; --timeout) { 18936193Sbostic DELAY(1000); 19036193Sbostic mtpr(PADC, 0); 19136193Sbostic if (master.mcs&MCS_FATALERROR) { 19236193Sbostic printf("hdc%d: fatal error.\n", io->i_ctlr); 19332529Sbostic return(1); 19432529Sbostic } 19536193Sbostic if (master.mcs&MCS_DONE) 19636193Sbostic return(0); 19732529Sbostic } 19837566Sbostic printf("hdc%d: timed out.\n", io->i_ctlr); 19936193Sbostic return(1); 20036193Sbostic } 20132529Sbostic 20236193Sbostic #ifdef COMPAT_42 20336193Sbostic hdmaptype(io, dlp, status, unit) 20436193Sbostic register struct iob *io; 20536193Sbostic register struct disklabel *dlp; 20636193Sbostic struct status *status; 20736193Sbostic int unit; 20836193Sbostic { 20936193Sbostic geometry_sector geometry; 21036193Sbostic geometry_block *geo; 21136193Sbostic struct mcb mcb; 21236193Sbostic int cnt; 21336193Sbostic char *strcpy(); 21432529Sbostic 21536193Sbostic printf("hd%d: unlabeled\n", unit); 21636193Sbostic /* 21736193Sbostic * Read the geometry block (at head = 0 sector = 0 of the drive 21836193Sbostic * definition cylinder), validate it (must have the correct version 21936193Sbostic * number, header, and checksum). 22036193Sbostic */ 22136193Sbostic mcb.command = HCMD_READ; 22236193Sbostic mcb.drive = unit; 22336193Sbostic mcb.cyl = status->def_cyl; 22436193Sbostic mcb.head = 0; 22536193Sbostic mcb.sector = 0; 22636193Sbostic mcb.chain[0].wcount = (long)(sizeof(geometry_sector) / sizeof(long)); 22736193Sbostic mcb.chain[0].memadr = (long)&geometry; 22836193Sbostic if (hdimcb(&mcb, io)) { 22936193Sbostic printf("hd%d: can't read default geometry.\n", io->i_unit); 23036193Sbostic return(ERDLAB); 23132529Sbostic } 23236193Sbostic geo = &geometry.geometry_block; 23336193Sbostic if (geo->version > 64000 || geo->version < 0) { 23436193Sbostic printf("hd%d: bad default geometry version#.\n", io->i_unit); 23536193Sbostic return(ENXIO); 23632529Sbostic } 23736193Sbostic if (strcmp(&geo->id[0], GB_ID)) { 23836193Sbostic printf("hd%d: bad default geometry header.\n", io->i_unit); 23936193Sbostic return(ENXIO); 24032529Sbostic } 24136193Sbostic GB_CHECKSUM(geo, cnt); 24236193Sbostic if (geometry.checksum != cnt) { 24336193Sbostic printf("hd%d: bad default geometry checksum.\n", io->i_unit); 24436193Sbostic return(ENXIO); 24532529Sbostic } 24636193Sbostic for (cnt = 0; cnt < GB_MAXPART; cnt++) { 24736193Sbostic dlp->d_partitions[cnt].p_offset = geo->partition[cnt].start; 24836193Sbostic dlp->d_partitions[cnt].p_size = geo->partition[cnt].length; 24932529Sbostic } 25036193Sbostic #ifdef RAW_SIZE 25136193Sbostic dlp->d_secsize = status->bytes_per_sec; 25236193Sbostic #else 25336193Sbostic dlp->d_secsize = 512; 25436193Sbostic #endif 25536193Sbostic dlp->d_nsectors = status->max_sector + 1; 25636193Sbostic dlp->d_ncylinders = status->max_cyl + 1; 25736193Sbostic dlp->d_ntracks = status->max_head + 1; 25836193Sbostic dlp->d_secpercyl = dlp->d_ntracks * dlp->d_nsectors; 25936193Sbostic dlp->d_npartitions = GB_MAXPART; 26036193Sbostic dlp->d_rpm = status->rpm; 26136193Sbostic (void)strcpy(dlp->d_typename, "hdc (prom)"); 26232560Sbostic return(0); 26332529Sbostic } 26436193Sbostic #endif /* COMPAT_42 */ 265