⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 at_wini.c

📁 minix3的源码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* This file contains the device dependent part of a driver for the IBM-AT * winchester controller.  Written by Adri Koppes. * * The file contains one entry point: * *   at_winchester_task:	main entry when system is brought up * * Changes: *   Aug 19, 2005   ATA PCI support, supports SATA  (Ben Gras) *   Nov 18, 2004   moved AT disk driver to user-space  (Jorrit N. Herder) *   Aug 20, 2004   watchdogs replaced by sync alarms  (Jorrit N. Herder) *   Mar 23, 2000   added ATAPI CDROM support  (Michael Temari) *   May 14, 2000   d-d/i rewrite  (Kees J. Bot) *   Apr 13, 1992   device dependent/independent split  (Kees J. Bot) */#include "at_wini.h"#include "../libpci/pci.h"#include <minix/sysutil.h>#include <minix/keymap.h>#include <sys/ioc_disk.h>#define ATAPI_DEBUG	    0	/* To debug ATAPI code. *//* I/O Ports used by winchester disk controllers. *//* Read and write registers */#define REG_CMD_BASE0	0x1F0	/* command base register of controller 0 */#define REG_CMD_BASE1	0x170	/* command base register of controller 1 */#define REG_CTL_BASE0	0x3F6	/* control base register of controller 0 */#define REG_CTL_BASE1	0x376	/* control base register of controller 1 */#define REG_DATA	    0	/* data register (offset from the base reg.) */#define REG_PRECOMP	    1	/* start of write precompensation */#define REG_COUNT	    2	/* sectors to transfer */#define REG_SECTOR	    3	/* sector number */#define REG_CYL_LO	    4	/* low byte of cylinder number */#define REG_CYL_HI	    5	/* high byte of cylinder number */#define REG_LDH		    6	/* lba, drive and head */#define   LDH_DEFAULT		0xA0	/* ECC enable, 512 bytes per sector */#define   LDH_LBA		0x40	/* Use LBA addressing */#define   ldh_init(drive)	(LDH_DEFAULT | ((drive) << 4))/* Read only registers */#define REG_STATUS	    7	/* status */#define   STATUS_BSY		0x80	/* controller busy */#define	  STATUS_RDY		0x40	/* drive ready */#define	  STATUS_WF		0x20	/* write fault */#define	  STATUS_SC		0x10	/* seek complete (obsolete) */#define	  STATUS_DRQ		0x08	/* data transfer request */#define	  STATUS_CRD		0x04	/* corrected data */#define	  STATUS_IDX		0x02	/* index pulse */#define	  STATUS_ERR		0x01	/* error */#define	  STATUS_ADMBSY	       0x100	/* administratively busy (software) */#define REG_ERROR	    1	/* error code */#define	  ERROR_BB		0x80	/* bad block */#define	  ERROR_ECC		0x40	/* bad ecc bytes */#define	  ERROR_ID		0x10	/* id not found */#define	  ERROR_AC		0x04	/* aborted command */#define	  ERROR_TK		0x02	/* track zero error */#define	  ERROR_DM		0x01	/* no data address mark *//* Write only registers */#define REG_COMMAND	    7	/* command */#define   CMD_IDLE		0x00	/* for w_command: drive idle */#define   CMD_RECALIBRATE	0x10	/* recalibrate drive */#define   CMD_READ		0x20	/* read data */#define   CMD_READ_EXT		0x24	/* read data (LBA48 addressed) */#define   CMD_WRITE		0x30	/* write data */#define	  CMD_WRITE_EXT		0x34	/* write data (LBA48 addressed) */#define   CMD_READVERIFY	0x40	/* read verify */#define   CMD_FORMAT		0x50	/* format track */#define   CMD_SEEK		0x70	/* seek cylinder */#define   CMD_DIAG		0x90	/* execute device diagnostics */#define   CMD_SPECIFY		0x91	/* specify parameters */#define   ATA_IDENTIFY		0xEC	/* identify drive *//* #define REG_CTL		0x206	*/ /* control register */#define REG_CTL		0	/* control register */#define   CTL_NORETRY		0x80	/* disable access retry */#define   CTL_NOECC		0x40	/* disable ecc retry */#define   CTL_EIGHTHEADS	0x08	/* more than eight heads */#define   CTL_RESET		0x04	/* reset controller */#define   CTL_INTDISABLE	0x02	/* disable interrupts */#if ENABLE_ATAPI#define   ERROR_SENSE           0xF0    /* sense key mask */#define     SENSE_NONE          0x00    /* no sense key */#define     SENSE_RECERR        0x10    /* recovered error */#define     SENSE_NOTRDY        0x20    /* not ready */#define     SENSE_MEDERR        0x30    /* medium error */#define     SENSE_HRDERR        0x40    /* hardware error */#define     SENSE_ILRQST        0x50    /* illegal request */#define     SENSE_UATTN         0x60    /* unit attention */#define     SENSE_DPROT         0x70    /* data protect */#define     SENSE_ABRT          0xb0    /* aborted command */#define     SENSE_MISCOM        0xe0    /* miscompare */#define   ERROR_MCR             0x08    /* media change requested */#define   ERROR_ABRT            0x04    /* aborted command */#define   ERROR_EOM             0x02    /* end of media detected */#define   ERROR_ILI             0x01    /* illegal length indication */#define REG_FEAT            1   /* features */#define   FEAT_OVERLAP          0x02    /* overlap */#define   FEAT_DMA              0x01    /* dma */#define REG_IRR             2   /* interrupt reason register */#define   IRR_REL               0x04    /* release */#define   IRR_IO                0x02    /* direction for xfer */#define   IRR_COD               0x01    /* command or data */#define REG_SAMTAG          3#define REG_CNT_LO          4   /* low byte of cylinder number */#define REG_CNT_HI          5   /* high byte of cylinder number */#define REG_DRIVE           6   /* drive select */#endif#define REG_STATUS          7   /* status */#define   STATUS_BSY            0x80    /* controller busy */#define   STATUS_DRDY           0x40    /* drive ready */#define   STATUS_DMADF          0x20    /* dma ready/drive fault */#define   STATUS_SRVCDSC        0x10    /* service or dsc */#define   STATUS_DRQ            0x08    /* data transfer request */#define   STATUS_CORR           0x04    /* correctable error occurred */#define   STATUS_CHECK          0x01    /* check error */#ifdef ENABLE_ATAPI#define   ATAPI_PACKETCMD       0xA0    /* packet command */#define   ATAPI_IDENTIFY        0xA1    /* identify drive */#define   SCSI_READ10           0x28    /* read from disk */#define   SCSI_SENSE            0x03    /* sense request */#define CD_SECTOR_SIZE		2048	/* sector size of a CD-ROM */#endif /* ATAPI *//* Interrupt request lines. */#define NO_IRQ		 0	/* no IRQ set yet */#define ATAPI_PACKETSIZE	12#define SENSE_PACKETSIZE	18/* Common command block */struct command {  u8_t	precomp;	/* REG_PRECOMP, etc. */  u8_t	count;  u8_t	sector;  u8_t	cyl_lo;  u8_t	cyl_hi;  u8_t	ldh;  u8_t	command;};/* Error codes */#define ERR		 (-1)	/* general error */#define ERR_BAD_SECTOR	 (-2)	/* block marked bad detected *//* Some controllers don't interrupt, the clock will wake us up. */#define WAKEUP		(32*HZ)	/* drive may be out for 31 seconds max *//* Miscellaneous. */#define MAX_DRIVES         8#define COMPAT_DRIVES      4#if _WORD_SIZE > 2#define MAX_SECS	 256	/* controller can transfer this many sectors */#else#define MAX_SECS	 127	/* but not to a 16 bit process */#endif#define MAX_ERRORS         4	/* how often to try rd/wt before quitting */#define NR_MINORS       (MAX_DRIVES * DEV_PER_DRIVE)#define SUB_PER_DRIVE	(NR_PARTITIONS * NR_PARTITIONS)#define NR_SUBDEVS	(MAX_DRIVES * SUB_PER_DRIVE)#define DELAY_USECS     1000	/* controller timeout in microseconds */#define DELAY_TICKS 	   1	/* controller timeout in ticks */#define DEF_TIMEOUT_TICKS 	300	/* controller timeout in ticks */#define RECOVERY_USECS 500000	/* controller recovery time in microseconds */#define RECOVERY_TICKS    30	/* controller recovery time in ticks */#define INITIALIZED	0x01	/* drive is initialized */#define DEAF		0x02	/* controller must be reset */#define SMART		0x04	/* drive supports ATA commands */#if ENABLE_ATAPI#define ATAPI		0x08	/* it is an ATAPI device */#else#define ATAPI		   0	/* don't bother with ATAPI; optimise out */#endif#define IDENTIFIED	0x10	/* w_identify done successfully */#define IGNORING	0x20	/* w_identify failed once *//* Timeouts and max retries. */int timeout_ticks = DEF_TIMEOUT_TICKS, max_errors = MAX_ERRORS;int wakeup_ticks = WAKEUP;long w_standard_timeouts = 0, w_pci_debug = 0, w_instance = 0, w_lba48 = 0, atapi_debug = 0;int w_testing = 0, w_silent = 0;int w_next_drive = 0;/* Variables. *//* The struct wini is indexed by controller first, then drive (0-3). * Controller 0 is always the 'compatability' ide controller, at * the fixed locations, whether present or not. */PRIVATE struct wini {		/* main drive struct, one entry per drive */  unsigned state;		/* drive state: deaf, initialized, dead */  unsigned w_status;		/* device status register */  unsigned base_cmd;		/* command base register */  unsigned base_ctl;		/* control base register */  unsigned irq;			/* interrupt request line */  unsigned irq_mask;		/* 1 << irq */  unsigned irq_need_ack;	/* irq needs to be acknowledged */  int irq_hook_id;		/* id of irq hook at the kernel */  int lba48;			/* supports lba48 */  unsigned lcylinders;		/* logical number of cylinders (BIOS) */  unsigned lheads;		/* logical number of heads */  unsigned lsectors;		/* logical number of sectors per track */  unsigned pcylinders;		/* physical number of cylinders (translated) */  unsigned pheads;		/* physical number of heads */  unsigned psectors;		/* physical number of sectors per track */  unsigned ldhpref;		/* top four bytes of the LDH (head) register */  unsigned precomp;		/* write precompensation cylinder / 4 */  unsigned max_count;		/* max request for this drive */  unsigned open_ct;		/* in-use count */  struct device part[DEV_PER_DRIVE];	/* disks and partitions */  struct device subpart[SUB_PER_DRIVE];	/* subpartitions */} wini[MAX_DRIVES], *w_wn;PRIVATE int w_device = -1;PRIVATE int w_controller = -1;PRIVATE int w_major = -1;PRIVATE char w_id_string[40];PRIVATE int win_tasknr;			/* my task number */PRIVATE int w_command;			/* current command in execution */PRIVATE u8_t w_byteval;			/* used for SYS_IRQCTL */PRIVATE int w_drive;			/* selected drive */PRIVATE int w_controller;		/* selected controller */PRIVATE struct device *w_dv;		/* device's base and size */FORWARD _PROTOTYPE( void init_params, (void) 				);FORWARD _PROTOTYPE( void init_drive, (struct wini *, int, int, int, 					int, int, int));FORWARD _PROTOTYPE( void init_params_pci, (int) 			);FORWARD _PROTOTYPE( int w_do_open, (struct driver *dp, message *m_ptr) 	);FORWARD _PROTOTYPE( struct device *w_prepare, (int dev) 		);FORWARD _PROTOTYPE( int w_identify, (void) 				);FORWARD _PROTOTYPE( char *w_name, (void) 				);FORWARD _PROTOTYPE( int w_specify, (void) 				);FORWARD _PROTOTYPE( int w_io_test, (void) 				);FORWARD _PROTOTYPE( int w_transfer, (int proc_nr, int opcode, off_t position,					iovec_t *iov, unsigned nr_req) 	);FORWARD _PROTOTYPE( int com_out, (struct command *cmd) 			);FORWARD _PROTOTYPE( void w_need_reset, (void) 				);FORWARD _PROTOTYPE( void ack_irqs, (unsigned int) 			);FORWARD _PROTOTYPE( int w_do_close, (struct driver *dp, message *m_ptr) );FORWARD _PROTOTYPE( int w_other, (struct driver *dp, message *m_ptr) 	);FORWARD _PROTOTYPE( int w_hw_int, (struct driver *dp, message *m_ptr) 	);FORWARD _PROTOTYPE( int com_simple, (struct command *cmd) 		);FORWARD _PROTOTYPE( void w_timeout, (void) 				);FORWARD _PROTOTYPE( int w_reset, (void) 				);FORWARD _PROTOTYPE( void w_intr_wait, (void) 				);FORWARD _PROTOTYPE( int at_intr_wait, (void) 				);FORWARD _PROTOTYPE( int w_waitfor, (int mask, int value) 		);FORWARD _PROTOTYPE( void w_geometry, (struct partition *entry) 		);#if ENABLE_ATAPIFORWARD _PROTOTYPE( int atapi_sendpacket, (u8_t *packet, unsigned cnt) 	);FORWARD _PROTOTYPE( int atapi_intr_wait, (void) 			);FORWARD _PROTOTYPE( int atapi_open, (void) 				);FORWARD _PROTOTYPE( void atapi_close, (void) 				);FORWARD _PROTOTYPE( int atapi_transfer, (int proc_nr, int opcode,			off_t position, iovec_t *iov, unsigned nr_req) 	);#endif/* Entry points to this driver. */PRIVATE struct driver w_dtab = {  w_name,		/* current device's name */  w_do_open,		/* open or mount request, initialize device */  w_do_close,		/* release device */  do_diocntl,		/* get or set a partition's geometry */  w_prepare,		/* prepare for I/O on a given minor device */  w_transfer,		/* do the I/O */  nop_cleanup,		/* nothing to clean up */  w_geometry,		/* tell the geometry of the disk */  nop_signal,		/* no cleanup needed on shutdown */  nop_alarm,		/* ignore leftover alarms */  nop_cancel,		/* ignore CANCELs */  nop_select,		/* ignore selects */  w_other,		/* catch-all for unrecognized commands and ioctls */  w_hw_int		/* leftover hardware interrupts */};/*===========================================================================* *				at_winchester_task			     * *===========================================================================*/PUBLIC int main(){/* Install signal handlers. Ask PM to transform signal into message. */  struct sigaction sa;  sa.sa_handler = SIG_MESS;  sigemptyset(&sa.sa_mask);  sa.sa_flags = 0;  if (sigaction(SIGTERM,&sa,NULL)<0) panic("RS","sigaction failed", errno);  /* Set special disk parameters then call the generic main loop. */  init_params();  signal(SIGTERM, SIG_IGN);  driver_task(&w_dtab);  return(OK);}/*===========================================================================* *				init_params				     * *===========================================================================*/PRIVATE void init_params(){/* This routine is called at startup to initialize the drive parameters. */  u16_t parv[2];  unsigned int vector, size;  int drive, nr_drives;  struct wini *wn;  u8_t params[16];  int s;  /* Boot variables. */  env_parse("ata_std_timeout", "d", 0, &w_standard_timeouts, 0, 1);  env_parse("ata_pci_debug", "d", 0, &w_pci_debug, 0, 1);  env_parse("ata_instance", "d", 0, &w_instance, 0, 8);  env_parse("ata_lba48", "d", 0, &w_lba48, 0, 1);  env_parse("atapi_debug", "d", 0, &atapi_debug, 0, 1);  if (w_instance == 0) {	  /* Get the number of drives from the BIOS data area */	  if ((s=sys_vircopy(SELF, BIOS_SEG, NR_HD_DRIVES_ADDR,  		 	SELF, D, (vir_bytes) params, NR_HD_DRIVES_SIZE)) != OK)  		panic(w_name(), "Couldn't read BIOS", s);	  if ((nr_drives = params[0]) > 2) nr_drives = 2;	  for (drive = 0, wn = wini; drive < COMPAT_DRIVES; drive++, wn++) {		if (drive < nr_drives) {		    /* Copy the BIOS parameter vector */		    vector = (drive == 0) ? BIOS_HD0_PARAMS_ADDR:BIOS_HD1_PARAMS_ADDR;		    size = (drive == 0) ? BIOS_HD0_PARAMS_SIZE:BIOS_HD1_PARAMS_SIZE;		    if ((s=sys_vircopy(SELF, BIOS_SEG, vector,					SELF, D, (vir_bytes) parv, size)) != OK)  				panic(w_name(), "Couldn't read BIOS", s);				/* Calculate the address of the parameters and copy them */  			if ((s=sys_vircopy(  				SELF, BIOS_SEG, hclick_to_physb(parv[1]) + parv[0],  				SELF, D, (phys_bytes) params, 16L))!=OK)  			    panic(w_name(),"Couldn't copy parameters", s);				/* Copy the parameters to the structures of the drive */			wn->lcylinders = bp_cylinders(params);			wn->lheads = bp_heads(params);			wn->lsectors = bp_sectors(params);			wn->precomp = bp_precomp(params) >> 2;		}		/* Fill in non-BIOS parameters. */		init_drive(wn,			drive < 2 ? REG_CMD_BASE0 : REG_CMD_BASE1,			drive < 2 ? REG_CTL_BASE0 : REG_CTL_BASE1,			NO_IRQ, 0, 0, drive);		w_next_drive++;  	}  }  /* Look for controllers on the pci bus. Skip none the first instance,   * skip one and then 2 for every instance, for every next instance.   */  if (w_instance == 0)  	init_params_pci(0);  else  	init_params_pci(w_instance*2-1);}#define ATA_IF_NOTCOMPAT1 (1L << 0)#define ATA_IF_NOTCOMPAT2 (1L << 2)/*===========================================================================* *				init_drive				     * *===========================================================================*/PRIVATE void init_drive(struct wini *w, int base_cmd, int base_ctl, int irq, int ack, int hook, int drive){	w->state = 0;	w->w_status = 0;	w->base_cmd = base_cmd;	w->base_ctl = base_ctl;	w->irq = irq;	w->irq_mask = 1 << irq;	w->irq_need_ack = ack;	w->irq_hook_id = hook;	w->ldhpref = ldh_init(drive);	w->max_count = MAX_SECS << SECTOR_SHIFT;	w->lba48 = 0;}/*===========================================================================* *				init_params_pci				     * *===========================================================================*/PRIVATE void init_params_pci(int skip){  int r, devind, drive;  u16_t vid, did;  pci_init();  for(drive = w_next_drive; drive < MAX_DRIVES; drive++)  	wini[drive].state = IGNORING;  for(r = pci_first_dev(&devind, &vid, &did);  	r != 0 && w_next_drive < MAX_DRIVES; r = pci_next_dev(&devind, &vid, &did)) {  	int interface, irq, irq_hook;  	/* Base class must be 01h (mass storage), subclass must  	 * be 01h (ATA).  	 */  	if (pci_attr_r8(devind, PCI_BCR) != 0x01 ||  	   pci_attr_r8(devind, PCI_SCR) != 0x01) {  	   continue;  	}  	/* Found a controller.  	 * Programming interface register tells us more.  	 */  	interface = pci_attr_r8(devind, PCI_PIFR);  	irq = pci_attr_r8(devind, PCI_ILR);  	/* Any non-compat drives? */  	if (interface & (ATA_IF_NOTCOMPAT1 | ATA_IF_NOTCOMPAT2)) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -