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

📄 acsi.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * acsi.c -- Device driver for Atari ACSI hard disks * * Copyright 1994 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> * * Some parts are based on hd.c by Linus Torvalds * * This file is subject to the terms and conditions of the GNU General Public * License.  See the file COPYING in the main directory of this archive for * more details. * *//* * Still to in this file: *  - If a command ends with an error status (!= 0), the following *    REQUEST SENSE commands (4 to fill the ST-DMA FIFO) are done by *    polling the _IRQ signal (not interrupt-driven). This should be *    avoided in future because it takes up a non-neglectible time in *    the interrupt service routine while interrupts are disabled. *    Maybe a timer interrupt will get lost :-( *//* * General notes: * *  - All ACSI devices (disks, CD-ROMs, ...) use major number 28. *    Minors are organized like it is with SCSI: The upper 4 bits *    identify the device, the lower 4 bits the partition. *    The device numbers (the upper 4 bits) are given in the same *    order as the devices are found on the bus. *  - Up to 8 LUNs are supported for each target (if CONFIG_ACSI_MULTI_LUN *    is defined), but only a total of 16 devices (due to minor *    numbers...). Note that Atari allows only a maximum of 4 targets *    (i.e. controllers, not devices) on the ACSI bus! *  - A optimizing scheme similar to SCSI scatter-gather is implemented. *  - Removable media are supported. After a medium change to device *    is reinitialized (partition check etc.). Also, if the device *    knows the PREVENT/ALLOW MEDIUM REMOVAL command, the door should *    be locked and unlocked when mounting the first or unmounting the *    last filesystem on the device. The code is untested, because I *    don't have a removable hard disk. * */#define MAJOR_NR ACSI_MAJOR#include <linux/config.h>#include <linux/module.h>#include <linux/errno.h>#include <linux/signal.h>#include <linux/sched.h>#include <linux/timer.h>#include <linux/fs.h>#include <linux/kernel.h>#include <linux/genhd.h>#include <linux/devfs_fs_kernel.h>#include <linux/delay.h>#include <linux/mm.h>#include <linux/major.h>#include <linux/blk.h>#include <linux/malloc.h>#include <linux/interrupt.h>#include <scsi/scsi.h> /* for SCSI_IOCTL_GET_IDLUN */typedef void Scsi_Device; /* hack to avoid including scsi.h */#include <scsi/scsi_ioctl.h>#include <linux/hdreg.h> /* for HDIO_GETGEO */#include <linux/blkpg.h>#include <asm/setup.h>#include <asm/pgtable.h>#include <asm/system.h>#include <asm/uaccess.h>#include <asm/atarihw.h>#include <asm/atariints.h>#include <asm/atari_acsi.h>#include <asm/atari_stdma.h>#include <asm/atari_stram.h>#define DEBUG#undef DEBUG_DETECT#undef NO_WRITE#define MAX_ERRORS     		8	/* Max read/write errors/sector */#define MAX_LUN				8	/* Max LUNs per target */#define MAX_DEV		   		16#define ACSI_BUFFER_SIZE			(16*1024) /* "normal" ACSI buffer size */#define ACSI_BUFFER_MINSIZE			(2048) 	  /* min. buf size if ext. DMA */#define ACSI_BUFFER_SIZE_ORDER	 	2		  /* order size for above */#define ACSI_BUFFER_MINSIZE_ORDER	0 	  	  /* order size for above */#define ACSI_BUFFER_SECTORS	(ACSI_BUFFER_SIZE/512)#define ACSI_BUFFER_ORDER \	(ATARIHW_PRESENT(EXTD_DMA) ? \	 ACSI_BUFFER_MINSIZE_ORDER : \	 ACSI_BUFFER_SIZE_ORDER)#define ACSI_TIMEOUT		(4*HZ)/* minimum delay between two commands */#define COMMAND_DELAY 500typedef enum {	NONE, HARDDISK, CDROM} ACSI_TYPE;struct acsi_info_struct {	ACSI_TYPE		type;			/* type of device */	unsigned		target;			/* target number */	unsigned		lun;			/* LUN in target controller */	unsigned		removable : 1;	/* Flag for removable media */	unsigned		read_only : 1;	/* Flag for read only devices */	unsigned		old_atari_disk : 1; /* Is an old Atari disk       */	unsigned		changed : 1;	/* Medium has been changed */	unsigned long 	size;			/* #blocks */} acsi_info[MAX_DEV];/* *	SENSE KEYS */#define NO_SENSE		0x00#define RECOVERED_ERROR 	0x01#define NOT_READY		0x02#define MEDIUM_ERROR		0x03#define HARDWARE_ERROR		0x04#define ILLEGAL_REQUEST 	0x05#define UNIT_ATTENTION		0x06#define DATA_PROTECT		0x07#define BLANK_CHECK		0x08#define COPY_ABORTED		0x0a#define ABORTED_COMMAND 	0x0b#define VOLUME_OVERFLOW 	0x0d#define MISCOMPARE		0x0e/* *	DEVICE TYPES */#define TYPE_DISK	0x00#define TYPE_TAPE	0x01#define TYPE_WORM	0x04#define TYPE_ROM	0x05#define TYPE_MOD	0x07#define TYPE_NO_LUN	0x7f/* The data returned by MODE SENSE differ between the old Atari * hard disks and SCSI disks connected to ACSI. In the following, both * formats are defined and some macros to operate on them potably. */typedef struct {	unsigned long	dummy[2];	unsigned long	sector_size;	unsigned char	format_code;#define ATARI_SENSE_FORMAT_FIX	1	#define ATARI_SENSE_FORMAT_CHNG	2	unsigned char	cylinders_h;	unsigned char	cylinders_l;	unsigned char	heads;	unsigned char	reduced_h;	unsigned char	reduced_l;	unsigned char	precomp_h;	unsigned char	precomp_l;	unsigned char	landing_zone;	unsigned char	steprate;	unsigned char	type;#define ATARI_SENSE_TYPE_FIXCHNG_MASK		4#define ATARI_SENSE_TYPE_SOFTHARD_MASK		8#define ATARI_SENSE_TYPE_FIX				4#define ATARI_SENSE_TYPE_CHNG				0#define ATARI_SENSE_TYPE_SOFT				0#define ATARI_SENSE_TYPE_HARD				8	unsigned char	sectors;} ATARI_SENSE_DATA;#define ATARI_CAPACITY(sd) \	(((int)((sd).cylinders_h<<8)|(sd).cylinders_l) * \	 (sd).heads * (sd).sectors)typedef struct {	unsigned char   dummy1;	unsigned char   medium_type;	unsigned char   dummy2;	unsigned char   descriptor_size;	unsigned long   block_count;	unsigned long   sector_size;	/* Page 0 data */	unsigned char	page_code;	unsigned char	page_size;	unsigned char	page_flags;	unsigned char	qualifier;} SCSI_SENSE_DATA;#define SCSI_CAPACITY(sd) 	((sd).block_count & 0xffffff)typedef union {	ATARI_SENSE_DATA	atari;	SCSI_SENSE_DATA		scsi;} SENSE_DATA;#define SENSE_TYPE_UNKNOWN	0#define SENSE_TYPE_ATARI	1#define SENSE_TYPE_SCSI		2#define SENSE_TYPE(sd)										\	(((sd).atari.dummy[0] == 8 &&							\	  ((sd).atari.format_code == 1 ||						\	   (sd).atari.format_code == 2)) ? SENSE_TYPE_ATARI :	\	 ((sd).scsi.dummy1 >= 11) ? SENSE_TYPE_SCSI :			\	 SENSE_TYPE_UNKNOWN)	 #define CAPACITY(sd)							\	(SENSE_TYPE(sd) == SENSE_TYPE_ATARI ?		\	 ATARI_CAPACITY((sd).atari) :				\	 SCSI_CAPACITY((sd).scsi))#define SECTOR_SIZE(sd)							\	(SENSE_TYPE(sd) == SENSE_TYPE_ATARI ?		\	 (sd).atari.sector_size :					\	 (sd).scsi.sector_size & 0xffffff)/* Default size if capacity cannot be determined (1 GByte) */#define	DEFAULT_SIZE	0x1fffff#define CARTRCH_STAT(dev,buf)					\	(acsi_info[(dev)].old_atari_disk ?			\	 (((buf)[0] & 0x7f) == 0x28) :					\	 ((((buf)[0] & 0x70) == 0x70) ?					\	  (((buf)[2] & 0x0f) == 0x06) :					\	  (((buf)[0] & 0x0f) == 0x06)))					\/* These two are also exported to other drivers that work on the ACSI bus and * need an ST-RAM buffer. */char 			*acsi_buffer;unsigned long 	phys_acsi_buffer;static int				NDevices = 0;static int				acsi_sizes[MAX_DEV<<4] = { 0, };static int				acsi_blocksizes[MAX_DEV<<4] = { 0, };static struct hd_struct	acsi_part[MAX_DEV<<4] = { {0,0}, };static int 				access_count[MAX_DEV] = { 0, };static char 			busy[MAX_DEV] = { 0, };static DECLARE_WAIT_QUEUE_HEAD(busy_wait);static int				CurrentNReq;static int				CurrentNSect;static char				*CurrentBuffer;#define SET_TIMER()	mod_timer(&acsi_timer, jiffies + ACSI_TIMEOUT)#define CLEAR_TIMER()	del_timer(&acsi_timer)static unsigned long	STramMask;#define STRAM_ADDR(a)	(((a) & STramMask) == 0)/* ACSI commands */static char tur_cmd[6]        = { 0x00, 0, 0, 0, 0, 0 };static char modesense_cmd[6]  = { 0x1a, 0, 0, 0, 24, 0 };static char modeselect_cmd[6] = { 0x15, 0, 0, 0, 12, 0 };static char inquiry_cmd[6]    = { 0x12, 0, 0, 0,255, 0 };static char reqsense_cmd[6]   = { 0x03, 0, 0, 0, 4, 0 };static char read_cmd[6]       = { 0x08, 0, 0, 0, 0, 0 };static char write_cmd[6]      = { 0x0a, 0, 0, 0, 0, 0 };static char pa_med_rem_cmd[6] = { 0x1e, 0, 0, 0, 0, 0 };#define CMDSET_TARG_LUN(cmd,targ,lun)			\    do {						\		cmd[0] = (cmd[0] & ~0xe0) | (targ)<<5;	\		cmd[1] = (cmd[1] & ~0xe0) | (lun)<<5;	\	} while(0)#define CMDSET_BLOCK(cmd,blk)						\    do {											\		unsigned long __blk = (blk);				\		cmd[3] = __blk; __blk >>= 8;				\		cmd[2] = __blk; __blk >>= 8;				\		cmd[1] = (cmd[1] & 0xe0) | (__blk & 0x1f);	\	} while(0)#define CMDSET_LEN(cmd,len)						\	do {										\		cmd[4] = (len);							\	} while(0)#define min(a,b)	(((a)<(b))?(a):(b))/* ACSI errors (from REQUEST SENSE); There are two tables, one for the * old Atari disks and one for SCSI on ACSI disks. */struct acsi_error {	unsigned char	code;	const char		*text;} atari_acsi_errors[] = {	{ 0x00, "No error (??)" },	{ 0x01, "No index pulses" },	{ 0x02, "Seek not complete" },	{ 0x03, "Write fault" },	{ 0x04, "Drive not ready" },	{ 0x06, "No Track 00 signal" },	{ 0x10, "ECC error in ID field" },	{ 0x11, "Uncorrectable data error" },	{ 0x12, "ID field address mark not found" },	{ 0x13, "Data field address mark not found" },	{ 0x14, "Record not found" },	{ 0x15, "Seek error" },	{ 0x18, "Data check in no retry mode" },	{ 0x19, "ECC error during verify" },	{ 0x1a, "Access to bad block" },	{ 0x1c, "Unformatted or bad format" },	{ 0x20, "Invalid command" },	{ 0x21, "Invalid block address" },	{ 0x23, "Volume overflow" },	{ 0x24, "Invalid argument" },	{ 0x25, "Invalid drive number" },	{ 0x26, "Byte zero parity check" },	{ 0x28, "Cartride changed" },	{ 0x2c, "Error count overflow" },	{ 0x30, "Controller selftest failed" }},	scsi_acsi_errors[] = {	{ 0x00, "No error (??)" },	{ 0x01, "Recovered error" },	{ 0x02, "Drive not ready" },	{ 0x03, "Uncorrectable medium error" },	{ 0x04, "Hardware error" },	{ 0x05, "Illegal request" },	{ 0x06, "Unit attention (Reset or cartridge changed)" },	{ 0x07, "Data protection" },	{ 0x08, "Blank check" },	{ 0x0b, "Aborted Command" },	{ 0x0d, "Volume overflow" }};/***************************** Prototypes *****************************/static int acsicmd_dma( const char *cmd, char *buffer, int blocks, int                        rwflag, int enable);static int acsi_reqsense( char *buffer, int targ, int lun);static void acsi_print_error( const unsigned char *errblk, int dev );static void acsi_interrupt (int irq, void *data, struct pt_regs *fp);static void unexpected_acsi_interrupt( void );static void bad_rw_intr( void );static void read_intr( void );static void write_intr( void);static void acsi_times_out( unsigned long dummy );static void copy_to_acsibuffer( void );static void copy_from_acsibuffer( void );static void do_end_requests( void );static void do_acsi_request( request_queue_t * );static void redo_acsi_request( void );static int acsi_ioctl( struct inode *inode, struct file *file, unsigned int                       cmd, unsigned long arg );static int acsi_open( struct inode * inode, struct file * filp );static int acsi_release( struct inode * inode, struct file * file );static void acsi_prevent_removal( int target, int flag );static int acsi_change_blk_size( int target, int lun);static int acsi_mode_sense( int target, int lun, SENSE_DATA *sd );static void acsi_geninit(void);static int revalidate_acsidisk( int dev, int maxusage );static int acsi_revalidate (dev_t);/************************* End of Prototypes **************************/struct timer_list acsi_timer = { NULL, NULL, 0, 0, acsi_times_out };#ifdef CONFIG_ATARI_SLMextern int attach_slm( int target, int lun );extern int slm_init( void );#endif/*********************************************************************** * *   ACSI primitives * **********************************************************************//* * The following two functions wait for _IRQ to become Low or High, * resp., with a timeout. The 'timeout' parameter is in jiffies * (10ms). * If the functions are called with timer interrupts on (int level < * 6), the timeout is based on the 'jiffies' variable to provide exact * timeouts for device probing etc. * If interrupts are disabled, the number of tries is based on the * 'loops_per_jiffy' variable. A rough estimation is sufficient here... */#define INT_LEVEL													\	({	unsigned __sr;												\		__asm__ __volatile__ ( "movew	%/sr,%0" : "=dm" (__sr) );	\		(__sr >> 8) & 7;											\	})int acsi_wait_for_IRQ( unsigned timeout ){	if (INT_LEVEL < 6) {		unsigned long maxjif = jiffies + timeout;		while (time_before(jiffies, maxjif))			if (!(mfp.par_dt_reg & 0x20)) return( 1 );	}	else {		long tries = loops_per_jiffy / 8 * timeout;		while( --tries >= 0 )			if (!(mfp.par_dt_reg & 0x20)) return( 1 );	}			return( 0 ); /* timeout! */}int acsi_wait_for_noIRQ( unsigned timeout ){	if (INT_LEVEL < 6) {		unsigned long maxjif = jiffies + timeout;		while (time_before(jiffies, maxjif))			if (mfp.par_dt_reg & 0x20) return( 1 );	}	else {		long tries = loops_per_jiffy * timeout / 8;		while( tries-- >= 0 )			if (mfp.par_dt_reg & 0x20) return( 1 );	}			return( 0 ); /* timeout! */}static struct timeval start_time;voidacsi_delay_start(void){	do_gettimeofday(&start_time);}/* wait from acsi_delay_start to now usec (<1E6) usec */voidacsi_delay_end(long usec){	struct timeval end_time;	long deltau,deltas;	do_gettimeofday(&end_time);	deltau=end_time.tv_usec - start_time.tv_usec;	deltas=end_time.tv_sec - start_time.tv_sec;	if (deltas > 1 || deltas < 0)		return;	if (deltas > 0)		deltau += 1000*1000;	if (deltau >= usec)		return;	udelay(usec-deltau);}/* acsicmd_dma() sends an ACSI command and sets up the DMA to transfer * 'blocks' blocks of 512 bytes from/to 'buffer'. * Because the _IRQ signal is used for handshaking the command bytes, * the ACSI interrupt has to be disabled in this function. If the end * of the operation should be signalled by a real interrupt, it has to be * reenabled afterwards. */

⌨️ 快捷键说明

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