|
DataMuseum.dkPresents historical artifacts from the history of: Regnecentalen RC-900 |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Regnecentalen RC-900 Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - download
Length: 33944 (0x8498) Types: TextFile Notes: UNIX file Names: »gendev.h«
└─⟦fdc69b24d⟧ Bits:30004152 SW95705I 386/ix Multi User Update 1 └─⟦fdc69b24d⟧ UNIX Filesystem └─⟦this⟧ »U1/new/usr/include/sys/gendev.h«
/* * Definitions for the Generic Device drivers. */ /* * Copyrighted as an unpublished work. * (c) Copyright 1986 INTERACTIVE Systems Corporation * All rights reserved. * * RESTRICTED RIGHTS * * These programs are supplied under a license. They may be used, * disclosed, and/or copied only as permitted under such license * agreement. Any copy must contain the above copyright notice and * this restricted rights notice. Use, copying, and/or disclosure * of the programs is strictly prohibited unless otherwise provided * in the license agreement. */ #ident "@(#)gendev.h 1.2 - 88/07/28" #define GDEV_MAXIOCTL 8 /* Maximum # of low-level IOCTL's supported */ #define GDEV_MAXDRV 8 /* Maximum # of drives per controller */ #define GDEV_CTL_INT 2 /* Maximum # of interrupt vectors per controller */ #define GDEV_DRQBLOX 1024 /* # of gdev_request_entries to allocate */ #define GDEV_MAX_INT 16 /* maximum # of interrupt levels */ #define GDEV_INTENTS 12 /* Max # of primary & secondary interrupt handlers */ #define GDEV_LOWLEV 10 /* # of doublewords of storage to reserve in */ /* gdev_ctl_block and gdev_parm_block for low- */ /* level driver code */ #define GDEV_SHAREMAX 3 /* Max # of drivers that can share a controller */ #define GDEV_MINORMAPS 48 /* Number of minormap entries to allocate */ #define GDEV_MAJORMAPS 48 /* Number of majormap entries to allocate */ #define SPLGDEV spl5() /* Change the following 2 defines as necessary to support more stuff */ #define GDEV_MAXCTLS 6 /* Max number of controller boards allowed */ #define GDEV_MAXDRIVS 16 /* Max number of drives allowed */ extern ushort gdev_drqblox; extern ushort gdev_maxctls; extern ushort gdev_maxdrivs; extern ushort gdev_max_int; extern ushort gdev_intents; extern ushort gdev_sharemax; /* * The special ioctl definitions block. This is defined in the config * structure and is pointed at by the dev controller block. */ struct special_ioctls { int spi_count; /* number of actual entries used */ struct { int ioctl_num; /* ioctl number */ int (*ioctl_code)(); /* function to handle that ioctl */ } spi_ents[GDEV_MAXIOCTL]; }; /* * Structure to hold driver-specific information for a controller. * There is one of these structures for each driver using a controller * in that controller's dcb. */ struct gdev_driver { int (*drv_CMD)(); /* Perform Command function */ int (*drv_OPEN)(); /* Device Opening function (or NULL) */ int (*drv_CLOSE)(); /* Device Closing function (or NULL) */ int (*drv_START)(); /* Start I/O function */ int (*drv_drvint)(); /* driver completion/error interrupt routine */ struct gdev_parm_block *(*drv_INT[GDEV_CTL_INT])(); /* interrupt funcs */ struct special_ioctls *drv_ioctls; /* special ioctls */ ushort drv_drives; /* Number of drives for this driver */ ushort drv_curdriv; /* Current drive for this driver */ ushort drv_firstdriv; /* idx of first drive for this driver */ ushort drv_baseminor; /* First minormap entry for this driver */ }; /* * Generic Device Controller Block. This structure contains information about * the configuration, capabilities, and status of a given controller board. */ struct gdev_ctl_block { char *dcb_name; /* Controller Name (text string for err msgs) */ ulong dcb_capab; /* Controller Capability flags (below) */ paddr_t dcb_memaddr1; /* Controller Memory Address (prime) */ paddr_t dcb_memaddr2; /* Controller Memory Address (secondary) */ ushort dcb_ioaddr1; /* Controller I/O Space Address (prime) */ ushort dcb_ioaddr2; /* Controller I/O Space Address (secondary) */ ushort dcb_dmachan1; /* DMA channel used (prime) */ ushort dcb_dmachan2; /* DMA channel used (secondary) */ ushort dcb_maxsec; /* Max # of blocks in single controller req */ ushort dcb_delay; /* Delay time for switching drives in 10us units */ ushort dcb_defsecsiz; /* Default block size for drives on this ctl */ ushort dcb_flags; /* Controller Activity flags (below) */ ushort dcb_drivers; /* Number of drivers using this controller */ ushort dcb_driveridx; /* current driver index into below struct */ int (*dcb_multint)(); /* CCAP_MULTI Master interrupt handler */ struct gdev_driver dcb_drv[GDEV_SHAREMAX]; /* driver-specific fields */ struct gdev_parm_block /* Pointers at Gdev Param Blocks */ *dcb_dpbs[GDEV_MAXDRV]; /* (one for EACH dev on controller) */ ulong dcb_lowlev[GDEV_LOWLEV]; /* Scratch space for low-level code */ }; typedef struct gdev_ctl_block *gdev_dcbp; extern struct gdev_ctl_block gdev_ctl_blocks[]; /* def'd in space.c */ extern ushort gdev_nextctl; /* next gdev_ctl_block to allocate */ /* * The following defines allow access to the driver dcb fields. */ #define drvidx(X) ((X)->dcb_driveridx) #define dcb_CMD(X) (X)->dcb_drv[drvidx(X)].drv_CMD #define dcb_OPEN(X) (X)->dcb_drv[drvidx(X)].drv_OPEN #define dcb_CLOSE(X) (X)->dcb_drv[drvidx(X)].drv_CLOSE #define dcb_START(X) (X)->dcb_drv[drvidx(X)].drv_START #define dcb_drvint(X) (X)->dcb_drv[drvidx(X)].drv_drvint #define dcb_INT(X,IDX) (X)->dcb_drv[drvidx(X)].drv_INT[IDX] #define dcb_ioctls(X) (X)->dcb_drv[drvidx(X)].drv_ioctls #define dcb_drives(X) (X)->dcb_drv[drvidx(X)].drv_drives #define dcb_firstdriv(X) (X)->dcb_drv[drvidx(X)].drv_firstdriv #define dcb_curdriv(X) (X)->dcb_drv[drvidx(X)].drv_curdriv #define dcb_baseminor(X) (X)->dcb_drv[drvidx(X)].drv_baseminor extern struct iobuf gdev_iobufs[]; /* V.3 io buffer headers (1 per drive) */ /* Controller Capability Flags: */ #define CCAP_MULTI 0x01 /* Multiple concurrent I/O requests supported */ #define CCAP_DMA 0x02 /* DMA supported */ #define CCAP_SCATGATH 0x04 /* Scatter-gather I/O supported */ #define CCAP_16BIT 0x08 /* Limit contiguous xfers to 64K (len & bound) */ #define CCAP_CYLLIM 0x10 /* I/O request limited to a single cylinder */ #define CCAP_CHAINSECT 0x20 /* Command chaining at sector boundaries supported */ #define CCAP_NOSEEK 0x40 /* No explicit SEEK commands should be used */ #define CCAP_RETRY 0x80 /* Controller can do automatic retries */ #define CCAP_ERRCOR 0x100 /* Controller can do error correction */ #define CCAP_SHARED 0x200 /* Controller can be shared between different */ /* drivers (up to GDEV_SHAREMAX of them). */ /* Used for disk & tape on same controller */ /* Controller Activity Flags: */ #define CFLG_BUSY 0x01 /* Controller is busy processing a request. */ /* For single-thread controllers, this is */ /* handled entirely by generic code. For */ /* multi-thread (CCAP_MULTI) controllers, */ /* low-level code should clear this and call */ /* the drv_START routine for the first driver */ /* when the controller is available */ /* to process another request */ #define CFLG_EXCLREQ 0x02 /* An exclusive controller request is pending */ /* (a 'wakeup' on &gdev_ctl_block will be */ /* done when controller goes idle) */ #define CFLG_EXCL 0x04 /* Someone has exclusive access to controller. */ /* Do not re-grant exclusivity until released */ #define CFLG_INIT 0x08 /* We are initializing this controller */ #define CFLG_INITDONE 0x10 /* Controller initialization has been done */ /* (intended for shared controllers) */ /* * Generic Device Parameter Block. This structure contains information about * the physical geometry of a device, its activities, and its state. */ struct gdev_parm_block { ulong dpb_flags; /* Drive flags (below) */ ulong dpb_cyls; /* Number of available cylinders on drive */ ulong dpb_rescyls; /* Number of reserved cylinders on drive */ ulong dpb_wpcyl; /* Write-precomp cyl (if necessary) */ ulong dpb_parkcyl; /* Head-parking cyl (if necessary) */ ulong dpb_pdsect; /* Default 'pdinfo' sector number */ ushort dpb_heads; /* Number of heads per cylinder */ ushort dpb_sectors; /* Number of available sectors per track */ ushort dpb_ressecs; /* Number of reserved sectors per track */ ushort dpb_secsiz; /* Sector size (in bytes) */ ushort dpb_secovhd; /* Sector overhead (in bytes) */ ushort dpb_state; /* Drive state (below) */ ushort dpb_intret; /* What happened on last interrupt (below) */ unchar dpb_devtype; /* Device type indicator (below) */ unchar dpb_subtype; /* Device sub-type (below) */ ushort dpb_command; /* Current command being executed on drive */ ushort dpb_savecmd; /* Saved command for retry-restore */ ushort dpb_drvcmd; /* Actual drive-level command being executed */ ushort dpb_drvflags; /* Drive-specific flags */ unchar dpb_interleave; /* Hardware Interleave Factor used on drive */ unchar dpb_skew; /* Skew factor (if known & intlv == 1, 0 otherwise */ ushort dpb_drverror; /* Last error code from drive */ ushort dpb_numparts; /* Number of partitions on drive */ ushort dpb_altsiz; /* Size of alternates map for drive (bytes) */ struct alt_table *dpb_alts; /* Pointer at alternates map for drive */ struct drq_entry *dpb_req; /* pointer at current request entry */ struct iobuf *dpb_que; /* pointer at request queue head */ /* * The following 5 fields are set up by Generic code for new transfers * and for retries. They are to be updated by low-level code (using * 'gdev_xferok' in genblklib.c) ONLY after SUCCESSFUL transfer of * some number of sectors to/from the drive has been assured. */ paddr_t dpb_curaddr; /* Current physical memory transfer address */ daddr_t dpb_cursect; /* Current sector number on drive */ ulong dpb_totcount; /* Total bytes xfer'd on this request so far */ ulong dpb_sectcount; /* Sectors remaining in current disk section */ struct drq_entry *dpb_memsect; /* Current memory section (if used) */ /* * The following 3 fields are used for maintaining running values during * the course of a transfer until the success or failure of the transfer * can be determined. They are set from the corresponding fields above * for each new disk section or retry operation. */ paddr_t dpb_newaddr; /* Active physical memory address for xfer */ ulong dpb_newcount; /* Bytes remaining in active memory section */ /* This gets set from dpb_memsect's drq_count */ struct drq_entry *dpb_newdrq; /* active memory section */ ushort dpb_curcyl; /* Current DISK cylinder. MUST BE MAINTAINED */ /* unless CCAP_NOSEEK is specified */ ushort dpb_retrycnt; /* Number of retries performed on command */ short dpb_blkshft; /* shift for blk->sector conversion (<0 == <<) */ ushort dpb_secbufsiz; /* size in bytes of sector buffers */ char *dpb_secbuf[2]; /* -> MEMXFER buffer (2 diff ones if chaining) */ unchar dpb_otypflgs[V_NUMPAR]; /* flags for OTYPs 0-3 (see open.h) */ /* bits are defined as 1<<otyp */ ushort dpb_otyplyr[V_NUMPAR]; /* count for OTYP_LYR calls (see open.h) */ struct alt_ent *dpb_firstalt[V_NUMPAR]; /* first alternate sector for partition */ /* NULL if none... */ ushort dpb_altcount[V_NUMPAR]; /* Number of alternates for partition */ struct partition dpb_parts[V_NUMPAR]; /* Partition table for drive */ ulong dpb_lowlev[GDEV_LOWLEV]; /* Scratch space for low-level code */ }; typedef struct gdev_parm_block *gdev_dpbp; extern struct gdev_parm_block gdev_parm_blocks[]; /* def'd in space.c */ extern ushort gdev_nextdriv; /* next gdev_parm_block to allocate */ /* Drive flags: */ #define DFLG_BUSY 0x01 /* Drive is currently busy */ #define DFLG_RETRY 0x02 /* Retries should be attempted on commands */ #define DFLG_ERRCORR 0x04 /* Error correction should be attempted */ #define DFLG_OPENING 0x08 /* Drive is currently being opened */ #define DFLG_VTOCOK 0x10 /* Drive has a valid pdinfo/vtoc/etc */ #define DFLG_CLOSING 0x20 /* Last partition on drive is being closed */ #define DFLG_VTOCSUP 0x40 /* VTOC/PDINFO/ALTS/etc supported on drive */ #define DFLG_REMOVE 0x80 /* Drive supports removable media */ #define DFLG_SPECIAL 0x100 /* A special (no queue entry) request in progress */ /* (a 'wakeup' on gdev_param_block will be done at */ /* completion of the request). */ #define DFLG_READING 0x200 /* This drive is currently involved in a READ */ /* request. Used in deciding whether READ or */ /* WRITE commands should be issued for I/O */ #define DFLG_OPEN 0x400 /* This drive is currently opened */ #define DFLG_OFFLINE 0x800 /* Drive is offline for some reason */ #define DFLG_FIXREC 0x1000 /* Drive supports fixed-length records only */ /* Above is intended for tape (cart vs mag) */ /* Drive states: */ #define DSTA_IDLE 0 /* Drive is idle */ #define DSTA_SEEKING 1 /* Drive is seeking */ #define DSTA_NORMIO 2 /* Drive is performing normal I/O (read/write) */ #define DSTA_RECAL 3 /* Drive is doing diagnostic recalibrate */ #define DSTA_GETERR 4 /* Drive is getting extended error code */ /* * Values for dpb_intret. This value is set by the controller-level * interrupt code to let the driver know what occurred during processing * of the last interrupt. This drives a switch after the controller-level * interrupt handler to determine what to do next. */ #define DINT_CONTINUE 1 /* Current controller command is continuing */ /* No intervention by generic code is necessary. */ #define DINT_COMPLETE 2 /* Current request has completed normally */ #define DINT_GENERROR 3 /* Some general error occurred */ /* (dpb_drverror is not accurate yet -- */ /* generic code will request error code) */ #define DINT_ERRABORT 4 /* Current command terminated abnormally */ /* (generic error code is in dpb_drverror) */ #define DINT_NEEDCMD 5 /* A command needs to be issued */ #define DINT_NEWSECT 6 /* Processing needs to be initiated on a new */ /* section request. */ /* Device type codes: */ #define DTYP_UNKNOWN 0 /* Unknown device type */ #define DTYP_DISK 1 /* Disk type device */ #define DTYP_TAPE 2 /* Tape type device */ /* Device sub-type codes: */ /* NONE OF THESE ARE CURRENTLY DEFINED. */ /* * Generic Device Error Numbers. Each controller-level handler must convert * its own controller's error codes into these. A standard array of these * numbers in a well-known order should be part of the driver's space.c * file to facilitate this translation. It may not be possible to get all * error codes from all controller/drive combinations. This list attempts * to be exhaustive. */ #define DERR_NOERR 0 /* No error found */ #define DERR_DAMNF 1 /* Data address mark not found */ #define DERR_TRK00 2 /* Unable to recalibrate to track 0 */ #define DERR_WFAULT 3 /* Write Fault on drive */ #define DERR_DNOTRDY 4 /* Drive is not ready */ #define DERR_CNOTRDY 5 /* Controller will not come ready */ #define DERR_NOSEEKC 6 /* Seek will not complete */ #define DERR_SEEKERR 7 /* Seek error (wrong cylinder found) */ #define DERR_NOIDX 8 /* No Index signal found */ #define DERR_WRTPROT 9 /* Medium is write-protected */ #define DERR_NODISK 10 /* Medium is not present in drive */ #define DERR_BADSECID 11 /* Error found in sector ID field */ #define DERR_SECNOTFND 12 /* Sector not found */ #define DERR_DATABAD 13 /* (uncorrectable) Error found in sector data */ #define DERR_BADMARK 14 /* Sector or track was marked bad */ #define DERR_FMTERR 15 /* Error during Format operation */ #define DERR_BADCMD 16 /* Illegal/erroneous command */ #define DERR_CTLERR 17 /* Controller error or failure */ #define DERR_ABORT 18 /* Command aborted with no apparent cause */ #define DERR_SEEKING 19 /* Drive is still seeking (try again later) */ #define DERR_MEDCHANGE 20 /* Medium has been changed in drive */ #define DERR_PASTEND 21 /* I/O past end of drive */ #define DERR_OVERRUN 22 /* Data overrun */ #define DERR_TIMEOUT 23 /* Command timeout */ #define DERR_DRVCONFIG 24 /* Unable to get valid drive configuration */ #define DERR_UNKNOWN 25 /* Undetermined error */ #define DERR_EOF 26 /* Found EOF on Read or EOM on Write */ #define DERR_ERRCOR 27 /* Correctable data error occurred */ /* * The following table is used to process dev errors. * It is indexed by the Generic error code in dpb_drverror. */ struct gdev_err_msg { ushort err_unixcod; /* Unix error code to return */ ushort err_flags; /* Error flags (see below) */ char *err_msgptr; /* Error message text */ }; /* Error message flag values: */ #define ERF_PANIC 0x01 /* This error type should panic system */ #define ERF_QUIET 0x02 /* Handle this one without saying anything */ #define ERF_NORETRY 0x04 /* Don't bother retrying this one... */ extern struct gdev_err_msg gdev_err_msgs[]; /* defined in space.c */ /* Drive Commands: */ #define DCMD_READ 1 /* Read Sectors/Blocks */ #define DCMD_WRITE 2 /* Write Sectors/Blocks */ #define DCMD_FORMAT 3 /* Format Tracks */ #define DCMD_SETPARMS 4 /* Set Drive Parameters */ #define DCMD_RECAL 5 /* Recalibrate */ #define DCMD_GETERR 6 /* Get Generic Error Code */ #define DCMD_SEEK 7 /* Seek to Cylinder */ #define DCMD_RETRY 9 /* Restart current command for retry */ #define DCMD_FMTDRV 10 /* Format entire drive */ #define DCMD_REWIND 11 /* Rewind */ #define DCMD_SEOF 12 /* Skip to File Mark */ #define DCMD_UNLOAD 13 /* Unload removable medium */ #define DCMD_SERVWRT 14 /* Write Servo Data */ #define DCMD_ERASE 15 /* Erase Tape */ #define DCMD_RETENSION 16 /* Retension Tape */ #define DCMD_WFM 17 /* Write File Mark */ #define DCMD_GETPARMS 18 /* Get Parameters from device */ #define DCMD_ENABUF 19 /* Enable buffered mode */ /* * Device Request Queue. This structure is used to contain all information * necessary to completely process a single strategy-level driver request. * It is pointed at by the first buffer header in a list for a request. * The entries in the chain are singly linked through drq_link. See the * description of the 'strategy' routine, above, for how this all works. * * Driver 'init' code creates a pool of these elements. 'strategy' calls * 'getdrq' to allocate them (which can cause a sleep if there are none). * Any controller-level code which advances the dpb_req pointer should call * 'reldrq' on the old one to give it back to the pool, or we run out * REAL quick. */ struct drq_entry { union { struct { uint drq_xcnt : 24; /* Byte or sector count */ uint drq_xtyp : 7; /* Entry type (see below) */ uint drq_xflgs : 1; /* special flag (during strategy ONLY) */ } drq_flags; uint drq_flgint; /* for zeroing all of the first word */ } drq_word1; ulong drq_addr1; /* Memory address 1 */ ulong drq_addr2; /* Disk or memory address 2 */ struct drq_entry *drq_link; /* Pointer at next entry in chain */ }; #define drq_count drq_word1.drq_flags.drq_xcnt #define drq_type drq_word1.drq_flags.drq_xtyp #define drq_phys drq_word1.drq_flags.drq_xflgs /* START or CONT has physical memaddr */ #define drq_virt drq_word1.drq_flags.drq_xflgs /* MEMBREAK has virt addr of brk in bufp */ #define drq_daddr(X) (daddr_t)((X)->drq_addr2) #define set_drq_daddr(X,VAL) (X)->drq_addr2 = (ulong)(VAL) #define drq_bufp(X) (struct buf *)((X)->drq_addr2) #define set_drq_bufp(X,VAL) (X)->drq_addr2 = (ulong)(VAL) #define drq_memaddr(X) (paddr_t)((X)->drq_addr1) #define set_drq_memaddr(X,VAL) (X)->drq_addr1 = (ulong)(VAL) #define drq_drqp(X) (struct drq_entry *)((X)->drq_addr1) #define set_drq_ptr(X,VAL) (X)->drq_addr1 = (ulong)(VAL) #define drq_srcaddr(X) (paddr_t)((X)->drq_addr1) #define set_drq_srcaddr(X,VAL) (X)->drq_addr1 = (ulong)(VAL) #define drq_dstaddr(X) (paddr_t)((X)->drq_addr2) #define set_drq_dstaddr(X,VAL) (X)->drq_addr2 = (ulong)(VAL) extern struct drq_entry drq_entries[]; /* def'd in space.c */ extern struct drq_entry *drq_freelist; /* def'd in space.c */ extern struct drq_entry *getdrq(); extern struct drq_entry *reldrq(); /* * drq_type values: */ #define DRQT_START 1 /* Start new transfer. drq_count is sector */ /* count, drq_daddr is start sector, drq_memaddr */ /* is beginning physical memory address. Need */ /* to seek to start, good time to allow overlap. */ #define DRQT_CONT 2 /* Like DRQT_START, but just a continuation of */ /* transfer in progress. Shouldn't need to seek */ /* or allow other I/O to intervene */ #define DRQT_MEMBREAK 3 /* Memory Address Discontinuity. drq_count is */ /* number of bytes before break point, drq_memaddr */ /* is new transfer address, drq_bufp (if non-NULL) */ /* points at buffer header to call 'iodone' on after */ /* break point is passed */ #define DRQT_MEMXFER 4 /* Memory-Memory Transfer. Used to simulate */ /* scatter/gather for non-buffered controllers that */ /* don't support it. drq_count is byte count, */ /* drq_srcaddr and drq_dstaddr are source & dest */ /* memory addresses, respectively. NOTE: most */ /* controller-level code should NEVER see these */ /* types of entry -- they're handled by generic code */ /* unless CCAP_CHAINSECT is set. */ /* * The following 2 drq_types are for TAPE ONLY. To allow a cartridge tape * unit (which supports only fixed blocks) to support the appearance of being * a variable-record-size device, we make use of a sector (block) buffer * allocated during tape drive initialization. If someone wants to write a * block that is not a multiple of <dpb_secsiz>, we write all but the last * block as normal, then copy the remnant into the block buffer with a * DRQT_MEMXFER. We then use DRQT_MEMCLEAR to zero the remainder of the * block. This block is then written to the tape. If someone wants to * read a non-multiple, we read all but the last block as normal, read the * last block into the block buffer, use DRQT_MEMXFER to transfer the fragment * the user wants, and use DRQT_IGNORE to discard the remaining bytes (this * causes alignment between memory and device sections). */ #define DRQT_MEMCLEAR 5 /* drq_srcaddr is the beginning of the area */ /* to zap, drq_count is the number of bytes */ #define DRQT_IGNORE 6 /* drq_count is the number of bytes to ingore */ /* * Device Configuration Tables. These tables contain information about expected * configurations of hardware present in a system. They map major and minor * device numbers to physical hardware devices, provide for default I/O and * memory address space values, controller capabilities expected, etc. The * information in these tables is advisory only! It is the job of the Board * Initialization routines to determine which (if any) of these capabilities * and parameters are actually valid. These are then used to fill in the * appropriate Device Controller Block and Device Parameter Block(s) for a * given controller and drive(s). */ struct cfg_int_entry { ushort cfg_intlev; /* interrupt level */ struct gdev_parm_block *(*cfg_INT)(); /* interrupt func */ }; struct gdev_cfg_entry { /* subset of the gdev_ctl_blk... */ char *cfg_name; /* Controller Name (text string for err msgs) */ ulong cfg_capab; /* Controller Capability flags (below) */ paddr_t cfg_memaddr1; /* Controller Memory Address (prime) */ paddr_t cfg_memaddr2; /* Controller Memory Address (secondary) */ ushort cfg_ioaddr1; /* Controller I/O Space Address (prime) */ ushort cfg_ioaddr2; /* Controller I/O Space Address (secondary) */ ushort cfg_dmachan1; /* DMA channel used (prime) */ ushort cfg_dmachan2; /* DMA channel used (secondary) */ ushort cfg_maxsec; /* Max # of sectors in single controller req */ ushort cfg_drives; /* Max number of drives on controller */ ushort cfg_delay; /* Delay time for switching drives in 10us units */ ushort cfg_baseminor; /* First entry in 'minormap' to be used */ ushort cfg_defsecsiz; /* Default sector size for drives on this ctl */ int (*cfg_BINIT)(); /* Initialize Board function */ int (*cfg_DINIT)(); /* Initialize Drive function */ int (*cfg_CMD)(); /* Perform Command function */ int (*cfg_OPEN)(); /* Device Opening function (or NULL) */ int (*cfg_CLOSE)(); /* Device Closing function (or NULL) */ int (*cfg_multint)(); /* CCAP_MULTI Master interrupt handler */ struct cfg_int_entry cfg_ints[GDEV_CTL_INT]; /* hardware interrupts */ struct special_ioctls cfg_ioctls; /* special ioctl routines */ }; typedef struct gdev_cfg_entry *gdev_cfgp; extern int (*gdev_drivers[])(); /* driver init funcs from space.c */ /* * Device Mapping Tables: Each class of devices (disks, tapes, etc) * supported by the Generic Driver code has its own major device number(s). * Usually there is only one major number assigned per class, but large * classes may have more than one (if more than 16 disk devices are needed, * for example). As each of the included Generic initialization routines * is run, it must announce its use of major numbers by filling in the * 'majormap' array entry/entries for itself. Each majormap entry indicates * the beginning of a contiguous group of 'minormap' entries (below) that * will be used for the class. All the devices in the class have the same * major number (or set of major numbers, if more than 1). * This will allow for a single 'config' file for each class * Given support for 16 partitions (or floppy disk formats) per * drive (4 bits), this allows us 4 drives (2 bits) on each of 4 controllers * (2 bits) to be specified in an 8 bit minor device code. * However, we actually use the top 4 bits of * the minor number to index into the 'minormap' table, below. This will * allow us to partition up the space as controllers require. For example, * we could have a controller with 2 drives (say floppies) to be devices * 0-31, another controller which supports 8 drives (a SCSI perhaps) to * be devices 32-159, and two more controllers which supports 2 drives each * (maybe ST-506) at the end (160-223). This would still leave us 2 drives * on another controller for spare. We don't care much about partition #, * although a floppy's device-open routine will need it to set up the drive * parms appropriately. This should make ANY user happy! * So, the minor device number looks like: * 7654 3210 * +----+----+ * |MIDX|PART| * +----+----+ * where MIDX is the index into 'minormap' (which gives us the controller * and drive on that controller) and PART is the partition number (or * floppy/tape format code). * * The minormap entries are filled in at init time by the generic code. * Each controller's cfg_entry says where it should start in the minormap * and how many entries it needs. If a controller is found, those are * filled in. * */ #define basedev(X) (minor(X) & 0xF0) /* dev for partition 0 */ #define baseidx(X) (minor(X) >> 4) /* minormap idx for basedev */ #define PARTITION(X) (minor(X) & 0x0F) /* partition # for dev */ struct majormap { unchar cnf_valid; /* If non-zero, this entry has been set */ unchar cnf_minorcnt; /* # of minormap entries for major # */ struct minormap *cnf_minorp; /* points at first minormap entry */ }; struct minormap { unchar cnf_valid; /* If non-zero, this entry has been set */ unchar cnf_bd; /* Board index */ unchar cnf_drv; /* Drive index on controller board */ unchar cnf_drvidx; /* driver's index into dcb_drv array */ struct gdev_ctl_block *cnf_dcb; /* points at dcb for board */ } ; extern struct majormap majormap[]; extern struct minormap minormap[]; /* defined in space.c */ extern ushort gdev_nextminor; /* next minormap entry to allocate */ extern ushort gdev_minormaps; /* # of minormap entries available */ extern ushort gdev_majormaps; /* # of majormap entries available */ #define board(X) (majormap[major(X)].cnf_minorp[baseidx(X)].cnf_bd) #define unit(X) (majormap[major(X)].cnf_minorp[baseidx(X)].cnf_drv) #define valid_dev(X) ((majormap[major(X)].cnf_minorp!=NULL) && \ (majormap[major(X)].cnf_minorp[baseidx(X)].cnf_valid)) #define driver_idx(X) (majormap[major(X)].cnf_minorp[baseidx(X)].cnf_drvidx) #define dcbptr(X) (majormap[major(X)].cnf_minorp[baseidx(X)].cnf_dcb) #define dpbptr(C,X) ((C)->dcb_dpbs[unit(X)]) /* * Here's how interrupts work... * Each driver, as it is processing its configuration table, builds up * dcb's -- one per controller, possibly shared between multiple drivers. * It is assumed that a controller can generate up to GDEV_CTL_INT unique * interrupts (each on a different vector, but with the SAME intpri). * ALL these interrupt vectors are pointed at the gendev_intr routine. * This routine looks at the gdev_int_routines table using the interrupt * level as an index, and finds a list of controllers using that interrupt, * as well as an index into that controller's interrupt table for the level * (in case a controller generates more than one interrupt). For non-multi- * thread controllers, the drv_int[int_idx] routine for each driver using * the controller is called in turn. These low-level hardware interrupt * routines get the dcb and the int_idx as arguments. If any of them return * non-NULL values, then the drv_drvint routine routine for that driver is * called with the dcb and the returned dpb as arguments. For multi-thread * controllers, the dcb_mastint routine is called. It must do whatever * initialization is required and call the other low-level driver interrupt * handlers as needed. For example, on a mailbox interface, the master * routine loops through the mailboxes, and calls each handler on a per- * mailbox basis. It is the responsibility of each of these low-level * driver interrupt routines to invoke the drv_drvint routine with the * passed dcb and the dpb for the device whenever a completion or error * condition is noted. */ struct gdev_int_entry { struct gdev_ctl_block *int_ctl; /* -> dcb for this interrupt */ ushort int_idx; /* index into drv_int tables for this interrupt */ struct gdev_int_entry *int_link; /* link to next interrupt entry */ }; extern struct gdev_int_entry *gdev_int_routines[]; /* declared in space.c */ extern ushort gdev_next_int; /* next int entry to allocate */ extern struct gdev_int_entry gdev_int_entries[]; /* Pool decl'd in space.c */ /* * some useful macros... */ #define blk_to_sect(BUFP, DPBP) (daddr_t) \ (((DPBP)->dpb_blkshft >= 0) ? \ ((BUFP)->b_blkno >> (DPBP)->dpb_blkshft) : \ ((BUFP)->b_blkno << (0 - (DPBP)->dpb_blkshft))) #define sect_to_blk(SECT, DPBP) (daddr_t) \ (((DPBP)->dpb_blkshft >= 0) ? \ ((SECT) << (DPBP)->dpb_blkshft) : \ ((SECT) >> (0 - (DPBP)->dpb_blkshft))) #define DSK_EEOF 127 /* for signalling EOF in b_error */ /* * The following are used in genblklib.c and space.c for allocating * memory areas... */ #define GDEV_MEM_GRAN 256 /* Memory allocation granularity (bytes) */ #define GDEV_MEM_BITS 32 /* Number of bits in a section bitmap */ #define GDEV_MEM_MAXBLK 8 /* Maximum # of sections to allocate */ struct gdev_mem_block { paddr_t dmb_baseaddr; /* Base address of memory section */ ushort dmb_maxhole; /* Size of biggest hole (in GDEV_MEM_GRAN units */ ulong dmb_bitmap; /* The allocation bitmap for the section */ }; extern ushort gdev_nextmem; /* Number of currently allocated blocks */ extern struct gdev_mem_block gdev_mem_blocks[]; /* The actual pool. */ extern ushort gdev_mem_lock; /* Lock for memory map */ extern ushort gdev_mem_gran; /* set in space.c */ extern ushort gdev_mem_maxblk; /* set in space.c */ /* * definitions of some useful routines in gendev.c... */ extern paddr_t gdev_getmem(); /* Get physically contiguous kernel memory */ extern void gdev_relmem(); /* Release previously allocated memory */ extern void gdev_getexcl(); /* Get exclusive access to controller */ extern void gdev_relexcl(); /* Release exclusive controller access */ extern struct drq_entry *getdrq(); /* get an empty drq_entry */ extern struct drq_entry *reldrq(); /* release a drq_entry to pool */ extern void reldrq_list(); /* release a list of drq_entries */ extern void gdev_xferok(); /* indicate [partial] transfer complete */ extern gdev_dcbp gdev_shrdcb(); /* get a [possibly shared] gdev_ctl_block */ extern void gdev_filldcb(); /* add values from cfg_entry to a dcb */ extern int gdev_cplerr(); /* handle device completion or error */ extern int gdev_start(); /* start activity on a controller */