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*49096Sbostic * @(#)hd.c 7.11 (Berkeley) 05/04/91
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"
1845796Sbostic #include "stand/saio.h"
1945796Sbostic #include "../include/mtpr.h"
2045796Sbostic #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
hdopen(io)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
hdstrategy(io,cmd)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;
148*49096Sbostic mcb.command = (cmd == F_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
hdimcb(mcb,io)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
hdmaptype(io,dlp,status,unit)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