xref: /csrg-svn/sys/tahoe/stand/hd.c (revision 43457)
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