📄 wd.c
字号:
/* * Roadrunner/pk * Copyright (C) 1989-2001 Cornfed Systems, Inc. * * The Roadrunner/pk operating system is free software; you can * redistribute and/or modify it under the terms of the GNU General * Public License, version 2, as published by the Free Software * Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the Free * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * * More information about the Roadrunner/pk operating system of * which this file is a part is available on the World-Wide Web * at: http://www.cornfed.com. * */#include <dev.h>#include <dev/wd.h>#include <errno.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys.h>#include <sys/boot.h>#include <sys/buf.h>#include <sys/i8259.h>#include <sys/intr.h>#include <sys/ioctl.h>#include <sys/mutex.h>#include <sys/part.h>#include <sys/proc.h>#include <sys/time.h>#include <sys/types.h>#define WD_CONTROLLERS 1#define WD_DRIVES 1#define WDC0 (wdctab[0])#define WD0 (wdtab[0])#define WDC0_IOBASE 0x01f0/* Controller registers */#define WDC_DATA 0x0000 /* 16-bit port */#define WDC_ERR 0x0001#define WDC_FEATURE 0x0001#define WDC_SECTORCNT 0x0002#define WDC_SECTOR 0x0003#define WDC_TRACKLSB 0x0004#define WDC_TRACKMSB 0x0005#define WDC_DRVHD 0x0006#define WDC_STATUS 0x0007#define WDC_COMMAND 0x0007#define WDC_ALT_STATUS 0x0206#define WDC_CONTROL 0x0206/* Controller commands */#define WDCTL_RST 0x04 /* Controller reset */#define WDCTL_4BITHD 0x08 /* Use 4 bits for head id *//* Drive commands */#define WDCMD_NULL 0x00#define WDCMD_READP 0xec#define WDCMD_RESET 0x10/* #define WDCMD_READ 0x21 */#define WDCMD_READ 0x20#define WDCMD_WRITE 0x30/* Controller status */#define WDCS_ERR 0x01 /* Error */#define WDCS_IDX 0x02 /* Index */#define WDCS_CORR 0x04 /* Corrected data */#define WDCS_DRQ 0x08 /* Data request */#define WDCS_DSC 0x10 /* Drive seek complete */#define WDCS_DWF 0x20 /* Drive write fault */#define WDCS_DRDY 0x40 /* Drive ready */#define WDCS_BSY 0x80 /* Controller busy *//* Controller error conditions */#define WDCE_AMNF 0x01 /* Address mark not found */#define WDCE_TK0NF 0x02 /* Track 0 not found */#define WDCE_ABRT 0x04 /* Abort */#define WDCE_MCR 0x08 /* Media change requested */#define WDCE_IDNF 0x10 /* Sector id not found */#define WDCE_MC 0x20 /* Media change */#define WDCE_UNC 0x40 /* Uncorrectable data error */#define WDCE_BBK 0x80 /* Bad block *//* Timeouts (in seconds) */#define WDTIMEOUT_DRDY 5#define WDTIMEOUT_DRQ 5#define WDTIMEOUT_CMD 2/* Parameters returned by read drive parameters command */struct wdparam { /* Drive information */ short config; /* General configuration bits */ u_short cylinders; /* Cylinders */ short reserved; u_short heads; /* Heads */ short unfbytespertrk; /* Unformatted bytes/track */ short unfbytes; /* Unformatted bytes/sector */ u_short sectors; /* Sectors per track */ short vendorunique[3]; /* Controller information */ char serial[20]; /* Serial number */#define WDTYPE_SINGLE 1 /* Single port, single sector buf */#define WDTYPE_DUAL 2 /* Dual port, multiple sector buf */#define WDTYPE_DUAL_CACHE 3 /* Above plus track cache */ short buffertype; /* Buffer type */ short buffersize; /* Buffer size, in 512-byte units */ short necc; /* ECC bytes appended */ char rev[8]; /* Firmware revision */ char model[40]; /* Model name */ short nsecperint; /* Sectors per interrupt */ short usedmovsd; /* Can use double word read/write? */ char pad[418];};struct wdc { struct mutex mutex; /* Controller mutex */ u_short iobase; /* I/O port registers base address */};struct wd { struct wdc *wdc; /* Controller */ struct wdparam param; /* Drive parameter block */ /* Geometry */ u_int blks; /* Number of blocks on drive */ u_int size; /* Size in Mbytes */ u_int tracks; /* Number of tracks */ u_int heads; /* Number of heads */ u_int sectorspertrack; /* Sectors per track */ /* Partition information */ struct part parttab[PARTS]; /* Current transfer location */ u_int blkno; /* Current block */ u_int track; /* Current track */ u_int head; /* Current head */ u_int sector; /* Current sector */};static struct wdc wdctab[WD_CONTROLLERS];static struct wd wdtab[WD_DRIVES];#if _DEBUGstatic voidwd_error(char *f, u_char error){ kprintf("%s: ", f); if (error & WDCE_BBK) kprintf("bad block "); if (error & WDCE_UNC) kprintf("uncorrectable data "); if (error & WDCE_MC) kprintf("media change "); if (error & WDCE_IDNF) kprintf("id not found "); if (error & WDCE_MCR) kprintf("media change requested "); if (error & WDCE_ABRT) kprintf("abort "); if (error & WDCE_TK0NF) kprintf("track 0 not found "); if (error & WDCE_AMNF) kprintf("address mark not found "); kprintf("\n");}#endifstatic intwd_wait(u_char cmd, u_char mask, int timeout){ time_t start; u_char status; for (start = time();;) { status = inb(WD0.wdc->iobase + WDC_ALT_STATUS); if (status & WDCS_ERR) { u_char error; error = inb(WD0.wdc->iobase + WDC_ERR);#if _DEBUG wd_error("wdwait", error);#endif switch (cmd) { case WDCMD_READ: return EDEVREAD; case WDCMD_WRITE: return EDEVWRITE; default: return ENOSYS; } } if (!(status & WDCS_BSY) && ((status & mask) == mask)) return 0; if (time() - start >= timeout) return ETIMEDOUT; }}static intwd_readp(struct wd *wd, char *drvstr){ int result; /* Issue read drive parameters command */ outb(wd->wdc->iobase + WDC_DRVHD, 0xa0); outb(wd->wdc->iobase + WDC_COMMAND, WDCMD_READP); /* Wait for data ready */ if (!(inb(wd->wdc->iobase + WDC_ALT_STATUS) & WDCS_DRQ) && (result = wd_wait(WDCMD_READ, WDCS_DRQ, WDTIMEOUT_DRQ)) < 0) return result; /* Read parameter data */ insw(wd->wdc->iobase + WDC_DATA, (void *) &(wd->param), SECTOR_SIZE / 2); /* Fill in drive parameters */ wd->tracks = wd->param.cylinders; wd->heads = wd->param.heads; wd->sectorspertrack = wd->param.sectors; wd->blks = wd->tracks * wd->heads * wd->sectorspertrack; wd->size = wd->blks * SECTOR_SIZE / 1048576; kprintf("%s: %u blks (%d Mbytes) %u trks %u hds %u sec/trk\n", drvstr, wd->blks, wd->size, wd->tracks, wd->heads, wd->sectorspertrack); return 0;}intwd_init(){ buf_t b; struct seek seekargs; struct dev_ops ops; int result; bzero(wdctab, WD_CONTROLLERS * sizeof(struct wdc)); bzero(wdtab, WD_DRIVES * sizeof(struct wd)); /* Initialize controller */ mutex_clear(&(WDC0.mutex)); WDC0.iobase = WDC0_IOBASE; /* Initialize drive */ WD0.wdc = &WDC0; /* Read drive parameters */ if ((result = wd_readp(&WD0, "wd0")) < 0) {#if _DEBUG kprintf("wd_init: wd0 read drive params failed (%s)\n", strerror(result));#endif return result; } /* Read partition information */ b = bget(SECTOR_SIZE); blen(b) = SECTOR_SIZE; seekargs.offset = 0; seekargs.whence = SEEK_SET; if ((result = wd_ioctl(SEEK_BLOCK, &seekargs)) < 0) {#if _DEBUG kprintf("wd_init: seek failed (%s)\n", strerror(result));#endif } else if ((result = wd_read(&b)) < 0) {#if _DEBUG kprintf("wd_init: read failed (%s)\n", strerror(result));#endif } else { int i; read_parttab(bstart(b), WD0.parttab); /* Determine which partition we booted from */ for (i = 0; i < PARTS; i++) if (WD0.parttab[i].off == bootparams.offset) bootparams.part = i; } brel(b); ops.init = wd0a_init; ops.shut = wd0a_shut; ops.ioctl = wd0a_ioctl; ops.specific.blk_ops.read = wd0a_read; ops.specific.blk_ops.write = wd0a_write; dev_inst("wd0a", DEV_TYPE_BLK, &ops); ops.init = wd0b_init; ops.shut = wd0b_shut; ops.ioctl = wd0b_ioctl; ops.specific.blk_ops.read = wd0b_read; ops.specific.blk_ops.write = wd0b_write; dev_inst("wd0b", DEV_TYPE_BLK, &ops); ops.init = wd0c_init; ops.shut = wd0c_shut; ops.ioctl = wd0c_ioctl; ops.specific.blk_ops.read = wd0c_read; ops.specific.blk_ops.write = wd0c_write; dev_inst("wd0c", DEV_TYPE_BLK, &ops); ops.init = wd0d_init; ops.shut = wd0d_shut; ops.ioctl = wd0d_ioctl; ops.specific.blk_ops.read = wd0d_read; ops.specific.blk_ops.write = wd0d_write; dev_inst("wd0d", DEV_TYPE_BLK, &ops); return 0;}intwd_shut(){ return 0;}intwd_ioctl(int cmd, void *args){ switch (cmd) { case LOCK: return mutex_lock(&(WDC0.mutex)); case UNLOCK: return mutex_unlock(&(WDC0.mutex)); case GET_GEOMETRY: { geometry_t geom; if (args == NULL) return EINVAL; geom = (geometry_t) args; geom->flags = GF_PARTITIONED; geom->tracks = WD0.param.cylinders; geom->heads = WD0.param.heads; geom->sectorspertrack = WD0.param.sectors; geom->bytespersector = SECTOR_SIZE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -