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

📄 aha_scsi.c

📁 MINIX2.0操作系统源码 MINIX2.0操作系统源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/*
 * This file contains the device dependent part of an experimental disk
 * and tape driver for the Adaptec 154x SCSI Host Adapter family, written
 * by James da Silva (jds@cs.umd.edu).
 *
 * I wrote this driver using the technical documentation for the AHA available
 * from the Adaptec BBS at 1-408-945-7727, and from the SCSI standard drafts
 * available on NCR's SCSI BBS at 1-316-636-8700.  I suggest you get both
 * these documents if you want to understand and hack this code.
 *
 * This code has been extensively modified by Kees J. Bot (kjb@cs.vu.nl) to
 * a point that James will barely recognize it as his.  It is completely
 * remodeled and doubled in both size and functionality.  It is no longer
 * considered experimental either.
 *
 * The supported device numbers are as follows:
 *   #	Name	Device
 *   0	sd0	disk 0, entire disk
 *   1	sd1	disk 0, partition 1
 *   2	sd2	disk 0, partition 2
 *   3	sd3	disk 0, partition 3
 *   4	sd4	disk 0, partition 4
 *   5	sd5	disk 1, entire disk
 *   6	sd6	disk 1, partition 1
 *  ..	....	....
 *  39	sd39	disk 7, partition 4
 *
 *  64	nrst0	tape 0, no rewind
 *  65	rst0	tape 0, rewind
 *  66	nrst1	tape 1, no rewind
 *  ..	....	....
 *  79	rst7	tape 7, rewind
 *
 * 128	sd1a	disk 0, partition 1, subpartition 1
 * 129	sd1b	disk 0, partition 1, subpartition 2
 * ...	....	....
 * 255	sd39d	disk 7, partition 4, subpartition 4
 *
 * The translation of device numbers to targets and logical units is very
 * simple:  The target is the same as the disk or tape number, the logical
 * unit is always zero.  Devices with logical unit numbers other then zero
 * are virtually extinct.  If you happen to have such a dinosaur device,
 * then you can reprogram (e.g.) sd35 and st7 to target 0, lun 1 from the
 * Boot Monitor with 'sd35=0,1'.
 *
 *
 * The file contains one entry point:
 *
 *   aha_scsi_task:	main entry when system is brought up
 *
 *
 * Changes:
 *	 5 May 1992 by Kees J. Bot: device dependent/independent split.
 *	 7 Jul 1992 by Kees J. Bot: speedup & features.
 *	28 Dec 1992 by Kees J. Bot: completely remodeled & virtual memory.
 *	18 Sep 1994 by Kees J. Bot: removed "send 2 commands at once" junk.
 */
#include "kernel.h"
#include "driver.h"
#include "drvlib.h"
#if ENABLE_ADAPTEC_SCSI
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mtio.h>
#include "assert.h"
INIT_ASSERT


#ifndef AHA_DEBUG
#define AHA_DEBUG	0	/* 1=print all SCSI errors | 2=dump ccb
				 * 4=show request | 8=dump scsi cmd
				 */
#endif

/* AHA-154x port addresses */
#define AHA_BASEREG	0x330	/* default base port address of AHA registers */
#define AHA_CNTLREG	aha_basereg+0	/* Control Register - write only */
#define AHA_STATREG	aha_basereg+0	/* Status Register - read only */
#define AHA_DATAREG	aha_basereg+1	/* Data Register - read/write */
#define AHA_INTRREG	aha_basereg+2	/* Interrupt Flags - read only */

/* control register bits */
#define AHA_HRST	0x80	/* bit 7 - Hard Reset */
#define AHA_SRST	0x40	/* bit 6 - Soft Reset */
#define AHA_IRST	0x20	/* bit 5 - Interrupt Reset */
#define AHA_SCRST	0x10	/* bit 4 - SCSI Bus Reset */
/*			0x08	 * bit 3 - Reserved (set to 0) */
/*			0x04	 * bit 2 - Reserved (set to 0) */
/*			0x02	 * bit 1 - Reserved (set to 0) */
/*			0x01	 * bit 0 - Reserved (set to 0) */

/* status register bits */
#define AHA_STST	0x80	/* bit 7 - Self Test in Progress */
#define AHA_DIAGF	0x40	/* bit 6 - Internal Diagnostic Failure */
#define AHA_INIT	0x20	/* bit 5 - Mailbox Initialization Required */
#define AHA_IDLE	0x10	/* bit 4 - SCSI Host Adapter Idle */
#define AHA_CDF		0x08	/* bit 3 - Command/Data Out Port Full */
#define AHA_DF		0x04	/* bit 2 - Data In Port Full */
/*			0x02	 * bit 1 - Reserved */
#define AHA_INVDCMD	0x01	/* bit 0 - Invalid Host Adapter Command */

/* interrupt flags register bits */
#define AHA_ANYINT	0x80	/* bit 7 - Any Interrupt */
/*			0x40	 * bit 6 - Reserved */
/*			0x20	 * bit 5 - Reserved */
/*			0x10	 * bit 4 - Reserved */
#define AHA_SCRD	0x08	/* bit 3 - SCSI Reset Detected */
#define AHA_HACC	0x04	/* bit 2 - Host Adapter Command Complete */
#define AHA_MBOE	0x02	/* bit 1 - Mailbox Out Empty */
#define AHA_MBIF	0x01	/* bit 0 - Mailbox In Full */

/* AHA board models */
#define AHA1540		0x30
#define AHA1540A	0x41
#define AHA1640		0x42
#define AHA1740		0x43
#define AHA1540C	0x44
#define AHA1540CF	0x45
#define BT545		0x20	/* BusLogic */

/* AHA Command Codes */
#define AHACOM_INITBOX		0x01	/* Mailbox Initialization */
#define AHACOM_STARTSCSI	0x02	/* Start SCSI Command */
#define AHACOM_HAINQUIRY	0x04	/* Host Adapter Inquiry */
#define AHACOM_SETIMEOUT	0x06	/* Set SCSI selection time out value */
#define AHACOM_BUSON		0x07	/* Set DMA bus on time */
#define AHACOM_BUSOFF		0x08	/* Set DMA bus off time */
#define AHACOM_SPEED		0x09	/* Set DMA transfer speed */
#define AHACOM_INSTALLED	0x0A	/* Return Installed Devices */
#define AHACOM_GETCONFIG	0x0B	/* Return Configuration Data */
#define AHACOM_GETSETUP		0x0D	/* Return Setup Data */
#define AHACOM_EXTBIOS		0x28	/* Return Extended BIOS Info */
#define AHACOM_MBOX_ENABLE	0x29	/* Enable Mailbox Interface */

/* AHA Mailbox Out Codes */
#define AHA_MBOXFREE	0x00	/* Mailbox is Free */
#define AHA_MBOXSTART	0x01	/* Start Command */
#define AHA_MBOXABORT	0x02	/* Abort Command */
/* AHA Mailbox In Codes */
#define AHA_MBOXOK	0x01	/* Command Completed Successfully */
#define AHA_MBOXERR	0x04	/* Command Completed with Error */


/* Basic types */
typedef unsigned char byte;
typedef byte big16[2];	/* 16 bit big-endian values */
typedef byte big24[3];	/* AHA uses 24 bit, big-endian values! */
typedef byte big32[4];	/* Group 1 SCSI commands use 32 bit big-endian values */

/* AHA Mailbox structure */
typedef struct {
  byte status;		/* Command or Status byte */
  big24 ccbptr;		/* pointer to Command Control Block */
} mailbox_t;

/* SCSI Group 0 Command Descriptor Block structure */
typedef union {
    struct {	/* Disk i/o commands */
	byte d_scsi_op;		/* SCSI Operation Code */
#	    define SCSI_UNITRDY  0x00	/* Test Unit Ready */
#	    define SCSI_REWIND   0x01	/* Rewind */
#	    define SCSI_REQSENSE 0x03	/* Request sense */
#	    define SCSI_RDLIMITS 0x05	/* Read Block Limits Opcode */
#	    define SCSI_READ     0x08	/* Group 0 Read Opcode */
#	    define SCSI_WRITE    0x0A	/* Group 0 Write Opcode */
#	    define SCSI_WREOF    0x10	/* Write File Marks */
#	    define SCSI_SPACE    0x11	/* Space over filemarks/blocks */
#	    define SCSI_INQUIRY  0x12	/* Group 0 Inquiry Opcode */
#	    define SCSI_MDSELECT 0x15	/* Group 0 Mode Select Opcode */
#	    define SCSI_ERASE    0x19	/* Erase Tape */
#	    define SCSI_MDSENSE  0x1A	/* Group 0 Mode Sense Opcode */
#	    define SCSI_STRTSTP  0x1B	/* Start/Stop */
#	    define SCSI_LOADUNLD 0x1B	/* Load/Unload */
        big24 d_lba;		/* LUN and logical block address */
	byte d_nblocks;		/* Transfer size in blocks */
	byte d_control;		/* Reserved and link bit fields, set to 0 */
    } d;
    struct {	/* Tape i/o commands */
	byte t_scsi_op;		/* SCSI Operation Code */
	byte t_fixed;		/* Fixed length? */
	big24 t_trlength;	/* Transfer length */
	byte t_control;		/* reserved and link bit fields, set to 0 */
    } t;
} cdb0_t;
#define scsi_op		d.d_scsi_op
#define lba		d.d_lba
#define nblocks		d.d_nblocks
#define fixed		t.t_fixed
#define trlength	t.t_trlength
#define control		d.d_control

/* SCSI Group 1 Command Descriptor Block structure */
typedef union {
    struct {	/* Disk i/o commands */
	byte d_scsi_op;		/* SCSI Operation Code */
#	    define SCSI_CAPACITY 0x25	/* Read Capacity */
#	    define SCSI_READ1    0x28	/* Group 1 Read Opcode */
#	    define SCSI_WRITE1   0x2A	/* Group 1 Write Opcode */
	byte d_lunra;		/* LUN etc. */
        big32 d_lba;		/* Logical Block Address */
	byte reserved;
	big16 d_nblocks;	/* transfer size in blocks */
	byte d_control;		/* reserved and link bit fields, set to 0 */
    } d;
} cdb1_t;
#define lunra		d.d_lunra

/* SCSI Request Sense Information */
typedef struct {
    byte errc;			/* Error Code, Error Class, and Valid bit */
    byte segnum;		/* Segment Number */
    byte key;			/* Sense Key */
#	define sense_key(key)	(key & 0x0F)	/* the key portion */
#	define sense_ili(key)	(key & 0x20)	/* illegal block size */
#	define sense_eom(key)	(key & 0x40)	/* end-of-media */
#	define sense_eof(key)	(key & 0x80)	/* filemark reached */
    big32 info;			/* sense info */
    byte len;			/* additional length */
    big32 comspec;		/* command specific info */
    byte add_code;		/* additional sense code */
    byte add_qual;		/* additional sense code qualifier */
} sense_t;

/* Interesting SCSI sense key types. */
#define SENSE_NO_SENSE		0x00
#define SENSE_RECOVERED		0x01
#define SENSE_NOT_READY		0x02
#define SENSE_HARDWARE		0x04
#define SENSE_UNIT_ATT		0x06
#define SENSE_BLANK_CHECK	0x08
#define SENSE_VENDOR		0x09
#define SENSE_ABORTED_CMD	0x0B

/* SCSI Inquiry Information */
typedef struct {
    byte devtype;		/* Peripheral Device Type */
#	define SCSI_DEVDISK	0	/* Direct-access */
#	define SCSI_DEVTAPE	1	/* Sequential-access */
#	define SCSI_DEVPRN	2	/* Printer */
#	define SCSI_DEVCPU	3	/* Processor */
#	define SCSI_DEVWORM	4	/* Write-Once Read-Multiple device */
#	define SCSI_DEVCDROM	5	/* Read-Only Direct-access */
#	define SCSI_DEVSCANNER	6	/* Scanner */
#	define SCSI_DEVOPTICAL	7	/* Optical Memory */
#	define SCSI_DEVJUKEBOX	8	/* Medium Changer device */
#	define SCSI_DEVCOMM	9	/* Communications device */
#	define SCSI_DEVMAX	9	/* Last device type we know about */
#	define SCSI_DEVUNKNOWN	10	/* If we do not know or care. */
    byte devqual;		/* Device-Type Qualifier */
#	define scsi_rmb(d)	(((d) & 0x80) != 0)	/* Removable? */
    byte stdver;		/* Version of standard compliance */
#	define scsi_isover(v)   (((v) & 0xC0) >> 6)	/* ISO version */
#	define scsi_ecmaver(v)  (((v) & 0x38) >> 3)	/* ECMA version */
#	define scsi_ansiver(v)  ((v) & 0x07)		/* ANSI version */
    byte format;		/* Response data format */
    byte len;			/* length of remaining info */
    byte reserved[2];
    byte flags;
#	define scsi_sync(f)	(((f) & 0x10) != 0)	/* Sync SCSI? */
    char vendor[8];		/* Vendor name */
    char product[16];		/* Product name */
    char revision[4];		/* Revision level */
    char extra[20];		/* Vendor specific */
} inquiry_t;

/* AHA Command Control Block structure */
typedef struct {
    byte opcode;		/* Operation Code */
#	define CCB_INIT		0x00		/* SCSI Initiator Command */
#	define CCB_TARGET	0x01		/* Target Mode Command */
#	define CCB_SCATTER	0x02	     /* Initiator with scatter/gather */
    byte addrcntl;		/* Address and Direction Control: */
#       define ccb_scid(id)     (((id)<<5)&0xE0) /* SCSI ID field */
#	define CCB_OUTCHECK	0x10		 /* Outbound length check */
#	define CCB_INCHECK	0x08		 /* Inbound length check */
#	define CCB_NOCHECK	0x00		 /* No length check */
#	define ccb_lun(lun)     ((lun)&0x07)	 /* SCSI LUN field */
    byte cmdlen;		/* SCSI Command Length (6 for Group 0) */
    byte senselen;		/* Request/Disable Sense, Allocation Length */
#	define CCB_SENSEREQ	0x0E		/* Request Sense, 14 bytes */
#	define CCB_SENSEOFF	0x01		/* Disable Request Sense */
    big24 datalen;		/* Data Length:  3 bytes, big endian */
    big24 dataptr;		/* Data Pointer: 3 bytes, big endian */
    big24 linkptr;		/* Link Pointer: 3 bytes, big endian */
    byte linkid;		/* Command Linking Identifier */
    byte hastat;		/* Host Adapter Status */
#	define HST_TIMEOUT	0x11		/* SCSI selection timeout */
    byte tarstat;		/* Target Device Status */
#	define TST_CHECK	0x02		/* Check status in sense[] */
#	define TST_LUNBUSY	0x08		/* Unit is very busy */
    byte reserved[2];		/* reserved, set to 0 */
    byte cmd[sizeof(cdb1_t)];	/* SCSI Command Descriptor Block */
    byte sense[sizeof(sense_t)];/* SCSI Request Sense Information */
} ccb_t;


	/* End of one chunk must be as "odd" as the start of the next. */
#define DMA_CHECK(end, start)	((((int) (end) ^ (int) (start)) & 1) == 0)

/* Scatter/Gather DMA list */
typedef struct {
    big24 datalen;		/* length of a memory segment */
    big24 dataptr;		/* address of a memory segment */
} dma_t;


/* Miscellaneous parameters */
#define SCSI_TIMEOUT	 250	/* SCSI selection timeout (ms), 0 = none */
#define AHA_TIMEOUT	 500	/* max msec wait for controller reset */

#define MAX_DEVICES	   8	/* 8 devices for the 8 SCSI targets */
#define NR_DISKDEVS	 (MAX_DEVICES * DEV_PER_DRIVE)
#define NR_TAPEDEVS	 (MAX_DEVICES * 2)
#define NR_GENDEVS	 (MAX_DEVICES)
#define SUB_PER_DRIVE	 (NR_PARTITIONS * NR_PARTITIONS)
#define NR_SUBDEVS	 (MAX_DEVICES * SUB_PER_DRIVE)
#define MINOR_st0	  64

#define TYPE_SD		   0	/* disk device number */
#define TYPE_NRST	   1	/* non rewind-on-close tape device */
#define TYPE_RST	   2	/* rewind-on-close tape device */


/* Variables */
PRIVATE struct scsi {	/* Per-device table */
    char targ;			/* SCSI Target ID */
    char lun;			/* SCSI Logical Unit Number */
    char state;			/* online? */
#	define S_PRESENT	0x01	/* Device exists */
#	define S_READY		0x02	/* Device is ready */
#	define S_RDONLY		0x04	/* Device is read-only */
    char devtype;		/* SCSI_DEVDISK, SCSI_DEVTAPE, ... */
    unsigned block_size;	/* device or media block size */
    unsigned count_max;		/* maximum single read or write */
    unsigned open_ct;		/* number of processes using the device */
    union {
	struct {		/* Tape data */
	    char open_mode;	/* open for reading or writing? */
	    char at_eof;	/* got EOF mark */
	    char need_eof;	/* need to write an eof mark */
	    char tfixed;	/* tape in fixed mode */
	    struct mtget tstat;	/* tape status info */
	    struct device dummypart;  /* something for s_prepare to return */
	} tape;
	struct {		/* Disk data */
	    struct device part[DEV_PER_DRIVE];    /* primaries: sd[0-4] */
	    struct device subpart[SUB_PER_DRIVE]; /* subparts: sd[1-4][a-d] */
	} disk;
    } u;
} scsi[MAX_DEVICES];

#define open_mode	u.tape.open_mode
#define at_eof		u.tape.at_eof
#define need_eof	u.tape.need_eof
#define tfixed		u.tape.tfixed
#define tstat		u.tape.tstat
#define dummypart	u.tape.dummypart
#define part		u.disk.part
#define subpart		u.disk.subpart

/* Tape device status (tstat.mt_dsreg). */
#define DS_OK		0	/* Device OK */
#define DS_ERR		1	/* Error state */
#define DS_EOF		2	/* Last read or space hit EOF */

/* SCSI device types */
PRIVATE char *scsi_devstr[SCSI_DEVMAX+1] = {
  "DISK", "TAPE", "PRINTER", "CPU", "WORM", "CDROM", "SCANNER", "OPTICAL",
  "JUKEBOX", "COMM"
};

/* SCSI sense key types */
PRIVATE char *str_scsi_sense[] = {
  "NO SENSE INFO", "RECOVERED ERROR", "NOT READY", "MEDIUM ERROR",
  "HARDWARE ERROR", "ILLEGAL REQUEST", "UNIT ATTENTION", "DATA PROTECT",
  "BLANK CHECK", "VENDOR UNIQUE ERROR", "COPY ABORTED", "ABORTED COMMAND",
  "EQUAL", "VOLUME OVERFLOW", "MISCOMPARE", "SENSE RESERVED"
};

/* Some of the above errors must be printed on the console. */
#if AHA_DEBUG & 1
#define sense_serious(key)	((key) != 0)
#else
#define sense_serious(key)	((0xFE1C & (1 << (key))) != 0)
#endif

/* Administration for one SCSI request. */
typedef struct request {
  unsigned count;		/* number of bytes to transfer */
  unsigned retry;		/* number of tries allowed if retryable */
  unsigned long pos;		/* first byte on the device to transfer */
  ccb_t ccb;			/* Command Control Block */
  dma_t dmalist[NR_IOREQS];	/* scatter/gather dma list */
  dma_t *dmaptr;		/* to add scatter/gather entries */
  dma_t *dmalimit;		/* adapter model dependent limit to list */
  struct iorequest_s *iov[NR_IOREQS];	/* affected I/O requests */
} request_t;

PRIVATE request_t request;
#define rq (&request)		/* current request (there is only one) */

#define ccb_cmd0(rq)	(* (cdb0_t *) (rq)->ccb.cmd)
#define ccb_cmd1(rq)	(* (cdb1_t *) (rq)->ccb.cmd)
#define ccb_sense(rq)	(* (sense_t *) ((rq)->ccb.cmd + (rq)->ccb.cmdlen))

PRIVATE int aha_basereg;	/* base I/O register */
PRIVATE int aha_model;		/* board model */
PRIVATE struct scsi *s_sp;	/* active SCSI device struct */
PRIVATE struct device *s_dv;	/* active partition */
PRIVATE int s_type;		/* sd, rst, nrst? */
PRIVATE unsigned long s_nextpos;/* next byte on the device to transfer */
PRIVATE unsigned long s_buf_blk;/* disk block currently in tmp_buf */
PRIVATE int s_opcode;		/* DEV_READ or DEV_WRITE */
PRIVATE int s_must;		/* must finish the current request? */
PRIVATE int aha_irq;		/* configured IRQ */
PRIVATE mailbox_t mailbox[2];	/* out and in mailboxes */
PRIVATE inquiry_t inqdata;	/* results of Inquiry command */


/* Functions */

FORWARD _PROTOTYPE( struct device *s_prepare, (int device) );
FORWARD _PROTOTYPE( char *s_name, (void) );
FORWARD _PROTOTYPE( int s_do_open, (struct driver *dp, message *m_ptr) );
FORWARD _PROTOTYPE( int scsi_probe, (void) );
FORWARD _PROTOTYPE( int scsi_sense, (void) );
FORWARD _PROTOTYPE( int scsi_inquiry, (void) );
FORWARD _PROTOTYPE( int scsi_ndisk, (void) );
FORWARD _PROTOTYPE( int scsi_ntape, (void) );
FORWARD _PROTOTYPE( int s_schedule, (int proc_nr, struct iorequest_s *iop) );
FORWARD _PROTOTYPE( int s_finish, (void) );
FORWARD _PROTOTYPE( int s_rdcdrom, (int proc_nr, struct iorequest_s *iop,
		unsigned long pos, unsigned nbytes, phys_bytes user_phys) );
FORWARD _PROTOTYPE( int s_do_close, (struct driver *dp, message *m_ptr) );

⌨️ 快捷键说明

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