1945 lines · 43.1 KB · C
RawDownload
/* * ata disk driver for file server. * derived from /sys/src/boot/pc/sdata.c and /sys/src/9/pc/sdata.c * * we can't write message into a ctl file on the file server, so * enable dma and rwm as advertised by the drive & controller. * if that doesn't work, fix the hardware or turn it off in the source * (set conf.idedma = 0). * */#include "all.h"#include "io.h"#include "mem.h" #define	dprint(...)	// print(__VA_ARGS__)#define idprint(...)	// print(__VA_ARGS__)  #define	HOWMANY(x, y)	(((x)+((y)-1))/(y))#define ROUNDUP(x, y)	(HOWMANY((x), (y))*(y)) enum{	IrqATA0	= 14,	IrqATA1	= 15,}; enum {	NCtlr=		8,	NCtlrdrv=	2,		/* fixed by hardware */	NDrive=		NCtlr*NCtlrdrv,	Maxxfer=	16*1024,	/* maximum transfer size/cmd */ 	Read = 0,	Write, 	/* I/O ports */	Ctlr0cmd =	0x1f0,	Ctlr0ctl =	0x3f4,	Ctlr1cmd =	0x170,	Ctlr1ctl =	0x374,	Ctl2cmd = Ctlr0ctl - Ctlr0cmd, 	Ok	= 0,	Check	= 1,	Retry	= 2,	Timeout	= 3,}; enum {	DbgCONFIG	= 0x0001,	/* detected drive config info */	DbgIDENTIFY	= 0x0002,	/* detected drive identify info */	DbgSTATE	= 0x0004,	/* dump state on panic */	DbgPROBE	= 0x0008,	/* trace device probing */	DbgDEBUG	= 0x0080,	/* the current problem... */	DbgINL		= 0x0100,	/* That Inil20+ message we hate */	Dbg48BIT	= 0x0200,	/* 48-bit LBA */	DbgBsy		= 0x0400,	/* interrupt but Bsy (shared IRQ) */}; /* adjust to taste */#define DEBUG		(DbgDEBUG|DbgCONFIG) enum {					/* I/O ports */	Data		= 0,	Error		= 1,		/* (read) */	Features	= 1,		/* (write) */	Count		= 2,		/* sector count<7-0>, sector count<15-8> */	Ir		= 2,		/* interrupt reason (PACKET) */	Sector		= 3,		/* sector number */	Lbalo		= 3,		/* LBA<7-0>, LBA<31-24> */	Cyllo		= 4,		/* cylinder low */	Bytelo		= 4,		/* byte count low (PACKET) */	Lbamid		= 4,		/* LBA<15-8>, LBA<39-32> */	Cylhi		= 5,		/* cylinder high */	Bytehi		= 5,		/* byte count hi (PACKET) */	Lbahi		= 5,		/* LBA<23-16>, LBA<47-40> */	Dh		= 6,		/* Device/Head, LBA<32-14> */	Status		= 7,		/* (read) */	Cmd		= 7,		/* (write) */ 	As		= 2,		/* Alternate Status (read) */	Dc		= 2,		/* Device Control (write) */}; enum {					/* Error */	Med		= 0x01,		/* Media error */	Ili		= 0x01,		/* command set specific (PACKET) */	Nm		= 0x02,		/* No Media */	Eom		= 0x02,		/* command set specific (PACKET) */	Abrt		= 0x04,		/* Aborted command */	Mcr		= 0x08,		/* Media Change Request */	Idnf		= 0x10,		/* no user-accessible address */	Mc		= 0x20,		/* Media Change */	Unc		= 0x40,		/* Uncorrectable data error */	Wp		= 0x40,		/* Write Protect */	Icrc		= 0x80,		/* Interface CRC error */}; enum {					/* Features */	Dma		= 0x01,		/* data transfer via DMA (PACKET) */	Ovl		= 0x02,		/* command overlapped (PACKET) */}; enum {					/* Interrupt Reason */	Cd		= 0x01,		/* Cmd/Data */	Io		= 0x02,		/* I/O direction */	Rel		= 0x04,		/* Bus Release */}; enum {					/* Device/Head */	Dev0		= 0xA0,		/* Master */	Dev1		= 0xB0,		/* Slave */	Lba		= 0x40,		/* LBA mode */}; enum {					/* internal flags */	Dllba		= 0x1,		/* LBA48 mode */}; enum {					/* Status, Alternate Status */	Err		= 0x01,		/* Error */	Chk		= 0x01,		/* Check error (PACKET) */	Drq		= 0x08,		/* Data Request */	Dsc		= 0x10,		/* Device Seek Complete */	Serv		= 0x10,		/* Service */	Df		= 0x20,		/* Device Fault */	Dmrd		= 0x20,		/* DMA ready (PACKET) */	Drdy		= 0x40,		/* Device Ready */	Bsy		= 0x80,		/* Busy */}; enum {					/* Cmd */	Cnop		= 0x00,		/* NOP */	Cdr		= 0x08,		/* Device Reset */	Crs		= 0x20,		/* Read Sectors */	Crs48		= 0x24,		/* Read Sectors Ext */	Crd48		= 0x25,		/* Read w/ DMA Ext */	Crdq48		= 0x26,		/* Read w/ DMA Queued Ext */	Crsm48		= 0x29,		/* Read Multiple Ext */	Cws		= 0x30,		/* Write Sectors */	Cws48		= 0x34,		/* Write Sectors Ext */	Cwd48		= 0x35,		/* Write w/ DMA Ext */	Cwdq48		= 0x36,		/* Write w/ DMA Queued Ext */	Cwsm48		= 0x39,		/* Write Multiple Ext */	Cedd		= 0x90,		/* Execute Device Diagnostics */	Cpkt		= 0xA0,		/* Packet */	Cidpkt		= 0xA1,		/* Identify Packet Device */	Crsm		= 0xC4,		/* Read Multiple */	Cwsm		= 0xC5,		/* Write Multiple */	Csm		= 0xC6,		/* Set Multiple */	Crdq		= 0xC7,		/* Read DMA queued */	Crd		= 0xC8,		/* Read DMA */	Cwd		= 0xCA,		/* Write DMA */	Cwdq		= 0xCC,		/* Write DMA queued */	Cstandby	= 0xE2,		/* Standby */	Cid		= 0xEC,		/* Identify Device */	Csf		= 0xEF,		/* Set Features */}; enum {					/* Device Control */	Nien		= 0x02,		/* (not) Interrupt Enable */	Srst		= 0x04,		/* Software Reset */	Hob		= 0x80,		/* High Order Bit [sic] */}; enum {					/* PCI Configuration Registers */	Bmiba		= 0x20,		/* Bus Master Interface Base Address */	Idetim		= 0x40,		/* IE Timing */	Sidetim		= 0x44,		/* Slave IE Timing */	Udmactl		= 0x48,		/* Ultra DMA/33 Control */	Udmatim		= 0x4A,		/* Ultra DMA/33 Timing */}; enum {					/* Bus Master IDE I/O Ports */	Bmicx		= 0,		/* Cmd */	Bmisx		= 2,		/* Status */	Bmidtpx		= 4,		/* Descriptor Table Pointer */}; enum {					/* Bmicx */	Ssbm		= 0x01,		/* Start/Stop Bus Master */	Rwcon		= 0x08,		/* Read/Write Control */}; enum {					/* Bmisx */	Bmidea		= 0x01,		/* Bus Master IDE Active */	Idedmae		= 0x02,		/* IDE DMA Error  (R/WC) */	Ideints		= 0x04,		/* IDE Interrupt Status (R/WC) */	Dma0cap		= 0x20,		/* Drive 0 DMA Capable */	Dma1cap		= 0x40,		/* Drive 0 DMA Capable */};enum {					/* Physical Region Descriptor */	PrdEOT		= 0x80000000,	/* Bus Master IDE Active */}; enum {					/* offsets into the identify info. */	Iconfig		= 0,		/* general configuration */	Ilcyl		= 1,		/* logical cylinders */	Ilhead		= 3,		/* logical heads */	Ilsec		= 6,		/* logical sectors per logical track */	Iserial		= 10,		/* serial number */	Ifirmware	= 23,		/* firmware revision */	Imodel		= 27,		/* model number */	Imaxrwm		= 47,		/* max. read/write multiple sectors */	Icapabilities	= 49,		/* capabilities */	Istandby	= 50,		/* device specific standby timer */	Ipiomode	= 51,		/* PIO data transfer mode number */	Ivalid		= 53,	Iccyl		= 54,		/* cylinders if (valid&0x01) */	Ichead		= 55,		/* heads if (valid&0x01) */	Icsec		= 56,		/* sectors if (valid&0x01) */	Iccap		= 57,		/* capacity if (valid&0x01) */	Irwm		= 59,		/* read/write multiple */	Ilba		= 60,		/* LBA size */	Imwdma		= 63,		/* multiword DMA mode */	Iapiomode	= 64,		/* advanced PIO modes supported */	Iminmwdma	= 65,		/* min. multiword DMA cycle time */	Irecmwdma	= 66,		/* rec. multiword DMA cycle time */	Iminpio		= 67,		/* min. PIO cycle w/o flow control */	Iminiordy	= 68,		/* min. PIO cycle with IORDY */	Ipcktbr		= 71,		/* time from PACKET to bus release */	Iserbsy		= 72,		/* time from SERVICE to !Bsy */	Iqdepth		= 75,		/* max. queue depth */	Imajor		= 80,		/* major version number */	Iminor		= 81,		/* minor version number */	Icsfs		= 82,		/* command set/feature supported */	Icsfe		= 85,		/* command set/feature enabled */	Iudma		= 88,		/* ultra DMA mode */	Ierase		= 89,		/* time for security erase */	Ieerase		= 90,		/* time for enhanced security erase */	Ipower		= 91,		/* current advanced power management */	Ilba48		= 100,		/* 48-bit LBA size (64 bits in 100-103) */	Irmsn		= 127,		/* removable status notification */	Isecstat	= 128,		/* security status */	Icfapwr		= 160,		/* CFA power mode */	Imediaserial	= 176,		/* current media serial number */	Icksum		= 255,		/* checksum */}; enum {					/* bit masks for config identify info */	Mpktsz		= 0x0003,	/* packet command size */	Mincomplete	= 0x0004,	/* incomplete information */	Mdrq		= 0x0060,	/* DRQ type */	Mrmdev		= 0x0080,	/* device is removable */	Mtype		= 0x1F00,	/* device type */	Mproto		= 0x8000,	/* command protocol */}; enum {					/* bit masks for capabilities identify info */	Mdma		= 0x0100,	/* DMA supported */	Mlba		= 0x0200,	/* LBA supported */	Mnoiordy	= 0x0400,	/* IORDY may be disabled */	Miordy		= 0x0800,	/* IORDY supported */	Msoftrst	= 0x1000,	/* needs soft reset when Bsy */	Mstdby		= 0x2000,	/* standby supported */	Mqueueing	= 0x4000,	/* queueing overlap supported */	Midma		= 0x8000,	/* interleaved DMA supported */}; enum {					/* bit masks for supported/enabled features */	Msmart		= 0x0001,	Msecurity	= 0x0002,	Mrmmedia	= 0x0004,	Mpwrmgmt	= 0x0008,	Mpkt		= 0x0010,	Mwcache		= 0x0020,	Mlookahead	= 0x0040,	Mrelirq		= 0x0080,	Msvcirq		= 0x0100,	Mreset		= 0x0200,	Mprotected	= 0x0400,	Mwbuf		= 0x1000,	Mrbuf		= 0x2000,	Mnop		= 0x4000,	Mmicrocode	= 0x0001,	Mqueued		= 0x0002,	Mcfa		= 0x0004,	Mapm		= 0x0008,	Mnotify		= 0x0010,	Mstandby	= 0x0020,	Mspinup		= 0x0040,	Mmaxsec		= 0x0100,	Mautoacoustic	= 0x0200,	Maddr48		= 0x0400,	Mdevconfov	= 0x0800,	Mflush		= 0x1000,	Mflush48	= 0x2000,	Msmarterror	= 0x0001,	Msmartselftest	= 0x0002,	Mmserial	= 0x0004,	Mmpassthru	= 0x0008,	Mlogging	= 0x0020,}; typedef struct Ctlr Ctlr;typedef struct Drive Drive; typedef struct Prd {	ulong	pa;			/* Physical Base Address */	int	count;} Prd; enum {	BMspan		= 64*1024,	/* must be power of 2 <= 64*1024 */	Nprd		= 512*1024/BMspan+2,}; typedef struct Ctlr {	int	cmdport;	int	ctlport;	int	irq;	int	tbdf;	int	bmiba;			/* bus master interface base address */	int	maxio;			/* sector count transfer maximum */	int	span;			/* don't span this boundary with dma */ 	Pcidev*	pcidev;	void	(*ienable)(Ctlr*); 	Drive*	drive[NCtlrdrv]; 	Prd*	prdt;			/* physical region descriptor table */	void*	prdtbase; 	QLock;				/* current command */	Drive*	curdrive;	int	command;		/* last command issued (debugging) */	Rendez;	int	done;	char	name[10];	Lock;				/* register access */} Ctlr; typedef struct Drive {	Ctlr*	ctlr; 	int	dev;	ushort	info[256];	int	c;			/* cylinder */	int	h;			/* head */	int	s;			/* sector */	uvlong	sectors;		/* total sectors */	int	secsize;		/* sector size */ 	int	dma;			/* DMA R/W possible */	int	dmactl;	int	rwm;			/* read/write multiple possible */	int	rwmctl; 	int	pkt;			/* PACKET device, length of pktcmd */	uchar	pktcmd[16];	int	pktdma;			/* this PACKET command using dma */ 	QLock;				/* drive access */	int	command;		/* current command */	int	write;	uchar*	data;	int	dlen;	uchar*	limit;	int	count;			/* sectors */	int	block;			/* R/W bytes per block */	int	status;	int	error;	int	flags;			/* internal flags */ 	int	driveno;		/* ctlr*NCtlrdrv + unit */	uchar	lba;		/* true if drive has logical block addressing */	uchar	online; 	Filter	rate[2];	int	fflag;} Drive; /* file-server-specific data */ static Ctlr *atactlr[NCtlr];static int	natactlr;static Drive *atadrive[NDrive];static Drive	*atadriveprobe(int driveno); voidpresleep(Rendez *r, int (*fn)(void*), void *v){	int x; 	if (u != nil) {		sleep(r, fn, v);		return;	}	/* else we're in predawn with no u */	x = spllo();	while (!fn(v))		continue;	splx(x);} voidpretsleep(Rendez *r, int (*fn)(void*), void *v, int msec){	int x;	ulong start; 	if (u != nil) {		tsleep(r, fn, v, msec);		return;	}	/* else we're in predawn with no u */	x = spllo();	for (start = m->ticks; TK2MS(Ticks - start) < msec && !fn(v); )		continue;	splx(x);} #define sleep	presleep#define tsleep	pretsleep static voidpc87415ienable(Ctlr* ctlr){	Pcidev *p;	int x; 	p = ctlr->pcidev;	if(p == nil)		return; 	x = pcicfgr32(p, 0x40);	if(ctlr->cmdport == p->mem[0].bar)		x &= ~0x00000100;	else		x &= ~0x00000200;	pcicfgw32(p, 0x40, x);} static voidatadumpstate(Drive* drive, Devsize lba, int count){	Prd *prd;	Pcidev *p;	Ctlr *ctlr;	int i, bmiba; 	if(!(DEBUG & DbgSTATE)){		USED(drive, lba, count);		return;	} 	ctlr = drive->ctlr;	print("command %2.2uX\n", ctlr->command);	print("data %8.8p limit %8.8p dlen %d status %uX error %uX\n",		drive->data, drive->limit, drive->dlen,		drive->status, drive->error);	print("lba %lld, count %d -> %d\n",			(Wideoff)lba, count, drive->count);	if(!(inb(ctlr->ctlport+As) & Bsy)){		for(i = 1; i < 7; i++)			print(" 0x%2.2uX", inb(ctlr->cmdport+i));		print(" 0x%2.2uX\n", inb(ctlr->ctlport+As));	}	if(drive->command == Cwd || drive->command == Crd){		bmiba = ctlr->bmiba;		prd = ctlr->prdt;		print("bmicx %2.2uX bmisx %2.2uX prdt %8.8p\n",			inb(bmiba+Bmicx), inb(bmiba+Bmisx), prd);		for(;;){			print("pa 0x%8.8luX count %8.8uX\n",				prd->pa, prd->count);			if(prd->count & PrdEOT)				break;			prd++;		}	}	if(ctlr->pcidev && ctlr->pcidev->vid == 0x8086){		p = ctlr->pcidev;		print("0x40: %4.4uX 0x42: %4.4uX",			pcicfgr16(p, 0x40), pcicfgr16(p, 0x42));		print("0x48: %2.2uX\n", pcicfgr8(p, 0x48));		print("0x4A: %4.4uX\n", pcicfgr16(p, 0x4A));	}} static intatadebug(int cmdport, int ctlport, char* fmt, ...){	int i, n;	va_list arg;	char buf[PRINTSIZE]; 	if(!(DEBUG & DbgPROBE)){		USED(cmdport, ctlport, fmt);		return 0;	} 	va_start(arg, fmt);	n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;	va_end(arg); 	if(cmdport){		if(buf[n-1] == '\n')			n--;

Lines 1–500 of 1945.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t