* Written by Julian Elischer (julian@tfs.com)
* for TRW Financial Systems for use under the MACH(2.5) operating system.
* TRW Financial Systems, in accordance with their agreement with Carnegie
* Mellon University, makes this software available to CMU to distribute
* or use in any manner that they see fit as long as this message is kept with
* the software. For this reason TFS also grants any other persons or
* organisations permission to use or modify this software.
* TFS supplies this software to be publicly redistributed
* on the understanding that TFS is not responsible for the correct
* functioning of this software in any circumstances.
* Bulogic/Bustek 32 bit Addressing Mode SCSI driver (Was bt742a.c)
* THIS DRIVER IS EXPERIMENTAL AND NOT ENABLED BY DEFAULT. It is
* provided here merely for reference purposes.
* NOTE: 1. Some bt5xx card can NOT handling 32 bit addressing mode.
* 2. OLD bt445s Revision A,B,C,D(nowired) + any firmware version
* has broken busmaster for handling 32 bit addressing on H/W bus side.
* 3. Extend probing still need to confirm by user base due to
* several H/W and firmware dependency. If you have a problem with
* extend probing, please contact to 'amurai@spec.co.jp'
* amurai@spec.co.jp 94/6/16
#ifdef KERNEL /* don't laugh.. it compiles to a program too.. look */
#include <i386/isa/isa_device.h>
#include <scsi/scsi_all.h>
#include <scsi/scsiconf.h>
typedef unsigned long int physaddr
;
#define BT_BASE bt->bt_base
#define BT_CTRL_STAT_PORT (BT_BASE + 0x0) /* control & status */
#define BT_CMD_DATA_PORT (BT_BASE + 0x1) /* cmds and datas */
#define BT_INTR_PORT (BT_BASE + 0x2) /* Intr. stat */
* BT_CTRL_STAT bits (write)
#define BT_HRST 0x80 /* Hardware reset */
#define BT_SRST 0x40 /* Software reset */
#define BT_IRST 0x20 /* Interrupt reset */
#define BT_SCRST 0x10 /* SCSI bus reset */
* BT_CTRL_STAT bits (read)
#define BT_STST 0x80 /* Self test in Progress */
#define BT_DIAGF 0x40 /* Diagnostic Failure */
#define BT_INIT 0x20 /* Mbx Init required */
#define BT_IDLE 0x10 /* Host Adapter Idle */
#define BT_CDF 0x08 /* cmd/data out port full */
#define BT_DF 0x04 /* Data in port full */
#define BT_INVDCMD 0x01 /* Invalid command */
* BT_CMD_DATA bits (write)
#define BT_NOP 0x00 /* No operation */
#define BT_MBX_INIT 0x01 /* Mbx initialization */
#define BT_START_SCSI 0x02 /* start scsi command */
#define BT_START_BIOS 0x03 /* start bios command */
#define BT_INQUIRE 0x04 /* Adapter Inquiry */
#define BT_MBO_INTR_EN 0x05 /* Enable MBO available interrupt */
#define BT_SEL_TIMEOUT_SET 0x06 /* set selection time-out */
#define BT_BUS_ON_TIME_SET 0x07 /* set bus-on time */
#define BT_BUS_OFF_TIME_SET 0x08 /* set bus-off time */
#define BT_SPEED_SET 0x09 /* set transfer speed */
#define BT_DEV_GET 0x0a /* return installed devices */
#define BT_CONF_GET 0x0b /* return configuration data */
#define BT_TARGET_EN 0x0c /* enable target mode */
#define BT_SETUP_GET 0x0d /* return setup data */
#define BT_WRITE_CH2 0x1a /* write channel 2 buffer */
#define BT_READ_CH2 0x1b /* read channel 2 buffer */
#define BT_WRITE_FIFO 0x1c /* write fifo buffer */
#define BT_READ_FIFO 0x1d /* read fifo buffer */
#define BT_ECHO 0x1e /* Echo command data */
#define BT_MBX_INIT_EXTENDED 0x81 /* Mbx initialization */
#define BT_INQUIRE_EXTENDED 0x8D /* Adapter Setup Inquiry */
/* The following command appeared at FirmWare 3.31 */
#define BT_ROUND_ROBIN 0x8f /* Enable/Disable(default) round robin */
#define BT_DISABLE 0x00 /* Parameter value for Disable */
#define BT_ENABLE 0x01 /* Parameter value for Enable */
* BT_INTR_PORT bits (read)
#define BT_ANY_INTR 0x80 /* Any interrupt */
#define BT_SCRD 0x08 /* SCSI reset detected */
#define BT_HACC 0x04 /* Command complete */
#define BT_MBOA 0x02 /* MBX out empty */
#define BT_MBIF 0x01 /* MBX in full */
* these could be bigger but we need the bt_data to fit on a single page..
#define BT_MBX_SIZE 32 /* mail box size (MAX 255 MBxs) */
/* don't need that many really */
#define BT_CCB_MAX 32 /* store up to 32CCBs at any one time */
/* in bt742a H/W ( Not MAX ? ) */
#define CCB_HASH_SIZE 32 /* when we have a physical addr. for */
/* a ccb and need to find the ccb in */
/* space, look it up in the hash table */
#define CCB_HASH_SHIFT 9 /* only hash on multiples of 512 */
#define CCB_HASH(x) ((((long int)(x))>>CCB_HASH_SHIFT) % CCB_HASH_SIZE)
#define bt_nextmbx( wmb, mbx, mbio ) \
if ( (wmb) == &((mbx)->mbio[BT_MBX_SIZE - 1 ]) ) \
(wmb) = &((mbx)->mbio[0]); \
typedef struct bt_mbx_out
{
typedef struct bt_mbx_in
{
BT_MBO
*tmbo
; /* Target Mail Box out */
BT_MBI
*tmbi
; /* Target Mail Box in */
#define BT_MBO_FREE 0x0 /* MBO entry is free */
#define BT_MBO_START 0x1 /* MBO activate entry */
#define BT_MBO_ABORT 0x2 /* MBO abort entry */
#define BT_MBI_FREE 0x0 /* MBI entry is free */
#define BT_MBI_OK 0x1 /* completed without error */
#define BT_MBI_ABORT 0x2 /* aborted ccb */
#define BT_MBI_UNKNOWN 0x3 /* Tried to abort invalid CCB */
#define BT_MBI_ERROR 0x4 /* Completed with error */
WARNING
...THIS WON
'T WORK(won't fit on
1 page
)
/* #define BT_NSEG 2048*/ /* Number of scatter gather segments - to much vm */
unsigned char:3, data_in
:1, data_out
:1,:3;
unsigned char scsi_cmd_length
;
unsigned char req_sense_length
;
/*------------------------------------longword boundary */
unsigned long data_length
;
/*------------------------------------longword boundary */
/*------------------------------------longword boundary */
unsigned char target_stat
;
/*------------------------------------longword boundary */
unsigned char scsi_cmd
[12]; /* 12 bytes (bytes only) */
/*------------------------------------4 longword boundary */
/*------------------------------------longword boundary */
/*-----end of HW fields-------------------------------longword boundary */
struct scsi_sense_data scsi_sense
;
/*------------------------------------longword boundary */
struct bt_scat_gath scat_gath
[BT_NSEG
];
/*------------------------------------longword boundary */
/*------------------------------------longword boundary */
struct scsi_xfer
*xfer
; /* the scsi_xfer for this cmd */
/*------------------------------------longword boundary */
struct bt_mbx_out
*mbx
; /* pointer to mail box */
/*------------------------------------longword boundary */
/*------------------------------------longword boundary */
struct bt_ccb
*nexthash
; /* if two hash the same */
/*------------------------------------longword boundary */
physaddr hashkey
; /*physaddr of this ccb */
/*------------------------------------longword boundary */
#define BT_INITIATOR_CCB 0x00 /* SCSI Initiator CCB */
#define BT_TARGET_CCB 0x01 /* SCSI Target CCB */
#define BT_INIT_SCAT_GATH_CCB 0x02 /* SCSI Initiator with scattter gather */
#define BT_RESET_CCB 0x81 /* SCSI Bus reset */
* bt_ccb.host_stat values
#define BT_OK 0x00 /* cmd ok */
#define BT_LINK_OK 0x0a /* Link cmd ok */
#define BT_LINK_IT 0x0b /* Link cmd ok + int */
#define BT_SEL_TIMEOUT 0x11 /* Selection time out */
#define BT_OVER_UNDER 0x12 /* Data over/under run */
#define BT_BUS_FREE 0x13 /* Bus dropped at unexpected time */
#define BT_INV_BUS 0x14 /* Invalid bus phase/sequence */
#define BT_BAD_MBO 0x15 /* Incorrect MBO cmd */
#define BT_BAD_CCB 0x16 /* Incorrect ccb opcode */
#define BT_BAD_LINK 0x17 /* Not same values of LUN for links */
#define BT_INV_TARGET 0x18 /* Invalid target direction */
#define BT_CCB_DUP 0x19 /* Duplicate CCB received */
#define BT_INV_CCB 0x1a /* Invalid CCB or segment list */
#define BT_ABORTED 42 /* pseudo value from driver */
u_char mbx
[3]; /* make a sense with back-word compatibility*/
#define BT_INQUIRE_REV_THIRD 0x84 /* Get Adapter FirmWare version #3 */
#define BT_INQUIRE_REV_FOURTH 0x85 /* Get Adapter FirmWare version #4 */
* Determine 32bit address/Data firmware functionality from the bus type
* Note: bt742a/747[s|d]/757/946/445s will return 'E'
* bt542b/545s/545d will return 'A'
* 94/05/18 amurai@spec.co.jp
#define BT_BUS_TYPE_24bit 'A' /* PC/AT 24 bit address bus type */
#define BT_BUS_TYPE_32bit 'E' /* EISA/VLB/PCI 32 bit address bus type */
#define BT_BUS_TYPE_MCA 'M' /* Micro chanel is ? forget it right now */
u_char bus_type
; /* Host adapter bus type */
u_char bios_addr
; /* Bios Address-Not used */
u_short max_seg
; /* Max segment List */
u_char num_mbx
; /* Number of mailbox */
int32 mbx_base
; /* mailbox base address */
u_char resv1
:2; /* ??? */
u_char maxsync
:1; /* ON: 10MB/s , OFF: 5MB/s */
u_char resv2
:2; /* ??? */
u_char sync
:1; /* ON: Sync, OFF: async ONLY!! */
u_char resv3
:2; /* ??? */
u_char firmid
[3]; /* Firmware ver. & rev. w/o last char */
#define BT_GET_BOARD_INFO 0x8b /* Get H/W ID and Revision */
u_char id
[4]; /* i.e bt742a -> '7','4','2','A' */
u_char ver
[2]; /* i.e Board Revision 'H' -> 'H', 0x00 */
#define BT_GET_SYNC_VALUE 0x8c /* Get Synchronous Value */
u_char value
[8]; /* Synchrnous value (value * 10 nsec) */
#define KVTOPHYS(x) vtophys(x)
#define INVALIDATE_CACHE {asm volatile( ".byte 0x0F ;.byte 0x08" ); }
u_char bt_scratch_buf
[256];
short bt_base
; /* base port for each board */
struct bt_mbx bt_mbx
; /* all our mailboxes */
struct bt_ccb
*bt_ccb_free
; /* list of free CCBs */
struct bt_ccb
*ccbhash
[CCB_HASH_SIZE
]; /* phys to kv hash */
int bt_int
; /* int. read off board */
int bt_dma
; /* DMA channel read of board */
int bt_scsi_dev
; /* adapters scsi id */
int numccbs
; /* how many we have malloc'd */
struct scsi_link sc_link
; /* prototype for devs */
/***********debug values *************/
void bt_timeout(caddr_t
, int);
void bt_inquire_setup_information();
u_int32
bt_adapter_info();
struct bt_ccb
*bt_get_ccb();
struct bt_ccb
*bt_ccb_phys_kv();
struct isa_driver btdriver
=
struct scsi_adapter bt_switch
=
/* the below structure is so we have a default dev struct for out link struct */
struct scsi_device bt_dev
=
NULL
, /* Use default error handler */
NULL
, /* have a queue, served by this */
NULL
, /* have no async handler */
NULL
, /* Use default 'done' routine */
#define BT_RESET_TIMEOUT 1000
printf("bt_data is %d bytes\n", sizeof(struct bt_data
));
printf("bt_ccb is %d bytes\n", sizeof(struct bt_ccb
));
printf("bt_mbx is %d bytes\n", sizeof(struct bt_mbx
));
* bt_cmd(unit,icnt, ocnt,wait, retval, opcode, args)
* Activate Adapter command
* icnt: number of args (outbound bytes written after opcode)
* ocnt: number of expected returned bytes
* wait: number of seconds to wait for response
* retval: buffer where to place returned bytes
* opcode: opcode BT_NOP, BT_MBX_INIT, BT_START_SCSI ...
* Performs an adapter command through the ports. Not to be confused with a
* scsi command, which is read in via the dma; one of the adapter commands
* tells it to read in a scsi command.
bt_cmd(unit
, icnt
, ocnt
, wait
, retval
, opcode
, args
)
struct bt_data
*bt
= btdata
[unit
];
* multiply the wait argument by a big constant
* Wait for the adapter to go idle, unless it's one of
* the commands which don't need this
if (opcode
!= BT_MBX_INIT
&& opcode
!= BT_START_SCSI
) {
sts
= inb(BT_CTRL_STAT_PORT
);
printf("bt%d: bt_cmd, host not idle(0x%x)\n", unit
, sts
);
* Now that it is idle, if we expect output, preflush the
while ((inb(BT_CTRL_STAT_PORT
)) & BT_DF
)
* Output the command and the number of arguments given
* for each byte, first check the port is empty.
/* include the command */
sts
= inb(BT_CTRL_STAT_PORT
);
sts
= inb(BT_CTRL_STAT_PORT
);
printf("bt%d: bt_cmd, cmd/data port full\n", unit
);
outb(BT_CTRL_STAT_PORT
, BT_SRST
);
outb(BT_CMD_DATA_PORT
, (u_char
) (*ic
++));
* If we expect input, loop that many times, each time,
* looking for the data register to have valid data
sts
= inb(BT_CTRL_STAT_PORT
);
sts
= inb(BT_CTRL_STAT_PORT
);
printf("bt%d: bt_cmd, cmd/data port empty %d\n",
oc
= inb(BT_CMD_DATA_PORT
);
* Wait for the board to report a finised instruction
printf("bt%d: bt_cmd, host not finished(0x%x)\n", unit
, sts
);
outb(BT_CTRL_STAT_PORT
, BT_IRST
);
* Check if the device can be found at the port given
* and if so, set it up ready for further work
* as an argument, takes the isa_device structure from
* find unit and check we have that many defined
printf("bt%d: unit number too high\n", unit
);
* Allocate a storage area for us
printf("bt%d: memory already allocated\n", unit
);
bt
= malloc(sizeof(struct bt_data
), M_TEMP
, M_NOWAIT
);
printf("bt%d: cannot malloc!\n", unit
);
bzero(bt
, sizeof(struct bt_data
));
bt
->bt_base
= dev
->id_iobase
;
* Try initialise a unit at this location
* sets up dma and bus speed, loads bt->bt_int
if (bt_init(unit
) != 0) {
* If it's there, put in it's interrupt vectors
dev
->id_irq
= (1 << bt
->bt_int
);
dev
->id_drq
= bt
->bt_dma
;
* Attach all the sub-devices we can find
struct bt_data
*bt
= btdata
[unit
];
* fill in the prototype scsi_link.
bt
->sc_link
.adapter_unit
= unit
;
bt
->sc_link
.adapter_targ
= bt
->bt_scsi_dev
;
bt
->sc_link
.adapter
= &bt_switch
;
bt
->sc_link
.device
= &bt_dev
;
* Forcely Bounce buffer mechanizum is ON for some broken busmaster
* chip with over 16Mbytes boundary for while...
* amurai@spec.co.jp 94/06/16
bt
->sc_link
.flags
= SDEV_BOUNCE
; /*XXX*/
* ask the adapter what subunits are present
scsi_attachdevs(&(bt
->sc_link
));
* Return some information to the caller about the adapter and its
return (2); /* 2 outstanding requests at a time per device */
* Catch an interrupt from the adaptor
struct bt_data
*bt
= btdata
[unit
];
* First acknowlege the interrupt, Then if it's
* not telling about a completed operation
stat
= inb(BT_INTR_PORT
);
/* Mail Box out empty ? */
printf("bt%d: Available Free mbo post\n", unit
);
/* Disable MBO available interrupt */
outb(BT_CMD_DATA_PORT
, BT_MBO_INTR_EN
);
wait
= 100000; /* 1 sec enough? */
if (!(inb(BT_CTRL_STAT_PORT
) & BT_CDF
))
printf("bt%d: bt_intr, cmd/data port full\n", unit
);
outb(BT_CTRL_STAT_PORT
, BT_SRST
);
outb(BT_CMD_DATA_PORT
, 0x00); /* Disable */
wakeup((caddr_t
)&bt
->bt_mbx
);
outb(BT_CTRL_STAT_PORT
, BT_IRST
);
outb(BT_CTRL_STAT_PORT
, BT_IRST
);
* If it IS then process the competed operation
while (wmbi
->stat
!= BT_MBI_FREE
) {
ccb
= bt_ccb_phys_kv(bt
, (wmbi
->ccb_addr
));
wmbi
->stat
= BT_MBI_FREE
;
printf("bt: BAD CCB ADDR!\n");
if ((stat
= wmbi
->stat
) != BT_MBI_OK
) {
if (bt_debug
& BT_SHOWMISC
)
ccb
->host_stat
= BT_ABORTED
;
ccb
= (struct bt_ccb
*) 0;
if (bt_debug
& BT_SHOWMISC
)
printf("unknown ccb for abort");
panic("Impossible mbxi status");
if ((bt_debug
& BT_SHOWCMDS
) && ccb
) {
printf("op=%x %x %x %x %x %x\n",
printf("stat %x for mbi addr = 0x%08x\n"
printf("addr = 0x%x\n", ccb
);
wmbi
->stat
= BT_MBI_FREE
;
untimeout(bt_timeout
, (caddr_t
)ccb
);
/* Set the IN mail Box pointer for next */ bt_nextmbx(wmbi
, wmbx
, mbi
);
for (i
= 0; i
< BT_MBX_SIZE
; i
++) {
if (wmbi
->stat
!= BT_MBI_FREE
) {
bt_nextmbx(wmbi
, wmbx
, mbi
);
printf("bt%d: mbi at 0x%08x should be found, stat=%02x..resync\n",
outb(BT_CTRL_STAT_PORT
, BT_IRST
);
* A ccb is put onto the free list.
bt_free_ccb(unit
, ccb
, flags
)
struct bt_data
*bt
= btdata
[unit
];
if (!(flags
& SCSI_NOMASK
))
ccb
->next
= bt
->bt_ccb_free
;
* If there were none, wake anybody waiting for one to come free,
* starting with queued entries.
wakeup((caddr_t
)&bt
->bt_ccb_free
);
if (!(flags
& SCSI_NOMASK
))
* If there are none, see if we can allocate a new one. If so, put it in
* the hash table too otherwise either return an error or sleep.
struct bt_data
*bt
= btdata
[unit
];
struct bt_mbx
*wmbx
; /* Mail Box pointer specified unit */
BT_MBO
*wmbo
; /* Out Mail Box pointer */
if (!(flags
& SCSI_NOMASK
))
* If we can and have to, sleep waiting for one to come free
* but only if we can't allocate a new one.
while (!(ccbp
= bt
->bt_ccb_free
)) {
if (bt
->numccbs
< BT_CCB_MAX
) {
if (ccbp
= (struct bt_ccb
*) malloc(sizeof(struct bt_ccb
),
bzero(ccbp
, sizeof(struct bt_ccb
));
ccbp
->flags
= CCB_ACTIVE
;
* put in the phystokv hash table
ccbp
->hashkey
= KVTOPHYS(ccbp
);
hashnum
= CCB_HASH(ccbp
->hashkey
);
ccbp
->nexthash
= bt
->ccbhash
[hashnum
];
bt
->ccbhash
[hashnum
] = ccbp
;
printf("bt%d: Can't malloc CCB\n", unit
);
if (!(flags
& SCSI_NOSLEEP
)) {
tsleep((caddr_t
)&bt
->bt_ccb_free
, PRIBIO
,
/* Get CCB from from free list */
bt
->bt_ccb_free
= ccbp
->next
;
ccbp
->flags
= CCB_ACTIVE
;
if (!(flags
& SCSI_NOMASK
))
* given a physical address, find the ccb that
bt_ccb_phys_kv(bt
, ccb_phys
)
int hashnum
= CCB_HASH(ccb_phys
);
struct bt_ccb
*ccbp
= bt
->ccbhash
[hashnum
];
if (ccbp
->hashkey
== ccb_phys
)
* Get a MBO and then Send it
bt_send_mbo(int unit
, int flags
, int cmd
, struct bt_ccb
*ccb
)
struct bt_data
*bt
= btdata
[unit
];
BT_MBO
*wmbo
; /* Mail Box Out pointer */
struct bt_mbx
*wmbx
; /* Mail Box pointer specified unit */
if (!(flags
& SCSI_NOMASK
))
/* Get the Target OUT mail Box pointer and move to Next */
wmbx
->tmbo
= (wmbo
== &(wmbx
->mbo
[BT_MBX_SIZE
- 1]) ?
&(wmbx
->mbo
[0]) : wmbo
+ 1);
* Check the outmail box is free or not.
* Note: Under the normal operation, it shuld NOT happen to wait.
while (wmbo
->cmd
!= BT_MBO_FREE
) {
wait
= 100000; /* 1 sec enough? */
/* Enable MBO available interrupt */
outb(BT_CMD_DATA_PORT
, BT_MBO_INTR_EN
);
if (!(inb(BT_CTRL_STAT_PORT
) & BT_CDF
))
printf("bt%d: bt_send_mbo, cmd/data port full\n", unit
);
outb(BT_CTRL_STAT_PORT
, BT_SRST
);
outb(BT_CMD_DATA_PORT
, 0x01); /* Enable */
tsleep((caddr_t
)wmbx
, PRIBIO
, "btsend", 0);
/* XXX */ /*can't do this! */
/* May be servicing an int */
/* Link CCB to the Mail Box */
wmbo
->ccb_addr
= KVTOPHYS(ccb
);
outb(BT_CMD_DATA_PORT
, BT_START_SCSI
);
if (!(flags
& SCSI_NOMASK
))
* We have a ccb which has been processed by the
* adaptor, now we look to see how the operation
* went. Wake up the owner if waiting
struct bt_data
*bt
= btdata
[unit
];
struct scsi_sense_data
*s1
, *s2
;
struct scsi_xfer
*xs
= ccb
->xfer
;
SC_DEBUG(xs
->sc_link
, SDEV_DB2
, ("bt_done\n"));
* Otherwise, put the results of the operation
* into the xfer and call whoever started it
if ((ccb
->host_stat
!= BT_OK
|| ccb
->target_stat
!= SCSI_OK
)
&& (!(xs
->flags
& SCSI_ERR_OK
))) {
switch (ccb
->host_stat
) {
case BT_ABORTED
: /* No response */
case BT_SEL_TIMEOUT
: /* No response */
SC_DEBUG(xs
->sc_link
, SDEV_DB3
,
("timeout reported back\n"));
default: /* Other scsi protocol messes */
xs
->error
= XS_DRIVER_STUFFUP
;
SC_DEBUG(xs
->sc_link
, SDEV_DB3
,
("unexpected host_stat: %x\n",
switch (ccb
->target_stat
) {
SC_DEBUG(xs
->sc_link
, SDEV_DB3
,
("unexpected target_stat: %x\n",
xs
->error
= XS_DRIVER_STUFFUP
;
} else { /* All went correctly OR errors expected */
bt_free_ccb(unit
, ccb
, xs
->flags
);
* Start the board, ready for normal operation
struct bt_data
*bt
= btdata
[unit
];
struct bt_board_info binfo
;
* reset board, If it doesn't respond, assume
* that it's not there.. good for the probe
outb(BT_CTRL_STAT_PORT
, BT_HRST
| BT_SRST
);
for (i
= BT_RESET_TIMEOUT
; i
; i
--) {
sts
= inb(BT_CTRL_STAT_PORT
);
if (sts
== (BT_IDLE
| BT_INIT
))
printf("bt_init: No answer from board\n");
* Displaying Board ID and Hardware Revision
* 94/05/18 amurai@spec.co.jp
bt_cmd(unit
, 1, sizeof(binfo
),0,&binfo
,BT_GET_BOARD_INFO
,sizeof(binfo
));
printf("bt%d: Bt%c%c%c%c/%c%d-", unit
,
* Make sure board has a capability of 32bit addressing.
* and Firmware also need a capability of 32bit addressing pointer
* in Extended mailbox and ccb structure.
* 94/05/18 amurai@spec.co.jp
bt_cmd(unit
, 1, sizeof(info
),0,&info
, BT_INQUIRE_EXTENDED
,sizeof(info
));
case BT_BUS_TYPE_24bit
: /* PC/AT 24 bit address bus */
printf("ISA(24bit) bus\n");
case BT_BUS_TYPE_32bit
: /* EISA/VLB/PCI 32 bit bus */
printf("PCI/EISA/VLB(32bit) bus\n");
case BT_BUS_TYPE_MCA
: /* forget it right now */
printf("MCA bus architecture...");
printf("Unknown state...");
if ( binfo
.id
[0] == '5' ) {
printf("bt%d: This driver is designed for using 32 bit addressing\n",unit
);
printf("bt%d: mode firmware and EISA/PCI/VLB bus architecture bus\n",unit
);
printf("bt%d: WITHOUT any software trick/overhead (i.e.bounce buffer).\n",unit
);
printf("bt%d: If you have more than 16MBytes memory\n",unit
);
printf("bt%d: your filesystem will get a serious damage.\n",unit
);
} else if ( info
.bus_type
== BT_BUS_TYPE_24bit
) {
printf("bt%d: Your board should report a 32bit bus architecture type..\n",unit
);
printf("bt%d: A firmware on your board may have a problem with over\n",unit
);
printf("bt%d: 16MBytes memory handling with this driver.\n",unit
);
* Assume we have a board at this stage
* setup dma channel from jumpers and save int
printf("bt%d: reading board settings, ", unit
);
bt_cmd(unit
, 0, sizeof(conf
), 0, &conf
, BT_CONF_GET
);
printf("illegal dma setting %x\n", conf
.chan
);
printf("busmastering, ");
printf("dma=%d, ", bt
->bt_dma
);
printf("illegal int setting\n");
printf("int=%d\n", bt
->bt_int
);
/* who are we on the scsi bus */
bt
->bt_scsi_dev
= conf
.scsi_dev
;
*((physaddr
*) ad
) = KVTOPHYS(&bt
->bt_mbx
);
bt_cmd(unit
, 5, 0, 0, 0, BT_MBX_INIT_EXTENDED
* Set Pointer chain null for just in case
* Link the ccb's into a free-list W/O mbox
* Initialize mail box status to free
if (bt
->bt_ccb_free
!= (struct bt_ccb
*) 0) {
printf("bt%d: bt_ccb_free is NOT initialized but init here\n",
bt
->bt_ccb_free
= (struct bt_ccb
*) 0;
for (i
= 0; i
< BT_MBX_SIZE
; i
++) {
bt
->bt_mbx
.mbo
[i
].cmd
= BT_MBO_FREE
;
bt
->bt_mbx
.mbi
[i
].stat
= BT_MBI_FREE
;
* Set up initial mail box for round-robin operation.
bt
->bt_mbx
.tmbo
= &bt
->bt_mbx
.mbo
[0];
bt
->bt_mbx
.tmbi
= &bt
->bt_mbx
.mbi
[0];
bt_inquire_setup_information(unit
, &info
);
* Note that we are going and return (to probe)
bt_inquire_setup_information(
struct bt_ext_info
*info
)
struct bt_data
*bt
= btdata
[unit
];
struct bt_sync_value sync
;
/* Inquire Installed Devices */
bzero( &dummy
[0], sizeof(dummy
) );
bt_cmd(unit
, 0, sizeof(dummy
), 100, &dummy
[0], BT_DEV_GET
);
* If board has a capbility of Syncrhonouse mode,
* Get a SCSI Synchronous value
bt_cmd(unit
, 1, sizeof(sync
), 100,
&sync
,BT_GET_SYNC_VALUE
,sizeof(sync
));
* Inquire Board ID to board for firmware version
bt_cmd(unit
, 0, sizeof(bID
), 0, &bID
, BT_INQUIRE
);
bt_cmd(unit
, 0, 1, 0, &sub_ver
[0], BT_INQUIRE_REV_THIRD
);
i
= ((int)(bID
.firm_revision
-'0')) * 10 + (int)(bID
.firm_version
-'0');
bt_cmd(unit
, 0, 1, 0, &sub_ver
[1], BT_INQUIRE_REV_FOURTH
);
* Below rev 3.3 firmware has a problem for issuing
* the BT_INQUIRE_REV_FOURTH command.
printf("bt%d: version %c.%c%s, ",
unit
, bID
.firm_revision
, bID
.firm_version
, sub_ver
);
* Obtain setup information from board.
bt_cmd(unit
, 1, sizeof(setup
), 0, &setup
, BT_SETUP_GET
, sizeof(setup
));
if (setup
.sync_neg
&& info
->s
.sync
) {
printf("fast sync, "); /* Max 10MB/s */
printf("sync, "); /* Max 5MB/s */
printf("async, "); /* Never try by board */
printf("async only, "); /* Doesn't has a capability on board */
printf("%d mbxs, %d ccbs\n", setup
.num_mbx
, BT_CCB_MAX
);
* Displayi SCSI negotiation value by each target.
for (i
= 0; i
< 8; i
++) {
if (!setup
.sync
[i
].valid
)
if ( (!setup
.sync
[i
].offset
&& !setup
.sync
[i
].period
)
printf("bt%d: targ %d async\n", unit
, i
);
printf("bt%d: targ %d sync rate=%2d.%02dMB/s(%dns), offset=%02d\n",
(100 % sync
.value
[i
]) * 100 / sync
.value
[i
],
* Enable round-robin scheme - appeared at firmware rev. 3.31
* Below rev 3.XX firmware has a problem for issuing
* BT_ROUND_ROBIN command amurai@spec.co.jp
if ( bID
.firm_revision
>= '3' ) {
printf("bt%d: Enabling Round robin scheme\n", unit
);
bt_cmd(unit
, 1, 0, 0, 0, BT_ROUND_ROBIN
, BT_ENABLE
);
printf("bt%d: Not Enabling Round robin scheme\n", unit
);
#define min(x,y) (x < y ? x : y)
if (bp
->b_bcount
> ((BT_NSEG
- 1) * PAGESIZ
)) {
bp
->b_bcount
= ((BT_NSEG
- 1) * PAGESIZ
);
* start a scsi operation given the command and the data address. Also needs
* the unit, target and lu.
struct scsi_sense_data
*s1
, *s2
;
int seg
; /* scatter gather seg being worked on */
physaddr thisphys
, nextphys
;
int unit
= xs
->sc_link
->adapter_unit
;
int bytes_this_seg
, bytes_this_page
, datalen
, flags
;
struct bt_data
*bt
= btdata
[unit
];
SC_DEBUG(xs
->sc_link
, SDEV_DB2
, ("bt_scsi_cmd\n"));
* get a ccb (mbox-out) to use. If the transfer
* is from a buf (possibly from interrupt time)
* then we can't allow it to sleep
flags
|= (SCSI_NOSLEEP
); /* just to be sure */
printf("bt%d: Already done?\n", unit
);
printf("bt%d: Not in use?\n", unit
);
if (!(ccb
= bt_get_ccb(unit
, flags
))) {
xs
->error
= XS_DRIVER_STUFFUP
;
return (TRY_AGAIN_LATER
);
SC_DEBUG(xs
->sc_link
, SDEV_DB3
,
("start ccb(%x)\n", ccb
));
* Put all the arguments for the xfer in the ccb
if (flags
& SCSI_RESET
) {
ccb
->opcode
= BT_RESET_CCB
;
/* can't use S/G if zero length */
ccb
->opcode
= (xs
->datalen
?
ccb
->target
= xs
->sc_link
->target
;
ccb
->lun
= xs
->sc_link
->lun
;
ccb
->scsi_cmd_length
= xs
->cmdlen
;
ccb
->sense_ptr
= KVTOPHYS(&(ccb
->scsi_sense
));
ccb
->req_sense_length
= sizeof(ccb
->scsi_sense
);
if ((xs
->datalen
) && (!(flags
& SCSI_RESET
))) { /* can use S/G only if not zero length */
ccb
->data_addr
= KVTOPHYS(ccb
->scat_gath
);
if (flags
& SCSI_DATA_UIO
) {
iovp
= ((struct uio
*) xs
->data
)->uio_iov
;
datalen
= ((struct uio
*) xs
->data
)->uio_iovcnt
;
while ((datalen
) && (seg
< BT_NSEG
)) {
sg
->seg_addr
= (physaddr
) iovp
->iov_base
;
xs
->datalen
+= sg
->seg_len
= iovp
->iov_len
;
SC_DEBUGN(xs
->sc_link
, SDEV_DB4
, ("(0x%x@0x%x)"
,iovp
->iov_len
, iovp
->iov_base
));
* Set up the scatter gather block
SC_DEBUG(xs
->sc_link
, SDEV_DB4
,
("%d @0x%x:- ", xs
->datalen
, xs
->data
));
thisphys
= KVTOPHYS(thiskv
);
while ((datalen
) && (seg
< BT_NSEG
)) {
/* put in the base address */
SC_DEBUGN(xs
->sc_link
, SDEV_DB4
,
/* do it at least once */
while ((datalen
) && (thisphys
== nextphys
))
* This page is contiguous (physically) with
* the the last, just extend the length
/* how far to the end of the page */
nextphys
= (thisphys
& (~(PAGESIZ
- 1)))
bytes_this_page
= nextphys
- thisphys
;
bytes_this_page
= min(bytes_this_page
bytes_this_seg
+= bytes_this_page
;
datalen
-= bytes_this_page
;
/* get more ready for the next page */
thiskv
= (thiskv
& (~(PAGESIZ
- 1)))
thisphys
= KVTOPHYS(thiskv
);
* next page isn't contiguous, finish the seg
SC_DEBUGN(xs
->sc_link
, SDEV_DB4
,
("(0x%x)", bytes_this_seg
));
sg
->seg_len
= bytes_this_seg
;
/* end of iov/kv decision */
ccb
->data_length
= seg
* sizeof(struct bt_scat_gath
);
SC_DEBUGN(xs
->sc_link
, SDEV_DB4
, ("\n"));
* there's still data, must have run out of segs!
printf("bt%d: bt_scsi_cmd, more than %d DMA segs\n",
xs
->error
= XS_DRIVER_STUFFUP
;
bt_free_ccb(unit
, ccb
, flags
);
} else { /* No data xfer, use non S/G values */
ccb
->data_addr
= (physaddr
) 0;
ccb
->link_addr
= (physaddr
) 0;
* Put the scsi command in the ccb and start it
if (!(flags
& SCSI_RESET
)) {
bcopy(xs
->cmd
, ccb
->scsi_cmd
, ccb
->scsi_cmd_length
);
if (bt_send_mbo(unit
, flags
, BT_MBO_START
, ccb
) == (BT_MBO
*) 0) {
xs
->error
= XS_DRIVER_STUFFUP
;
bt_free_ccb(unit
, ccb
, flags
);
return (TRY_AGAIN_LATER
);
* Usually return SUCCESSFULLY QUEUED
SC_DEBUG(xs
->sc_link
, SDEV_DB3
, ("cmd_sent\n"));
if (!(flags
& SCSI_NOMASK
)) {
timeout(bt_timeout
, (caddr_t
)ccb
, (xs
->timeout
* hz
) / 1000);
return (SUCCESSFULLY_QUEUED
);
* If we can't use interrupts, poll on completion
return (bt_poll(unit
, xs
, ccb
));
* Poll a particular unit, looking for a particular xs
struct bt_data
*bt
= btdata
[unit
];
/* timeouts are in msec, so we loop in 1000 usec cycles */
* If we had interrupts enabled, would we
stat
= inb(BT_INTR_PORT
);
if (stat
& BT_ANY_INTR
) {
if (xs
->flags
& ITSDONE
) {
DELAY(1000); /* only happens in boot so ok */
* We timed out, so call the timeout handler manually,
* accounting for the fact that the clock is not running yet
* by taking out the clock queue entry it makes.
bt_timeout((caddr_t
)ccb
, 0);
* because we are polling, take out the timeout entry
untimeout(bt_timeout
, (caddr_t
)ccb
);
* Once again, wait for the int bit
stat
= inb(BT_INTR_PORT
);
if (stat
& BT_ANY_INTR
) {
if (xs
->flags
& ITSDONE
) {
DELAY(1000); /* only happens in boot so ok */
* We timed out again... This is bad. Notice that
* this time there is no clock queue entry to remove.
bt_timeout((caddr_t
)ccb
, 0);
bt_timeout(caddr_t arg1
, int arg2
)
struct bt_ccb
* ccb
= (struct bt_ccb
*)arg1
;
* A timeout routine in kernel DONOT unlink
* Entry chains when time outed....So infinity Loop..
* 94/04/20 amurai@spec.co.jp
untimeout(bt_timeout
, (caddr_t
)ccb
);
unit
= ccb
->xfer
->sc_link
->adapter_unit
;
bt_print_active_ccbs(unit
);
* If the ccb's mbx is not free, then the board has gone Far East?
if (bt_ccb_phys_kv(bt
, ccb
->mbx
->ccb_addr
) == ccb
&&
ccb
->mbx
->cmd
!= BT_MBO_FREE
) {
printf("bt%d: not taking commands!\n", unit
);
* If it has been through before, then
* a previous abort has failed, don't
if (ccb
->flags
== CCB_ABORTED
) {
printf("bt%d: Abort Operation has timed out\n", unit
);
ccb
->xfer
->retries
= 0; /* I MEAN IT ! */
ccb
->host_stat
= BT_ABORTED
;
/* abort the operation that has timed out */
printf("bt%d: Try to abort\n", unit
);
bt_send_mbo(unit
, ~SCSI_NOMASK
,
/* 2 secs for the abort */
ccb
->flags
= CCB_ABORTED
;
timeout(bt_timeout
, (caddr_t
)ccb
, 2 * hz
);
printf("ccb:%x op:%x cmdlen:%d senlen:%d\n"
printf(" datlen:%d hstat:%x tstat:%x flags:%x\n"
bt_print_active_ccbs(int unit
)
struct bt_data
*bt
= btdata
[unit
];
while (i
< CCB_HASH_SIZE
) {
if (ccb
->flags
!= CCB_FREE
)