diff options
Diffstat (limited to 'sys')
39 files changed, 0 insertions, 25864 deletions
diff --git a/sys/i386/isa/aha1542.c b/sys/i386/isa/aha1542.c deleted file mode 100644 index b5f17a6..0000000 --- a/sys/i386/isa/aha1542.c +++ /dev/null @@ -1,1851 +0,0 @@ -/* - * (Mostly) 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. - * - * $Id: aha1542.c,v 1.78 1998/06/21 14:53:07 bde Exp $ - */ - -/* - * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 - */ - -#include "aha.h" -#include "opt_tune_1542.h" - -#include <sys/param.h> -#include <sys/buf.h> -#include <sys/kernel.h> -#include <sys/malloc.h> -#include <sys/systm.h> - -#include <machine/clock.h> -#include <machine/stdarg.h> - -#include <scsi/scsiconf.h> -#include <scsi/scsi_debug.h> - -#include <vm/vm.h> -#include <vm/pmap.h> - -#include <i386/isa/isa_device.h> - -/************************** board definitions *******************************/ - -/* - * I/O Port Interface - */ - -#define AHA_BASE aha->aha_base -#define AHA_CTRL_STAT_PORT (AHA_BASE + 0x0) /* control & status */ -#define AHA_CMD_DATA_PORT (AHA_BASE + 0x1) /* cmds and datas */ -#define AHA_INTR_PORT (AHA_BASE + 0x2) /* Intr. stat */ - -/* - * AHA_CTRL_STAT bits (write) - */ - -#define AHA_HRST 0x80 /* Hardware reset */ -#define AHA_SRST 0x40 /* Software reset */ -#define AHA_IRST 0x20 /* Interrupt reset */ -#define AHA_SCRST 0x10 /* SCSI bus reset */ - -/* - * AHA_CTRL_STAT bits (read) - */ - -#define AHA_STST 0x80 /* Self test in Progress */ -#define AHA_DIAGF 0x40 /* Diagnostic Failure */ -#define AHA_INIT 0x20 /* Mbx Init required */ -#define AHA_IDLE 0x10 /* Host Adapter Idle */ -#define AHA_CDF 0x08 /* cmd/data out port full */ -#define AHA_DF 0x04 /* Data in port full */ -#define AHA_INVDCMD 0x01 /* Invalid command */ - -/* - * AHA_CMD_DATA bits (write) - */ - -#define AHA_NOP 0x00 /* No operation */ -#define AHA_MBX_INIT 0x01 /* Mbx initialization */ -#define AHA_START_SCSI 0x02 /* start scsi command */ -#define AHA_START_BIOS 0x03 /* start bios command */ -#define AHA_INQUIRE 0x04 /* Adapter Inquiry */ -#define AHA_MBO_INTR_EN 0x05 /* Enable MBO available interrupt */ -#define AHA_SEL_TIMEOUT_SET 0x06 /* set selection time-out */ -#define AHA_BUS_ON_TIME_SET 0x07 /* set bus-on time */ -#define AHA_BUS_OFF_TIME_SET 0x08 /* set bus-off time */ -#define AHA_SPEED_SET 0x09 /* set transfer speed */ -#define AHA_DEV_GET 0x0a /* return installed devices */ -#define AHA_CONF_GET 0x0b /* return configuration data */ -#define AHA_TARGET_EN 0x0c /* enable target mode */ -#define AHA_SETUP_GET 0x0d /* return setup data */ -#define AHA_WRITE_CH2 0x1a /* write channel 2 buffer */ -#define AHA_READ_CH2 0x1b /* read channel 2 buffer */ -#define AHA_WRITE_FIFO 0x1c /* write fifo buffer */ -#define AHA_READ_FIFO 0x1d /* read fifo buffer */ -#define AHA_ECHO 0x1e /* Echo command data */ -#define AHA_EXT_BIOS 0x28 /* return extended bios info */ -#define AHA_MBX_ENABLE 0x29 /* enable mail box interface */ - -struct aha_cmd_buf { - u_char byte[16]; -}; - -/* - * AHA_INTR_PORT bits (read) - */ - -#define AHA_ANY_INTR 0x80 /* Any interrupt */ -#define AHA_SCRD 0x08 /* SCSI reset detected */ -#define AHA_HACC 0x04 /* Command complete */ -#define AHA_MBOA 0x02 /* MBX out empty */ -#define AHA_MBIF 0x01 /* MBX in full */ - -/* - * Mail box defs - */ - -#define AHA_MBX_SIZE 16 /* mail box size */ - -struct aha_mbx { - struct aha_mbx_out { - unsigned char cmd; - unsigned char ccb_addr[3]; - } mbo[AHA_MBX_SIZE]; - struct aha_mbx_in { - unsigned char stat; - unsigned char ccb_addr[3]; - } mbi[AHA_MBX_SIZE]; -}; - -/* - * mbo.cmd values - */ - -#define AHA_MBO_FREE 0x0 /* MBO entry is free */ -#define AHA_MBO_START 0x1 /* MBO activate entry */ -#define AHA_MBO_ABORT 0x2 /* MBO abort entry */ - -/* - * mbi.stat values - */ - -#define AHA_MBI_FREE 0x0 /* MBI entry is free */ -#define AHA_MBI_OK 0x1 /* completed without error */ -#define AHA_MBI_ABORT 0x2 /* aborted ccb */ -#define AHA_MBI_UNKNOWN 0x3 /* Tried to abort invalid CCB */ -#define AHA_MBI_ERROR 0x4 /* Completed with error */ - -#define AHA_MBI_TGT_NO_CCB 0x10 /* Target received, no CCB ready */ - -/* FOR OLD VERSIONS OF THE !%$@ this may have to be 16 (yuk) */ -#define AHA_NSEG 17 /* Number of scatter gather segments <= 16 */ - /* allow 64 K i/o (min) */ - -struct aha_ccb { - unsigned char opcode; - unsigned char lun:3; - unsigned char data_in:1; /* must be 0 */ - unsigned char data_out:1; /* must be 0 */ - unsigned char target:3; - unsigned char scsi_cmd_length; - unsigned char req_sense_length; - unsigned char data_length[3]; - unsigned char data_addr[3]; - unsigned char link_addr[3]; - unsigned char link_id; - unsigned char host_stat; - unsigned char target_stat; - unsigned char reserved[2]; - struct scsi_generic scsi_cmd; - struct scsi_sense_data scsi_sense; - struct aha_scat_gath { - unsigned char seg_len[3]; - unsigned char seg_addr[3]; - } scat_gath[AHA_NSEG]; - struct aha_ccb *next; - struct scsi_xfer *xfer; /* the scsi_xfer for this cmd */ - struct aha_mbx_out *mbx; /* pointer to mail box */ - int flags; -#define CCB_FREE 0 -#define CCB_ACTIVE 1 -#define CCB_ABORTED 2 -}; - -/* - * opcode fields - */ - -#define AHA_INITIATOR_CCB 0x00 /* SCSI Initiator CCB */ -#define AHA_TARGET_CCB 0x01 /* SCSI Target CCB */ -#define AHA_INIT_SCAT_GATH_CCB 0x02 /* SCSI Initiator with scatter gather */ -#define AHA_RESET_CCB 0x81 /* SCSI Bus reset */ - -#define AHA_INIT_RESID_CCB 0x03 /* SCSI Initiator CCB */ -#define AHA_INIT_SG_RESID_CCB 0x04 /* SCSI initiator with scatter gather */ - -/* - * aha_ccb.host_stat values - */ - -#define AHA_OK 0x00 /* cmd ok */ -#define AHA_LINK_OK 0x0a /* Link cmd ok */ -#define AHA_LINK_IT 0x0b /* Link cmd ok + int */ -#define AHA_SEL_TIMEOUT 0x11 /* Selection time out */ -#define AHA_OVER_UNDER 0x12 /* Data over/under run */ -#define AHA_BUS_FREE 0x13 /* Bus dropped at unexpected time */ -#define AHA_INV_BUS 0x14 /* Invalid bus phase/sequence */ -#define AHA_BAD_MBO 0x15 /* Incorrect MBO cmd */ -#define AHA_BAD_CCB 0x16 /* Incorrect ccb opcode */ -#define AHA_BAD_LINK 0x17 /* Not same values of LUN for links */ -#define AHA_INV_TARGET 0x18 /* Invalid target direction */ -#define AHA_CCB_DUP 0x19 /* Duplicate CCB received */ -#define AHA_INV_CCB 0x1a /* Invalid CCB or segment list */ -#define AHA_ABORTED 42 - -struct aha_setup { - u_char sync_neg:1; - u_char parity:1; - u_char:6; - u_char speed; - u_char bus_on; - u_char bus_off; - u_char num_mbx; - u_char mbx[3]; - struct { - u_char offset:4; - u_char period:3; - u_char valid:1; - } sync[8]; - u_char disc_sts; -}; - -struct aha_config { - u_char chan; - u_char intr; - u_char scsi_dev:3; - u_char:5; -}; - -struct aha_inquire -{ - u_char boardid; /* type of board */ - /* 0x20 (' ') = BusLogic 545, but it gets - the command wrong, only returns - one byte */ - /* 0x31 ('1') = AHA-1540 */ - /* 0x41 ('A') = AHA-1540A/1542A/1542B */ - /* 0x42 ('B') = AHA-1640 */ - /* 0x43 ('C') = AHA-1542C */ - /* 0x44 ('D') = AHA-1542CF */ - /* 0x45 ('E') = AHA-1542CF, BIOS v2.01 */ - /* 0x46 ('F') = AHA-1542CP, "Plug'nPlay" */ - u_char spec_opts; /* special options ID */ - /* 0x41 = Board is standard model */ - u_char revision_1; /* firmware revision [0-9A-Z] */ - u_char revision_2; /* firmware revision [0-9A-Z] */ -}; - -struct aha_extbios -{ - u_char flags; /* Bit 3 == 1 extended bios enabled */ - u_char mailboxlock; /* mail box lock code to unlock it */ -}; - -#define INT9 0x01 -#define INT10 0x02 -#define INT11 0x04 -#define INT12 0x08 -#define INT14 0x20 -#define INT15 0x40 - -#define CHAN0 0x01 -#define CHAN5 0x20 -#define CHAN6 0x40 -#define CHAN7 0x80 - -/*********************************** end of board definitions***************/ - -#define PHYSTOKV(x) ((intptr_t)(((long int)(x)) ^ aha->kv_phys_xor)) -#define KVTOPHYS(x) vtophys(x) -#define AHA_DMA_PAGES AHA_NSEG - -#define PAGESIZ 4096 - -#ifdef AHADEBUG -int aha_debug = 1; -#endif /*AHADEBUG */ - -static struct aha_data { - int aha_base; /* base port for each board */ - /* - * xor this with a physaddr to get a kv addr and visa versa - * for items in THIS STRUCT only. - * Used to get the CCD's physical and kv addresses from each - * other. - */ - long int kv_phys_xor; - struct aha_mbx aha_mbx; /* all the mailboxes */ - struct aha_ccb *aha_ccb_free; /* the next free ccb */ - struct aha_ccb aha_ccb[AHA_MBX_SIZE]; /* all the CCBs */ - int unit; /* unit number */ - int aha_int; /* irq level */ - int aha_dma; /* DMA req channel */ - int aha_scsi_dev; /* scsi bus address */ - int flags; - - /* We use different op codes for different revs of the board - * if we think residual codes will work. - */ - short init_opcode; /* Command to use for initiator */ - short sg_opcode; /* Command to use for scatter/gather */ - struct scsi_link sc_link; /* prototype for subdevs */ -} *ahadata[NAHA]; - -static u_int32_t aha_adapter_info __P((int unit)); -static int ahaattach __P((struct isa_device *dev)); -#ifdef TUNE_1542 -static int aha_bus_speed_check __P((struct aha_data *aha, int speed)); -static int aha_set_bus_speed __P((struct aha_data *aha)); -#endif -static int aha_cmd __P((struct aha_data *aha, int icnt, int ocnt, int wait, - u_char *retval, u_char opcode, ...)); -static void aha_done __P((struct aha_data *aha, struct aha_ccb *ccb)); -static int aha_escape __P((struct scsi_xfer *xs, struct aha_ccb *ccb)); -static void aha_free_ccb __P((struct aha_data *aha, struct aha_ccb *ccb, - int flags)); -static struct aha_ccb * - aha_get_ccb __P((struct aha_data *aha, int flags)); -static int aha_init __P((struct aha_data *aha)); -static void ahaminphys __P((struct buf *bp)); -static int aha_poll __P((struct aha_data *aha, struct scsi_xfer *xs, - struct aha_ccb *ccb)); -static int ahaprobe __P((struct isa_device *dev)); -static int32_t aha_scsi_cmd __P((struct scsi_xfer *xs)); -static timeout_t - aha_timeout; -static char *board_rev __P((struct aha_data *aha, int type)); -static int physcontig __P((int kv, int len)); -static void put_host_stat __P((int host_stat)); - -static struct scsi_adapter aha_switch = -{ - aha_scsi_cmd, - ahaminphys, - 0, - 0, - aha_adapter_info, - "aha", - { 0, 0 } -}; - -/* the below structure is so we have a default dev struct for out link struct */ -static struct scsi_device aha_dev = -{ - NULL, /* Use default error handler */ - NULL, /* have a queue, served by this */ - NULL, /* have no async handler */ - NULL, /* Use default 'done' routine */ - "aha", - 0, - { 0, 0 } -}; - -struct isa_driver ahadriver = -{ - ahaprobe, - ahaattach, - "aha" -}; - -static int ahaunit = 0; - -#define aha_abortmbx(mbx) \ - (mbx)->cmd = AHA_MBO_ABORT; \ - outb(AHA_CMD_DATA_PORT, AHA_START_SCSI); -#define aha_startmbx(mbx) \ - (mbx)->cmd = AHA_MBO_START; \ - outb(AHA_CMD_DATA_PORT, AHA_START_SCSI); - -#define AHA_RESET_TIMEOUT 2000 /* time to wait for reset (mSec) */ - -/* - * aha_cmd(struct aha_data *aha,icnt, ocnt,wait, retval, opcode, ...) - * 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 AHA_NOP, AHA_MBX_INIT, AHA_START_SCSI, etc - * ... : parameters to the command specified by opcode - * - * 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 but that one is done - * separately. This is only called during set-up. - * - */ -static int -#ifdef __STDC__ -aha_cmd(struct aha_data *aha, int icnt, int ocnt, int wait, u_char *retval, - u_char opcode, ... ) -#else -aha_cmd(aha, icnt, ocnt, wait, retval, opcode, va_alist) - struct aha_data *aha, - int icnt, - int ocnt, - int wait, - u_char *retval, - u_char opcode, - va_dcl -#endif -{ - va_list ap; - u_char oc; - u_char data; - register int i; - int sts; - - /* - * multiply the wait argument by a big constant - * zero defaults to 1 sec.. - * all wait loops are in 50uSec cycles - */ - if (wait) - wait *= 20000; - else - wait = 20000; - /* - * Wait for the adapter to go idle, unless it's one of - * the commands which don't need this - */ - if (opcode != AHA_MBX_INIT && opcode != AHA_START_SCSI) { - i = 20000; /*do this for upto about a second */ - while (--i) { - sts = inb(AHA_CTRL_STAT_PORT); - if (sts & AHA_IDLE) { - break; - } - DELAY(50); - } - if (!i) { - printf("aha%d: aha_cmd, host not idle(0x%x)\n", - aha->unit, sts); - return (ENXIO); - } - } - /* - * Now that it is idle, if we expect output, preflush the - * queue feeding to us. - */ - if (ocnt) { - while ((inb(AHA_CTRL_STAT_PORT)) & AHA_DF) - inb(AHA_CMD_DATA_PORT); - } - /* - * Output the command and the number of arguments given - * for each byte, first check the port is empty. - */ - va_start(ap, opcode); - for(data = opcode; icnt >=0; icnt--, data = (u_char)va_arg(ap, int)) { - sts = inb(AHA_CTRL_STAT_PORT); - for (i = wait; i; i--) { - sts = inb(AHA_CTRL_STAT_PORT); - if (!(sts & AHA_CDF)) - break; - DELAY(50); - } - if (i == 0) { - printf("aha%d: aha_cmd, cmd/data port full\n", - aha->unit); - outb(AHA_CTRL_STAT_PORT, AHA_SRST); - return (ENXIO); - } - outb(AHA_CMD_DATA_PORT, data); - } - /* - * If we expect input, loop that many times, each time, - * looking for the data register to have valid data - */ - while (ocnt--) { - sts = inb(AHA_CTRL_STAT_PORT); - for (i = wait; i; i--) { - sts = inb(AHA_CTRL_STAT_PORT); - if (sts & AHA_DF) - break; - DELAY(50); - } - if (i == 0) { - printf("aha%d: aha_cmd, cmd/data port empty %d\n", - aha->unit, ocnt); - return (ENXIO); - } - oc = inb(AHA_CMD_DATA_PORT); - if (retval) - *retval++ = oc; - } - /* - * Wait for the board to report a finised instruction - */ - i = 20000; - while (--i) { - sts = inb(AHA_INTR_PORT); - if (sts & AHA_HACC) { - break; - } - DELAY(50); - } - if (i == 0) { - printf("aha%d: aha_cmd, host not finished(0x%x)\n", - aha->unit, sts); - return (ENXIO); - } - outb(AHA_CTRL_STAT_PORT, AHA_IRST); - return 0; -} - -/* - * 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 - * autoconf.c - */ -static int -ahaprobe(dev) - struct isa_device *dev; -{ - int unit = ahaunit; - struct aha_data *aha; - - /* - * find unit and check we have that many defined - */ - if (unit >= NAHA) { - printf("aha%d: unit number too high\n", unit); - return 0; - } - dev->id_unit = unit; - - /* - * a quick safety check so we can be sleazy later - */ - if (sizeof(struct aha_data) > PAGESIZ) { - printf("aha struct > pagesize\n"); - return 0; - } - /* - * Allocate a storage area for us - */ - if (ahadata[unit]) { - printf("aha%d: memory already allocated\n", unit); - return 0; - } - aha = malloc(sizeof(struct aha_data), M_TEMP, M_NOWAIT); - if (!aha) { - printf("aha%d: cannot malloc!\n", unit); - return 0; - } - bzero(aha, sizeof(struct aha_data)); - ahadata[unit] = aha; - aha->unit = unit; - aha->aha_base = dev->id_iobase; - - /* - * Try initialise a unit at this location - * sets up dma and bus speed, loads aha->aha_int - */ - if (aha_init(aha) != 0) { - ahadata[unit] = NULL; - free(aha, M_TEMP); - return 0; - } - /* - * Calculate the xor product of the aha struct's - * physical and virtual address. This allows us - * to change addresses within the structure - * from physical to virtual easily, as long as - * the structure is less than 1 page in size. - * This is used to recognise CCBs which are in - * this struct and which are refered to by the - * hardware using physical addresses. - * (assumes malloc returns a chunk that doesn't - * span pages) - * eventually use the hash table in aha1742.c - */ - aha->kv_phys_xor = (intptr_t) aha ^ (KVTOPHYS(aha)); - - /* - * If it's there, put in it's interrupt vectors - */ - dev->id_irq = (1 << aha->aha_int); - dev->id_drq = aha->aha_dma; - ahaunit++; - return 0x4; -} - -/* - * Attach all the sub-devices we can find - */ -static int -ahaattach(dev) - struct isa_device *dev; -{ - int unit = dev->id_unit; - struct aha_data *aha = ahadata[unit]; - struct scsibus_data *scbus; - - /* - * fill in the prototype scsi_link. - */ - aha->sc_link.adapter_unit = unit; - aha->sc_link.adapter_targ = aha->aha_scsi_dev; - aha->sc_link.adapter_softc = aha; - aha->sc_link.adapter = &aha_switch; - aha->sc_link.device = &aha_dev; - aha->sc_link.flags = aha->flags;; - - /* - * Prepare the scsibus_data area for the upperlevel - * scsi code. - */ - scbus = scsi_alloc_bus(); - if(!scbus) - return 0; - scbus->adapter_link = &aha->sc_link; - - /* - * ask the adapter what subunits are present - */ - scsi_attachdevs(scbus); - - return 1; -} - -/* - * Return some information to the caller about the adapter and its - * capabilities. - */ -static u_int32_t -aha_adapter_info(unit) - int unit; -{ - return (2); /* 2 outstanding requests at a time per device */ -} - -/* - * Catch an interrupt from the adaptor - */ -void -ahaintr(unit) - int unit; -{ - unsigned char stat; - register int i; - struct aha_data *aha = ahadata[unit]; - -#ifdef AHADEBUG - printf("ahaintr "); -#endif /*AHADEBUG */ - /* - * First acknowledge the interrupt, Then if it's not telling about - * a completed operation just return. - */ - stat = inb(AHA_INTR_PORT); - outb(AHA_CTRL_STAT_PORT, AHA_IRST); - if (!(stat & AHA_MBIF)) - return; -#ifdef AHADEBUG - printf("mbxin "); -#endif /*AHADEBUG */ - /* - * If it IS then process the completed operation - */ - for (i = 0; i < AHA_MBX_SIZE; i++) { - struct aha_mbx_in *mbi = aha->aha_mbx.mbi + i; - - if (mbi->stat != AHA_MBI_FREE) { - struct aha_ccb *ccb = - (struct aha_ccb *)PHYSTOKV(scsi_3btou(mbi->ccb_addr)); - - stat = mbi->stat; - - switch (stat) { - case AHA_MBI_OK: - break; - - case AHA_MBI_ABORT: -#ifdef AHADEBUG - if (aha_debug) - printf("abort"); -#endif /*AHADEBUG */ - ccb->host_stat = AHA_ABORTED; - break; - - case AHA_MBI_TGT_NO_CCB: - /* We enabled target mode and received a SEND - * or RECEIVE command from the initiator, but - * we don't have any CCB registered to handle the command. - * At this point it would be nice to wakeup a - * process sleeping on this event via an ioctl, - * returning whether it is a SEND or RECEIVE and the - * required length. - * However, I want to look at the CAM documentation before - * I start extending the API at all. - */ -#ifdef NOISE_WHEN_TGT_NO_CDB - printf("Target received, but no CCB ready.\n"); - printf("Initiator & lun: %02x\n", mbi->ccb_addr[0]); - printf("Max data length: %06x\n", - (mbi->ccb_addr[1] << 16) | (mbi->ccb_addr[2] << 8) - + 255); -#endif -#ifdef AHADEBUG - if (aha_debug) - printf("target-no-ccb"); -#endif /*AHADEBUG */ - ccb = 0; - break; - - case AHA_MBI_UNKNOWN: - ccb = 0; -#ifdef AHADEBUG - if (aha_debug) - printf("unknown ccb for abort "); -#endif /*AHADEBUG */ - /* may have missed it */ - /* no such ccb known for abort */ - - case AHA_MBI_ERROR: - /* XXX ccb is still set up? Driver fails without it? */ - break; - - default: - panic("Impossible mbxi status"); - - } -#ifdef AHADEBUG - if (aha_debug && ccb && stat != AHA_MBI_OK) { - u_char *cp; - cp = (u_char *) (&(ccb->scsi_cmd)); - printf("op=%x %x %x %x %x %x\n", - cp[0], cp[1], cp[2], - cp[3], cp[4], cp[5]); - printf("stat %x for mbi[%d]\n" - ,mbi->stat, i); - printf("addr = 0x%x\n", ccb); - } -#endif /*AHADEBUG */ - if (ccb) { - untimeout(aha_timeout, (caddr_t)ccb, - ccb->xfer->timeout_ch); - aha_done(aha, ccb); - } - mbi->stat = AHA_MBI_FREE; - } - } -} - -/* - * A ccb (and hence a mbx-out) is put onto the - * free list. - */ -static void -aha_free_ccb(aha, ccb, flags) - struct aha_data *aha; - struct aha_ccb *ccb; - int flags; -{ - unsigned int opri = 0; - - if (!(flags & SCSI_NOMASK)) - opri = splbio(); - - ccb->next = aha->aha_ccb_free; - aha->aha_ccb_free = ccb; - ccb->flags = CCB_FREE; - /* - * If there were none, wake anybody waiting for - * one to come free, starting with queued entries - */ - if (!ccb->next) { - wakeup((caddr_t)&aha->aha_ccb_free); - } - if (!(flags & SCSI_NOMASK)) - splx(opri); -} - -/* - * Get a free ccb (and hence mbox-out entry) - */ -static struct aha_ccb * -aha_get_ccb(aha, flags) - struct aha_data *aha; - int flags; -{ - unsigned opri = 0; - struct aha_ccb *rc; - - if (!(flags & SCSI_NOMASK)) - opri = splbio(); - /* - * If we can and have to, sleep waiting for one - * to come free - */ - while ((!(rc = aha->aha_ccb_free)) && (!(flags & SCSI_NOSLEEP))) { - tsleep((caddr_t)&aha->aha_ccb_free, PRIBIO, "ahaccb", 0); - } - if (rc) { - aha->aha_ccb_free = aha->aha_ccb_free->next; - rc->flags = CCB_ACTIVE; - } - if (!(flags & SCSI_NOMASK)) - splx(opri); - return (rc); -} - -static void -put_host_stat(int host_stat) -{ - int i; - - struct { int host_stat; char *text; } tab[] = { - { AHA_OK, "Cmd ok" }, - { AHA_LINK_OK, "Link cmd ok" }, - { AHA_LINK_IT, "Link cmd ok + int" }, - { AHA_SEL_TIMEOUT, "Selection time out" }, - { AHA_OVER_UNDER, "Data over/under run" }, - { AHA_BUS_FREE, "Bus dropped at unexpected time" }, - { AHA_INV_BUS, "Invalid bus phase/sequence" }, - { AHA_BAD_MBO, "Incorrect MBO cmd" }, - { AHA_BAD_CCB, "Incorrect ccb opcode" }, - { AHA_BAD_LINK, "Not same values of LUN for links" }, - { AHA_INV_TARGET, "Invalid target direction" }, - { AHA_CCB_DUP, "Duplicate CCB received" }, - { AHA_INV_CCB, "Invalid CCB or segment list" }, - { AHA_ABORTED, "Software abort" }, - }; - - for (i = 0; i < (int)(sizeof(tab) / sizeof(tab[0])); i++) { - if (tab[i].host_stat == host_stat) { - printf("%s\n", tab[i].text); - return; - } - } - - printf("Unknown host_stat %02x\n", host_stat); -} - -/* - * 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 - */ -static void -aha_done(aha, ccb) - struct aha_data *aha; - struct aha_ccb *ccb; -{ - struct scsi_sense_data *s1, *s2; - struct scsi_xfer *xs = ccb->xfer; - - SC_DEBUG(xs->sc_link, SDEV_DB2, ("aha_done\n")); - /* - * Otherwise, put the results of the operation - * into the xfer and call whoever started it - */ - if (!(xs->flags & INUSE)) { - printf("aha%d: exiting but not in use!\n", aha->unit); -#ifdef DIAGNOSTIC - panic("aha1542 exiting but not in use"); -#endif - } - xs->status = ccb->target_stat; - xs->resid = 0; - - if (((ccb->host_stat != AHA_OK) || (ccb->target_stat != SCSI_OK)) - && ((xs->flags & SCSI_ERR_OK) == 0)) { - /* - * We have an error, that we cannot ignore. - */ - s1 = (struct scsi_sense_data *) (((char *) (&ccb->scsi_cmd)) - + ccb->scsi_cmd_length); - s2 = &(xs->sense); - - if (ccb->host_stat) { - SC_DEBUG(xs->sc_link, SDEV_DB3, ("host err 0x%x\n", - ccb->host_stat)); - switch (ccb->host_stat) { - case AHA_ABORTED: - xs->error = XS_TIMEOUT; - break; - case AHA_SEL_TIMEOUT: - xs->error = XS_SELTIMEOUT; - break; - - case AHA_OVER_UNDER: /* Over run / under run */ - switch(ccb->opcode) - { - case AHA_TARGET_CCB: - xs->resid = xs->datalen - scsi_3btoi(ccb->data_length); - xs->flags |= SCSI_RESID_VALID; - if (xs->resid <= 0) - xs->error = XS_LENGTH; - break; - - case AHA_INIT_RESID_CCB: - case AHA_INIT_SG_RESID_CCB: - xs->resid = scsi_3btoi(ccb->data_length); - xs->flags |= SCSI_RESID_VALID; - if (xs->resid <= 0) - xs->error = XS_LENGTH; - break; - - default: - xs->error = XS_LENGTH; - } - break; - - default: /* Other scsi protocol messes */ - xs->error = XS_DRIVER_STUFFUP; - printf("aha%d: ", aha->unit); - put_host_stat(ccb->host_stat); - } - } else { - SC_DEBUG(xs->sc_link, SDEV_DB3, ("target err 0x%x\n", - ccb->target_stat)); - switch (ccb->target_stat) { - case 0x02: - /* structure copy!!!!! */ - *s2 = *s1; - xs->error = XS_SENSE; - break; - case 0x08: - xs->error = XS_BUSY; - break; - default: - printf("aha%d:target_stat%x\n", - aha->unit, ccb->target_stat); - xs->error = XS_DRIVER_STUFFUP; - } - } - } - - xs->flags |= ITSDONE; - aha_free_ccb(aha, ccb, xs->flags); - scsi_done(xs); -} - -/* Macro to determine that a rev is potentially a new valid one - * so that the driver doesn't keep breaking on new revs as it - * did for the CF and CP. - */ -#define PROBABLY_NEW_BOARD(REV) (REV > 0x43 && REV < 0x56) - -static char *board_rev(struct aha_data *aha, int type) -{ - switch(type) - { - case 0x20: return "Buslogic 545?"; - case 0x31: return "AHA-1540"; - case 0x41: return "AHA-154x[AB]"; - case 0x42: return "AHA-1640"; - case 0x43: return "AHA-1542C"; - case 0x44: return "AHA-1542CF"; - case 0x45: return "AHA-1542CF BIOS v2.01"; - case 0x46: return "AHA-1542CP"; - - default: - - - if (PROBABLY_NEW_BOARD(type)) - { - printf("aha%d: Assuming type %02x is a new board.\n", - aha->unit, type); - return "New Adaptec rev?"; - } - - printf("aha%d: type %02x is an unknown board.\n", - aha->unit, type); - return "Unknown board"; - } -} - -/* - * Start the board, ready for normal operation - */ -static int -aha_init(aha) - struct aha_data *aha; -{ - char *desc; - unsigned char ad[3]; - volatile int i, sts; - struct aha_config conf; - struct aha_inquire inquire; - struct aha_extbios extbios; - - /* Assume that residual codes don't work. If they - * do we enable that after we figure out what kind of - * board it is. - */ - aha->init_opcode = AHA_INITIATOR_CCB; - aha->sg_opcode = AHA_INIT_SCAT_GATH_CCB; - - /* - * reset board, If it doesn't respond, assume - * that it's not there.. good for the probe - */ - - outb(AHA_CTRL_STAT_PORT, AHA_HRST | AHA_SRST); - - for (i = AHA_RESET_TIMEOUT; i; i--) { - sts = inb(AHA_CTRL_STAT_PORT); - if (sts == (AHA_IDLE | AHA_INIT)) { - break; - } - DELAY(1000); /* calibrated in msec */ - } -#ifdef AHADEBUG - printf("aha_init: AHA_RESET_TIMEOUT went to %d\n", i); -#endif /* AHADEBUG */ - if (i == 0) { -#ifdef AHADEBUG - if (aha_debug) - printf("aha_init: No answer from board\n"); -#endif /*AHADEBUG */ - return (ENXIO); - } - - /* - * Assume we have a board at this stage, do an adapter inquire - * to find out what type of controller it is. If the AHA_INQUIRE - * command fails, blatter about it, nuke the boardid so the 1542C - * stuff gets skipped over, and reset the board again. - */ - if(aha_cmd(aha, 0, sizeof(inquire), 1, - (u_char *)&inquire, AHA_INQUIRE)) { - /* - * Blah.. not a real adaptec board!!! - * Seems that the Buslogic 545S and the DTC3290 both get - * this wrong. - */ - printf ("aha%d: not a REAL adaptec board, may cause warnings\n", - aha->unit); - inquire.boardid = 0; - outb(AHA_CTRL_STAT_PORT, AHA_HRST | AHA_SRST); - for (i = AHA_RESET_TIMEOUT; i; i--) { - sts = inb(AHA_CTRL_STAT_PORT); - if (sts == (AHA_IDLE | AHA_INIT)) { - break; - } - DELAY(1000); /* calibrated in msec */ - } -#ifdef AHADEBUG - printf("aha_init2: AHA_RESET_TIMEOUT went to %d\n", i); -#endif /* AHADEBUG */ - if (i == 0) { -#ifdef AHADEBUG - if (aha_debug) - printf("aha_init2: No answer from board\n"); -#endif /*AHADEBUG */ - return (ENXIO); - } - } -#ifdef AHADEBUG - printf("aha%d: inquire %x, %x, %x, %x\n", - aha->unit, - inquire.boardid, inquire.spec_opts, - inquire.revision_1, inquire.revision_2); -#endif /* AHADEBUG */ - - aha->flags = SDEV_BOUNCE; - -#define PRVERBOSE(x) if (bootverbose) printf x - - /* - * If we are a new type of 1542 board (anything newer than a 1542C) - * then disable the extended bios so that the - * mailbox interface is unlocked. - * This is also true for the 1542B Version 3.20. First Adaptec - * board that supports >1Gb drives. - * No need to check the extended bios flags as some of the - * extensions that cause us problems are not flagged in that byte. - */ - desc = board_rev(aha, inquire.boardid); - - PRVERBOSE( ("aha%d: Rev %02x (%s) V%c.%c", - aha->unit, inquire.boardid, desc, inquire.revision_1, - inquire.revision_2) ); - - if (PROBABLY_NEW_BOARD(inquire.boardid) || - (inquire.boardid == 0x41 - && inquire.revision_1 == 0x31 && inquire.revision_2 == 0x34)) { - aha_cmd(aha, 0, sizeof(extbios), 0, - (u_char *)&extbios, AHA_EXT_BIOS); -#ifdef AHADEBUG - printf("aha%d: extended bios flags %x\n", aha->unit, extbios.flags); -#endif /* AHADEBUG */ - - PRVERBOSE( (", enabling mailbox") ); - - aha_cmd(aha, 2, 0, 0, 0, AHA_MBX_ENABLE, - 0, extbios.mailboxlock); - } - - /* Which boards support residuals? Some early 1542A's apparently - * don't. The 1542B with V0.5 of the software does, so I've - * arbitrarily set that as the earliest rev. - */ - if (PROBABLY_NEW_BOARD(inquire.boardid) || - (inquire.boardid == 0x41 - && (inquire.revision_1 > '0' || inquire.revision_2 >= '5'))) { - - PRVERBOSE( (", enabling residuals") ); - - aha->init_opcode = AHA_INIT_RESID_CCB; - aha->sg_opcode = AHA_INIT_SG_RESID_CCB; - } - - /* Which boards support target operations? The 1542C completely - * locks up the SCSI bus if you enable them. I'm only sure - * about the B, which was sold in the OEM market as a target - * board. - */ - if (inquire.boardid == 0x41) { - PRVERBOSE( (", target ops") ); - aha->flags |= SDEV_TARGET_OPS; - } - - PRVERBOSE( ("\n") ); - - /* - * setup dma channel from jumpers and save int - * level - */ - PRVERBOSE(("aha%d: reading board settings, ", aha->unit)); - - if (inquire.boardid == 0x20) { - DELAY(1000); /* for Bustek 545 */ - } - - aha_cmd(aha, 0, sizeof(conf), 0, (u_char *)&conf, AHA_CONF_GET); - switch (conf.chan) { - case CHAN0: - outb(0x0b, 0x0c); - outb(0x0a, 0x00); - aha->aha_dma = 0; - break; - case CHAN5: - outb(0xd6, 0xc1); - outb(0xd4, 0x01); - aha->aha_dma = 5; - break; - case CHAN6: - outb(0xd6, 0xc2); - outb(0xd4, 0x02); - aha->aha_dma = 6; - break; - case CHAN7: - outb(0xd6, 0xc3); - outb(0xd4, 0x03); - aha->aha_dma = 7; - break; - default: - printf("aha%d: illegal dma jumper setting\n", aha->unit); - return (EIO); - } - - PRVERBOSE( ("dma=%d ", aha->aha_dma) ); - - switch (conf.intr) { - case INT9: - aha->aha_int = 9; - break; - case INT10: - aha->aha_int = 10; - break; - case INT11: - aha->aha_int = 11; - break; - case INT12: - aha->aha_int = 12; - break; - case INT14: - aha->aha_int = 14; - break; - case INT15: - aha->aha_int = 15; - break; - default: - printf("aha%d: illegal int jumper setting\n", aha->unit); - return (EIO); - } - - PRVERBOSE( ("int=%d ", aha->aha_int) ); - - /* who are we on the scsi bus? */ - aha->aha_scsi_dev = conf.scsi_dev; - - PRVERBOSE( ("id=%d ", aha->aha_scsi_dev) ); - - /* - * Change the bus on/off times to not clash with other dma users. - */ - aha_cmd(aha, 1, 0, 0, 0, AHA_BUS_ON_TIME_SET, 7); - aha_cmd(aha, 1, 0, 0, 0, AHA_BUS_OFF_TIME_SET, 4); - -#ifdef TUNE_1542 - /* - * Initialize memory transfer speed - * Not compiled in by default because it breaks some machines - */ - if (!(aha_set_bus_speed(aha))) { - return (EIO); - } -#else - PRVERBOSE( (" (bus speed defaulted)\n") ); -#endif /*TUNE_1542*/ - /* - * Initialize mail box - */ - scsi_uto3b(KVTOPHYS(&aha->aha_mbx), ad); - - aha_cmd(aha, 4, 0, 0, 0, AHA_MBX_INIT, - AHA_MBX_SIZE, - ad[0], - ad[1], - ad[2]); - - /* - * link the ccb's with the mbox-out entries and - * into a free-list - * this is a kludge but it works - */ - for (i = 0; i < AHA_MBX_SIZE; i++) { - aha->aha_ccb[i].next = aha->aha_ccb_free; - aha->aha_ccb_free = &aha->aha_ccb[i]; - aha->aha_ccb_free->flags = CCB_FREE; - aha->aha_ccb_free->mbx = &aha->aha_mbx.mbo[i]; - scsi_uto3b(KVTOPHYS(aha->aha_ccb_free), aha->aha_mbx.mbo[i].ccb_addr); - } - /* - * Note that we are going and return (to probe) - */ - return 0; -} - -static void -ahaminphys(bp) - struct buf *bp; -{ -/* aha seems to explode with 17 segs (64k may require 17 segs) */ -/* on old boards so use a max of 16 segs if you have problems here */ - if (bp->b_bcount > ((AHA_NSEG - 1) * PAGESIZ)) { - bp->b_bcount = ((AHA_NSEG - 1) * PAGESIZ); - } -} - -static int -aha_escape(xs, ccb) - struct scsi_xfer *xs; - struct aha_ccb *ccb; -{ - int ret = 0; - int s; - - if (xs->cmd) - { - switch(xs->cmd->opcode) - { - case SCSI_OP_RESET: - ccb->opcode = AHA_RESET_CCB; - ret = 0; - break; - - case SCSI_OP_TARGET: - s= splbio(); - aha_cmd((struct aha_data *)xs->sc_link->adapter_softc, - 2, 0, 0, 0, AHA_TARGET_EN, - (int)xs->cmd->bytes[0], (int)1); - splx(s); - ret = COMPLETE; - break; - - default: - ret = ESCAPE_NOT_SUPPORTED; - break; - } - } - else - { - ccb->opcode = AHA_RESET_CCB; - ret = 0; - } - - return ret; -} - -#define physdb(ARG) (void)(ARG) - -/* physcontig: Scan forward from a KV and return length to the - * end of physically contiguous addresses. This belongs in - * i386/.../something_or_other.c - * XXX: Find the right thing in the kernel. - */ -static int physcontig(int kv, int len) -{ - int len_was = len; - u_long kvl = (u_long)kv; - - int phys_len; - u_long phys, prev_phys; - - prev_phys = KVTOPHYS(kvl); - - /* We go at least to the end of this page: - */ - phys_len = PAGESIZ - (prev_phys & (PAGESIZ - 1)); - len -= phys_len; - kvl += phys_len; - prev_phys &= ~(PAGESIZ - 1); - - while (len > 0) - { - phys = KVTOPHYS(kvl); - - if (phys != prev_phys + PAGESIZ) - { - physdb(("phys %08x != prev_phys %08x + PAGESIZ\n", - phys, prev_phys)); - - break; - } - - prev_phys = phys; - kvl += PAGESIZ; - len -= PAGESIZ; - } - - phys_len = (len < 0) ? len_was : (len_was - len); - - physdb(("physcontig(%08x, %d) = %d\n", kv, len_was, phys_len)); - - return phys_len; -} -/* - * start a scsi operation given the command and - * the data address. Also needs the unit, target - * and lu - */ -static int32_t -aha_scsi_cmd(xs) - struct scsi_xfer *xs; -{ - struct scsi_link *sc_link = xs->sc_link; - struct aha_data *aha; - struct aha_ccb *ccb; - struct aha_scat_gath *sg; - int seg; /* scatter gather seg being worked on */ - int thiskv; - int thisphys, nextphys; - int bytes_this_seg, bytes_this_page, datalen, flags; - int s; - - aha = (struct aha_data *)sc_link->adapter_softc; - - SC_DEBUG(xs->sc_link, SDEV_DB2, ("aha_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 = xs->flags; - if (!(ccb = aha_get_ccb(aha, flags))) { - xs->error = XS_DRIVER_STUFFUP; - return (TRY_AGAIN_LATER); - } - if (ccb->mbx->cmd != AHA_MBO_FREE) - printf("aha%d: MBO %02x and not %02x (free)\n", - aha->unit, ccb->mbx->cmd, AHA_MBO_FREE); - - /* - * Put all the arguments for the xfer in the ccb - */ - ccb->xfer = xs; - if (flags & SCSI_RESET) { - ccb->opcode = AHA_RESET_CCB; - } else { - /* can't use S/G if zero length */ - ccb->opcode = (xs->datalen ? - aha->sg_opcode - : aha->init_opcode); - } - ccb->target = sc_link->target; - ccb->data_out = 0; - ccb->data_in = 0; - ccb->lun = sc_link->lun; - ccb->scsi_cmd_length = xs->cmdlen; - - /* Some devices (e.g, Microtek ScanMaker II) - * fall on the ground if you ask for anything but - * an exact number of sense bytes (wiping out the - * sense data) - * XXX: This was lost at some point in scsi_ioctl.c. - */ - ccb->req_sense_length = (xs->req_sense_length) - ? xs->req_sense_length - : sizeof(ccb->scsi_sense); - - /* XXX: I propose we move the reset handling into the escape - * handling. - */ - if (flags & SCSI_RESET) { - flags |= SCSI_ESCAPE; - xs->cmd->opcode = SCSI_OP_RESET; - } - - /* Set up the CCB. For an escape function, the escape hook may - * set it up for us. - */ - - if (flags & SCSI_ESCAPE) { - int ret; - ret = aha_escape(xs, ccb); - if (ret) - return ret; - } - else if (flags & SCSI_TARGET) - { - ccb->opcode = AHA_TARGET_CCB; - - /* These must be set up for target mode: - */ - if (flags & SCSI_DATA_IN) - ccb->data_in = 1; - if (flags & SCSI_DATA_OUT) - ccb->data_out = 1; - } - else - { - ccb->opcode = (xs->datalen? /* can't use S/G if zero length */ - AHA_INIT_SCAT_GATH_CCB - :AHA_INITIATOR_CCB); - } - - switch(ccb->opcode) - { - case AHA_TARGET_CCB: - if (xs->data) - scsi_uto3b(KVTOPHYS((int)xs->data), ccb->data_addr); - else - scsi_uto3b(0, ccb->data_addr); - - /* For non scatter-gather I/O (and Target mode doesn't do - * scatter-gather) we need to truncate the transfer - * at the first non consecutive physical address. - */ - scsi_uto3b(physcontig((int)xs->data, xs->datalen), ccb->data_length); - break; - - /* This should be folded in with TARGET_CCB once - * physcontig is debugged. - */ - case AHA_INITIATOR_CCB: - case AHA_INIT_RESID_CCB: - - if (xs->data) - scsi_uto3b(KVTOPHYS((int)xs->data), ccb->data_addr); - else - scsi_uto3b(0, ccb->data_addr); - - scsi_uto3b(xs->datalen, ccb->data_length); - break; - - case AHA_RESET_CCB: - scsi_uto3b(0, ccb->data_addr); - scsi_uto3b(0, ccb->data_length); - break; - - case AHA_INIT_SCAT_GATH_CCB: - case AHA_INIT_SG_RESID_CCB: - scsi_uto3b(KVTOPHYS(ccb->scat_gath), ccb->data_addr ); - sg = ccb->scat_gath ; - seg = 0; -#ifdef TFS_ONLY - if (flags & SCSI_DATA_UIO) { - iovp = ((struct uio *) xs->data)->uio_iov; - datalen = ((struct uio *) xs->data)->uio_iovcnt; - while ((datalen) && (seg < AHA_NSEG)) { - scsi_uto3b(iovp->iov_base, sg->seg_addr); - scsi_uto3b(iovp->iov_len, sg->seg_len); - SC_DEBUGN(xs->sc_link, SDEV_DB4, ("UIO(0x%x@0x%x)" - ,iovp->iov_len - ,iovp->iov_base)); - sg++; - iovp++; - seg++; - datalen--; - } - } else -#endif /*TFS_ONLY */ - { - /* - * Set up the scatter gather block - */ - - SC_DEBUG(xs->sc_link, SDEV_DB4, - ("%ld @%p:- ", xs->datalen, xs->data)); - datalen = xs->datalen; - thiskv = (int) xs->data; - thisphys = KVTOPHYS(thiskv); - - while ((datalen) && (seg < AHA_NSEG)) { - bytes_this_seg = 0; - - /* put in the base address */ - scsi_uto3b(thisphys, sg->seg_addr); - - SC_DEBUGN(xs->sc_link, SDEV_DB4, - ("0x%x", thisphys)); - - /* do it at least once */ - nextphys = thisphys; - while ((datalen) && (thisphys == nextphys)) { - /* - * This page is contiguous (physically) - * with the the last, just extend the - * length - */ - /* check it fits on the ISA bus */ - if (thisphys > 0xFFFFFF) - { - printf("aha%d: DMA beyond" - " end Of ISA: 0x%x\n", - aha->unit, thisphys); - xs->error = XS_DRIVER_STUFFUP; - aha_free_ccb(aha, ccb, flags); - return (HAD_ERROR); - } - /** how far to the end of the page ***/ - nextphys = (thisphys & (~(PAGESIZ - 1))) - + PAGESIZ; - bytes_this_page = nextphys - thisphys; - /**** or the data ****/ - bytes_this_page = min(bytes_this_page - ,datalen); - bytes_this_seg += bytes_this_page; - datalen -= bytes_this_page; - - /**** get more ready for the next page ****/ - thiskv = (thiskv & (~(PAGESIZ - 1))) - + PAGESIZ; - if (datalen) - thisphys = KVTOPHYS(thiskv); - } - /* - * next page isn't contiguous, finish the seg - */ - SC_DEBUGN(xs->sc_link, SDEV_DB4, - ("(0x%x)", bytes_this_seg)); - scsi_uto3b(bytes_this_seg, sg->seg_len); - sg++; - seg++; - } - } - scsi_uto3b(seg * sizeof(struct aha_scat_gath), ccb->data_length); - SC_DEBUGN(xs->sc_link, SDEV_DB4, ("\n")); - - if (datalen) { /* there's still data, must have run out of segs! */ - printf("aha%d: aha_scsi_cmd, more than %d DMA segs\n", - aha->unit, AHA_NSEG); - xs->error = XS_DRIVER_STUFFUP; - aha_free_ccb(aha, ccb, flags); - return (HAD_ERROR); - } - break; - - default: - printf("aha_scsi_cmd%d: Illegal CCB opcode.\n", aha->unit); - xs->error = XS_DRIVER_STUFFUP; - aha_free_ccb(aha,ccb,flags); - return HAD_ERROR; - } - - scsi_uto3b(0, ccb->link_addr); - /* - * Put the scsi command in the ccb and start it - */ - if (!(flags & SCSI_ESCAPE)) - bcopy(xs->cmd, &ccb->scsi_cmd, ccb->scsi_cmd_length); - if (!(flags & SCSI_NOMASK)) { - s = splbio(); /* stop instant timeouts */ - xs->timeout_ch = timeout(aha_timeout, (caddr_t)ccb, - (xs->timeout * hz) / 1000); - aha_startmbx(ccb->mbx); - /* - * Usually return SUCCESSFULLY QUEUED - */ - splx(s); - SC_DEBUG(xs->sc_link, SDEV_DB3, ("sent\n")); - return (SUCCESSFULLY_QUEUED); - } - aha_startmbx(ccb->mbx); - SC_DEBUG(xs->sc_link, SDEV_DB3, ("cmd sent, waiting\n")); - - /* - * If we can't use interrupts, poll on completion - */ - return (aha_poll(aha, xs, ccb)); /* only during boot */ -} - -/* - * Poll a particular unit, looking for a particular xs - */ -static int -aha_poll(aha, xs, ccb) - struct aha_data *aha; - struct scsi_xfer *xs; - struct aha_ccb *ccb; -{ - int count = xs->timeout; - u_char stat; - - /*timeouts are in msec, so we loop in 1000uSec cycles */ - while (count) { - /* - * If we had interrupts enabled, would we - * have got an interrupt? - */ - stat = inb(AHA_INTR_PORT); - if (stat & AHA_ANY_INTR) { - ahaintr(aha->unit); - } - if (xs->flags & ITSDONE) { - break; - } - DELAY(1000); /* only happens in boot so ok */ - count--; - } - if (count == 0) { - /* - * We timed out, so call the timeout handler - * manually, accout for the fact that the - * clock is not running yet by taking out the - * clock queue entry it makes - */ - aha_timeout((caddr_t)ccb); - - /* - * because we are polling, - * take out the timeout entry aha_timeout made - */ - untimeout(aha_timeout, (caddr_t)ccb, ccb->xfer->timeout_ch); - count = 2000; - while (count) { - /* - * Once again, wait for the int bit - */ - stat = inb(AHA_INTR_PORT); - if (stat & AHA_ANY_INTR) { - ahaintr(aha->unit); - } - if (xs->flags & ITSDONE) { - break; - } - DELAY(1000); /* only happens in boot so ok */ - count--; - } - if (count == 0) { - /* - * We timed out again.. this is bad - * Notice that this time there is no - * clock queue entry to remove - */ - aha_timeout((caddr_t)ccb); - } - } - if (xs->error) - return (HAD_ERROR); - return (COMPLETE); - -} - -#ifdef TUNE_1542 -/* - * Try all the speeds from slowest to fastest.. if it finds a - * speed that fails, back off one notch from the last working - * speed (unless there is no other notch). - * Returns the nSEC value of the time used - * or 0 if it could get a working speed (or the NEXT speed - * failed) - */ -static struct bus_speed -{ - char arg; - int nsecs; -}aha_bus_speeds[] = -{ - {0x88,100}, - {0x99,150}, - {0xaa,200}, - {0xbb,250}, - {0xcc,300}, - {0xdd,350}, - {0xee,400}, - {0xff,450} -}; - -static int -aha_set_bus_speed(aha) - struct aha_data *aha; -{ - int speed; - int lastworking; - int retval,retval2; - - lastworking = -1; - speed = 7; - while (1) { - retval = aha_bus_speed_check(aha,speed); - if(retval != 0) { - lastworking = speed; - } - if((retval == 0) || (speed == 0)) { - if(lastworking == -1) { - printf("No working bus speed for aha154X\n"); - return 0; - } - printf("%d nSEC ok, using " - ,aha_bus_speeds[lastworking].nsecs); - if(lastworking == 7) { /* is slowest already */ - printf("marginal "); - } else { - lastworking++; - } - retval2 = aha_bus_speed_check(aha,lastworking); - if(retval2 == 0) { - printf("test retry failed.. aborting.\n"); - return 0; - } - printf("%d nSEC\n",retval2); - return retval2 ; - - } - speed--; - } -} - -/* - * Set the DMA speed to the Nth speed and try an xfer. If it - * fails return 0, if it succeeds return the nSec value selected - * If there is no such speed return HAD_ERROR. - */ -static char aha_test_string[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz!@"; - -u_char aha_scratch_buf[256]; - -static int -aha_bus_speed_check(aha, speed) - struct aha_data *aha; - int speed; -{ - int numspeeds = sizeof(aha_bus_speeds) / sizeof(struct bus_speed); - int loopcount; - u_char ad[3]; - - /* - * Check we have such an entry - */ - if (speed >= numspeeds) - return (HAD_ERROR); /* illegal speed */ - - /* - * Set the dma-speed - */ - aha_cmd(aha, 1, 0, 0, 0, AHA_SPEED_SET, aha_bus_speeds[speed].arg); - - /* - * put the test data into the buffer and calculate - * its address. Read it onto the board - */ - scsi_uto3b(KVTOPHYS(aha_scratch_buf), ad); - for(loopcount = 2000;loopcount;loopcount--) - { - strcpy(aha_scratch_buf, aha_test_string); - - aha_cmd(aha, 3, 0, 0, 0, AHA_WRITE_FIFO, ad[0], ad[1], ad[2]); - - /* - * clear the buffer then copy the contents back from the - * board. - */ - bzero(aha_scratch_buf, 54); /* 54 bytes transfered by test */ - - aha_cmd(aha, 3, 0, 0, 0, AHA_READ_FIFO, ad[0], ad[1], ad[2]); - - /* - * Compare the original data and the final data and - * return the correct value depending upon the result - */ - if (strcmp(aha_test_string, aha_scratch_buf)) - return 0; /* failed test */ - } - /* copy succeded assume speed ok */ - - return (aha_bus_speeds[speed].nsecs); - -} -#endif /*TUNE_1542*/ - -static void -aha_timeout(void *arg1) -{ - struct aha_ccb * ccb = (struct aha_ccb *)arg1; - int s = splbio(); - struct aha_data *aha; - - aha = (struct aha_data *)ccb->xfer->sc_link->adapter_softc; - sc_print_addr(ccb->xfer->sc_link); - printf("timed out "); - - /* - * If The ccb's mbx is not free, then - * the board has gone south - */ - if (ccb->mbx->cmd != AHA_MBO_FREE) { - printf("\nadapter not taking commands.. frozen?!\n"); -#ifdef DIAGNOSTIC - panic("aha1542 frozen"); -#endif - } - /* - * If it has been through before, then - * a previous abort has failed, don't - * try abort again - */ - if (ccb->flags == CCB_ABORTED) { - /* abort timed out */ - printf(" AGAIN\n"); - ccb->xfer->retries = 0; /* I MEAN IT ! */ - ccb->host_stat = AHA_ABORTED; - aha_done(aha, ccb); - } else { - /* abort the operation that has timed out */ - printf("\n"); - aha_abortmbx(ccb->mbx); - /* 4 secs for the abort */ - ccb->xfer->timeout_ch = timeout(aha_timeout, - (caddr_t)ccb, 4 * hz); - ccb->flags = CCB_ABORTED; - } splx(s); -} diff --git a/sys/i386/scsi/93cx6.c b/sys/i386/scsi/93cx6.c deleted file mode 100644 index 6a1ecb1..0000000 --- a/sys/i386/scsi/93cx6.c +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Interface for the 93C66/56/46/26/06 serial eeprom parts. - * - * Copyright (c) 1995, 1996 Daniel M. Eischen - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice immediately at the beginning of the file, without modification, - * this list of conditions, and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Absolutely no warranty of function or purpose is made by the author - * Daniel M. Eischen. - * 4. Modifications may be freely made to this file if the above conditions - * are met. - * - * $Id: 93cx6.c,v 1.10 1997/02/22 09:38:36 peter Exp $ - */ - -/* - * The instruction set of the 93C66/56/46/26/06 chips are as follows: - * - * Start OP * - * Function Bit Code Address** Data Description - * ------------------------------------------------------------------- - * READ 1 10 A5 - A0 Reads data stored in memory, - * starting at specified address - * EWEN 1 00 11XXXX Write enable must preceed - * all programming modes - * ERASE 1 11 A5 - A0 Erase register A5A4A3A2A1A0 - * WRITE 1 01 A5 - A0 D15 - D0 Writes register - * ERAL 1 00 10XXXX Erase all registers - * WRAL 1 00 01XXXX D15 - D0 Writes to all registers - * EWDS 1 00 00XXXX Disables all programming - * instructions - * *Note: A value of X for address is a don't care condition. - * **Note: There are 8 address bits for the 93C56/66 chips unlike - * the 93C46/26/06 chips which have 6 address bits. - * - * The 93C46 has a four wire interface: clock, chip select, data in, and - * data out. In order to perform one of the above functions, you need - * to enable the chip select for a clock period (typically a minimum of - * 1 usec, with the clock high and low a minimum of 750 and 250 nsec - * respectively). While the chip select remains high, you can clock in - * the instructions (above) starting with the start bit, followed by the - * OP code, Address, and Data (if needed). For the READ instruction, the - * requested 16-bit register contents is read from the data out line but - * is preceded by an initial zero (leading 0, followed by 16-bits, MSB - * first). The clock cycling from low to high initiates the next data - * bit to be sent from the chip. - * - */ - -#include <sys/param.h> -#include <sys/systm.h> -#if defined(__FreeBSD__) -#include <i386/scsi/93cx6.h> -#elif defined(__NetBSD__) -#include <machine/bus.h> -#include <dev/ic/smc93cx6var.h> -#endif - -/* - * Right now, we only have to read the SEEPROM. But we make it easier to - * add other 93Cx6 functions. - */ -static struct seeprom_cmd { - unsigned char len; - unsigned char bits[3]; -} seeprom_read = {3, {1, 1, 0}}; - -/* - * Wait for the SEERDY to go high; about 800 ns. - */ -#define CLOCK_PULSE(sd, rdy) \ - while ((SEEPROM_INB(sd) & rdy) == 0) { \ - ; /* Do nothing */ \ - } - -/* - * Read the serial EEPROM and returns 1 if successful and 0 if - * not successful. - */ -int -read_seeprom(sd, buf, start_addr, count) - struct seeprom_descriptor *sd; - u_int16_t *buf; -#if defined(__FreeBSD__) - u_int start_addr; - u_int count; -#elif defined(__NetBSD__) - bus_io_size_t start_addr; - bus_io_size_t count; -#endif -{ - int i = 0; - u_int k = 0; - u_int16_t v; - u_int8_t temp; - - /* - * Read the requested registers of the seeprom. The loop - * will range from 0 to count-1. - */ - for (k = start_addr; k < count + start_addr; k++) { - /* Send chip select for one clock cycle. */ - temp = sd->sd_MS ^ sd->sd_CS; - SEEPROM_OUTB(sd, temp ^ sd->sd_CK); - CLOCK_PULSE(sd, sd->sd_RDY); - - /* - * Now we're ready to send the read command followed by the - * address of the 16-bit register we want to read. - */ - for (i = 0; i < seeprom_read.len; i++) { - if (seeprom_read.bits[i] != 0) - temp ^= sd->sd_DO; - SEEPROM_OUTB(sd, temp); - CLOCK_PULSE(sd, sd->sd_RDY); - SEEPROM_OUTB(sd, temp ^ sd->sd_CK); - CLOCK_PULSE(sd, sd->sd_RDY); - if (seeprom_read.bits[i] != 0) - temp ^= sd->sd_DO; - } - /* Send the 6 or 8 bit address (MSB first, LSB last). */ - for (i = (sd->sd_chip - 1); i >= 0; i--) { - if ((k & (1 << i)) != 0) - temp ^= sd->sd_DO; - SEEPROM_OUTB(sd, temp); - CLOCK_PULSE(sd, sd->sd_RDY); - SEEPROM_OUTB(sd, temp ^ sd->sd_CK); - CLOCK_PULSE(sd, sd->sd_RDY); - if ((k & (1 << i)) != 0) - temp ^= sd->sd_DO; - } - - /* - * Now read the 16 bit register. An initial 0 precedes the - * register contents which begins with bit 15 (MSB) and ends - * with bit 0 (LSB). The initial 0 will be shifted off the - * top of our word as we let the loop run from 0 to 16. - */ - v = 0; - for (i = 16; i >= 0; i--) { - SEEPROM_OUTB(sd, temp); - CLOCK_PULSE(sd, sd->sd_RDY); - v <<= 1; - if (SEEPROM_INB(sd) & sd->sd_DI) - v |= 1; - SEEPROM_OUTB(sd, temp ^ sd->sd_CK); - CLOCK_PULSE(sd, sd->sd_RDY); - } - - buf[k - start_addr] = v; - - /* Reset the chip select for the next command cycle. */ - temp = sd->sd_MS; - SEEPROM_OUTB(sd, temp); - CLOCK_PULSE(sd, sd->sd_RDY); - SEEPROM_OUTB(sd, temp ^ sd->sd_CK); - CLOCK_PULSE(sd, sd->sd_RDY); - SEEPROM_OUTB(sd, temp); - CLOCK_PULSE(sd, sd->sd_RDY); - } -#if 0 - printf ("Serial EEPROM:"); - for (k = 0; k < count; k = k + 1) { - if (((k % 8) == 0) && (k != 0)) - { - printf ("\n "); - } - printf (" 0x%x", buf[k]); - } - printf ("\n"); -#endif - return (1); -} diff --git a/sys/i386/scsi/93cx6.h b/sys/i386/scsi/93cx6.h deleted file mode 100644 index a253e75..0000000 --- a/sys/i386/scsi/93cx6.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Interface to the 93C46 serial EEPROM that is used to store BIOS - * settings for the aic7xxx based adaptec SCSI controllers. It can - * also be used for 93C26 and 93C06 serial EEPROMS. - * - * Copyright (c) 1994, 1995 Justin T. Gibbs. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice immediately at the beginning of the file, without modification, - * this list of conditions, and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Absolutely no warranty of function or purpose is made by the author - * Justin T. Gibbs. - * 4. Modifications may be freely made to this file if the above conditions - * are met. - * - * $Id: 93cx6.h,v 1.7 1997/02/22 09:38:37 peter Exp $ - */ - -#include <sys/param.h> -#if !defined(__NetBSD__) -#include <sys/systm.h> -#endif - -typedef enum { - C46 = 6, - C56_66 = 8 -} seeprom_chip_t; - -struct seeprom_descriptor { -#if defined(__FreeBSD__) - u_int32_t sd_iobase; - volatile u_int8_t *sd_maddr; -#elif defined(__NetBSD__) - bus_chipset_tag_t sd_bc; - bus_io_handle_t sd_ioh; - bus_io_size_t sd_offset; -#endif - seeprom_chip_t sd_chip; - u_int16_t sd_MS; - u_int16_t sd_RDY; - u_int16_t sd_CS; - u_int16_t sd_CK; - u_int16_t sd_DO; - u_int16_t sd_DI; -}; - -/* - * This function will read count 16-bit words from the serial EEPROM and - * return their value in buf. The port address of the aic7xxx serial EEPROM - * control register is passed in as offset. The following parameters are - * also passed in: - * - * CS - Chip select - * CK - Clock - * DO - Data out - * DI - Data in - * RDY - SEEPROM ready - * MS - Memory port mode select - * - * A failed read attempt returns 0, and a successful read returns 1. - */ - -#if defined(__FreeBSD__) -#define SEEPROM_INB(sd) \ - (((sd)->sd_maddr != NULL) ? \ - *((sd)->sd_maddr) : \ - inb((sd)->sd_iobase)) -#define SEEPROM_OUTB(sd, value) \ - (((sd)->sd_maddr != NULL) ? \ - (void)(*((sd)->sd_maddr) = (value)) : \ - outb((sd)->sd_iobase, (value))) - -#elif defined(__NetBSD__) -#define SEEPROM_INB(sd) \ - bus_io_read_1(sd->sd_bc, sd->sd_ioh, sd->sd_offset) -#define SEEPROM_OUTB(sd, value) \ - bus_io_write_1(sd->sd_bc, sd->sd_ioh, sd->sd_offset, value) -#endif - -#if defined(__FreeBSD__) -int read_seeprom __P((struct seeprom_descriptor *sd, - u_int16_t *buf, u_int start_addr, u_int count)); -#elif defined(__NetBSD__) -int read_seeprom __P((struct seeprom_descriptor *sd, - u_int16_t *buf, bus_io_size_t start_addr, bus_io_size_t count)); -#endif diff --git a/sys/i386/scsi/advansys.c b/sys/i386/scsi/advansys.c deleted file mode 100644 index e48362e..0000000 --- a/sys/i386/scsi/advansys.c +++ /dev/null @@ -1,783 +0,0 @@ -/* - * Generic driver for the Advanced Systems Inc. SCSI controllers - * Product specific probe and attach routines can be found in: - * - * i386/isa/adv_isa.c ABP5140, ABP542, ABP5150, ABP842, ABP852 - * - * Copyright (c) 1996 Justin T. Gibbs. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice immediately at the beginning of the file, without modification, - * this list of conditions, and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id$ - */ -/* - * Ported from: - * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters - * - * Copyright (c) 1995-1996 Advanced System Products, Inc. - * All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that redistributions of source - * code retain the above copyright notice and this comment without - * modification. - */ - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/malloc.h> -#include <sys/buf.h> - -#include <machine/clock.h> - -#include <scsi/scsi_all.h> -#include <scsi/scsi_message.h> -#include <scsi/scsiconf.h> - -#include <vm/vm.h> -#include <vm/vm_param.h> -#include <vm/pmap.h> - -#include <i386/scsi/advansys.h> - -static void adv_scsi_cmd __P((struct scsi_xfer *xs)); -static void advminphys __P((struct buf *bp)); -static timeout_t - adv_timeout; -static int adv_qdone __P((struct adv_softc *adv)); -static void adv_done __P((struct adv_softc *adv, - struct adv_q_done_info *qdonep)); -static int adv_poll __P((struct adv_softc *ahc, struct scsi_xfer *xs)); - -struct adv_softc *advsoftcs[NADV]; /* XXX Config should handle this */ - -static struct scsi_adapter adv_switch = -{ - adv_scsi_cmd, - advminphys, - NULL, - NULL, - "adv" -}; - -static void -adv_scsi_cmd(xs) - struct scsi_xfer *xs; -{ - struct adv_softc *adv; - struct adv_scsi_q scsiq; - struct adv_sg_head sghead; - - SC_DEBUG(xs->sc_link, SDEV_DB2, ("adv_scsi_cmd\n")); - - adv = (struct adv_softc *)xs->sc_link->scsibus->adpt_link.adpt_softc; - - /* - * Build up the request - */ - scsiq.q1.cntl = 0; - scsiq.q1.sg_queue_cnt = 0; - scsiq.q1.status = 0; - scsiq.q1.q_no = 0; - scsiq.q1.target_id = ADV_TID_TO_TARGET_ID(xs->sc_link->target); - scsiq.q1.target_lun = xs->sc_link->lun; - scsiq.q1.sense_addr = (u_int32_t)vtophys(&xs->sense); - scsiq.q1.sense_len = sizeof(xs->sense); - scsiq.q1.data_cnt = 0; - scsiq.q1.data_addr = 0; - scsiq.q1.user_def = 0; - scsiq.q2.xs_ptr = (u_int32_t)xs; - scsiq.q2.target_ix = ADV_TIDLUN_TO_IX(xs->sc_link->target, xs->sc_link->lun); - scsiq.q2.flag = 0; - scsiq.q2.cdb_len = xs->cmdlen; - scsiq.q2.tag_code = xs->tag_type; - scsiq.q2.vm_id = 0; - scsiq.sg_head = NULL; - scsiq.cdbptr = &xs->cmd; - - if (xs->datalen) { - /* - * Determin the number of segments needed for this - * transfer. We should only use SG if we need more - * than one. - */ - int seg; - u_int32_t datalen; - vm_offset_t vaddr; - u_int32_t paddr; - u_int32_t nextpaddr; - struct adv_sg_entry *sg; - - seg = 0; - datalen = xs->datalen; - vaddr = (vm_offset_t)xs->data; - paddr = vtophys(vaddr); - sg = &sghead.sg_list[0]; - - while ((datalen > 0) && (seg < ADV_MAX_SG_LIST)) { - /* put in the base address and length */ - sg->addr = paddr; - sg->bytes = 0; - - /* do it at least once */ - nextpaddr = paddr; - - while ((datalen > 0) && (paddr == nextpaddr)) { - u_int32_t size; - /* - * This page is contiguous (physically) - * with the the last, just extend the - * length - */ - /* how far to the end of the page */ - nextpaddr = (paddr & (~PAGE_MASK)) + PAGE_SIZE; - - /* - * Compute the maximum size - */ - size = nextpaddr - paddr; - if (size > datalen) - size = datalen; - - sg->bytes += size; - vaddr += size; - datalen -= size; - if (datalen > 0) - paddr = vtophys(vaddr); - } - /* - * next page isn't contiguous, finish the seg - */ - seg++; - sg++; - } - if (seg > 1) { - scsiq.q1.cntl |= QC_SG_HEAD; - scsiq.sg_head = &sghead; - sghead.entry_cnt = sghead.entry_to_copy = seg; - sghead.res = 0; - } - scsiq.q1.data_addr = sghead.sg_list[0].addr; - scsiq.q1.data_cnt = sghead.sg_list[0].bytes; - } - - if (adv_execute_scsi_queue(adv, &scsiq) != 0) { - xs->error = XS_QUEUE_RESOURCE_SHORTAGE; - scsi_done(xs); - } else if ((xs->flags & SCSI_POLL) != 0) { - /* - * If we can't use interrupts, poll for completion - */ - int s; - - s = splbio(); - if (adv_poll(adv, xs)) { - if (!(xs->flags & SCSI_SILENT)) - printf("cmd fail\n"); - adv_timeout(xs); - } - splx(s); - } -} - - -static void -advminphys(bp) - struct buf *bp; -{ - if (bp->b_bcount > ((ADV_MAX_SG_LIST - 1) * PAGE_SIZE)) - bp->b_bcount = ((ADV_MAX_SG_LIST - 1) * PAGE_SIZE); -} - -static void -adv_timeout(arg) - void *arg; -{ - printf("adv: Ooops. Had a timeout\n"); -} - -struct adv_softc * -adv_alloc(unit, iobase) - int unit; - u_long iobase; -{ - struct adv_softc *adv; - int i; - - if (unit >= NADV) { - printf("adv: unit number (%d) too high\n", unit); - return NULL; - } - - /* - * Allocate a storage area for us - */ - if (advsoftcs[unit]) { - printf("adv%d: memory already allocated\n", unit); - return NULL; - } - - adv = malloc(sizeof(struct adv_softc), M_DEVBUF, M_NOWAIT); - if (!adv) { - printf("adv%d: cannot malloc!\n", unit); - return NULL; - } - bzero(adv, sizeof(struct adv_softc)); - advsoftcs[unit] = adv; - adv->unit = unit; - adv->iobase = iobase; - - /* Set reasonable defaults incase we can't read the EEPROM */ - adv->max_openings = ADV_DEF_MAX_TOTAL_QNG; - adv->start_motor = TARGET_BIT_VECTOR_SET; - adv->disc_enable = TARGET_BIT_VECTOR_SET; - adv->cmd_qng_enabled = TARGET_BIT_VECTOR_SET; - adv->scsi_id = 7; - - for (i = 0; i <= ADV_MAX_TID; i++) - adv->sdtr_data[i] = ADV_DEF_SDTR_OFFSET | (ADV_DEF_SDTR_INDEX << 4); - - return(adv); -} - -void -adv_free(adv) - struct adv_softc *adv; -{ - if (adv->sense_buffers != NULL) - free(adv->sense_buffers, M_DEVBUF); - free(adv, M_DEVBUF); -} - -int -adv_init(adv) - struct adv_softc *adv; -{ - struct adv_eeprom_config eeprom_config; - int checksum, i; - u_int16_t config_lsw; - u_int16_t config_msw; - - adv_get_board_type(adv); - - /* - * Stop script execution. - */ - adv_write_lram_16(adv, ADV_HALTCODE_W, 0x00FE); - adv_stop_execution(adv); - adv_reset_chip_and_scsi_bus(adv); - /* - * The generic SCSI code does a minimum delay for us - * already. - */ - /* DELAY(3 * 1000 * 1000);*/ /* 3 Second Delay */ - if (adv_is_chip_halted(adv) == 0) { - printf("adv%d: Unable to halt adapter. Initialization" - "failed\n", adv->unit); - return (1); - } - ADV_OUTW(adv, ADV_REG_PROG_COUNTER, ADV_MCODE_START_ADDR); - if (ADV_INW(adv, ADV_REG_PROG_COUNTER) != ADV_MCODE_START_ADDR) { - printf("adv%d: Unable to set program counter. Initialization" - "failed\n", adv->unit); - return (1); - } - - config_lsw = ADV_INW(adv, ADV_CONFIG_LSW); - config_msw = ADV_INW(adv, ADV_CONFIG_MSW); - -#if 0 - /* XXX Move to PCI probe code */ - if (adv->type & ADV_PCI) { -#if CC_DISABLE_PCI_PARITY_INT - config_msw &= 0xFFC0; - ADV_OUTW(adv, ADV_CONFIG_MSW, config_msw); -#endif - - if (asc_dvc->cfg->pci_device_id == ASC_PCI_DEVICE_ID_REV_A) { - asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ADD_ONE_BYTE; - } - } -#endif - if ((config_msw & ADV_CFG_MSW_CLR_MASK) != 0) { - config_msw &= (~(ADV_CFG_MSW_CLR_MASK)); - /* - * XXX The Linux code flags this as an error, - * but what should we report to the user??? - * It seems that clearing the config register - * makes this error recoverable. - */ - ADV_OUTW(adv, ADV_CONFIG_MSW, config_msw); - } - - /* Suck in the configuration from the EEProm */ - checksum = adv_get_eeprom_config(adv, &eeprom_config); - - eeprom_config.cfg_msw &= (~(ADV_CFG_MSW_CLR_MASK)); - - if (ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_AUTO_CONFIG) { - /* - * XXX The Linux code sets a warning level for this - * condition, yet nothing of meaning is printed to - * the user. What does this mean??? - */ - if (adv->chip_version == 3) { - if (eeprom_config.cfg_lsw != config_lsw) { - /* XXX Yet another supposed Warning */ - eeprom_config.cfg_lsw = - ADV_INW(adv, ADV_CONFIG_LSW); - } - if (eeprom_config.cfg_msw != config_msw) { - /* XXX Yet another supposed Warning */ - eeprom_config.cfg_msw = - ADV_INW(adv, ADV_CONFIG_MSW); - } - } - } - eeprom_config.cfg_lsw |= ADV_CFG_LSW_HOST_INT_ON; - if (checksum == eeprom_config.chksum) { - if (adv_test_external_lram(adv) == 0) { - if (adv->type & ADV_PCI) { - eeprom_config.cfg_msw |= 0x0800; - config_msw |= 0x0800; - ADV_OUTW(adv, ADV_CONFIG_MSW, config_msw); - eeprom_config.max_total_qng = ADV_MAX_PCI_INRAM_TOTAL_QNG; - eeprom_config.max_tag_qng = ADV_MAX_INRAM_TAG_QNG; - } - } - /* XXX What about wide bussed cards?? */ - for (i = 0; i <= 7; i++) - adv->sdtr_data[i] = eeprom_config.sdtr_data[i]; - - /* Range/Sanity checking */ - if (eeprom_config.max_total_qng < ADV_MIN_TOTAL_QNG) { - eeprom_config.max_total_qng = ADV_MIN_TOTAL_QNG; - } - if (eeprom_config.max_total_qng > ADV_MAX_TOTAL_QNG) { - eeprom_config.max_total_qng = ADV_MAX_TOTAL_QNG; - } - if (eeprom_config.max_tag_qng > eeprom_config.max_total_qng) { - eeprom_config.max_tag_qng = eeprom_config.max_total_qng; - } - if (eeprom_config.max_tag_qng < ADV_MIN_TAG_Q_PER_DVC) { - eeprom_config.max_tag_qng = ADV_MIN_TAG_Q_PER_DVC; - } - adv->max_openings = eeprom_config.max_total_qng; - - if ((eeprom_config.use_cmd_qng & eeprom_config.disc_enable) != - eeprom_config.use_cmd_qng) { - eeprom_config.disc_enable |= eeprom_config.use_cmd_qng; - printf("adv:%d: WARNING! One or more targets with tagged " - "queuing enabled have the disconnection priveledge " - "disabled.\n" - "adv:%d: Overriding disconnection settings to " - "allow tagged queueing devices to disconnect.\n ", - adv->unit, adv->unit); - } -#if 0 - /* - * XXX We should range check our target ID - * based on the width of our bus - */ - EEPROM_SET_SCSIID(eeprom_config, - EEPROM_SCSIID(eeprom_config) & ADV_MAX_TID); -#endif - adv->initiate_sdtr = eeprom_config.init_sdtr; - adv->disc_enable = eeprom_config.disc_enable; - adv->cmd_qng_enabled = eeprom_config.use_cmd_qng; - adv->isa_dma_speed = EEPROM_DMA_SPEED(eeprom_config); - adv->scsi_id = EEPROM_SCSIID(eeprom_config); - adv->start_motor = eeprom_config.start_motor; - adv->control = eeprom_config.cntl; - adv->no_scam = eeprom_config.no_scam; - } else { - /* - * Use the defaults that adv was initialized with. - */ - /* - * XXX Fixup EEPROM with default values??? - */ - printf("adv%d: Warning EEPROM Checksum mismatch. " - "Using default device parameters\n", adv->unit); - } - -#if 0 - /* XXX Do this in the PCI probe */ - if ((adv->btype & ADV_PCI) && - !(asc_dvc->dvc_cntl & ASC_CNTL_NO_PCI_FIX_ASYN_XFER)) { - if ((asc_dvc->cfg->pci_device_id == ASC_PCI_DEVICE_ID_REV_A) || - (asc_dvc->cfg->pci_device_id == ASC_PCI_DEVICE_ID_REV_B)) { - asc_dvc->pci_fix_asyn_xfer = ASC_ALL_DEVICE_BIT_SET; - } - } -#endif - if (adv_set_eeprom_config(adv, &eeprom_config) != 0) - printf("adv:%d: WARNING! Failure writing to EEPROM.\n"); - - /* Allocate space for our sense buffers */ - /* XXX this should really be done by the generic SCSI layer by ensuring - * that all scsi_xfer structs are allocated below 16M if any controller - * needs to bounce. - */ - if (adv->type & ADV_ISA) { - adv->sense_buffers = (struct scsi_sense_data *)contigmalloc(sizeof(struct scsi_sense_data) * adv->max_openings, - M_DEVBUF, M_NOWAIT, 0ul, 0xfffffful, 1ul, - 0x10000ul); - if (adv->sense_buffers == NULL) { - printf("adv%d: Unable to allocate sense buffer space.\n"); - return (1); - } - - } - - if (adv_init_lram_and_mcode(adv)) - return (1); - - return (0); -} - -void -adv_intr(arg) - void *arg; -{ - struct adv_softc *adv; - u_int16_t chipstat; - u_int16_t saved_ram_addr; - u_int8_t ctrl_reg; - u_int8_t saved_ctrl_reg; - int status; - u_int8_t host_flag; - - adv = (struct adv_softc *)arg; - - ctrl_reg = ADV_INB(adv, ADV_CHIP_CTRL); - saved_ctrl_reg = ctrl_reg & (~(ADV_CC_SCSI_RESET | ADV_CC_CHIP_RESET | - ADV_CC_SINGLE_STEP | ADV_CC_DIAG | ADV_CC_TEST)); - - - if ((chipstat = ADV_INW(adv, ADV_CHIP_STATUS)) & ADV_CSW_INT_PENDING) { - - adv_ack_interrupt(adv); - - host_flag = adv_read_lram_8(adv, ADVV_HOST_FLAG_B); - adv_write_lram_8(adv, ADVV_HOST_FLAG_B, - host_flag | ADV_HOST_FLAG_IN_ISR); - saved_ram_addr = ADV_INW(adv, ADV_LRAM_ADDR); - - if ((chipstat & ADV_CSW_HALTED) - && (ctrl_reg & ADV_CC_SINGLE_STEP)) { - adv_isr_chip_halted(adv); - saved_ctrl_reg &= ~ADV_CC_HALT; - } else { - if ((adv->control & ADV_CNTL_INT_MULTI_Q) != 0) { - while (((status = adv_qdone(adv)) & 0x01) != 0) - ; - } else { - do { - status = adv_qdone(adv); - } while (status == 0x11); - } - } - ADV_OUTW(adv, ADV_LRAM_ADDR, saved_ram_addr); -#ifdef DIAGNOSTIC - if (ADV_INW(adv, ADV_LRAM_ADDR) != saved_ram_addr) - panic("adv_intr: Unable to set LRAM addr"); -#endif - adv_write_lram_8(adv, ADVV_HOST_FLAG_B, host_flag); - } - - ADV_OUTB(adv, ADV_CHIP_CTRL, saved_ctrl_reg); -} - -int -adv_qdone(adv) - struct adv_softc *adv; -{ - u_int8_t next_qp; - u_int8_t i; - u_int8_t n_q_used; - u_int8_t sg_list_qp; - u_int8_t sg_queue_cnt; - u_int8_t done_q_tail; - u_int8_t tid_no; - target_bit_vector target_id; - u_int16_t q_addr; - u_int16_t sg_q_addr; - struct adv_q_done_info scsiq_buf; - struct adv_q_done_info *scsiq; - int false_overrun; - u_int8_t tag_code; - - n_q_used = 1; - scsiq = &scsiq_buf; - done_q_tail = adv_read_lram_16(adv, ADVV_DONE_Q_TAIL_W) & 0xFF; - q_addr = ADV_QNO_TO_QADDR(done_q_tail); - next_qp = adv_read_lram_8(adv, q_addr + ADV_SCSIQ_B_FWD); - if (next_qp != ADV_QLINK_END) { - adv_write_lram_16(adv, ADVV_DONE_Q_TAIL_W, next_qp); - q_addr = ADV_QNO_TO_QADDR(next_qp); - - sg_queue_cnt = adv_copy_lram_doneq(adv, q_addr, scsiq, adv->max_dma_count); - - adv_write_lram_8(adv, q_addr + ADV_SCSIQ_B_STATUS, - scsiq->q_status & ~(QS_READY | QS_ABORTED)); - tid_no = ADV_TIX_TO_TID(scsiq->d2.target_ix); - target_id = ADV_TIX_TO_TARGET_ID(scsiq->d2.target_ix); - if ((scsiq->cntl & QC_SG_HEAD) != 0) { - sg_q_addr = q_addr; - sg_list_qp = next_qp; - for (i = 0; i < sg_queue_cnt; i++) { - sg_list_qp = adv_read_lram_8(adv, - sg_q_addr + ADV_SCSIQ_B_FWD); - sg_q_addr = ADV_QNO_TO_QADDR(sg_list_qp); -#ifdef DIAGNOSTIC - if (sg_list_qp == ASC_QLINK_END) { - panic("adv_qdone: Corrupted SG list encountered"); - } -#endif - adv_write_lram_8(adv, sg_q_addr + ADV_SCSIQ_B_STATUS, - QS_FREE); - } - - n_q_used = sg_queue_cnt + 1; - adv_write_lram_16(adv, ADVV_DONE_Q_TAIL_W, sg_list_qp); - } -#if 0 - /* XXX Fix later */ - if (adv->queue_full_or_busy & target_id) { - cur_target_qng = adv_read_lram_8(adv, - ADV_QADR_BEG + scsiq->d2.target_ix); - if (cur_target_qng < adv->max_dvc_qng[tid_no]) { - scsi_busy = adv_read_lram_8(adv, ADVV_SCSIBUSY_B); - scsi_busy &= ~target_id; - adv_write_lram_8(adv, ADVV_SCSIBUSY_B, scsi_busy); - adv->queue_full_or_busy &= ~target_id; - } - } -#endif -#ifdef DIAGNOSTIC - if (adv->cur_total_qng < n_q_used) - panic("adv_qdone: Attempting to free more queues than are active"); -#endif - adv->cur_active -= n_q_used; - - if ((scsiq->d2.xs_ptr == 0) || - ((scsiq->q_status & QS_ABORTED) != 0)) - return (0x11); - else if (scsiq->q_status == QS_DONE) { - - false_overrun = FALSE; - - if (adv->bug_fix_control & ADV_BUG_FIX_ADD_ONE_BYTE) { - tag_code = adv_read_lram_8(adv, q_addr + ADV_SCSIQ_B_TAG_CODE); - if (tag_code & ADV_TAG_FLAG_ADD_ONE_BYTE) { - if (scsiq->remain_bytes != 0) { - scsiq->remain_bytes--; - if (scsiq->remain_bytes == 0) - false_overrun = TRUE; - } - } - } - if ((scsiq->d3.done_stat == QD_WITH_ERROR) && - (scsiq->d3.host_stat == QHSTA_M_DATA_OVER_RUN)) { - if ((scsiq->cntl & (QC_DATA_IN | QC_DATA_OUT)) == 0) { - scsiq->d3.done_stat = QD_NO_ERROR; - scsiq->d3.host_stat = QHSTA_NO_ERROR; - } else if (false_overrun) { - scsiq->d3.done_stat = QD_NO_ERROR; - scsiq->d3.host_stat = QHSTA_NO_ERROR; - } - } - - if ((scsiq->cntl & QC_NO_CALLBACK) == 0) - adv_done(adv, scsiq); - else { - if ((adv_read_lram_8(adv, q_addr + ADV_SCSIQ_CDB_BEG) == - START_STOP)) { - adv->unit_not_ready &= ~target_id; - if (scsiq->d3.done_stat != QD_NO_ERROR) - adv->start_motor &= ~target_id; - } - } - return (1); - } else { - panic("adv_qdone: completed scsiq with unknown status"); -#if 0 - /* - * XXX Doesn't this simply indicate a software bug? - * What does setting the lram error code do for - * you. Would we even recover? - */ - AscSetLibErrorCode(asc_dvc, ASCQ_ERR_Q_STATUS); - - FATAL_ERR_QDONE: - if ((scsiq->cntl & QC_NO_CALLBACK) == 0) { - (*asc_isr_callback) (asc_dvc, scsiq); - } - return (0x80); -#endif - } - } - return (0); -} - - -void -adv_done(adv, qdonep) - struct adv_softc *adv; - struct adv_q_done_info *qdonep; -{ - struct scsi_xfer *xs; - - xs = (struct scsi_xfer *)qdonep->d2.xs_ptr; - - xs->status = qdonep->d3.scsi_stat; - /* - * 'qdonep' contains the command's ending status. - */ - switch (qdonep->d3.done_stat) { - case QD_NO_ERROR: - switch (qdonep->d3.host_stat) { - case QHSTA_NO_ERROR: - break; - case QHSTA_M_SEL_TIMEOUT: - xs->error = XS_SELTIMEOUT; - break; - default: - /* QHSTA error occurred */ -#if 0 - /* XXX Can I get more explicit information here? */ - xs->error = XS_DRIVER_STUFFUP; -#endif - break; - } - break; - - case QD_WITH_ERROR: - switch (qdonep->d3.host_stat) { - case QHSTA_NO_ERROR: - if ((qdonep->d3.scsi_stat == STATUS_CHECK_CONDITION) - || (qdonep->d3.scsi_stat == STATUS_COMMAND_TERMINATED)) { - /* We have valid sense information to return */ - xs->error = XS_SENSE; - if (adv->sense_buffers != NULL) - /* Structure copy */ - xs->sense = adv->sense_buffers[qdonep->q_no]; - } - break; - case QHSTA_M_SEL_TIMEOUT: - xs->error = XS_SELTIMEOUT; - break; - default: -#if 0 - /* XXX Can I get more explicit information here? */ - xs->error = XS_DRIVER_STUFFUP; -#endif - break; - } - break; - - case QD_ABORTED_BY_HOST: - /* XXX Should have an explicit ABORTED error code */ - xs->error = XS_ABORTED; - break; - - default: -#if 0 - printf("adv_done: Unknown done status 0x%x\n", - qdonep->d3.done_stat); - xs->error = XS_DRIVER_STUFFUP; -#endif - break; - } - xs->flags |= SCSI_ITSDONE; - scsi_done(xs); - return; -} - -/* - * Function to poll for command completion when - * interrupts are disabled (crash dumps) - */ -static int -adv_poll(adv, xs) - struct adv_softc *adv; - struct scsi_xfer *xs; -{ - int wait; - - wait = xs->timeout; - do { - DELAY(1000); - adv_intr((void *)adv); - } while (--wait && ((xs->flags & SCSI_ITSDONE) == 0)); - if (wait == 0) { - printf("adv%d: board is not responding\n", adv->unit); - return (EIO); - } - return (0); -} - -/* - * Attach all the sub-devices we can find - */ -int -adv_attach(adv) - struct adv_softc *adv; -{ - struct scsi_bus *scbus; - struct scsi_queue *scsiq; - - scsiq = scsi_alloc_queue(adv->max_openings); - if (scsiq == NULL) - return 0; - - /* - * Prepare the scsi_bus area for the upperlevel scsi code. - */ - scbus = scsi_alloc_bus(&adv_switch, adv, adv->unit, scsiq); - if (scbus == NULL) { - scsi_free_queue(scsiq); - return 0; - } - - /* Override defaults */ - if ((adv->type & ADV_ISA) != 0) - scbus->adpt_link.adpt_flags |= SADPT_BOUNCE; - scbus->adpt_link.adpt_target = adv->scsi_id; - scbus->adpt_link.adpt_openings = 2; /* XXX Is this correct for these cards? */ - scbus->adpt_link.adpt_tagged_openings = adv->max_openings; - - /* - * ask the adapter what subunits are present - */ - if(bootverbose) - printf("adv%d: Probing SCSI bus\n", adv->unit); - - scsi_attachdevs(scbus); - - return 1; -} diff --git a/sys/i386/scsi/advansys.h b/sys/i386/scsi/advansys.h deleted file mode 100644 index 47bca6a..0000000 --- a/sys/i386/scsi/advansys.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Generic driver for the Advanced Systems Inc. SCSI controllers - * Product specific probe and attach routines can be found in: - * - * XXX Fill this in. - * - * Copyright (c) 1996 Justin T. Gibbs. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice immediately at the beginning of the file, without modification, - * this list of conditions, and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id$ - */ - -#ifndef _ADVANSYS_H_ -#define _ADVANSYS_H_ - -#include "adv.h" -#include <dev/advansys/advlib.h> - -struct adv_softc * adv_alloc __P((int unit, u_long iobase)); -void adv_free __P((struct adv_softc *adv)); -int adv_init __P((struct adv_softc *adv)); -void adv_intr __P((void *arg)); -int adv_attach __P((struct adv_softc *adv)); - -extern struct adv_softc *advsoftcs[NADV]; /* XXX Config should handle this */ -#endif /* _ADVANSYS_H_ */ diff --git a/sys/i386/scsi/aic7xxx.c b/sys/i386/scsi/aic7xxx.c deleted file mode 100644 index 4ded5b5..0000000 --- a/sys/i386/scsi/aic7xxx.c +++ /dev/null @@ -1,3867 +0,0 @@ -/* - * Generic driver for the aic7xxx based adaptec SCSI controllers - * Product specific probe and attach routines can be found in: - * i386/eisa/aic7770.c 27/284X and aic7770 motherboard controllers - * pci/aic7870.c 3940, 2940, aic7880, aic7870, aic7860, - * and aic7850 controllers - * - * Copyright (c) 1994-1997 Justin Gibbs. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification, immediately at the beginning of the file. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * Where this Software is combined with software released under the terms of - * the GNU Public License ("GPL") and the terms of the GPL would require the - * combined work to also be released under the terms of the GPL, the terms - * and conditions of this License will apply in addition to those of the - * GPL with the exception of any terms or conditions of this License that - * conflict with, or are expressly prohibited by, the GPL. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id: aic7xxx.c,v 1.126 1997/09/27 19:38:27 gibbs Exp $ - */ -/* - * TODO: - * Implement Target Mode - * - * A few notes on features of the driver. - * - * SCB paging takes advantage of the fact that devices stay disconnected - * from the bus a relatively long time and that while they're disconnected, - * having the SCBs for these transactions down on the host adapter is of - * little use. Instead of leaving this idle SCB down on the card we copy - * it back up into kernel memory and reuse the SCB slot on the card to - * schedule another transaction. This can be a real payoff when doing random - * I/O to tagged queueing devices since there are more transactions active at - * once for the device to sort for optimal seek reduction. The algorithm goes - * like this... - * - * The sequencer maintains two lists of its hardware SCBs. The first is the - * singly linked free list which tracks all SCBs that are not currently in - * use. The second is the doubly linked disconnected list which holds the - * SCBs of transactions that are in the disconnected state sorted most - * recently disconnected first. When the kernel queues a transaction to - * the card, a hardware SCB to "house" this transaction is retrieved from - * either of these two lists. If the SCB came from the disconnected list, - * a check is made to see if any data transfer or SCB linking (more on linking - * in a bit) information has been changed since it was copied from the host - * and if so, DMAs the SCB back up before it can be used. Once a hardware - * SCB has been obtained, the SCB is DMAed from the host. Before any work - * can begin on this SCB, the sequencer must ensure that either the SCB is - * for a tagged transaction or the target is not already working on another - * non-tagged transaction. If a conflict arises in the non-tagged case, the - * sequencer finds the SCB for the active transactions and sets the SCB_LINKED - * field in that SCB to this next SCB to execute. To facilitate finding - * active non-tagged SCBs, the last four bytes of up to the first four hardware - * SCBs serve as a storage area for the currently active SCB ID for each - * target. - * - * When a device reconnects, a search is made of the hardware SCBs to find - * the SCB for this transaction. If the search fails, a hardware SCB is - * pulled from either the free or disconnected SCB list and the proper - * SCB is DMAed from the host. If the SCB_ABORTED control bit is set - * in the control byte of the SCB while it was disconnected, the sequencer - * will send an abort or abort tag message to the target during the - * reconnection and signal the kernel that the abort was successfull. - * - * When a command completes, a check for non-zero status and residuals is - * made. If either of these conditions exists, the SCB is DMAed back up to - * the host so that it can interpret this information. Additionally, in the - * case of bad status, the sequencer generates a special interrupt and pauses - * itself. This allows the host to setup a request sense command if it - * chooses for this target synchronously with the error so that sense - * information isn't lost. - * - */ - -#include <sys/param.h> -#include <sys/systm.h> -#if defined(__NetBSD__) -#include <sys/device.h> -#include <machine/bus.h> -#include <machine/intr.h> -#endif /* defined(__NetBSD__) */ - -#include <sys/malloc.h> -#include <sys/buf.h> - -#include <scsi/scsi_message.h> -#if defined(__NetBSD__) -#include <scsi/scsi_debug.h> -#endif -#include <scsi/scsiconf.h> -#include <scsi/scsi_debug.h> - -#if defined(__FreeBSD__) -#include <machine/clock.h> -#endif - -#include <vm/vm.h> -#include <vm/pmap.h> - -#if defined(__FreeBSD__) -#include <i386/scsi/aic7xxx.h> -#include <dev/aic7xxx/sequencer.h> -#include <aic7xxx_reg.h> -#include <aic7xxx_seq.h> -#endif /* defined(__FreeBSD__) */ - -#if defined(__NetBSD__) -#include <dev/ic/aic7xxxreg.h> -#include <dev/ic/aic7xxxvar.h> - -#define bootverbose 1 - -#if DEBUGTARGET < 0 /* Negative numbers for disabling cause warnings */ -#define DEBUGTARGET 17 -#endif -#endif /* defined(__NetBSD__) */ - -#include <sys/kernel.h> - -#define MAX(a,b) (((a) > (b)) ? (a) : (b)) -#define MIN(a,b) (((a) < (b)) ? (a) : (b)) -#define ALL_TARGETS -1 -#define ALL_LUNS -1 -#define ALL_CHANNELS '\0' - -#if defined(__FreeBSD__) -u_long ahc_unit = 0; -#endif - -#ifdef AHC_DEBUG -static int ahc_debug = AHC_DEBUG; -#endif - -#ifdef AHC_BROKEN_CACHE -int ahc_broken_cache = 1; - -/* - * "wbinvd" cause writing back whole cache (both CPU internal & external) - * to memory, so that the instruction takes a lot of time. - * This makes machine slow. - */ -#define INVALIDATE_CACHE() __asm __volatile("wbinvd") -#endif - -/**** bit definitions for SCSIDEF ****/ -#define HSCSIID 0x07 /* our SCSI ID */ -#define HWSCSIID 0x0f /* our SCSI ID if Wide Bus */ - -static void ahcminphys __P((struct buf *bp)); -static int32_t ahc_scsi_cmd __P((struct scsi_xfer *xs)); -static void ahc_run_waiting_queue __P((struct ahc_softc *ahc)); -static struct scb * - ahc_get_scb __P((struct ahc_softc *ahc, u_int32_t flags)); -static void ahc_free_scb __P((struct ahc_softc *ahc, struct scb *scb)); -static struct scb * - ahc_alloc_scb __P((struct ahc_softc *ahc)); -static __inline void pause_sequencer __P((struct ahc_softc *ahc)); -static __inline void unpause_sequencer __P((struct ahc_softc *ahc, - int unpause_always)); -static __inline void restart_sequencer __P((struct ahc_softc *ahc)); - -#define AHC_BUSRESET_DELAY 1000 /* Reset delay in us */ - -static struct scsi_adapter ahc_switch = -{ - ahc_scsi_cmd, - ahcminphys, - NULL, - NULL, -#if defined(__FreeBSD__) - NULL, - "ahc", - { 0, 0 } -#endif -}; - -static struct scsi_device ahc_dev = -{ - NULL, /* Use default error handler */ - NULL, /* have a queue, served by this */ - NULL, /* have no async handler */ - NULL, /* Use default 'done' routine */ -#if defined(__FreeBSD__) - "ahc", - 0, - { 0, 0 } -#endif -}; - -static __inline void -pause_sequencer(ahc) - struct ahc_softc *ahc; -{ - ahc_outb(ahc, HCNTRL, ahc->pause); - - /* - * Since the sequencer can disable pausing in a critical section, we - * must loop until it actually stops. - */ - while ((ahc_inb(ahc, HCNTRL) & PAUSE) == 0) - ; -} - -static __inline void -unpause_sequencer(ahc, unpause_always) - struct ahc_softc *ahc; - int unpause_always; -{ - if (unpause_always - || (ahc_inb(ahc, INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) == 0) - ahc_outb(ahc, HCNTRL, ahc->unpause); -} - -/* - * Restart the sequencer program from address zero - */ -static __inline void -restart_sequencer(ahc) - struct ahc_softc *ahc; -{ - pause_sequencer(ahc); - ahc_outb(ahc, SEQCTL, SEQRESET|FASTMODE); - unpause_sequencer(ahc, /*unpause_always*/TRUE); -} - -#if defined(__FreeBSD__) -#define IS_SCSIBUS_B(ahc, sc_link) \ - (((u_int32_t)((sc_link)->fordriver) & SELBUSB) != 0) -#else /* NetBSD/OpenBSD */ -#define IS_SCSIBUS_B(ahc, sc_link) \ - ((sc_link)->scsibus == (ahc)->sc_link_b.scsibus) -#endif - -#define SCB_TARGET(scb) \ - (((scb)->hscb->tcl & TID) >> 4) -#define SCB_LUN(scb) \ - ((scb)->hscb->tcl & LID) -#define SCB_IS_SCSIBUS_B(scb) \ - (((scb)->hscb->tcl & SELBUSB) != 0) - -static u_int8_t ahc_abort_wscb __P((struct ahc_softc *ahc, struct scb *scbp, - u_int8_t scbpos, u_int8_t prev, - u_int32_t xs_error)); -static void ahc_done __P((struct ahc_softc *ahc, struct scb *scbp)); -static void ahc_handle_seqint __P((struct ahc_softc *ahc, u_int8_t intstat)); -static void ahc_handle_scsiint __P((struct ahc_softc *ahc, - u_int8_t intstat)); -static void ahc_handle_devreset __P((struct ahc_softc *ahc, - int target, char channel)); -static void ahc_loadseq __P((struct ahc_softc *ahc)); -static struct patch * - ahc_next_patch __P((struct patch *cur_patch, int options, - int instrptr)); -static void ahc_download_instr(struct ahc_softc *ahc, int options, - int instrptr, u_int8_t *dconsts); -static int ahc_match_scb __P((struct scb *scb, int target, char channel, - int lun, u_int8_t tag)); -static int ahc_poll __P((struct ahc_softc *ahc, int wait)); -#ifdef AHC_DEBUG -static void ahc_print_scb __P((struct scb *scb)); -#endif -static u_int8_t ahc_find_scb __P((struct ahc_softc *ahc, struct scb *scb)); -static int ahc_search_qinfifo __P((struct ahc_softc *ahc, int target, - char channel, int lun, u_int8_t tag, - u_int32_t flags, u_int32_t xs_error, - int requeue)); -static int ahc_reset_channel __P((struct ahc_softc *ahc, char channel, - u_int32_t xs_error, int initiate_reset)); -static int ahc_reset_device __P((struct ahc_softc *ahc, int target, - char channel, int lun, u_int8_t tag, - u_int32_t xs_error)); -static u_int8_t ahc_rem_scb_from_disc_list __P((struct ahc_softc *ahc, - u_int8_t scbptr)); -static void ahc_add_curscb_to_free_list __P((struct ahc_softc *ahc)); -static void ahc_clear_intstat __P((struct ahc_softc *ahc)); -static void ahc_reset_current_bus __P((struct ahc_softc *ahc)); -static void ahc_run_done_queue __P((struct ahc_softc *ahc)); -static void ahc_untimeout_done_queue __P((struct ahc_softc *ahc)); -static void ahc_scsirate __P((struct ahc_softc* ahc, u_int8_t *scsirate, - u_int8_t *period, u_int8_t *offset, - char channel, int target)); -#if defined(__FreeBSD__) -static timeout_t - ahc_timeout; -#elif defined(__NetBSD__) -static void ahc_timeout __P((void *)); -#endif - -static u_int8_t ahc_index_busy_target __P((struct ahc_softc *ahc, int target, - char channel, int unbusy)); - -static void ahc_busy_target __P((struct ahc_softc *ahc, int target, - char channel, u_int8_t scbid)); - -static void ahc_construct_sdtr __P((struct ahc_softc *ahc, int start_byte, - u_int8_t period, u_int8_t offset)); - -static void ahc_construct_wdtr __P((struct ahc_softc *ahc, int start_byte, - u_int8_t bus_width)); - -static void ahc_calc_residual __P((struct scb *scb)); - -#if defined(__FreeBSD__) - -char *ahc_name(ahc) - struct ahc_softc *ahc; -{ - static char name[10]; - - sprintf(name, "ahc%d", ahc->unit); - return (name); -} - -#elif defined(__NetBSD__) -struct cfdriver ahc_cd = { - NULL, "ahc", DV_DULL -}; -#endif - -#ifdef AHC_DEBUG -static void -ahc_print_scb(scb) - struct scb *scb; -{ - struct hardware_scb *hscb = scb->hscb; - - printf("scb:%p control:0x%x tcl:0x%x cmdlen:%d cmdpointer:0x%lx\n", - scb, - hscb->control, - hscb->tcl, - hscb->cmdlen, - hscb->cmdpointer ); - printf(" datlen:%d data:0x%lx segs:0x%x segp:0x%lx\n", - hscb->datalen, - hscb->data, - hscb->SG_segment_count, - hscb->SG_list_pointer); - printf(" sg_addr:%lx sg_len:%ld\n", - hscb->ahc_dma[0].addr, - hscb->ahc_dma[0].len); -} - -#endif - -static struct { - u_int8_t errno; - char *errmesg; -} hard_error[] = { - { ILLHADDR, "Illegal Host Access" }, - { ILLSADDR, "Illegal Sequencer Address referrenced" }, - { ILLOPCODE, "Illegal Opcode in sequencer program" }, - { PARERR, "Sequencer Ram Parity Error" } -}; - - -/* - * Valid SCSIRATE values. (p. 3-17) - * Provides a mapping of tranfer periods in ns to the proper value to - * stick in the scsiscfr reg to use that transfer rate. - */ -static struct { - int sxfr; - /* Rates in Ultra mode have bit 8 of sxfr set */ -#define ULTRA_SXFR 0x100 - u_int8_t period; /* Period to send to SCSI target */ - char *rate; -} ahc_syncrates[] = { - { 0x100, 12, "20.0" }, - { 0x110, 15, "16.0" }, - { 0x120, 18, "13.4" }, - { 0x000, 25, "10.0" }, - { 0x010, 31, "8.0" }, - { 0x020, 37, "6.67" }, - { 0x030, 43, "5.7" }, - { 0x040, 50, "5.0" }, - { 0x050, 56, "4.4" }, - { 0x060, 62, "4.0" }, - { 0x070, 68, "3.6" } -}; - -static int ahc_num_syncrates = - sizeof(ahc_syncrates) / sizeof(ahc_syncrates[0]); - -/* - * Allocate a controller structure for a new device and initialize it. - */ -#if defined(__FreeBSD__) -struct ahc_softc * -ahc_alloc(unit, iobase, maddr, type, flags, scb_data) - int unit; - u_int32_t iobase; -#elif defined(__NetBSD__) -void -ahc_construct(ahc, bc, ioh, maddr, type, flags) - struct ahc_softc *ahc; - bus_chipset_tag_t bc; - bus_io_handle_t ioh; -#endif - vm_offset_t maddr; - ahc_type type; - ahc_flag flags; - struct scb_data *scb_data; -{ - /* - * find unit and check we have that many defined - */ -#if defined(__FreeBSD__) - struct ahc_softc *ahc; - size_t alloc_size; - - /* - * Allocate a storage area for us - */ - if (scb_data == NULL) - /* - * We are not sharing SCB space with another controller - * so allocate our own SCB data space. - */ - alloc_size = sizeof(struct full_ahc_softc); - else - alloc_size = sizeof(struct ahc_softc); - ahc = malloc(alloc_size, M_DEVBUF, M_NOWAIT); - if (!ahc) { - printf("ahc%d: cannot malloc!\n", unit); - return NULL; - } - bzero(ahc, alloc_size); -#endif - if (scb_data == NULL) { - struct full_ahc_softc* full_softc = (struct full_ahc_softc*)ahc; - ahc->scb_data = &full_softc->scb_data_storage; - STAILQ_INIT(&ahc->scb_data->free_scbs); - } else - ahc->scb_data = scb_data; - STAILQ_INIT(&ahc->waiting_scbs); - STAILQ_INIT(&ahc->cmplete_scbs); -#if defined(__FreeBSD__) - ahc->unit = unit; -#endif -#if defined(__FreeBSD__) - ahc->baseport = iobase; -#elif defined(__NetBSD__) - ahc->sc_bc = bc; - ahc->sc_ioh = ioh; -#endif - ahc->maddr = (volatile u_int8_t *)maddr; - ahc->type = type; - ahc->flags = flags; - ahc->unpause = (ahc_inb(ahc, HCNTRL) & IRQMS) | INTEN; - ahc->pause = ahc->unpause | PAUSE; - -#if defined(__FreeBSD__) - return (ahc); -#endif -} - -void -ahc_free(ahc) - struct ahc_softc *ahc; -{ -#if defined(__FreeBSD__) - free(ahc, M_DEVBUF); - return; -#endif -} - -void -ahc_reset(ahc) - struct ahc_softc *ahc; -{ - u_int8_t hcntrl; - int wait; - - /* Retain the IRQ type accross the chip reset */ - hcntrl = (ahc_inb(ahc, HCNTRL) & IRQMS) | INTEN; - - ahc_outb(ahc, HCNTRL, CHIPRST | PAUSE); - /* - * Ensure that the reset has finished - */ - wait = 1000; - while (--wait && !(ahc_inb(ahc, HCNTRL) & CHIPRSTACK)) - DELAY(1000); - if (wait == 0) { - printf("%s: WARNING - Failed chip reset! " - "Trying to initialize anyway.\n", ahc_name(ahc)); - } - ahc_outb(ahc, HCNTRL, hcntrl | PAUSE); -} - -/* - * Look up the valid period to SCSIRATE conversion in our table. - */ -static void -ahc_scsirate(ahc, scsirate, period, offset, channel, target ) - struct ahc_softc *ahc; - u_int8_t *scsirate; - u_int8_t *period; - u_int8_t *offset; - char channel; - int target; -{ - int i; - u_int32_t ultra_enb_addr; - u_int8_t sxfrctl0; - u_int8_t ultra_enb; - - i = ahc_num_syncrates; /* Default to async */ - - if (*period >= ahc_syncrates[0].period && *offset != 0) { - for (i = 0; i < ahc_num_syncrates; i++) { - - if (*period <= ahc_syncrates[i].period) { - /* - * Watch out for Ultra speeds when ultra is not - * enabled and vice-versa. - */ - if (!(ahc->type & AHC_ULTRA) - && (ahc_syncrates[i].sxfr & ULTRA_SXFR)) { - /* - * This should only happen if the - * drive is the first to negotiate - * and chooses a high rate. We'll - * just move down the table util - * we hit a non ultra speed. - */ - continue; - } - *scsirate = (ahc_syncrates[i].sxfr & 0xF0) - | (*offset & 0x0f); - *period = ahc_syncrates[i].period; - - if (bootverbose) { - printf("%s: target %d synchronous at " - "%sMHz, offset = 0x%x\n", - ahc_name(ahc), target, - ahc_syncrates[i].rate, *offset ); - } - break; - } - } - } - if (i >= ahc_num_syncrates) { - /* Use asynchronous transfers. */ - *scsirate = 0; - *period = 0; - *offset = 0; - if (bootverbose) - printf("%s: target %d using asynchronous transfers\n", - ahc_name(ahc), target ); - } - /* - * Ensure Ultra mode is set properly for - * this target. - */ - ultra_enb_addr = ULTRA_ENB; - if (channel == 'B' || target > 7) - ultra_enb_addr++; - ultra_enb = ahc_inb(ahc, ultra_enb_addr); - sxfrctl0 = ahc_inb(ahc, SXFRCTL0); - if (*scsirate != 0 && (ahc_syncrates[i].sxfr & ULTRA_SXFR)) { - ultra_enb |= 0x01 << (target & 0x07); - sxfrctl0 |= FAST20; - } else { - ultra_enb &= ~(0x01 << (target & 0x07)); - sxfrctl0 &= ~FAST20; - } - ahc_outb(ahc, ultra_enb_addr, ultra_enb); - ahc_outb(ahc, SXFRCTL0, sxfrctl0); -} - -#if defined(__NetBSD__) -int -ahcprint(aux, name) - void *aux; - char *name; -{ - if (name != NULL) - printf("%s: scsibus ", name); - return UNCONF; -} -#endif - - -/* - * Attach all the sub-devices we can find - */ -int -ahc_attach(ahc) - struct ahc_softc *ahc; -{ - struct scsibus_data *scbus; - -#ifdef AHC_BROKEN_CACHE - if (cpu_class == CPUCLASS_386) /* doesn't have "wbinvd" instruction */ - ahc_broken_cache = 0; -#endif - /* - * fill in the prototype scsi_links. - */ -#if defined(__FreeBSD__) - ahc->sc_link.adapter_unit = ahc->unit; - ahc->sc_link.adapter_targ = ahc->our_id; - ahc->sc_link.fordriver = 0; -#elif defined(__NetBSD__) - ahc->sc_link.adapter_target = ahc->our_id; -#endif - ahc->sc_link.adapter_softc = ahc; - ahc->sc_link.adapter = &ahc_switch; - ahc->sc_link.opennings = 2; - ahc->sc_link.device = &ahc_dev; - ahc->sc_link.flags = DEBUGLEVEL; - - if (ahc->type & AHC_TWIN) { - /* Configure the second scsi bus */ - ahc->sc_link_b = ahc->sc_link; -#if defined(__FreeBSD__) - ahc->sc_link_b.adapter_targ = ahc->our_id_b; - ahc->sc_link_b.adapter_bus = 1; - ahc->sc_link_b.fordriver = (void *)SELBUSB; -#elif defined(__NetBSD__) - ahc->sc_link_b.adapter_target = ahc->our_id_b; -#endif - } - - -#if defined(__FreeBSD__) - /* - * Prepare the scsibus_data area for the upperlevel - * scsi code. - */ - scbus = scsi_alloc_bus(); - if(!scbus) - return 0; - scbus->adapter_link = (ahc->flags & AHC_CHANNEL_B_PRIMARY) ? - &ahc->sc_link_b : &ahc->sc_link; - if (ahc->type & AHC_WIDE) - scbus->maxtarg = 15; - - /* - * ask the adapter what subunits are present - */ - if (bootverbose) - printf("ahc%d: Probing channel %c\n", ahc->unit, - (ahc->flags & AHC_CHANNEL_B_PRIMARY) ? 'B' : 'A'); - scsi_attachdevs(scbus); - scbus = NULL; /* Upper-level SCSI code owns this now */ - - if (ahc->type & AHC_TWIN) { - scbus = scsi_alloc_bus(); - if (!scbus) - return 0; - scbus->adapter_link = (ahc->flags & AHC_CHANNEL_B_PRIMARY) ? - &ahc->sc_link : &ahc->sc_link_b; - if (ahc->type & AHC_WIDE) - scbus->maxtarg = 15; - if (bootverbose) - printf("ahc%d: Probing Channel %c\n", ahc->unit, - (ahc->flags & AHC_CHANNEL_B_PRIMARY) ? 'A': 'B'); - scsi_attachdevs(scbus); - scbus = NULL; /* Upper-level SCSI code owns this now */ - } -#elif defined(__NetBSD__) - /* - * XXX - Update MI SCSI code - * - * if(ahc->type & AHC_WIDE) - * max target of both channel A and B = 15; - */ - - /* - * ask the adapter what subunits are present - */ - if ((ahc->flags & AHC_CHANNEL_B_PRIMARY) == 0) { - /* make IS_SCSIBUS_B() == false, while probing channel A */ - ahc->sc_link_b.scsibus = 0xff; - - if (ahc->type & AHC_TWIN) - printf("%s: Probing channel A\n", ahc_name(ahc)); - config_found((void *)ahc, &ahc->sc_link, ahcprint); - if (ahc->type & AHC_TWIN) { - printf("%s: Probing channel B\n", ahc_name(ahc)); - config_found((void *)ahc, &ahc->sc_link_b, ahcprint); - } - } else { - /* - * if implementation of IS_SCSIBUS_B() is changed to use - * ahc->sc_link.scsibus, then "ahc->sc_link.scsibus = 0xff;" - * is needed, here. - */ - - /* assert(ahc->type & AHC_TWIN); */ - printf("%s: Probing channel B\n", ahc_name(ahc)); - config_found((void *)ahc, &ahc->sc_link_b, ahcprint); - printf("%s: Probing channel A\n", ahc_name(ahc)); - config_found((void *)ahc, &ahc->sc_link, ahcprint); - } -#endif - return 1; -} - -/* - * Catch an interrupt from the adapter - */ -#if defined(__FreeBSD__) -void -#elif defined (__NetBSD__) -int -#endif -ahc_intr(arg) - void *arg; -{ - struct ahc_softc *ahc; - u_int8_t intstat; - - ahc = (struct ahc_softc *)arg; - intstat = ahc_inb(ahc, INTSTAT); - /* - * Is this interrupt for me? or for - * someone who is sharing my interrupt? - */ - if (!(intstat & INT_PEND)) -#if defined(__FreeBSD__) - return; -#elif defined(__NetBSD__) - return 0; -#endif - - if (intstat & CMDCMPLT) { - struct scb *scb; - u_int8_t scb_index; - u_int8_t qoutcnt; - int int_cleared; - - int_cleared = 0; - while ((qoutcnt = (ahc_inb(ahc, QOUTCNT) & ahc->qcntmask)) != 0) { - ahc->cmdoutcnt += qoutcnt; - for (; qoutcnt > 0; qoutcnt--) { - scb_index = ahc_inb(ahc, QOUTFIFO); - scb = ahc->scb_data->scbarray[scb_index]; - if (!scb || !(scb->flags & SCB_ACTIVE)) { - printf("%s: WARNING " - "no command for scb %d " - "(cmdcmplt)\nQOUTCNT == %d\n", - ahc_name(ahc), scb_index, - qoutcnt); - continue; - } - STAILQ_INSERT_TAIL(&ahc->cmplete_scbs, scb, - links); - } - if ((ahc->flags & AHC_PAGESCBS) != 0) { - if (ahc->cmdoutcnt >= ahc->qfullcount) { - /* - * Since paging only occurs on - * aic78X0 chips, we can use - * Auto Access Pause to clear - * the command count. - */ - ahc_outb(ahc, CMDOUTCNT, 0); - ahc->cmdoutcnt = 0; - } - } - while((scb = ahc->cmplete_scbs.stqh_first) != NULL) { - STAILQ_REMOVE_HEAD(&ahc->cmplete_scbs, links); - /* - * Save off the residual if there is one. - */ - if (scb->hscb->residual_SG_segment_count != 0) - ahc_calc_residual(scb); - if ((scb->flags & SCB_QUEUED_ABORT) != 0) { - /* Have to clean up any possible - * entries in the waiting queue and - * QINFIFO. - */ - int target; - char channel; - int lun; - u_int8_t tag; - - tag = SCB_LIST_NULL; - target = scb->xs->sc_link->target; - lun = scb->xs->sc_link->lun; - channel = (scb->hscb->tcl & SELBUSB) - ? 'B': 'A'; - if (scb->hscb->control & TAG_ENB) - tag = scb->hscb->tag; - ahc_reset_device(ahc, - target, - channel, - lun, - tag, - scb->xs->error); - ahc_run_done_queue(ahc); - } - ahc_done(ahc, scb); - } - ahc_outb(ahc, CLRINT, CLRCMDINT); - int_cleared++; - } - - if (int_cleared == 0) - ahc_outb(ahc, CLRINT, CLRCMDINT); - } - if (intstat & BRKADRINT) { - /* - * We upset the sequencer :-( - * Lookup the error message - */ - int i, error, num_errors; - - error = ahc_inb(ahc, ERROR); - num_errors = sizeof(hard_error)/sizeof(hard_error[0]); - for (i = 0; error != 1 && i < num_errors; i++) - error >>= 1; - printf("%s: brkadrint, %s at seqaddr = 0x%x\n", - ahc_name(ahc), hard_error[i].errmesg, - (ahc_inb(ahc, SEQADDR1) << 8) | - ahc_inb(ahc, SEQADDR0)); - - ahc_reset_device(ahc, ALL_TARGETS, ALL_CHANNELS, ALL_LUNS, - SCB_LIST_NULL, XS_DRIVER_STUFFUP); - ahc_run_done_queue(ahc); - } - if (intstat & SEQINT) - ahc_handle_seqint(ahc, intstat); - - if (intstat & SCSIINT) - ahc_handle_scsiint(ahc, intstat); - - if (ahc->waiting_scbs.stqh_first != NULL) - ahc_run_waiting_queue(ahc); -#if defined(__NetBSD__) - return 1; -#endif -} - -static void -ahc_handle_seqint(ahc, intstat) - struct ahc_softc *ahc; - u_int8_t intstat; -{ - struct scb *scb; - u_int16_t targ_mask; - u_int8_t target; - int scratch_offset; - char channel; - - if ((ahc_inb(ahc, SEQ_FLAGS) & RESELECTED) != 0) - target = ahc_inb(ahc, SELID); - else - target = ahc_inb(ahc, SCSIID); - target = (target >> 4) & 0x0f; - scratch_offset = target; - channel = ahc_inb(ahc, SBLKCTL) & SELBUSB ? 'B': 'A'; - if (channel == 'B') - scratch_offset += 8; - targ_mask = (0x01 << scratch_offset); - - switch (intstat & SEQINT_MASK) { - case NO_MATCH: - { - /* - * This could be for a normal abort request. - * Figure out the SCB that we were trying to find - * and only give an error if we didn't ask for this - * to happen. - */ - u_int8_t scb_index; - u_int8_t busy_scbid; - u_int8_t arg1; - - busy_scbid = ahc_index_busy_target(ahc, target, channel, - /*unbusy*/FALSE); - arg1 = ahc_inb(ahc, ARG_1); - - if (arg1 == SCB_LIST_NULL) - /* Untagged Request */ - scb_index = busy_scbid; - else - scb_index = arg1; - - if (scb_index < ahc->scb_data->numscbs) { - scb = ahc->scb_data->scbarray[scb_index]; - - if (scb->hscb->control & ABORT_SCB) { - /* - * We expected this. Let the busfree - * handler take care of this when we - * the abort is finially sent. - * Set IDENTIFY_SEEN so that the busfree - * handler knows that there is an SCB to - * cleanup. - */ - ahc_outb(ahc, SEQ_FLAGS, ahc_inb(ahc, SEQ_FLAGS) - | IDENTIFY_SEEN); - sc_print_addr(scb->xs->sc_link); - printf("reconnect SCB abort successfull\n"); - break; - } - } - - printf("%s:%c:%d: no active SCB for reconnecting " - "target - issuing BUS DEVICE RESET\n", - ahc_name(ahc), channel, target); - printf("SAVED_TCL == 0x%x ARG_1 == 0x%x SEQADDR == 0x%x\n", - ahc_inb(ahc, SAVED_TCL), arg1, - (ahc_inb(ahc, SEQADDR1) << 8) - | ahc_inb(ahc, SEQADDR0)); - - ahc_handle_devreset(ahc, target, channel); - - break; - } - case NO_MATCH_BUSY: - { - /* - * XXX Leave this as a panic for the time being since - * it indicates a bug in the timeout code for this - * to happen. - */ - u_int8_t scb_index; - - scb_index = ahc_inb(ahc, CUR_SCBID); - scb = ahc->scb_data->scbarray[scb_index]; - - panic("%s:%c:%d: Target busy link failure.\n", - ahc_name(ahc), (scb->hscb->tcl & SELBUSB) ? 'B' : 'A', - scb->xs->sc_link->target); - } - case SEND_REJECT: - { - u_int8_t rejbyte = ahc_inb(ahc, ACCUM); - printf("%s:%c:%d: Warning - unknown message received from " - "target (0x%x). SEQ_FLAGS == 0x%x. Rejecting\n", - ahc_name(ahc), channel, target, rejbyte, - ahc_inb(ahc, SEQ_FLAGS)); - break; - } - case NO_IDENT: - { - /* - * The reconnecting target either did not send an identify - * message, or did, but we didn't find and SCB to match and - * before it could respond to our ATN/abort, it hit a dataphase. - * The only safe thing to do is to blow it away with a bus - * reset. - */ - int found; - - printf("%s:%c:%d: Target did not send an IDENTIFY message. " - "LASTPHASE = 0x%x, SAVED_TCL == 0x%x\n", - ahc_name(ahc), channel, target, ahc_inb(ahc, LASTPHASE), - ahc_inb(ahc, SAVED_TCL)); - found = ahc_reset_channel(ahc, channel, XS_TIMEOUT, - /*initiate reset*/TRUE); - printf("%s: Issued Channel %c Bus Reset. " - "%d SCBs aborted\n", ahc_name(ahc), channel, found); - break; - } - case BAD_PHASE: - if (ahc_inb(ahc, LASTPHASE) == P_BUSFREE) { - printf("%s:%c:%d: Missed busfree.\n", ahc_name(ahc), - channel, target); - restart_sequencer(ahc); - } else { - printf("%s:%c:%d: unknown scsi bus phase. Attempting " - "to continue\n", ahc_name(ahc), channel, target); - } - break; - case EXTENDED_MSG: - { - u_int8_t message_length; - u_int8_t message_code; - u_int8_t scb_index; - - message_length = ahc_inb(ahc, MSGIN_EXT_LEN); - message_code = ahc_inb(ahc, MSGIN_EXT_OPCODE); - scb_index = ahc_inb(ahc, SCB_TAG); - scb = ahc->scb_data->scbarray[scb_index]; - switch (message_code) { - case MSG_EXT_SDTR: - { - u_int8_t period; - u_int8_t offset; - u_int8_t saved_offset; - u_int8_t targ_scratch; - u_int8_t maxoffset; - u_int8_t rate; - - if (message_length != MSG_EXT_SDTR_LEN) { - ahc_outb(ahc, RETURN_1, SEND_REJ); - break; - } - period = ahc_inb(ahc, MSGIN_EXT_BYTES); - saved_offset = ahc_inb(ahc, MSGIN_EXT_BYTES + 1); - targ_scratch = ahc_inb(ahc, TARG_SCRATCH - + scratch_offset); - if (targ_scratch & WIDEXFER) - maxoffset = MAX_OFFSET_16BIT; - else - maxoffset = MAX_OFFSET_8BIT; - offset = MIN(saved_offset, maxoffset); - ahc_scsirate(ahc, &rate, &period, &offset, - channel, target); - /* Preserve the WideXfer flag */ - targ_scratch = rate | (targ_scratch & WIDEXFER); - - /* - * Update both the target scratch area and the - * current SCSIRATE. - */ - ahc_outb(ahc, TARG_SCRATCH + scratch_offset, - targ_scratch); - ahc_outb(ahc, SCSIRATE, targ_scratch); - - /* - * See if we initiated Sync Negotiation - * and didn't have to fall down to async - * transfers. - */ - if ((scb->flags & SCB_MSGOUT_SDTR) != 0) { - /* We started it */ - if (saved_offset == offset) { - /* - * Don't send an SDTR back to - * the target - */ - ahc_outb(ahc, RETURN_1, 0); - } else - /* Went too low - force async */ - ahc_outb(ahc, RETURN_1, SEND_REJ); - } else { - /* - * Send our own SDTR in reply - */ - printf("Sending SDTR!!\n"); - ahc_construct_sdtr(ahc, /*start_byte*/0, - period, offset); - ahc_outb(ahc, RETURN_1, SEND_MSG); - } - ahc->needsdtr &= ~targ_mask; - break; - } - case MSG_EXT_WDTR: - { - u_int8_t scratch, bus_width; - - if (message_length != MSG_EXT_WDTR_LEN) { - ahc_outb(ahc, RETURN_1, SEND_REJ); - break; - } - - bus_width = ahc_inb(ahc, MSGIN_EXT_BYTES); - scratch = ahc_inb(ahc, TARG_SCRATCH + scratch_offset); - - if ((scb->flags & SCB_MSGOUT_WDTR) != 0) { - /* - * Don't send a WDTR back to the - * target, since we asked first. - */ - ahc_outb(ahc, RETURN_1, 0); - switch (bus_width){ - case BUS_8_BIT: - scratch &= 0x7f; - break; - case BUS_16_BIT: - if (bootverbose) - printf("%s: target %d using " - "16Bit transfers\n", - ahc_name(ahc), target); - scratch |= WIDEXFER; - break; - case BUS_32_BIT: - /* - * How can we do 32bit transfers - * on a 16bit bus? - */ - ahc_outb(ahc, RETURN_1, SEND_REJ); - printf("%s: target %d requested 32Bit " - "transfers. Rejecting...\n", - ahc_name(ahc), target); - break; - default: - break; - } - } else { - /* - * Send our own WDTR in reply - */ - switch (bus_width) { - case BUS_8_BIT: - scratch &= 0x7f; - break; - case BUS_32_BIT: - case BUS_16_BIT: - if (ahc->type & AHC_WIDE) { - /* Negotiate 16_BITS */ - bus_width = BUS_16_BIT; - if (bootverbose) - printf("%s: target %d " - "using 16Bit " - "transfers\n", - ahc_name(ahc), - target); - scratch |= WIDEXFER; - } else - bus_width = BUS_8_BIT; - break; - default: - break; - } - ahc_construct_wdtr(ahc, /*start_byte*/0, - bus_width); - ahc_outb(ahc, RETURN_1, SEND_MSG); - } - ahc->needwdtr &= ~targ_mask; - ahc_outb(ahc, TARG_SCRATCH + scratch_offset, scratch); - ahc_outb(ahc, SCSIRATE, scratch); - break; - } - default: - /* Unknown extended message. Reject it. */ - ahc_outb(ahc, RETURN_1, SEND_REJ); - } - break; - } - case REJECT_MSG: - { - /* - * What we care about here is if we had an - * outstanding SDTR or WDTR message for this - * target. If we did, this is a signal that - * the target is refusing negotiation. - */ - - u_int8_t targ_scratch; - u_int8_t scb_index; - - scb_index = ahc_inb(ahc, SCB_TAG); - scb = ahc->scb_data->scbarray[scb_index]; - - targ_scratch = ahc_inb(ahc, TARG_SCRATCH - + scratch_offset); - - if ((scb->flags & SCB_MSGOUT_WDTR) != 0) { - /* note 8bit xfers and clear flag */ - targ_scratch &= 0x7f; - ahc->needwdtr &= ~targ_mask; - printf("%s:%c:%d: refuses WIDE negotiation. Using " - "8bit transfers\n", ahc_name(ahc), - channel, target); - } else if ((scb->flags & SCB_MSGOUT_SDTR) != 0) { - /* note asynch xfers and clear flag */ - targ_scratch &= 0xf0; - ahc->needsdtr &= ~targ_mask; - printf("%s:%c:%d: refuses synchronous negotiation. " - "Using asynchronous transfers\n", - ahc_name(ahc), - channel, target); - } else { - /* - * Otherwise, we ignore it. - */ -#ifdef AHC_DEBUG - if (ahc_debug & AHC_SHOWMISC) - printf("%s:%c:%d: Message reject -- ignored\n", - ahc_name(ahc), channel, target); -#endif - break; - } - ahc_outb(ahc, TARG_SCRATCH + scratch_offset, targ_scratch); - ahc_outb(ahc, SCSIRATE, targ_scratch); - break; - } - case BAD_STATUS: - { - u_int8_t scb_index; - struct scsi_xfer *xs; - struct hardware_scb *hscb; - - /* - * The sequencer will notify us when a command - * has an error that would be of interest to - * the kernel. This allows us to leave the sequencer - * running in the common case of command completes - * without error. The sequencer will already have - * dma'd the SCB back up to us, so we can reference - * the in kernel copy directly. - */ - - scb_index = ahc_inb(ahc, SCB_TAG); - scb = ahc->scb_data->scbarray[scb_index]; - hscb = scb->hscb; - - /* - * Set the default return value to 0 (don't - * send sense). The sense code will change - * this if needed and this reduces code - * duplication. - */ - ahc_outb(ahc, RETURN_1, 0); - if (!(scb && (scb->flags & SCB_ACTIVE))) { - printf("%s:%c:%d: ahc_intr - referenced scb " - "not valid during seqint 0x%x scb(%d)\n", - ahc_name(ahc), - channel, target, intstat, - scb_index); - goto clear; - } - - xs = scb->xs; - - xs->status = hscb->status; - switch (hscb->status){ - case SCSI_OK: - printf("%s: Interrupted for staus of" - " 0???\n", ahc_name(ahc)); - break; - case SCSI_CHECK: -#ifdef AHC_DEBUG - if (ahc_debug & AHC_SHOWSENSE) { - sc_print_addr(xs->sc_link); - printf("SCB %d: requests Check Status\n", - scb->hscb->tag); - } -#endif - - if ((xs->error == XS_NOERROR) - && !(scb->flags & SCB_SENSE)) { - struct ahc_dma_seg *sg = scb->ahc_dma; - struct scsi_sense *sc = &(scb->sense_cmd); - - /* - * Save off the residual if there is one. - */ - if (hscb->residual_SG_segment_count != 0) - ahc_calc_residual(scb); - -#ifdef AHC_DEBUG - if (ahc_debug & AHC_SHOWSENSE) { - sc_print_addr(xs->sc_link); - printf("Sending Sense\n"); - } -#endif -#if defined(__FreeBSD__) - sc->op_code = REQUEST_SENSE; -#elif defined(__NetBSD__) - sc->opcode = REQUEST_SENSE; -#endif - sc->byte2 = xs->sc_link->lun << 5; - sc->length = sizeof(struct scsi_sense_data); - sc->control = 0; - - sg->addr = vtophys(&xs->sense); - sg->len = sizeof(struct scsi_sense_data); - - /* XXX should allow disconnection, but - * can't as it might allow overlapped - * tagged commands. - */ - /* hscb->control &= DISCENB; */ - hscb->control = 0; - hscb->status = 0; - hscb->SG_segment_count = 1; - hscb->SG_list_pointer = vtophys(sg); - hscb->data = sg->addr; - /* Maintain SCB_LINKED_NEXT */ - hscb->datalen &= 0xFF000000; - hscb->datalen |= sg->len; - hscb->cmdpointer = vtophys(sc); - hscb->cmdlen = sizeof(*sc); - scb->sg_count = hscb->SG_segment_count; - scb->flags |= SCB_SENSE; - /* - * Ensure the target is busy since this - * will be an untagged request. - */ - ahc_busy_target(ahc, target, channel, - hscb->tag); - ahc_outb(ahc, RETURN_1, SEND_SENSE); - - /* - * Ensure we have enough time to actually - * retrieve the sense. - */ - untimeout(ahc_timeout, (caddr_t)scb, - scb->xs->timeout_ch); - scb->xs->timeout_ch = timeout(ahc_timeout, - (caddr_t)scb, hz); - break; - } - /* - * Clear the SCB_SENSE Flag and have - * the sequencer do a normal command - * complete with either a "DRIVER_STUFFUP" - * error or whatever other error condition - * we already had. - */ - scb->flags &= ~SCB_SENSE; - if (xs->error == XS_NOERROR) - xs->error = XS_DRIVER_STUFFUP; - break; - case SCSI_QUEUE_FULL: - if (scb->hscb->control & TAG_ENB) { - /* - * The upper level SCSI code in 3.0 - * handles this properly... - */ - struct scsi_link *sc_link; - - sc_link = xs->sc_link; - if (sc_link->active > 2 - && sc_link->opennings != 0) { - /* truncate the opennings */ - sc_link->opennings = 0; - sc_print_addr(sc_link); - printf("Tagged openings reduced to " - "%d\n", sc_link->active); - } - /* - * XXX requeue this unconditionally. - */ - scb->xs->retries++; - scb->xs->error = XS_BUSY; - break; - } - /* Else treat as if it is a BUSY condition */ - scb->hscb->status = SCSI_BUSY; - /* Fall Through... */ - case SCSI_BUSY: - xs->error = XS_BUSY; - sc_print_addr(xs->sc_link); - printf("Target Busy\n"); - break; - case SCSI_RSVD: - xs->error = XS_BUSY; /*XXX*/ - sc_print_addr(xs->sc_link); - printf("Target Reserved\n"); - break; - default: - sc_print_addr(xs->sc_link); - printf("unexpected targ_status: %x\n", hscb->status); - xs->error = XS_DRIVER_STUFFUP; - break; - } - break; - } - case AWAITING_MSG: - { - int scb_index; - u_int8_t message_offset; - - scb_index = ahc_inb(ahc, SCB_TAG); - scb = ahc->scb_data->scbarray[scb_index]; - - /* - * This SCB had MK_MESSAGE set in its control byte, - * informing the sequencer that we wanted to send a - * special message to this target. - */ - message_offset = ahc_inb(ahc, MSG_LEN); - if (scb->flags & SCB_DEVICE_RESET) { - ahc_outb(ahc, MSG_OUT, MSG_BUS_DEV_RESET); - ahc_outb(ahc, MSG_LEN, 1); - sc_print_addr(scb->xs->sc_link); - printf("Bus Device Reset Message Sent\n"); - } else if (scb->flags & SCB_ABORT) { - if ((scb->hscb->control & TAG_ENB) != 0) - ahc_outb(ahc, MSG_OUT + message_offset, - MSG_ABORT_TAG); - else - ahc_outb(ahc, MSG_OUT + message_offset, - MSG_ABORT); - ahc_outb(ahc, MSG_LEN, message_offset + 1); - sc_print_addr(scb->xs->sc_link); - printf("Abort Message Sent\n"); - } else if (scb->flags & SCB_MSGOUT_WDTR) { - ahc_construct_wdtr(ahc, message_offset, BUS_16_BIT); - } else if (scb->flags & SCB_MSGOUT_SDTR) { - int sxfr; - int i; - u_int16_t ultraenable; - u_int8_t target_scratch; - - /* Pull the user defined setting */ - target_scratch = ahc_inb(ahc, TARG_SCRATCH - + scratch_offset); - - sxfr = target_scratch & SXFR; - ultraenable = ahc_inb(ahc, ULTRA_ENB) - | (ahc_inb(ahc, ULTRA_ENB + 1) << 8); - - if (ultraenable & targ_mask) - /* Want an ultra speed in the table */ - sxfr |= 0x100; - - for (i = 0; i < ahc_num_syncrates; i++) - if (sxfr == ahc_syncrates[i].sxfr) - break; - - ahc_construct_sdtr(ahc, message_offset, - ahc_syncrates[i].period, - (target_scratch & WIDEXFER) ? - MAX_OFFSET_16BIT : MAX_OFFSET_8BIT); - } else - panic("ahc_intr: AWAITING_MSG for an SCB that " - "does not have a waiting message"); - break; - } - case DATA_OVERRUN: - { - /* - * When the sequencer detects an overrun, it - * sets STCNT to 0x00ffffff and allows the - * target to complete its transfer in - * BITBUCKET mode. - */ - u_int8_t scbindex = ahc_inb(ahc, SCB_TAG); - u_int8_t lastphase = ahc_inb(ahc, LASTPHASE); - u_int32_t overrun; - int i; - scb = ahc->scb_data->scbarray[scbindex]; - overrun = ahc_inb(ahc, STCNT) - | (ahc_inb(ahc, STCNT + 1) << 8) - | (ahc_inb(ahc, STCNT + 2) << 16); - overrun = 0x00ffffff - overrun; - sc_print_addr(scb->xs->sc_link); - printf("data overrun of %d bytes detected in %s phase." - " Tag == 0x%x. Forcing a retry.\n", overrun, - lastphase == P_DATAIN ? "Data-In" : "Data-Out", - scb->hscb->tag); - sc_print_addr(scb->xs->sc_link); - printf("%s seen Data Phase. Length = %d. NumSGs = %d.\n", - ahc_inb(ahc, SEQ_FLAGS) & DPHASE ? "Have" : "Haven't", - scb->xs->datalen, scb->sg_count); - for (i = 0; i < scb->sg_count; i++) { - printf("sg[%d] - Addr 0x%x : Length %d\n", - i, - scb->ahc_dma[i].addr, - scb->ahc_dma[i].len); - } - /* - * Set this and it will take affect when the - * target does a command complete. - */ - scb->xs->error = XS_DRIVER_STUFFUP; - break; - } -#if NOT_YET - /* XXX Fill these in later */ - case MESG_BUFFER_BUSY: - break; - case MSGIN_PHASEMIS: - break; -#endif -#if 0 - case SCB_TRACE_POINT: - { - /* - * Print out the bus phase - */ - char *phase; - u_int8_t scbindex = ahc_inb(ahc, SCB_TAG); - u_int8_t lastphase = ahc_inb(ahc, LASTPHASE); - - scb = ahc->scb_data->scbarray[scbindex]; - sc_print_addr(scb->xs->sc_link); - - switch (lastphase) { - case P_DATAOUT: - phase = "Data-Out"; - break; - case P_DATAIN: - phase = "Data-In"; - break; - case P_COMMAND: - phase = "Command"; - break; - case P_MESGOUT: - phase = "Message-Out"; - break; - case P_STATUS: - phase = "Status"; - break; - case P_MESGIN: - phase = "Message-In"; - break; - default: - phase = "busfree"; - break; - } - printf("- %s\n", phase); - break; - } -#endif - case ABORT_CMDCMPLT: - /* This interrupt serves to pause the sequencer - * until we can clean up the QOUTFIFO allowing us - * to hanle any abort SCBs that may have completed - * yet still have an SCB in the QINFIFO or - * waiting for selection queue. By the time we get - * here, we should have already cleaned up the - * queues, so all we need to do is unpause the sequencer. - */ - break; - default: - printf("ahc_intr: seqint, " - "intstat == 0x%x, scsisigi = 0x%x\n", - intstat, ahc_inb(ahc, SCSISIGI)); - break; - } - -clear: - /* - * Clear the upper byte that holds SEQINT status - * codes and clear the SEQINT bit. - */ - ahc_outb(ahc, CLRINT, CLRSEQINT); - - /* - * The sequencer is paused immediately on - * a SEQINT, so we should restart it when - * we're done. - */ - unpause_sequencer(ahc, /*unpause_always*/TRUE); -} - -static void -ahc_handle_scsiint(ahc, intstat) - struct ahc_softc *ahc; - u_int8_t intstat; -{ - u_int8_t scb_index; - u_int8_t status; - struct scb *scb; - - scb_index = ahc_inb(ahc, SCB_TAG); - status = ahc_inb(ahc, SSTAT1); - - if (scb_index < ahc->scb_data->numscbs) { - scb = ahc->scb_data->scbarray[scb_index]; - if ((scb->flags & SCB_ACTIVE) == 0) - scb = NULL; - } else - scb = NULL; - - if ((status & SCSIRSTI) != 0) { - char channel; - channel = (ahc_inb(ahc, SBLKCTL) & SELBUSB) ? 'B' : 'A'; - printf("%s: Someone reset channel %c\n", - ahc_name(ahc), channel); - ahc_reset_channel(ahc, - channel, - XS_BUSY, - /* Initiate Reset */FALSE); - scb = NULL; - } else if ((status & BUSFREE) != 0 && (status & SELTO) == 0) { - /* - * First look at what phase we were last in. - * If its message out, chances are pretty good - * that the busfree was in response to one of - * our abort requests. - */ - u_int8_t lastphase = ahc_inb(ahc, LASTPHASE); - u_int8_t target = (ahc_inb(ahc, SAVED_TCL) >> 4) & 0x0f; - char channel = ahc_inb(ahc, SBLKCTL) & SELBUSB ? 'B': 'A'; - int printerror = 1; - - ahc_outb(ahc, SCSISEQ, 0); - if (lastphase == P_MESGOUT) { - u_int8_t sindex; - u_int8_t message; - - sindex = ahc_inb(ahc, SINDEX); - message = ahc_inb(ahc, sindex - 1); - - if (message == MSG_ABORT) { - - sc_print_addr(scb->xs->sc_link); - printf("SCB %d - Abort Completed.\n", - scb->hscb->tag); - ahc_reset_device(ahc, target, channel, - SCB_LUN(scb), - SCB_LIST_NULL, - XS_TIMEOUT); - ahc_run_done_queue(ahc); - scb = NULL; - printerror = 0; - } else if (message == MSG_ABORT_TAG) { - - sc_print_addr(scb->xs->sc_link); - printf("SCB %d - Abort Tag Completed.\n", - scb->hscb->tag); - ahc_reset_device(ahc, - target, - channel, - SCB_LUN(scb), - scb->hscb->tag, - XS_TIMEOUT); - ahc_run_done_queue(ahc); - scb = NULL; - printerror = 0; - } else if (message == MSG_BUS_DEV_RESET) { - ahc_handle_devreset(ahc, target, - channel); - scb = NULL; - printerror = 0; - } - } - if (printerror != 0) { - if (scb != NULL) { - u_int8_t tag; - - if ((scb->hscb->control & TAG_ENB) != 0) - tag = scb->hscb->tag; - else - tag = SCB_LIST_NULL; - ahc_reset_device(ahc, target, channel, - SCB_LUN(scb), tag, XS_TIMEOUT); - } else { - /* - * XXX can we handle this better? - * Reset the bus? Send a Bus Device Reset? - */ - ahc_reset_device(ahc, target, channel, - ALL_LUNS, SCB_LIST_NULL, - XS_TIMEOUT); - printf("%s: ", ahc_name(ahc)); - } - printf("Unexpected busfree. LASTPHASE == 0x%x\n" - "SEQADDR == 0x%x\n", - lastphase, (ahc_inb(ahc, SEQADDR1) << 8) - | ahc_inb(ahc, SEQADDR0)); - } - ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) & ~ENBUSFREE); - ahc_outb(ahc, CLRSINT1, CLRBUSFREE); - ahc_outb(ahc, CLRINT, CLRSCSIINT); - restart_sequencer(ahc); - } else if ((status & SELTO) != 0) { - struct scsi_xfer *xs; - u_int8_t scbptr; - u_int8_t nextscb; - - scbptr = ahc_inb(ahc, WAITING_SCBH); - ahc_outb(ahc, SCBPTR, scbptr); - scb_index = ahc_inb(ahc, SCB_TAG); - - if (scb_index < ahc->scb_data->numscbs) { - scb = ahc->scb_data->scbarray[scb_index]; - if ((scb->flags & SCB_ACTIVE) == 0) - scb = NULL; - } else - scb = NULL; - - if (scb == NULL) { - printf("%s: ahc_intr - referenced scb not " - "valid during SELTO scb(%d)\n", - ahc_name(ahc), scb_index); - printf("SEQADDR = 0x%x SCSISEQ = 0x%x " - "SSTAT0 = 0x%x SSTAT1 = 0x%x\n", - ahc_inb(ahc, SEQADDR0) - | (ahc_inb(ahc, SEQADDR1) << 8), - ahc_inb(ahc, SCSISEQ), ahc_inb(ahc, SSTAT0), - ahc_inb(ahc,SSTAT1)); - } else { - /* - * XXX If we queued an abort tag, go clean up the - * disconnected list. - */ - xs = scb->xs; - xs->error = XS_SELTIMEOUT; - /* - * Clear any pending messages for the timed out - * target, and mark the target as free - */ - ahc_outb(ahc, MSG_LEN, 0); - ahc_index_busy_target(ahc, SCB_TARGET(scb), - SCB_IS_SCSIBUS_B(scb) ? 'B' : 'A', - /*unbusy*/TRUE); - - ahc_outb(ahc, SCB_CONTROL, 0); - /* Shift the waiting Q forward. */ - nextscb = ahc_inb(ahc, SCB_NEXT); - ahc_outb(ahc, WAITING_SCBH, nextscb); - - ahc_add_curscb_to_free_list(ahc); - } - /* Stop the selection */ - ahc_outb(ahc, SCSISEQ, 0); - - ahc_outb(ahc, CLRSINT1, CLRSELTIMEO|CLRBUSFREE); - - ahc_outb(ahc, CLRINT, CLRSCSIINT); - - restart_sequencer(ahc); - } else if (scb == NULL) { - printf("%s: ahc_intr - referenced scb not " - "valid during scsiint 0x%x scb(%d)\n" - "SIMODE0 = 0x%x, SIMODE1 = 0x%x, SSTAT0 = 0x%x\n" - "SEQADDR = 0x%x\n", ahc_name(ahc), - status, scb_index, ahc_inb(ahc, SIMODE0), - ahc_inb(ahc, SIMODE1), ahc_inb(ahc, SSTAT0), - (ahc_inb(ahc, SEQADDR1) << 8) - | ahc_inb(ahc, SEQADDR0)); - ahc_outb(ahc, CLRSINT1, status); - ahc_outb(ahc, CLRINT, CLRSCSIINT); - unpause_sequencer(ahc, /*unpause_always*/TRUE); - scb = NULL; - } else if ((status & SCSIPERR) != 0) { - /* - * Determine the bus phase and - * queue an appropriate message - */ - char *phase; - u_int8_t mesg_out = MSG_NOOP; - u_int8_t lastphase = ahc_inb(ahc, LASTPHASE); - struct scsi_xfer *xs; - - xs = scb->xs; - sc_print_addr(xs->sc_link); - - switch (lastphase) { - case P_DATAOUT: - phase = "Data-Out"; - break; - case P_DATAIN: - phase = "Data-In"; - mesg_out = MSG_INITIATOR_DET_ERR; - break; - case P_COMMAND: - phase = "Command"; - break; - case P_MESGOUT: - phase = "Message-Out"; - break; - case P_STATUS: - phase = "Status"; - mesg_out = MSG_INITIATOR_DET_ERR; - break; - case P_MESGIN: - phase = "Message-In"; - mesg_out = MSG_PARITY_ERROR; - break; - default: - phase = "unknown"; - break; - } - printf("parity error during %s phase.\n", phase); - - /* - * We've set the hardware to assert ATN if we - * get a parity error on "in" phases, so all we - * need to do is stuff the message buffer with - * the appropriate message. "In" phases have set - * mesg_out to something other than MSG_NOP. - */ - if (mesg_out != MSG_NOOP) { - ahc_outb(ahc, MSG_OUT, mesg_out); - ahc_outb(ahc, MSG_LEN, 1); - scb = NULL; - } else - /* - * Should we allow the target to make - * this decision for us? If we get a - * sense request from the drive, we will - * not fetch it since xs->error != XS_NOERROR. - * perhaps we need two error fields in the - * xs structure? - */ - xs->error = XS_DRIVER_STUFFUP; - ahc_outb(ahc, CLRSINT1, CLRSCSIPERR); - ahc_outb(ahc, CLRINT, CLRSCSIINT); - unpause_sequencer(ahc, /*unpause_always*/TRUE); - } else { - sc_print_addr(scb->xs->sc_link); - printf("Unknown SCSIINT. Status = 0x%x\n", status); - ahc_outb(ahc, CLRSINT1, status); - ahc_outb(ahc, CLRINT, CLRSCSIINT); - unpause_sequencer(ahc, /*unpause_always*/TRUE); - scb = NULL; - } - if (scb != NULL) { - /* We want to process the command */ - ahc_done(ahc, scb); - } -} - -static void -ahc_handle_devreset(ahc, target, channel) - struct ahc_softc *ahc; - int target; - char channel; -{ - u_int16_t targ_mask; - u_int8_t targ_scratch; - int scratch_offset = target; - int found; - - if (channel == 'B') - scratch_offset += 8; - targ_mask = (0x01 << scratch_offset); - /* - * Go back to async/narrow transfers and - * renegotiate. - */ - ahc->needsdtr |= ahc->needsdtr_orig & targ_mask; - ahc->needwdtr |= ahc->needwdtr_orig & targ_mask; - ahc->sdtrpending &= ~targ_mask; - ahc->wdtrpending &= ~targ_mask; - targ_scratch = ahc_inb(ahc, TARG_SCRATCH + scratch_offset); - targ_scratch &= SXFR; - ahc_outb(ahc, TARG_SCRATCH + scratch_offset, targ_scratch); - found = ahc_reset_device(ahc, target, channel, ALL_LUNS, - SCB_LIST_NULL, XS_NOERROR); - printf("%s: Bus Device Reset delivered. %d SCBs aborted\n", - ahc_name(ahc), found); - ahc_run_done_queue(ahc); -} - -/* - * We have a scb which has been processed by the - * adaptor, now we look to see how the operation - * went. - */ -static void -ahc_done(ahc, scb) - struct ahc_softc *ahc; - struct scb *scb; -{ - struct scsi_xfer *xs = scb->xs; - - SC_DEBUG(xs->sc_link, SDEV_DB2, ("ahc_done\n")); - /* - * If the recovery SCB completes, we have to be - * out of our timeout. - */ - if (scb->flags & SCB_RECOVERY_SCB) { - ahc->in_timeout = FALSE; - sc_print_addr(scb->xs->sc_link); - printf("no longer in timeout\n"); - } - /* - * Put the results of the operation - * into the xfer and call whoever started it - */ - /* Don't override the error value. */ - if (xs->error == XS_NOERROR - && (scb->flags & SCB_SENSE) != 0) - xs->error = XS_SENSE; - -#if defined(__FreeBSD__) - if ((xs->flags & SCSI_ERR_OK) && !(xs->error == XS_SENSE)) { - /* All went correctly OR errors expected */ - xs->error = XS_NOERROR; - } -#elif defined(__NetBSD__) - /* - * Since NetBSD doesn't have error ignoring operation mode - * (SCSI_ERR_OK in FreeBSD), we don't have to care this case. - */ -#endif - xs->flags |= ITSDONE; -#ifdef AHC_TAGENABLE - /* - * This functionality will be provided by the generic SCSI layer - * in FreeBSD 3.0. - */ - if (xs->cmd->opcode == INQUIRY && xs->error == XS_NOERROR) { - struct scsi_inquiry_data *inq_data; - u_int16_t mask = 0x01 << (xs->sc_link->target | - (scb->hscb->tcl & 0x08)); - /* - * Sneak a look at the results of the SCSI Inquiry - * command and see if we can do Tagged queing. This - * should really be done by the higher level drivers. - */ - inq_data = (struct scsi_inquiry_data *)xs->data; - if ((inq_data->flags & SID_CmdQue) - && !(ahc->tagenable & mask)) { - printf("%s: target %d Tagged Queuing Device\n", - ahc_name(ahc), xs->sc_link->target); - ahc->tagenable |= mask; - if (ahc->scb_data->maxhscbs >= 16 - || (ahc->flags & AHC_PAGESCBS)) { - /* Default to 8 tags */ - xs->sc_link->opennings += 6; - } else { - /* - * Default to 4 tags on whimpy - * cards that don't have much SCB - * space and can't page. This prevents - * a single device from hogging all - * slots. We should really have a better - * way of providing fairness. - */ - xs->sc_link->opennings += 2; - } - } - } -#endif /* AHC_TAGENABLE */ - if ((scb->flags & (SCB_MSGOUT_WDTR|SCB_MSGOUT_SDTR)) != 0) { - /* - * Turn off the pending flags for any DTR messages - * regardless of whether they completed successfully - * or not. This ensures that we don't have lingering - * state after we abort an SCB. - */ - u_int16_t mask; - - mask = (0x01 << (xs->sc_link->target - | (IS_SCSIBUS_B(ahc, xs->sc_link) ? SELBUSB : 0))); - if (scb->flags & SCB_MSGOUT_WDTR) - ahc->wdtrpending &= ~mask; - if (scb->flags & SCB_MSGOUT_SDTR) - ahc->sdtrpending &= ~mask; - } - untimeout(ahc_timeout, (caddr_t)scb, scb->xs->timeout_ch); - ahc_free_scb(ahc, scb); - /* - * If we're polling, we rely on the ITS_DONE flag in the xs structure - * to know that the command has completed. Unfortunately, scsi_done - * can cause the same xs to get requeued putting us in an infinite - * loop. So, we defer the scsi_done call until the poll routine exits - * its loop. I hate the way this works. - */ - if ((xs->flags & SCSI_NOMASK) == 0) - scsi_done(xs); -} - -/* - * Start the board, ready for normal operation - */ -int -ahc_init(ahc) - struct ahc_softc *ahc; -{ - u_int8_t scsi_conf, sblkctl, sxfrctl1, i; - u_int16_t ultraenable = 0; - int max_targ = 15; - /* - * Assume we have a board at this stage and it has been reset. - */ - - /* Handle the SCBPAGING option */ -#ifndef AHC_SCBPAGING_ENABLE - ahc->flags &= ~AHC_PAGESCBS; -#endif - - /* Determine channel configuration and who we are on the scsi bus. */ - switch ((sblkctl = ahc_inb(ahc, SBLKCTL) & 0x0a)) { - case 0: - ahc->our_id = (ahc_inb(ahc, SCSICONF) & HSCSIID); - ahc->flags &= ~AHC_CHANNEL_B_PRIMARY; - if ((ahc->type & AHC_39X) != 0) { - char channel = 'A'; - - if ((ahc->flags & (AHC_CHNLB|AHC_CHNLC)) != 0) - channel = ahc->flags & AHC_CHNLB ? 'B' : 'C'; - printf("Channel %c, SCSI Id=%d, ", channel, - ahc->our_id); - } else - printf("Single Channel, SCSI Id=%d, ", ahc->our_id); - ahc_outb(ahc, SEQ_FLAGS, ahc->flags & AHC_PAGESCBS); - break; - case 2: - ahc->our_id = (ahc_inb(ahc, SCSICONF + 1) & HWSCSIID); - ahc->flags &= ~AHC_CHANNEL_B_PRIMARY; - if ((ahc->type & AHC_39X) != 0) { - char channel = 'A'; - - if ((ahc->flags & (AHC_CHNLB|AHC_CHNLC)) != 0) - channel = ahc->flags & AHC_CHNLB ? 'B' : 'C'; - printf("Wide Channel %c, SCSI Id=%d, ", channel, - ahc->our_id); - } else - printf("Wide Channel, SCSI Id=%d, ", ahc->our_id); - ahc->type |= AHC_WIDE; - ahc_outb(ahc, SEQ_FLAGS, WIDE_BUS | (ahc->flags & AHC_PAGESCBS)); - break; - case 8: - ahc->our_id = (ahc_inb(ahc, SCSICONF) & HSCSIID); - ahc->our_id_b = (ahc_inb(ahc, SCSICONF + 1) & HSCSIID); - printf("Twin Channel, A SCSI Id=%d, B SCSI Id=%d, ", - ahc->our_id, ahc->our_id_b); - ahc->type |= AHC_TWIN; - ahc_outb(ahc, SEQ_FLAGS, TWIN_BUS | (ahc->flags & AHC_PAGESCBS)); - break; - default: - printf(" Unsupported adapter type. Ignoring\n"); - return(-1); - } - - /* Determine the number of SCBs and initialize them */ - - if (ahc->scb_data->maxhscbs == 0) { - /* SCB 0 heads the free list */ - ahc_outb(ahc, FREE_SCBH, 0); - for (i = 0; i < AHC_SCB_MAX; i++) { - ahc_outb(ahc, SCBPTR, i); - ahc_outb(ahc, SCB_CONTROL, i); - if(ahc_inb(ahc, SCB_CONTROL) != i) - break; - ahc_outb(ahc, SCBPTR, 0); - if(ahc_inb(ahc, SCB_CONTROL) != 0) - break; - ahc_outb(ahc, SCBPTR, i); - - /* Clear the control byte. */ - ahc_outb(ahc, SCB_CONTROL, 0); - - /* Set the next pointer */ - ahc_outb(ahc, SCB_NEXT, i+1); - - /* Make the tag number invalid */ - ahc_outb(ahc, SCB_TAG, SCB_LIST_NULL); - - /* No Busy non-tagged targets yet */ - ahc_outb(ahc, SCB_BUSYTARGETS, SCB_LIST_NULL); - ahc_outb(ahc, SCB_BUSYTARGETS + 1, SCB_LIST_NULL); - ahc_outb(ahc, SCB_BUSYTARGETS + 2, SCB_LIST_NULL); - ahc_outb(ahc, SCB_BUSYTARGETS + 3, SCB_LIST_NULL); - } - - /* Make that the last SCB terminates the free list */ - ahc_outb(ahc, SCBPTR, i-1); - ahc_outb(ahc, SCB_NEXT, SCB_LIST_NULL); - - /* Ensure we clear the 0 SCB's control byte. */ - ahc_outb(ahc, SCBPTR, 0); - ahc_outb(ahc, SCB_CONTROL, 0); - - ahc->scb_data->maxhscbs = i; - } - - if ((ahc->scb_data->maxhscbs < AHC_SCB_MAX) - && (ahc->flags & AHC_PAGESCBS)) { - u_int8_t max_scbid = 255; - - /* Determine the number of valid bits in the FIFOs */ - ahc_outb(ahc, QINFIFO, max_scbid); - max_scbid = ahc_inb(ahc, QINFIFO); - ahc->scb_data->maxscbs = MIN(AHC_SCB_MAX, max_scbid + 1); - printf("%d/%d SCBs\n", ahc->scb_data->maxhscbs, - ahc->scb_data->maxscbs); - } else { - ahc->scb_data->maxscbs = ahc->scb_data->maxhscbs; - ahc->flags &= ~AHC_PAGESCBS; - printf("%d SCBs\n", ahc->scb_data->maxhscbs); - } - -#ifdef AHC_DEBUG - if (ahc_debug & AHC_SHOWMISC) { - printf("%s: hardware scb %d bytes; kernel scb %d bytes; " - "ahc_dma %d bytes\n", - ahc_name(ahc), - sizeof(struct hardware_scb), - sizeof(struct scb), - sizeof(struct ahc_dma_seg)); - } -#endif /* AHC_DEBUG */ - - /* Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1, for both channels*/ - if (ahc->type & AHC_TWIN) { - /* - * The device is gated to channel B after a chip reset, - * so set those values first - */ - ahc_outb(ahc, SCSIID, ahc->our_id_b); - scsi_conf = ahc_inb(ahc, SCSICONF + 1); - sxfrctl1 = ahc_inb(ahc, SXFRCTL1); - ahc_outb(ahc, SXFRCTL1, (scsi_conf & (ENSPCHK|STIMESEL)) - |(sxfrctl1 & STPWEN) - |ENSTIMER|ACTNEGEN); - ahc_outb(ahc, SIMODE1, ENSELTIMO|ENSCSIRST|ENSCSIPERR); - if (ahc->type & AHC_ULTRA) - ahc_outb(ahc, SXFRCTL0, DFON|SPIOEN|FAST20); - else - ahc_outb(ahc, SXFRCTL0, DFON|SPIOEN); - - if (scsi_conf & RESET_SCSI) { - /* Reset the bus */ - if (bootverbose) - printf("%s: Resetting Channel B\n", - ahc_name(ahc)); - ahc_reset_current_bus(ahc); - } - - /* Select Channel A */ - ahc_outb(ahc, SBLKCTL, 0); - } - ahc_outb(ahc, SCSIID, ahc->our_id); - scsi_conf = ahc_inb(ahc, SCSICONF); - sxfrctl1 = ahc_inb(ahc, SXFRCTL1); - ahc_outb(ahc, SXFRCTL1, (scsi_conf & (ENSPCHK|STIMESEL)) - |(sxfrctl1 & STPWEN) - |ENSTIMER|ACTNEGEN); - ahc_outb(ahc, SIMODE1, ENSELTIMO|ENSCSIRST|ENSCSIPERR); - if (ahc->type & AHC_ULTRA) - ahc_outb(ahc, SXFRCTL0, DFON|SPIOEN|FAST20); - else - ahc_outb(ahc, SXFRCTL0, DFON|SPIOEN); - - if (scsi_conf & RESET_SCSI) { - /* Reset the bus */ - if (bootverbose) - printf("%s: Resetting Channel A\n", ahc_name(ahc)); - - ahc_reset_current_bus(ahc); - } - - /* - * Look at the information that board initialization or - * the board bios has left us. In the lower four bits of each - * target's scratch space any value other than 0 indicates - * that we should initiate synchronous transfers. If it's zero, - * the user or the BIOS has decided to disable synchronous - * negotiation to that target so we don't activate the needsdtr - * flag. - */ - ahc->needsdtr_orig = 0; - ahc->needwdtr_orig = 0; - - /* Grab the disconnection disable table and invert it for our needs */ - if (ahc->flags & AHC_USEDEFAULTS) { - printf("%s: Host Adapter Bios disabled. Using default SCSI " - "device parameters\n", ahc_name(ahc)); - ahc->discenable = 0xff; - } else - ahc->discenable = ~((ahc_inb(ahc, DISC_DSB + 1) << 8) - | ahc_inb(ahc, DISC_DSB)); - - if (!(ahc->type & (AHC_WIDE|AHC_TWIN))) - max_targ = 7; - - for (i = 0; i <= max_targ; i++) { - u_int8_t target_settings; - if (ahc->flags & AHC_USEDEFAULTS) { - target_settings = 0; /* 10MHz/20MHz */ - ahc->needsdtr_orig |= (0x01 << i); - ahc->needwdtr_orig |= (0x01 << i); - if (ahc->type & AHC_ULTRA) - ultraenable |= (0x01 << i); - } else { - /* Take the settings leftover in scratch RAM. */ - target_settings = ahc_inb(ahc, TARG_SCRATCH + i); - - if (target_settings & 0x0f) { - ahc->needsdtr_orig |= (0x01 << i); - /*Default to a asynchronous transfers(0 offset)*/ - target_settings &= 0xf0; - } - if (target_settings & 0x80) { - ahc->needwdtr_orig |= (0x01 << i); - /* - * We'll set the Wide flag when we - * are successful with Wide negotiation. - * Turn it off for now so we aren't - * confused. - */ - target_settings &= 0x7f; - } - if (ahc->type & AHC_ULTRA) { - /* - * Enable Ultra for any target that - * has a valid ultra syncrate setting. - */ - u_int8_t rate = target_settings & 0x70; - if (rate == 0x00 || rate == 0x10 || - rate == 0x20 || rate == 0x40) { - if (rate == 0x40) { - /* Treat 10MHz specially */ - target_settings &= ~0x70; - } else - ultraenable |= (0x01 << i); - } - } - } - ahc_outb(ahc, TARG_SCRATCH+i,target_settings); - } - /* - * If we are not a WIDE device, forget WDTR. This - * makes the driver work on some cards that don't - * leave these fields cleared when the BIOS is not - * installed. - */ - if ((ahc->type & AHC_WIDE) == 0) - ahc->needwdtr_orig = 0; - ahc->needsdtr = ahc->needsdtr_orig; - ahc->needwdtr = ahc->needwdtr_orig; - ahc->sdtrpending = 0; - ahc->wdtrpending = 0; - ahc->tagenable = 0; - ahc->orderedtag = 0; - - ahc_outb(ahc, ULTRA_ENB, ultraenable & 0xff); - ahc_outb(ahc, ULTRA_ENB + 1, (ultraenable >> 8) & 0xff); - -#ifdef AHC_DEBUG - /* How did we do? */ - if (ahc_debug & AHC_SHOWMISC) - printf("NEEDSDTR == 0x%x\nNEEDWDTR == 0x%x\n" - "DISCENABLE == 0x%x\n", ahc->needsdtr, - ahc->needwdtr, ahc->discenable); -#endif - /* - * Allocate enough "hardware scbs" to handle - * the maximum number of concurrent transactions - * we can have active. We have to use contigmalloc - * if this array crosses a page boundary since the - * sequencer depends on this array being physically - * contiguous. - */ - if (ahc->scb_data->hscbs == NULL) { - size_t array_size; - u_int32_t hscb_physaddr; - - array_size = ahc->scb_data->maxscbs*sizeof(struct hardware_scb); - if (array_size > PAGE_SIZE) { - ahc->scb_data->hscbs = (struct hardware_scb *) - contigmalloc(array_size, M_DEVBUF, - M_NOWAIT, 0ul, 0xffffffff, - PAGE_SIZE, 0x10000); - } else { - ahc->scb_data->hscbs = (struct hardware_scb *) - malloc(array_size, M_DEVBUF, M_NOWAIT); - } - - if (ahc->scb_data->hscbs == NULL) { - printf("%s: unable to allocate hardware SCB array. " - "Failing attach\n", ahc_name(ahc)); - return (-1); - } - /* At least the control byte of each hscb needs to be zeroed */ - bzero(ahc->scb_data->hscbs, array_size); - - /* Tell the sequencer where it can find the hscb array. */ - hscb_physaddr = vtophys(ahc->scb_data->hscbs); - ahc_outb(ahc, HSCB_ADDR, hscb_physaddr & 0xFF); - ahc_outb(ahc, HSCB_ADDR + 1, (hscb_physaddr >> 8)& 0xFF); - ahc_outb(ahc, HSCB_ADDR + 2, (hscb_physaddr >> 16)& 0xFF); - ahc_outb(ahc, HSCB_ADDR + 3, (hscb_physaddr >> 24)& 0xFF); - } - - /* - * Q-Full-Count. Some cards have more Q space - * then SCBs. - */ - if (ahc->type & AHC_AIC7770) { - ahc->qfullcount = 4; - ahc->qcntmask = 0x07; - } else if (ahc->type & AHC_AIC7850) { - ahc->qfullcount = 8; - ahc->qcntmask = 0x0f; - } else if (ahc->scb_data->maxhscbs == 255) { - /* 7870/7880 with external SRAM */ - ahc->qfullcount = 255; - ahc->qcntmask = 0xff; - } else { - /* 7870/7880 */ - ahc->qfullcount = 16; - ahc->qcntmask = 0x1f; - } - - ahc_outb(ahc, CMDOUTCNT, 0); - - /* We don't have any waiting selections */ - ahc_outb(ahc, WAITING_SCBH, SCB_LIST_NULL); - - /* Our disconnection list is empty too */ - ahc_outb(ahc, DISCONNECTED_SCBH, SCB_LIST_NULL); - - /* Message out buffer starts empty */ - ahc_outb(ahc, MSG_LEN, 0x00); - - /* - * Load the Sequencer program and Enable the adapter - * in "fast" mode. - */ - if (bootverbose) - printf("%s: Downloading Sequencer Program...", - ahc_name(ahc)); - - ahc_loadseq(ahc); - - if (bootverbose) - printf("Done\n"); - - unpause_sequencer(ahc, /*unpause_always*/TRUE); - - /* - * Note that we are going and return (to probe) - */ - ahc->flags |= AHC_INIT; - return (0); -} - -static void -ahcminphys(bp) - struct buf *bp; -{ -/* - * Even though the card can transfer up to 16megs per command - * we are limited by the number of segments in the dma segment - * list that we can hold. The worst case is that all pages are - * discontinuous physically, hense the "page per segment" limit - * enforced here. - */ - if (bp->b_bcount > ((AHC_NSEG - 1) * PAGE_SIZE)) { - bp->b_bcount = ((AHC_NSEG - 1) * PAGE_SIZE); - } -#if defined(__NetBSD__) - minphys(bp); -#endif -} - -/* - * start a scsi operation given the command and - * the data address, target, and lun all of which - * are stored in the scsi_xfer struct - */ -static int32_t -ahc_scsi_cmd(xs) - struct scsi_xfer *xs; -{ - struct scb *scb; - struct hardware_scb *hscb; - struct ahc_softc *ahc; - u_int16_t mask; - int flags; - int s; - - ahc = (struct ahc_softc *)xs->sc_link->adapter_softc; - mask = (0x01 << (xs->sc_link->target - | (IS_SCSIBUS_B(ahc, xs->sc_link) ? SELBUSB : 0))); - SC_DEBUG(xs->sc_link, SDEV_DB2, ("ahc_scsi_cmd\n")); - flags = xs->flags; - - /* - * get an scb to use. If the transfer - * is from a buf (possibly from interrupt time) - * then we can't allow it to sleep - */ - if ((scb = ahc_get_scb(ahc, flags)) == NULL) { - xs->error = XS_DRIVER_STUFFUP; - return (TRY_AGAIN_LATER); - } - hscb = scb->hscb; - SC_DEBUG(xs->sc_link, SDEV_DB3, ("start scb(%p)\n", scb)); - scb->xs = xs; - - /* - * Put all the arguments for the xfer in the scb - */ - if (ahc->discenable & mask) { - hscb->control |= DISCENB; - if (ahc->tagenable & mask) - hscb->control |= MSG_SIMPLE_Q_TAG; - if (ahc->orderedtag & mask) { - /* XXX this should be handled by the upper SCSI layer */ - printf("Ordered Tag sent\n"); - hscb->control |= MSG_ORDERED_Q_TAG; - ahc->orderedtag &= ~mask; - } - } - - if (flags & SCSI_RESET) { - scb->flags |= SCB_DEVICE_RESET; - hscb->control |= MK_MESSAGE; - } else if ((ahc->needwdtr & mask) && !(ahc->wdtrpending & mask)) { - ahc->wdtrpending |= mask; - hscb->control |= MK_MESSAGE; - scb->flags |= SCB_MSGOUT_WDTR; - } else if((ahc->needsdtr & mask) && !(ahc->sdtrpending & mask)) { - ahc->sdtrpending |= mask; - hscb->control |= MK_MESSAGE; - scb->flags |= SCB_MSGOUT_SDTR; - } - -#if 0 - /* Set the trace flag if this is the target we want to trace */ - if (ahc->unit == 2 && xs->sc_link->target == 3) - hscb->control |= TRACE_SCB; -#endif - - hscb->tcl = ((xs->sc_link->target << 4) & 0xF0) - | (IS_SCSIBUS_B(ahc,xs->sc_link)? SELBUSB : 0) - | (xs->sc_link->lun & 0x07); - hscb->cmdlen = xs->cmdlen; - hscb->cmdpointer = vtophys(xs->cmd); - xs->resid = 0; - xs->status = 0; - - /* Only use S/G if non-zero length */ - if (xs->datalen) { - int seg; - u_int32_t datalen; - vm_offset_t vaddr; - u_int32_t paddr; - u_int32_t nextpaddr; - struct ahc_dma_seg *sg; - - seg = 0; - datalen = xs->datalen; - vaddr = (vm_offset_t)xs->data; - paddr = vtophys(vaddr); - sg = scb->ahc_dma; - hscb->SG_list_pointer = vtophys(sg); - - while ((datalen > 0) && (seg < AHC_NSEG)) { - /* put in the base address and length */ - sg->addr = paddr; - sg->len = 0; - - /* do it at least once */ - nextpaddr = paddr; - - while ((datalen > 0) && (paddr == nextpaddr)) { - u_int32_t size; - /* - * This page is contiguous (physically) - * with the the last, just extend the - * length - */ - /* how far to the end of the page */ - nextpaddr = (paddr & (~PAGE_MASK)) + PAGE_SIZE; - - /* - * Compute the maximum size - */ - size = nextpaddr - paddr; - if (size > datalen) - size = datalen; - - sg->len += size; - vaddr += size; - datalen -= size; - if (datalen > 0) - paddr = vtophys(vaddr); - } - /* - * next page isn't contiguous, finish the seg - */ - seg++; - sg++; - } - hscb->SG_segment_count = seg; - scb->sg_count = hscb->SG_segment_count; - - /* Copy the first SG into the data pointer area */ - hscb->data = scb->ahc_dma->addr; - hscb->datalen = scb->ahc_dma->len | (SCB_LIST_NULL << 24); - if (datalen) { - /* there's still data, must have run out of segs! */ - printf("%s: ahc_scsi_cmd: more than %d DMA segs\n", - ahc_name(ahc), AHC_NSEG); - xs->error = XS_DRIVER_STUFFUP; - ahc_free_scb(ahc, scb); - return (COMPLETE); - } -#ifdef AHC_BROKEN_CACHE - if (ahc_broken_cache) - INVALIDATE_CACHE(); -#endif - } else { - /* - * No data xfer, use non S/G values - */ - hscb->SG_segment_count = 0; - scb->sg_count = hscb->SG_segment_count; - hscb->SG_list_pointer = 0; - hscb->data = 0; - hscb->datalen = (SCB_LIST_NULL << 24); - } - -#ifdef AHC_DEBUG - if((ahc_debug & AHC_SHOWSCBS) && (xs->sc_link->target == DEBUGTARGET)) - ahc_print_scb(scb); -#endif - s = splbio(); - - STAILQ_INSERT_TAIL(&ahc->waiting_scbs, scb, links); - - scb->flags |= SCB_ACTIVE|SCB_WAITINGQ; - - ahc_run_waiting_queue(ahc); - - if ((flags & SCSI_NOMASK) == 0) { - scb->xs->timeout_ch = timeout(ahc_timeout, (caddr_t)scb, - (xs->timeout * hz) / 1000); - splx(s); - return (SUCCESSFULLY_QUEUED); - } - /* - * If we can't use interrupts, poll for completion - */ - SC_DEBUG(xs->sc_link, SDEV_DB3, ("cmd_poll\n")); - do { - if (ahc_poll(ahc, xs->timeout)) { - if (!(xs->flags & SCSI_SILENT)) - printf("cmd fail\n"); - ahc_timeout(scb); - break; - } - } while ((xs->flags & ITSDONE) == 0); /* a non command complete intr */ - scsi_done(xs); - splx(s); - return (COMPLETE); -} - -/* - * Look for space in the QINFIFO and queue as many SCBs in the waiting - * queue as possible. Assumes that it is called at splbio(). - */ -static void -ahc_run_waiting_queue(ahc) - struct ahc_softc *ahc; -{ - struct scb *scb; - - pause_sequencer(ahc); - - if (ahc->curqincnt >= ahc->qfullcount) { - ahc->curqincnt = ahc_inb(ahc, QINCNT) & ahc->qcntmask; - } - - while ((scb = ahc->waiting_scbs.stqh_first) != NULL - && (ahc->curqincnt < ahc->qfullcount)) { - - STAILQ_REMOVE_HEAD(&ahc->waiting_scbs, links); - scb->flags &= ~SCB_WAITINGQ; - - ahc_outb(ahc, QINFIFO, scb->hscb->tag); - - if ((ahc->flags & AHC_PAGESCBS) != 0) - /* - * We only care about this statistic when paging - * since it is impossible to overflow the qinfifo - * in the non-paging case. - */ - ahc->curqincnt++; - } - unpause_sequencer(ahc, /*Unpause always*/FALSE); -} - -/* - * An scb (and hence an scb entry on the board) is put onto the - * free list. - */ -static void -ahc_free_scb(ahc, scb) - struct ahc_softc *ahc; - struct scb *scb; -{ - struct hardware_scb *hscb; - int opri; - - hscb = scb->hscb; - - opri = splbio(); - - /* Clean up for the next user */ - scb->flags = SCB_FREE; - hscb->control = 0; - hscb->status = 0; - - STAILQ_INSERT_HEAD(&ahc->scb_data->free_scbs, scb, links); - if (scb->links.stqe_next == NULL) { - /* - * If there were no SCBs available, wake anybody waiting - * for one to come free. - */ - wakeup((caddr_t)&ahc->scb_data->free_scbs); - } -#ifdef AHC_DEBUG - ahc->activescbs--; -#endif - splx(opri); -} - -/* - * Get a free scb, either one already assigned to a hardware slot - * on the adapter or one that will require an SCB to be paged out before - * use. If there are none, see if we can allocate a new SCB. Otherwise - * either return an error or sleep. - */ -static struct scb * -ahc_get_scb(ahc, flags) - struct ahc_softc *ahc; - u_int32_t flags; -{ - struct scb *scbp; - int opri; - - opri = splbio(); - /* - * If we can and have to, sleep waiting for one to come free - * but only if we can't allocate a new one. - */ - while (1) { - if ((scbp = ahc->scb_data->free_scbs.stqh_first)) { - STAILQ_REMOVE_HEAD(&ahc->scb_data->free_scbs, links); - } else if(ahc->scb_data->numscbs < ahc->scb_data->maxscbs) { - scbp = ahc_alloc_scb(ahc); - if (scbp == NULL) - printf("%s: Can't malloc SCB\n", ahc_name(ahc)); - } else if ((flags & SCSI_NOSLEEP) == 0) { - tsleep((caddr_t)&ahc->scb_data->free_scbs, PRIBIO, - "ahcscb", 0); - continue; - } - break; - } - -#ifdef AHC_DEBUG - if (scbp) { - ahc->activescbs++; - if((ahc_debug & AHC_SHOWSCBCNT) - && (ahc->activescbs == ahc->scb_data->maxhscbs)) - printf("%s: Max SCBs active\n", ahc_name(ahc)); - } -#endif - - splx(opri); - - return (scbp); -} - - -static struct scb * -ahc_alloc_scb(ahc) - struct ahc_softc *ahc; -{ - static struct ahc_dma_seg *next_sg_array = NULL; - static int sg_arrays_free = 0; - struct scb *newscb; - - newscb = (struct scb *) malloc(sizeof(struct scb), M_DEVBUF, M_NOWAIT); - if (newscb != NULL) { - bzero(newscb, sizeof(struct scb)); - if (next_sg_array == NULL) { - size_t alloc_size = sizeof(struct ahc_dma_seg) - * AHC_NSEG; - sg_arrays_free = PAGE_SIZE / alloc_size; - alloc_size *= sg_arrays_free; - if (alloc_size == 0) - panic("%s: SG list doesn't fit in a page", - ahc_name(ahc)); - next_sg_array = (struct ahc_dma_seg *) - malloc(alloc_size, M_DEVBUF, M_NOWAIT); - } - if (next_sg_array != NULL) { - struct hardware_scb *hscb; - - newscb->ahc_dma = next_sg_array; - sg_arrays_free--; - if (sg_arrays_free == 0) - next_sg_array = NULL; - else - next_sg_array = &next_sg_array[AHC_NSEG]; - hscb = &ahc->scb_data->hscbs[ahc->scb_data->numscbs]; - newscb->hscb = hscb; - hscb->control = 0; - hscb->status = 0; - hscb->tag = ahc->scb_data->numscbs; - hscb->residual_data_count[2] = 0; - hscb->residual_data_count[1] = 0; - hscb->residual_data_count[0] = 0; - hscb->residual_SG_segment_count = 0; - ahc->scb_data->numscbs++; - /* - * Place in the scbarray - * Never is removed. - */ - ahc->scb_data->scbarray[hscb->tag] = newscb; - } else { - free(newscb, M_DEVBUF); - newscb = NULL; - } - } - return newscb; -} - -static void -ahc_loadseq(struct ahc_softc *ahc) -{ - int options; - struct patch *cur_patch; - int i; - int downloaded; - u_int8_t download_consts[4]; - - options = 1; /* Code for all options */ - downloaded = 0; - if ((ahc->type & AHC_ULTRA) != 0) - options |= ULTRA; - if ((ahc->type & AHC_TWIN) != 0) - options |= TWIN_CHANNEL; - if (ahc->scb_data->maxscbs > ahc->scb_data->maxhscbs) - options |= SCB_PAGING; - - /* Setup downloadable constant table */ - download_consts[SCBCOUNT] = ahc->scb_data->maxhscbs; - download_consts[COMP_SCBCOUNT] = -ahc->scb_data->maxscbs & 0xFF; - download_consts[FIFODEPTH] = ahc->qfullcount; - download_consts[QCNTMASK] = ahc->qcntmask; - - cur_patch = patches; - ahc_outb(ahc, SEQCTL, PERRORDIS|LOADRAM); - ahc_outb(ahc, SEQADDR0, 0); - ahc_outb(ahc, SEQADDR1, 0); - - for(i = 0; i < sizeof(seqprog)/4; i++) { - cur_patch = ahc_next_patch(cur_patch, options, i); - - if (cur_patch && cur_patch->begin <= i && cur_patch->end > i) - /* Skip this instruction for this configuration */ - continue; - ahc_download_instr(ahc, options, i, download_consts); - downloaded++; - } - - ahc_outb(ahc, SEQCTL, FASTMODE); - ahc_outb(ahc, SEQADDR0, 0); - ahc_outb(ahc, SEQADDR1, 0); - if (bootverbose) - printf("%s: %d instructions downloaded\n", ahc_name(ahc), - downloaded); -} - -static struct patch * -ahc_next_patch(cur_patch, options, instrptr) - struct patch *cur_patch; - int options; - int instrptr; -{ - while(cur_patch != NULL) { - if (((cur_patch->options & options) != 0 - && cur_patch->negative == FALSE) - || ((cur_patch->options & options) == 0 - && cur_patch->negative == TRUE) - || (instrptr >= cur_patch->end)) { - /* - * Either we want to keep this section of code, - * or we have consumed this patch. Skip to the - * next patch. - */ - cur_patch++; - if (cur_patch->options == 0) - /* Out of patches */ - cur_patch = NULL; - } else - /* Found an okay patch */ - break; - } - return (cur_patch); -} - -static void -ahc_download_instr(struct ahc_softc *ahc, int options, - int instrptr, u_int8_t *dconsts) -{ - u_int8_t opcode; - struct ins_format3 instr; - - /* Structure copy */ - instr = *(struct ins_format3 *)&seqprog[instrptr * 4]; - - /* Pull the opcode */ - opcode = (instr.opcode_addr & ~DOWNLOAD_CONST_IMMEDIATE) >> 1; - switch (opcode) { - case AIC_OP_JMP: - case AIC_OP_JC: - case AIC_OP_JNC: - case AIC_OP_CALL: - case AIC_OP_JNE: - case AIC_OP_JNZ: - case AIC_OP_JE: - case AIC_OP_JZ: - { - int address_offset; - u_int address; - struct patch *patch; - int i; - - address_offset = 0; - address = instr.address; - address |= (instr.opcode_addr & ADDR_HIGH_BIT) << 8; - for (i = 0; i < sizeof(patches)/sizeof(patches[0]); i++) { - patch = &patches[i]; - if (((patch->options & options) == 0 - && patch->negative == FALSE) - || ((patch->options & options) != 0 - && patch->negative == TRUE)) { - if (address >= patch->end) - address_offset += - patch->end - patch->begin; - } - } - address -= address_offset; - instr.address = address & 0xFF; - instr.opcode_addr &= ~ADDR_HIGH_BIT; - instr.opcode_addr |= (address >> 8) & ADDR_HIGH_BIT; - /* FALLTHROUGH */ - } - case AIC_OP_OR: - case AIC_OP_AND: - case AIC_OP_XOR: - case AIC_OP_ADD: - case AIC_OP_ADC: - if ((instr.opcode_addr & DOWNLOAD_CONST_IMMEDIATE) != 0) { - instr.immediate = dconsts[instr.immediate]; - } - instr.opcode_addr &= ~DOWNLOAD_CONST_IMMEDIATE; - /* FALLTHROUGH */ - case AIC_OP_ROL: - ahc_outsb(ahc, SEQRAM, &instr.immediate, 4); - break; - default: - panic("Unknown opcode encountered in seq program"); - break; - } -} - -/* - * Function to poll for command completion when - * interrupts are disabled (crash dumps) - */ -static int -ahc_poll(ahc, wait) - struct ahc_softc *ahc; - int wait; /* in msec */ -{ - while (--wait) { - DELAY(1000); - if (ahc_inb(ahc, INTSTAT) & INT_PEND) - break; - } if (wait == 0) { - printf("%s: board is not responding\n", ahc_name(ahc)); - return (EIO); - } - ahc_intr((void *)ahc); - return (0); -} - -static void -ahc_timeout(arg) - void *arg; -{ - struct scb *scb = (struct scb *)arg; - struct ahc_softc *ahc; - int s, found; - u_int8_t bus_state; - char channel; - - ahc = (struct ahc_softc *)scb->xs->sc_link->adapter_softc; - - s = splbio(); - - /* - * Ensure that the card doesn't do anything - * behind our back. Also make sure that we - * didn't "just" miss an interrupt that would - * affect this timeout. - */ - do { - ahc_intr(ahc); - pause_sequencer(ahc); - } while (ahc_inb(ahc, INTSTAT) & INT_PEND); - - if (!(scb->flags & SCB_ACTIVE)) { - /* Previous timeout took care of me already */ - printf("Timedout SCB handled by another timeout\n"); - unpause_sequencer(ahc, /*unpause_always*/TRUE); - splx(s); - return; - } - - if (ahc->in_timeout) { - /* - * Some other SCB has started a recovery operation - * and is still working on cleaning things up. - */ - if ((scb->flags & SCB_RECOVERY_SCB) == 0) { - /* - * This is not the SCB that started this timeout - * processing. Give this scb another lifetime so - * that it can continue once we deal with the - * timeout. - */ - scb->flags |= SCB_TIMEDOUT; - sc_print_addr(scb->xs->sc_link); - printf("SCB 0x%x timedout while recovery in progress\n", - scb->hscb->tag); - scb->xs->timeout_ch = - timeout(ahc_timeout, (caddr_t)scb, - (scb->xs->timeout * hz) / 1000); - unpause_sequencer(ahc, /*unpause_always*/TRUE); - splx(s); - return; - } - } - ahc->in_timeout = TRUE; - - sc_print_addr(scb->xs->sc_link); - printf("SCB 0x%x - timed out ", scb->hscb->tag); - /* - * Take a snapshot of the bus state and print out - * some information so we can track down driver bugs. - */ - bus_state = ahc_inb(ahc, LASTPHASE); - - switch(bus_state) - { - case P_DATAOUT: - printf("in dataout phase"); - break; - case P_DATAIN: - printf("in datain phase"); - break; - case P_COMMAND: - printf("in command phase"); - break; - case P_MESGOUT: - printf("in message out phase"); - break; - case P_STATUS: - printf("in status phase"); - break; - case P_MESGIN: - printf("in message in phase"); - break; - case P_BUSFREE: - printf("while idle, LASTPHASE == 0x%x", - bus_state); - break; - default: - /* - * We aren't in a valid phase, so assume we're - * idle. - */ - printf("invalid phase, LASTPHASE == 0x%x", - bus_state); - break; - } - - printf(", SCSISIGI == 0x%x\n", ahc_inb(ahc, SCSISIGI)); - - printf("SEQADDR = 0x%x SCSISEQ = 0x%x SSTAT0 = 0x%x SSTAT1 = 0x%x\n", - ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8), - ahc_inb(ahc, SCSISEQ), ahc_inb(ahc, SSTAT0), - ahc_inb(ahc,SSTAT1)); - /* Decide our course of action */ - - channel = (scb->hscb->tcl & SELBUSB) ? 'B': 'A'; - if (scb->flags & SCB_ABORT) { - /* - * Been down this road before. - * Do a full bus reset. - */ -bus_reset: - scb->flags |= SCB_RECOVERY_SCB; - found = ahc_reset_channel(ahc, channel, XS_TIMEOUT, - /*Initiate Reset*/TRUE); - printf("%s: Issued Channel %c Bus Reset. " - "%d SCBs aborted\n", ahc_name(ahc), channel, found); - } else if ((scb->hscb->control & TAG_ENB) != 0 - && (scb->flags & SCB_SENTORDEREDTAG) == 0) { - /* - * We could be starving this command - * try sending an ordered tag command - * to the target we come from. - */ - u_int16_t mask; - - mask = (0x01 << (scb->xs->sc_link->target - | (IS_SCSIBUS_B(ahc, scb->xs->sc_link) ? - SELBUSB : 0))); - scb->flags |= SCB_SENTORDEREDTAG|SCB_RECOVERY_SCB; - ahc->orderedtag |= mask; - scb->xs->timeout_ch = timeout(ahc_timeout, (caddr_t)scb, - (5 * hz)); - unpause_sequencer(ahc, /*unpause_always*/TRUE); - printf("Ordered Tag queued\n"); - } else { - /* - * Send an Abort Message: - * The target that is holding up the bus may not - * be the same as the one that triggered this timeout - * (different commands have different timeout lengths). - * Our strategy here is to queue an abort message - * to the timed out target if it is disconnected. - * Otherwise, if we have an active target we stuff the - * message buffer with an abort message and assert ATN - * in the hopes that the target will let go of the bus - * and go to the mesgout phase. If this fails, we'll - * get another timeout 2 seconds later which will attempt - * a bus reset. - */ - u_int8_t saved_scbptr; - u_int8_t active_scb_index; - struct scb *active_scb; - - saved_scbptr = ahc_inb(ahc, SCBPTR); - active_scb_index = ahc_inb(ahc, SCB_TAG); - active_scb = ahc->scb_data->scbarray[active_scb_index]; - - if (bus_state != P_BUSFREE) { - if (active_scb_index >= ahc->scb_data->numscbs) { - /* Go "immediatly" to the bus reset */ - /* - * XXX queue an abort for the timedout SCB - * instead. - */ - sc_print_addr(scb->xs->sc_link); - printf("SCB %d: Yucky Immediate reset. " - "Flags = 0x%x\n", scb->hscb->tag, - scb->flags); - goto bus_reset; - } - /* Send the abort to the active SCB */ - ahc_outb(ahc, MSG_LEN, 1); - ahc_outb(ahc, MSG_OUT, - (active_scb->hscb->control & TAG_ENB) == 0 ? - MSG_ABORT : MSG_ABORT_TAG); - ahc_outb(ahc, SCSISIGO, bus_state|ATNO); - sc_print_addr(active_scb->xs->sc_link); - printf("abort message in message buffer\n"); - active_scb->flags |= SCB_ABORT|SCB_RECOVERY_SCB; - if (active_scb != scb) { - untimeout(ahc_timeout, - (caddr_t)active_scb, - active_scb->xs->timeout_ch); - /* Give scb a new lease on life */ - scb->xs->timeout_ch = - timeout(ahc_timeout, (caddr_t)scb, - (scb->xs->timeout * hz) / 1000); - } - active_scb->xs->timeout_ch = - timeout(ahc_timeout, active_scb, 2 * hz); - unpause_sequencer(ahc, /*unpause_always*/TRUE); - } else { - int disconnected; - u_int8_t hscb_index; - u_int8_t linked_next; - - disconnected = FALSE; - hscb_index = ahc_find_scb(ahc, scb); - if (hscb_index == SCB_LIST_NULL) { - disconnected = TRUE; - linked_next = (scb->hscb->datalen >> 24) - & 0xFF; - } else { - ahc_outb(ahc, SCBPTR, hscb_index); - if (ahc_inb(ahc, SCB_CONTROL) & DISCONNECTED) - disconnected = TRUE; - linked_next = ahc_inb(ahc, SCB_LINKED_NEXT); - } - - if (disconnected) { - /* - * Simply set the ABORT_SCB control bit - * and preserve the linked next pointer - */ - scb->hscb->control |= ABORT_SCB|MK_MESSAGE; - scb->hscb->datalen &= ~0xFF000000; - scb->hscb->datalen |= linked_next << 24; - if ((ahc->flags & AHC_PAGESCBS) == 0) - scb->hscb->control &= ~DISCONNECTED; - scb->flags |= SCB_QUEUED_ABORT - | SCB_ABORT|SCB_RECOVERY_SCB; - if (hscb_index != SCB_LIST_NULL) { - u_int8_t scb_control; - - scb_control = ahc_inb(ahc, SCB_CONTROL); - ahc_outb(ahc, SCB_CONTROL, - scb_control | MK_MESSAGE - | ABORT_SCB); - } - /* - * Actually re-queue this SCB in case we can - * select the device before it reconnects. If - * the transaction we want to abort is not - * tagged, unbusy it first so that we don't - * get held back from sending the command. - */ - if ((scb->hscb->control & TAG_ENB) == 0) { - int target; - int lun; - - target = scb->xs->sc_link->target; - lun = scb->xs->sc_link->lun; - ahc_search_qinfifo(ahc, target, - channel, - lun, - SCB_LIST_NULL, - 0, 0, - /*requeue*/TRUE); - } - sc_print_addr(scb->xs->sc_link); - printf("Queueing an Abort SCB\n"); - STAILQ_INSERT_HEAD(&ahc->waiting_scbs, scb, - links); - scb->flags |= SCB_WAITINGQ; - scb->xs->timeout_ch = - timeout(ahc_timeout, (caddr_t)scb, - (2000 * hz) / 1000); - ahc_outb(ahc, SCBPTR, saved_scbptr); - /* - * ahc_run_waiting_queue may unpause us - * so do this last. - */ - ahc_run_waiting_queue(ahc); - /* - * If we are using AAP, ahc_run_waiting_queue - * will not unpause us, so ensure we are - * unpaused. - */ - unpause_sequencer(ahc, /*unpause_always*/FALSE); - } else { - /* Go "immediatly" to the bus reset */ - sc_print_addr(scb->xs->sc_link); - printf("SCB %d: Immediate reset. " - "Flags = 0x%x\n", scb->hscb->tag, - scb->flags); - goto bus_reset; - } - } - } - splx(s); -} - -/* - * Look through the SCB array of the card and attempt to find the - * hardware SCB that corresponds to the passed in SCB. Return - * SCB_LIST_NULL if unsuccessful. This routine assumes that the - * card is already paused. - */ -static u_int8_t -ahc_find_scb(ahc, scb) - struct ahc_softc *ahc; - struct scb *scb; -{ - u_int8_t saved_scbptr; - u_int8_t curindex; - - saved_scbptr = ahc_inb(ahc, SCBPTR); - for (curindex = 0; curindex < ahc->scb_data->maxhscbs; curindex++) { - ahc_outb(ahc, SCBPTR, curindex); - if (ahc_inb(ahc, SCB_TAG) == scb->hscb->tag) - break; - } - ahc_outb(ahc, SCBPTR, saved_scbptr); - if (curindex >= ahc->scb_data->maxhscbs) - curindex = SCB_LIST_NULL; - - return curindex; -} - -static int -ahc_search_qinfifo(ahc, target, channel, lun, tag, flags, xs_error, requeue) - struct ahc_softc *ahc; - int target; - char channel; - int lun; - u_int8_t tag; - u_int32_t flags; - u_int32_t xs_error; - int requeue; -{ - u_int8_t saved_queue[AHC_SCB_MAX]; - int queued = ahc_inb(ahc, QINCNT) & ahc->qcntmask; - int i; - int found; - struct scb *scbp; - STAILQ_HEAD(, scb) removed_scbs; - - found = 0; - STAILQ_INIT(&removed_scbs); - for (i = 0; i < (queued - found); i++) { - saved_queue[i] = ahc_inb(ahc, QINFIFO); - scbp = ahc->scb_data->scbarray[saved_queue[i]]; - if (ahc_match_scb(scbp, target, channel, lun, tag)) { - /* - * We found an scb that needs to be removed. - */ - if (requeue) { - STAILQ_INSERT_HEAD(&removed_scbs, scbp, links); - } else { - scbp->flags |= flags; - scbp->flags &= ~SCB_ACTIVE; - scbp->xs->error = xs_error; - } - i--; - found++; - } - } - /* Now put the saved scbs back. */ - for (queued = 0; queued < i; queued++) - ahc_outb(ahc, QINFIFO, saved_queue[queued]); - - if (requeue) { - while ((scbp = removed_scbs.stqh_first) != NULL) { - STAILQ_REMOVE_HEAD(&removed_scbs, links); - STAILQ_INSERT_HEAD(&ahc->waiting_scbs, scbp, links); - scbp->flags |= SCB_WAITINGQ; - } - } - - return found; -} - - -/* - * The device at the given target/channel has been reset. Abort - * all active and queued scbs for that target/channel. - */ -static int -ahc_reset_device(ahc, target, channel, lun, tag, xs_error) - struct ahc_softc *ahc; - int target; - char channel; - int lun; - u_int8_t tag; - u_int32_t xs_error; -{ - struct scb *scbp; - u_int8_t active_scb; - int i; - int found; - - /* restore this when we're done */ - active_scb = ahc_inb(ahc, SCBPTR); - - /* - * Deal with the busy target and linked next issues. - */ - { - int min_target, max_target; - u_int8_t busy_scbid; - - /* Make all targets 'relative' to bus A */ - if (target == ALL_TARGETS) { - switch (channel) { - case 'A': - min_target = 0; - max_target = ahc->type & AHC_WIDE ? 15 : 7; - break; - case 'B': - min_target = 8; - max_target = 15; - break; - case ALL_CHANNELS: - min_target = 0; - max_target = ahc->type & (AHC_WIDE|AHC_TWIN) - ? 15 : 7; - break; - default: - /* Shutup warning */ - min_target = 0; - max_target = 0; - panic("ahc_reset_device: Bogus Channel"); - /* NOTREACHED */ - } - } else { - min_target = max_target - = target + (channel == 'B' ? 8 : 0); - } - - for (i = min_target; i <= max_target; i++) { - busy_scbid = ahc_index_busy_target(ahc, i, 'A', - /*unbusy*/FALSE); - if (busy_scbid < ahc->scb_data->numscbs) { - struct scb *busy_scb; - struct scb *next_scb; - u_int8_t next_scbid; - - busy_scb = ahc->scb_data->scbarray[busy_scbid]; - - next_scbid = busy_scb->hscb->datalen >> 24; - - if (next_scbid == SCB_LIST_NULL) { - busy_scbid = ahc_find_scb(ahc, - busy_scb); - - if (busy_scbid != SCB_LIST_NULL) { - ahc_outb(ahc, SCBPTR, - busy_scbid); - next_scbid = ahc_inb(ahc, - SCB_LINKED_NEXT); - } - } - - if (ahc_match_scb(busy_scb, target, channel, - lun, tag)) { - ahc_index_busy_target(ahc, i, 'A', - /*unbusy*/TRUE); - } - - if (next_scbid != SCB_LIST_NULL) { - next_scb = ahc->scb_data->scbarray[next_scbid]; - if (ahc_match_scb(next_scb, target, - channel, lun, tag)) - continue; - /* Requeue for later processing */ - STAILQ_INSERT_HEAD(&ahc->waiting_scbs, - next_scb, links); - next_scb->flags |= SCB_WAITINGQ; - } - } - } - } - /* - * Remove any entries from the Queue-In FIFO. - */ - found = ahc_search_qinfifo(ahc, target, channel, lun, tag, - SCB_ABORTED|SCB_QUEUED_FOR_DONE, xs_error, - /*requeue*/FALSE); - - /* - * Search waiting for selection list. - */ - { - u_int8_t next, prev; - - next = ahc_inb(ahc, WAITING_SCBH); /* Start at head of list. */ - prev = SCB_LIST_NULL; - - while (next != SCB_LIST_NULL) { - u_int8_t scb_index; - - ahc_outb(ahc, SCBPTR, next); - scb_index = ahc_inb(ahc, SCB_TAG); - if (scb_index >= ahc->scb_data->numscbs) { - panic("Waiting List inconsistency. " - "SCB index == %d, yet numscbs == %d.", - scb_index, ahc->scb_data->numscbs); - } - scbp = ahc->scb_data->scbarray[scb_index]; - if (ahc_match_scb(scbp, target, channel, lun, tag)) { - u_int8_t linked_next; - - next = ahc_abort_wscb(ahc, scbp, next, prev, - xs_error); - linked_next = ahc_inb(ahc, SCB_LINKED_NEXT); - if (linked_next != SCB_LIST_NULL) { - struct scb *next_scb; - - /* - * Re-queue the waiting SCB via the - * waiting list. - */ - next_scb = - ahc->scb_data->scbarray[linked_next]; - if (!ahc_match_scb(next_scb, target, - channel, lun, tag)) { - STAILQ_INSERT_HEAD(&ahc->waiting_scbs, - next_scb, - links); - next_scb->flags |= SCB_WAITINGQ; - } - } - found++; - } else { - prev = next; - next = ahc_inb(ahc, SCB_NEXT); - } - } - } - /* - * Go through the disconnected list and remove any entries we - * have queued for completion, 0'ing their control byte too. - */ - { - u_int8_t next, prev; - - next = ahc_inb(ahc, DISCONNECTED_SCBH); - prev = SCB_LIST_NULL; - - while (next != SCB_LIST_NULL) { - u_int8_t scb_index; - - ahc_outb(ahc, SCBPTR, next); - scb_index = ahc_inb(ahc, SCB_TAG); - if (scb_index >= ahc->scb_data->numscbs) { - panic("Disconnected List inconsistency. " - "SCB index == %d, yet numscbs == %d.", - scb_index, ahc->scb_data->numscbs); - } - scbp = ahc->scb_data->scbarray[scb_index]; - if (ahc_match_scb(scbp, target, channel, lun, tag)) { - next = ahc_rem_scb_from_disc_list(ahc, next); - } else { - prev = next; - next = ahc_inb(ahc, SCB_NEXT); - } - } - } - /* - * Go through the hardware SCB array looking for commands that - * were active but not on any list. - */ - for(i = 0; i < ahc->scb_data->maxhscbs; i++) { - u_int8_t scbid; - - ahc_outb(ahc, SCBPTR, i); - scbid = ahc_inb(ahc, SCB_TAG); - if (scbid < ahc->scb_data->numscbs) { - scbp = ahc->scb_data->scbarray[scbid]; - if (ahc_match_scb(scbp, target, channel, lun, tag)) { - ahc_add_curscb_to_free_list(ahc); - } - } - } - /* - * Go through the entire SCB array now and look for - * commands for this target that are still active. These - * are other tagged commands that were disconnected when - * the reset occured or untagged commands that were linked - * to the command that preceeded it. - */ - for (i = 0; i < ahc->scb_data->numscbs; i++) { - scbp = ahc->scb_data->scbarray[i]; - if ((scbp->flags & SCB_ACTIVE) != 0 - && ahc_match_scb(scbp, target, channel, lun, tag)) { - scbp->flags |= SCB_ABORTED|SCB_QUEUED_FOR_DONE; - scbp->flags &= ~SCB_ACTIVE; - scbp->xs->error = xs_error; - found++; - - if ((scbp->flags & SCB_WAITINGQ) != 0) { - STAILQ_REMOVE(&ahc->waiting_scbs, scbp, scb, - links); - scbp->flags &= ~SCB_WAITINGQ; - } - } - } - ahc_outb(ahc, SCBPTR, active_scb); - return found; -} - -static u_int8_t -ahc_rem_scb_from_disc_list(ahc, scbptr) - struct ahc_softc *ahc; - u_int8_t scbptr; -{ - u_int8_t next; - u_int8_t prev; - - ahc_outb(ahc, SCBPTR, scbptr); - next = ahc_inb(ahc, SCB_NEXT); - prev = ahc_inb(ahc, SCB_PREV); - - ahc_outb(ahc, SCB_CONTROL, 0); - - ahc_add_curscb_to_free_list(ahc); - - if (prev != SCB_LIST_NULL) { - ahc_outb(ahc, SCBPTR, prev); - ahc_outb(ahc, SCB_NEXT, next); - } else - ahc_outb(ahc, DISCONNECTED_SCBH, next); - - if (next != SCB_LIST_NULL) { - ahc_outb(ahc, SCBPTR, next); - ahc_outb(ahc, SCB_PREV, prev); - } - return next; -} - -static void -ahc_add_curscb_to_free_list(ahc) - struct ahc_softc *ahc; -{ - /* Invalidate the tag so that ahc_find_scb doesn't think it's active */ - ahc_outb(ahc, SCB_TAG, SCB_LIST_NULL); - - ahc_outb(ahc, SCB_NEXT, ahc_inb(ahc, FREE_SCBH)); - ahc_outb(ahc, FREE_SCBH, ahc_inb(ahc, SCBPTR)); -} - -/* - * Manipulate the waiting for selection list and return the - * scb that follows the one that we remove. - */ -static u_char -ahc_abort_wscb (ahc, scbp, scbpos, prev, xs_error) - struct ahc_softc *ahc; - struct scb *scbp; - u_int8_t scbpos; - u_int8_t prev; - u_int32_t xs_error; -{ - u_int8_t curscb, next; - /* - * Select the SCB we want to abort and - * pull the next pointer out of it. - */ - curscb = ahc_inb(ahc, SCBPTR); - ahc_outb(ahc, SCBPTR, scbpos); - next = ahc_inb(ahc, SCB_NEXT); - - /* Clear the necessary fields */ - ahc_outb(ahc, SCB_CONTROL, 0); - - ahc_add_curscb_to_free_list(ahc); - - /* update the waiting list */ - if (prev == SCB_LIST_NULL) - /* First in the list */ - ahc_outb(ahc, WAITING_SCBH, next); - else { - /* - * Select the scb that pointed to us - * and update its next pointer. - */ - ahc_outb(ahc, SCBPTR, prev); - ahc_outb(ahc, SCB_NEXT, next); - } - - /* - * Point us back at the original scb position - * and inform the SCSI system that the command - * has been aborted. - */ - ahc_outb(ahc, SCBPTR, curscb); - scbp->flags |= SCB_ABORTED|SCB_QUEUED_FOR_DONE; - scbp->flags &= ~SCB_ACTIVE; - scbp->xs->error = xs_error; - return next; -} - -static u_int8_t -ahc_index_busy_target(ahc, target, channel, unbusy) - struct ahc_softc *ahc; - int target; - char channel; - int unbusy; -{ - u_int8_t active_scb; - u_int8_t info_scb; - u_int8_t busy_scbid; - u_int32_t scb_offset; - - info_scb = target / 4; - if (channel == 'B') - info_scb += 2; - active_scb = ahc_inb(ahc, SCBPTR); - ahc_outb(ahc, SCBPTR, info_scb); - scb_offset = SCB_BUSYTARGETS + (target & 0x03); - busy_scbid = ahc_inb(ahc, scb_offset); - if (unbusy) - ahc_outb(ahc, scb_offset, SCB_LIST_NULL); - ahc_outb(ahc, SCBPTR, active_scb); - return busy_scbid; -} - -static void -ahc_busy_target(ahc, target, channel, scbid) - struct ahc_softc *ahc; - int target; - char channel; - u_int8_t scbid; -{ - u_int8_t active_scb; - u_int8_t info_scb; - u_int32_t scb_offset; - - info_scb = target / 4; - if (channel == 'B') - info_scb += 2; - active_scb = ahc_inb(ahc, SCBPTR); - ahc_outb(ahc, SCBPTR, info_scb); - scb_offset = SCB_BUSYTARGETS + (target & 0x03); - ahc_outb(ahc, scb_offset, scbid); - ahc_outb(ahc, SCBPTR, active_scb); - return; -} - -static void -ahc_clear_intstat(ahc) - struct ahc_softc *ahc; -{ - /* Clear any interrupt conditions this may have caused */ - ahc_outb(ahc, CLRSINT0, CLRSELDO|CLRSELDI|CLRSELINGO); - ahc_outb(ahc, CLRSINT1, CLRSELTIMEO|CLRATNO|CLRSCSIRSTI - |CLRBUSFREE|CLRSCSIPERR|CLRPHASECHG| - CLRREQINIT); - ahc_outb(ahc, CLRINT, CLRSCSIINT); -} - -static void -ahc_reset_current_bus(ahc) - struct ahc_softc *ahc; -{ - u_int8_t scsiseq; - - ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) & ~ENSCSIRST); - scsiseq = ahc_inb(ahc, SCSISEQ); - ahc_outb(ahc, SCSISEQ, scsiseq | SCSIRSTO); - - DELAY(AHC_BUSRESET_DELAY); - /* Turn off the bus reset */ - ahc_outb(ahc, SCSISEQ, scsiseq & ~SCSIRSTO); - - ahc_clear_intstat(ahc); - - /* Re-enable reset interrupts */ - ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) | ENSCSIRST); -} - -static int -ahc_reset_channel(ahc, channel, xs_error, initiate_reset) - struct ahc_softc *ahc; - char channel; - u_int32_t xs_error; - int initiate_reset; -{ - u_int32_t offset, offset_max; - int found; - u_int8_t sblkctl; - char cur_channel; - - pause_sequencer(ahc); - /* - * Clean up all the state information for the - * pending transactions on this bus. - */ - found = ahc_reset_device(ahc, ALL_TARGETS, channel, ALL_LUNS, - SCB_LIST_NULL, xs_error); - if (channel == 'B') { - ahc->needsdtr |= (ahc->needsdtr_orig & 0xff00); - ahc->sdtrpending &= 0x00ff; - ahc->orderedtag &= 0x00ff; - offset = TARG_SCRATCH + 8; - offset_max = TARG_SCRATCH + 16; - } else if (ahc->type & AHC_WIDE){ - ahc->needsdtr = ahc->needsdtr_orig; - ahc->needwdtr = ahc->needwdtr_orig; - ahc->orderedtag = 0; - ahc->sdtrpending = 0; - ahc->wdtrpending = 0; - offset = TARG_SCRATCH; - offset_max = TARG_SCRATCH + 16; - } else { - ahc->needsdtr |= (ahc->needsdtr_orig & 0x00ff); - ahc->sdtrpending &= 0xff00; - ahc->orderedtag &= 0xff00; - offset = TARG_SCRATCH; - offset_max = TARG_SCRATCH + 8; - } - - for (; offset < offset_max; offset++) { - /* - * Revert to async/narrow transfers - * until we renegotiate. - */ - u_int8_t targ_scratch; - - targ_scratch = ahc_inb(ahc, offset); - targ_scratch &= SXFR; - ahc_outb(ahc, offset, targ_scratch); - } - - /* - * Reset the bus if we are initiating this reset and - * restart/unpause the sequencer - */ - sblkctl = ahc_inb(ahc, SBLKCTL); - cur_channel = (sblkctl & SELBUSB) ? 'B' : 'A'; - if (cur_channel != channel) { - /* Case 1: Command for another bus is active - * Stealthily reset the other bus without - * upsetting the current bus. - */ - ahc_outb(ahc, SBLKCTL, sblkctl ^ SELBUSB); - ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) & ~ENBUSFREE); - if (initiate_reset) - ahc_reset_current_bus(ahc); - ahc_outb(ahc, SCSISEQ, 0); - ahc_clear_intstat(ahc); - ahc_outb(ahc, SBLKCTL, sblkctl); - unpause_sequencer(ahc, /*unpause_always*/FALSE); - } else { - /* Case 2: A command from this bus is active or we're idle */ - ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) & ~ENBUSFREE); - if (initiate_reset) - ahc_reset_current_bus(ahc); - ahc_outb(ahc, SCSISEQ, 0); - ahc_clear_intstat(ahc); - restart_sequencer(ahc); - } - /* - * Untimeout our scbs now in case we have to delay our done - * processing. - */ - ahc_untimeout_done_queue(ahc); - ahc_run_done_queue(ahc); - return found; -} - -static void -ahc_run_done_queue(ahc) - struct ahc_softc *ahc; -{ - int i; - struct scb *scbp; - - for (i = 0; i < ahc->scb_data->numscbs; i++) { - scbp = ahc->scb_data->scbarray[i]; - if (scbp->flags & SCB_QUEUED_FOR_DONE) - ahc_done(ahc, scbp); - } -} - -static void -ahc_untimeout_done_queue(ahc) - struct ahc_softc *ahc; -{ - int i; - struct scb *scbp; - - for (i = 0; i < ahc->scb_data->numscbs; i++) { - scbp = ahc->scb_data->scbarray[i]; - if (scbp->flags & SCB_QUEUED_FOR_DONE) - untimeout(ahc_timeout, (caddr_t)scbp, - scbp->xs->timeout_ch); - } -} - -static int -ahc_match_scb (scb, target, channel, lun, tag) - struct scb *scb; - int target; - char channel; - int lun; - u_int8_t tag; -{ - int targ = (scb->hscb->tcl >> 4) & 0x0f; - char chan = (scb->hscb->tcl & SELBUSB) ? 'B' : 'A'; - int slun = scb->hscb->tcl & 0x07; - int match; - - match = ((chan == channel) || (channel == ALL_CHANNELS)); - if (match != 0) - match = ((targ == target) || (target == ALL_TARGETS)); - if (match != 0) - match = ((lun == slun) || (lun == ALL_LUNS)); - if (match != 0) - match = ((tag == scb->hscb->tag) || (tag == SCB_LIST_NULL)); - - return match; -} - -static void -ahc_construct_sdtr(ahc, start_byte, period, offset) - struct ahc_softc *ahc; - int start_byte; - u_int8_t period; - u_int8_t offset; -{ - ahc_outb(ahc, MSG_OUT + start_byte, MSG_EXTENDED); - ahc_outb(ahc, MSG_OUT + 1 + start_byte, MSG_EXT_SDTR_LEN); - ahc_outb(ahc, MSG_OUT + 2 + start_byte, MSG_EXT_SDTR); - ahc_outb(ahc, MSG_OUT + 3 + start_byte, period); - ahc_outb(ahc, MSG_OUT + 4 + start_byte, offset); - ahc_outb(ahc, MSG_LEN, start_byte + 5); -} - -static void -ahc_construct_wdtr(ahc, start_byte, bus_width) - struct ahc_softc *ahc; - int start_byte; - u_int8_t bus_width; -{ - ahc_outb(ahc, MSG_OUT + start_byte, MSG_EXTENDED); - ahc_outb(ahc, MSG_OUT + 1 + start_byte, MSG_EXT_WDTR_LEN); - ahc_outb(ahc, MSG_OUT + 2 + start_byte, MSG_EXT_WDTR); - ahc_outb(ahc, MSG_OUT + 3 + start_byte, bus_width); - ahc_outb(ahc, MSG_LEN, start_byte + 4); -} - -static void -ahc_calc_residual(scb) - struct scb *scb; -{ - struct scsi_xfer *xs; - struct hardware_scb *hscb; - int resid_sgs; - - xs = scb->xs; - hscb = scb->hscb; - - /* - * If the disconnected flag is still set, this is bogus - * residual information left over from a sequencer - * pagin/pageout, so ignore this case. - */ - if ((scb->hscb->control & DISCONNECTED) == 0 - && (scb->flags & SCB_SENSE) == 0) { - /* - * Remainder of the SG where the transfer - * stopped. - */ - xs->resid = (hscb->residual_data_count[2] <<16) | - (hscb->residual_data_count[1] <<8) | - (hscb->residual_data_count[0]); - - /* - * Add up the contents of all residual - * SG segments that are after the SG where - * the transfer stopped. - */ - resid_sgs = scb->hscb->residual_SG_segment_count - 1; - while (resid_sgs > 0) { - int sg; - - sg = scb->sg_count - resid_sgs; - xs->resid += scb->ahc_dma[sg].len; - resid_sgs--; - } -#if defined(__FreeBSD__) - xs->flags |= SCSI_RESID_VALID; -#elif defined(__NetBSD__) - /* XXX - Update to do this right */ -#endif - } - - /* - * Clean out the residual information in this SCB for its - * next consumer. - */ - hscb->residual_data_count[2] = 0; - hscb->residual_data_count[1] = 0; - hscb->residual_data_count[0] = 0; - hscb->residual_SG_segment_count = 0; - -#ifdef AHC_DEBUG - if (ahc_debug & AHC_SHOWMISC) { - sc_print_addr(xs->sc_link); - printf("Handled Residual of %ld bytes\n" ,xs->resid); - } -#endif -} diff --git a/sys/i386/scsi/aic7xxx.h b/sys/i386/scsi/aic7xxx.h deleted file mode 100644 index 1794cec..0000000 --- a/sys/i386/scsi/aic7xxx.h +++ /dev/null @@ -1,403 +0,0 @@ -/* - * Interface to the generic driver for the aic7xxx based adaptec - * SCSI controllers. This is used to implement product specific - * probe and attach routines. - * - * Copyright (c) 1994-1997 Justin Gibbs. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification, immediately at the beginning of the file. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * Where this Software is combined with software released under the terms of - * the GNU Public License ("GPL") and the terms of the GPL would require the - * combined work to also be released under the terms of the GPL, the terms - * and conditions of this License will apply in addition to those of the - * GPL with the exception of any terms or conditions of this License that - * conflict with, or are expressly prohibited by, the GPL. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id: aic7xxx.h,v 1.42 1997/08/13 17:02:47 gibbs Exp $ - */ - -#ifndef _AIC7XXX_H_ -#define _AIC7XXX_H_ - -#if defined(__FreeBSD__) -#include "ahc.h" /* for NAHC from config */ -#include "opt_aic7xxx.h" /* for config options */ -#endif - -#if defined(__NetBSD__) -/* - * convert FreeBSD's <sys/queue.h> symbols to NetBSD's - */ -#define STAILQ_ENTRY SIMPLEQ_ENTRY -#define STAILQ_HEAD SIMPLEQ_HEAD -#define STAILQ_INIT SIMPLEQ_INIT -#define STAILQ_INSERT_HEAD SIMPLEQ_INSERT_HEAD -#define STAILQ_INSERT_TAIL SIMPLEQ_INSERT_TAIL -#define STAILQ_REMOVE_HEAD(head, field) \ - SIMPLEQ_REMOVE_HEAD(head, (head)->sqh_first, field) -#define stqh_first sqh_first -#define stqe_next sqe_next -#endif - -#define AHC_NSEG 32 /* The number of dma segments supported. - * AHC_NSEG can be maxed out at 256 entries, - * but the kernel will never need to transfer - * such a large (1MB) request. To reduce the - * driver's memory consumption, we reduce the - * max to 32. 16 would work if all transfers - * are paged alined since the kernel will only - * generate at most a 64k transfer, but to - * handle non-page aligned transfers, you need - * 17, so we round to the next power of two - * to make allocating SG space easy and - * efficient. - */ - -#define AHC_SCB_MAX 255 /* - * Up to 255 SCBs on some types of aic7xxx - * based boards. The aic7870 have 16 internal - * SCBs, but external SRAM bumps this to 255. - * The aic7770 family have only 4, and the - * aic7850 has only 3. - */ - - -typedef u_int32_t physaddr; -#if defined(__FreeBSD__) -extern u_long ahc_unit; -#endif - -struct ahc_dma_seg { - physaddr addr; - u_int32_t len; -}; - -typedef enum { - AHC_NONE = 0x0000, - AHC_ULTRA = 0x0001, /* Supports 20MHz Transfers */ - AHC_WIDE = 0x0002, /* Wide Channel */ - AHC_TWIN = 0x0008, /* Twin Channel */ - AHC_AIC7770 = 0x0010, - AHC_AIC7850 = 0x0020, - AHC_AIC7860 = 0x0021, /* ULTRA version of the aic7850 */ - AHC_AIC7870 = 0x0040, - AHC_AIC7880 = 0x0041, - AHC_AIC78X0 = 0x0060, /* PCI Based Controller */ - AHC_274 = 0x0110, /* EISA Based Controller */ - AHC_284 = 0x0210, /* VL/ISA Based Controller */ - AHC_294AU = 0x0421, /* aic7860 based '2940' */ - AHC_294 = 0x0440, /* PCI Based Controller */ - AHC_294U = 0x0441, /* ULTRA PCI Based Controller */ - AHC_394 = 0x0840, /* Twin Channel PCI Controller */ - AHC_394U = 0x0841, /* ULTRA, Twin Channel PCI Controller */ - AHC_398 = 0x1040, /* Multi Channel PCI RAID Controller */ - AHC_398U = 0x1041, /* ULTRA, Multi Channel PCI - * RAID Controller - */ - AHC_39X = 0x1800 /* Multi Channel PCI Adapter */ -}ahc_type; - -typedef enum { - AHC_FNONE = 0x00, - AHC_INIT = 0x01, - AHC_RUNNING = 0x02, - AHC_PAGESCBS = 0x04, /* Enable SCB paging */ - AHC_CHANNEL_B_PRIMARY = 0x08, /* - * On twin channel adapters, probe - * channel B first since it is the - * primary bus. - */ - AHC_USEDEFAULTS = 0x10, /* - * For cards without an seeprom - * or a BIOS to initialize the chip's - * SRAM, we use the default target - * settings. - */ - AHC_CHNLB = 0x20, /* - * Second controller on 3940/398X - * Also encodes the offset in the - * SEEPROM for CHNLB info (32) - */ - AHC_CHNLC = 0x40 /* - * Third controller on 3985 - * Also encodes the offset in the - * SEEPROM for CHNLC info (64) - */ -} ahc_flag; - -typedef enum { - SCB_FREE = 0x0000, - SCB_ACTIVE = 0x0001, - SCB_ABORTED = 0x0002, - SCB_DEVICE_RESET = 0x0004, - SCB_SENSE = 0x0008, - SCB_TIMEDOUT = 0x0010, - SCB_QUEUED_FOR_DONE = 0x0020, - SCB_RECOVERY_SCB = 0x0040, - SCB_WAITINGQ = 0x0080, - SCB_ASSIGNEDQ = 0x0100, - SCB_SENTORDEREDTAG = 0x0200, - SCB_MSGOUT_SDTR = 0x0400, - SCB_MSGOUT_WDTR = 0x0800, - SCB_ABORT = 0x1000, - SCB_QUEUED_ABORT = 0x2000 -} scb_flag; - -/* - * The driver keeps up to MAX_SCB scb structures per card in memory. The SCB - * consists of a "hardware SCB" mirroring the fields availible on the card - * and additional information the kernel stores for each transaction. - */ -struct hardware_scb { -/*0*/ u_int8_t control; -/*1*/ u_int8_t tcl; /* 4/1/3 bits */ -/*2*/ u_int8_t status; -/*3*/ u_int8_t SG_segment_count; -/*4*/ physaddr SG_list_pointer; -/*8*/ u_int8_t residual_SG_segment_count; -/*9*/ u_int8_t residual_data_count[3]; -/*12*/ physaddr data; -/*16*/ u_int32_t datalen; /* Really only three bits, but its - * faster to treat it as a long on - * a quad boundary. - */ -/*20*/ physaddr cmdpointer; -/*24*/ u_int8_t cmdlen; -/*25*/ u_int8_t tag; /* Index into our kernel SCB array. - * Also used as the tag for tagged I/O - */ -#define SCB_PIO_TRANSFER_SIZE 26 /* amount we need to upload/download - * via PIO to initialize a transaction. - */ -/*26*/ u_int8_t next; /* Used for threading SCBs in the - * "Waiting for Selection" and - * "Disconnected SCB" lists down - * in the sequencer. - */ -/*27*/ u_int8_t prev; - -/*28*/ u_int32_t pad; /* - * Unused by the kernel, but we require - * the padding so that the array of - * hardware SCBs is alligned on 32 byte - * boundaries so the sequencer can - * index them easily. - */ -}; - -struct scb { - struct hardware_scb *hscb; - STAILQ_ENTRY(scb) links; /* for chaining */ - struct scsi_xfer *xs; /* the scsi_xfer for this cmd */ - scb_flag flags; - struct ahc_dma_seg *ahc_dma;/* Pointer to SG segments */ - struct scsi_sense sense_cmd; - u_int8_t sg_count;/* How full ahc_dma_seg is */ - u_int8_t position;/* Position in card's scbarray */ -}; - -struct scb_data { - struct hardware_scb *hscbs; /* Array of hardware SCBs */ - struct scb *scbarray[AHC_SCB_MAX]; /* Array of kernel SCBs */ - STAILQ_HEAD(, scb) free_scbs; /* - * Pool of SCBs ready to be assigned - * commands to execute. - */ - u_int8_t numscbs; - u_int8_t maxhscbs; /* Number of SCBs on the card */ - u_int8_t maxscbs; /* - * Max SCBs we allocate total including - * any that will force us to page SCBs - */ -}; - -struct ahc_busreset_args { - struct ahc_softc *ahc; - char bus; -}; - -struct ahc_softc { -#if defined(__FreeBSD__) - int unit; -#elif defined(__NetBSD__) - struct device sc_dev; - void *sc_ih; - bus_chipset_tag_t sc_bc; - bus_io_handle_t sc_ioh; -#endif - ahc_type type; - ahc_flag flags; -#if defined(__FreeBSD__) - u_int32_t baseport; -#endif - volatile u_int8_t *maddr; - struct scb_data *scb_data; - struct scsi_link sc_link; - struct scsi_link sc_link_b; /* Second bus for Twin channel cards */ - STAILQ_HEAD(, scb) waiting_scbs;/* - * SCBs waiting ready to go but - * waiting for space in the QINFIFO. - */ - STAILQ_HEAD(, scb) cmplete_scbs;/* - * SCBs out of the QOUTFIFO, waiting - * to be ahc_done'd. - */ - u_int8_t activescbs; - u_int8_t cmdoutcnt; - u_int16_t needsdtr_orig; /* Targets we initiate sync neg with */ - u_int16_t needwdtr_orig; /* Targets we initiate wide neg with */ - u_int16_t needsdtr; /* Current list of negotiated targets */ - u_int16_t needwdtr; /* Current list of negotiated targets */ - u_int16_t sdtrpending; /* Pending SDTR to these targets */ - u_int16_t wdtrpending; /* Pending WDTR to these targets */ - u_int16_t tagenable; /* Targets that can handle tags */ - u_int16_t orderedtag; /* Targets to use ordered tag on */ - u_int16_t discenable; /* Targets allowed to disconnect */ - u_int8_t our_id; /* our scsi id */ - u_int8_t our_id_b; /* B channel scsi id */ - u_int8_t qcntmask; /* - * Mask of valid registers in the - * Q*CNT registers. - */ - u_int8_t qfullcount; /* - * The maximum number of entries - * storable in the Q*FIFOs. - */ - u_int8_t curqincnt; /* - * The current value we "think" the - * QINCNT has. The reason it is - * "think" is that this is a cached - * value that is only updated when - * curqincount == qfullcount to reduce - * the amount of accesses made to the - * card. - */ - u_int8_t unpause; - u_int8_t pause; - u_int8_t in_timeout; -}; - -struct full_ahc_softc { - struct ahc_softc softc; - struct scb_data scb_data_storage; -}; - -/* #define AHC_DEBUG */ -#ifdef AHC_DEBUG -/* Different debugging levels used when AHC_DEBUG is defined */ -#define AHC_SHOWMISC 0x0001 -#define AHC_SHOWCMDS 0x0002 -#define AHC_SHOWSCBS 0x0004 -#define AHC_SHOWABORTS 0x0008 -#define AHC_SHOWSENSE 0x0010 -#define AHC_SHOWSCBCNT 0x0020 - -extern int ahc_debug; /* Initialized in i386/scsi/aic7xxx.c */ -#endif - -#if defined(__FreeBSD__) -char *ahc_name __P((struct ahc_softc *ahc)); - -struct ahc_softc *ahc_alloc __P((int unit, u_int32_t io_base, - vm_offset_t maddr, ahc_type type, - ahc_flag flags, struct scb_data *scb_data)); -#elif defined(__NetBSD__) - -#define ahc_name(ahc) (ahc)->sc_dev.dv_xname - -void ahc_construct __P((struct ahc_softc *ahc, bus_chipset_tag_t bc, bus_io_handle_t ioh, ahc_type type, ahc_flag flags)); -#endif -void ahc_reset __P((struct ahc_softc *ahc)); -void ahc_free __P((struct ahc_softc *)); -int ahc_init __P((struct ahc_softc *)); -int ahc_attach __P((struct ahc_softc *)); -#if defined(__FreeBSD__) -void ahc_intr __P((void *arg)); -#elif defined(__NetBSD__) -int ahc_intr __P((void *arg)); -#endif - -#if defined(__FreeBSD__) -static __inline u_int8_t ahc_inb __P((struct ahc_softc *ahc, u_int32_t port)); -static __inline void ahc_outb __P((struct ahc_softc *ahc, u_int32_t port, - u_int8_t val)); -static __inline void ahc_outsb __P((struct ahc_softc *ahc, u_int32_t port, - u_int8_t *valp, size_t size)); - -static __inline u_int8_t -ahc_inb(ahc, port) - struct ahc_softc *ahc; - u_int32_t port; -{ - if (ahc->maddr != NULL) - return ahc->maddr[port]; - else - return inb(ahc->baseport + port); -} - -static __inline void -ahc_outb(ahc, port, val) - struct ahc_softc *ahc; - u_int32_t port; - u_int8_t val; -{ - if (ahc->maddr != NULL) - ahc->maddr[port] = val; - else - outb(ahc->baseport + port, val); -} - -static __inline void -ahc_outsb(ahc, port, valp, size) - struct ahc_softc *ahc; - u_int32_t port; - u_int8_t *valp; - size_t size; -{ - if (ahc->maddr != NULL) { - __asm __volatile(" - cld; - 1: lodsb; - movb %%al,(%0); - loop 1b" : - : - "r" ((ahc)->maddr + (port)), - "S" ((valp)), "c" ((size)) : - "%esi", "%ecx", "%eax"); - } else - outsb(ahc->baseport + port, valp, size); -} -#elif defined(__NetBSD__) -#define ahc_inb(ahc, port) \ - bus_io_read_1((ahc)->sc_bc, (ahc)->sc_ioh, port) -#define ahc_outb(ahc, port, val) \ - bus_io_write_1((ahc)->sc_bc, (ahc)->sc_ioh, port, val) -#define ahc_outsb(ahc, port, valp, size) \ - bus_io_write_multi_1((ahc)->sc_bc, (ahc)->sc_ioh, port, valp, size) -#endif - -#endif /* _AIC7XXX_H_ */ diff --git a/sys/i386/scsi/bt.c b/sys/i386/scsi/bt.c deleted file mode 100644 index d3d0ec0..0000000 --- a/sys/i386/scsi/bt.c +++ /dev/null @@ -1,1583 +0,0 @@ -/* - * 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. - * - * $Id: bt.c,v 1.16 1998/02/20 13:37:37 bde Exp $ - */ - -/* - * Bulogic/Bustek 32 bit Addressing Mode SCSI driver. - * - * NOTE: 1. Some bt5xx card can NOT handle 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. Extended probing still needs confirmation from our user base, due - * to several H/W and firmware dependencies. If you have a problem - * with extended probing, please contact 'amurai@spec.co.jp' - * - * amurai@spec.co.jp 94/6/16 - */ - -#include <sys/param.h> -#include <sys/systm.h> - -#include <sys/malloc.h> -#include <sys/buf.h> -#include <sys/kernel.h> -#include <sys/sysctl.h> - -#include <machine/clock.h> -#include <machine/stdarg.h> - -#include <vm/vm.h> -#include <vm/pmap.h> - -#include <scsi/scsiconf.h> -#include <scsi/scsi_debug.h> - -#include <i386/scsi/btreg.h> - -struct bt_data *btdata[NBT]; - -/* - * I/O Port Interface - */ - -#define BT_BASE bt->bt_base -#define BT_CTRL_STAT_PORT (BT_BASE + 0x0) /* control & status */ -/* ReadOps WriteOps */ -#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 */ -#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 */ -#define BT_STAT_MASK \ - (BT_STST | BT_DIAGF | BT_INIT | BT_IDLE | BT_CDF | BT_DF | BT_INVDCMD) - -#define BT_CMD_DATA_PORT (BT_BASE + 0x1) /* cmds and datas */ -/* ReadOps WriteOps */ -#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 intr */ -#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_REV_THIRD 0x84 /* Get FirmWare version #3 */ -#define BT_INQUIRE_REV_FOURTH 0x85 /* Get FirmWare version #4 */ -#define BT_INQUIRE_EXTENDED 0x8D /* Adapter Setup Inquiry */ -/* The following commands appeared at FirmWare 3.31 */ -#define BT_ROUND_ROBIN 0x8f /* Enable/Disable round robin */ -#define BT_STRICT_ROUND_ROBIN 0x00 /* Parameter for strict mode */ -#define BT_AGRES_ROUND_ROBIN 0x01 /* Parameter for back compat */ - -#define BT_INTR_PORT (BT_BASE + 0x2) /* Intr. stat */ -/* ReadOps WriteOps */ -#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 */ - -struct bt_cmd_buf { - u_char byte[16]; -}; - - -#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]); \ - else \ - (wmb)++; - -struct bt_boardID { - u_char board_type; - u_char custom_feture; - char firm_revision; - u_char firm_version; -}; - -struct bt_setup { - u_char sync_neg:1; - u_char parity:1; - u_char :6; - u_char speed; - u_char bus_on; - u_char bus_off; - u_char num_mbx; - u_char mbx[3]; /* for backwards compatibility */ - struct { - u_char offset:4; - u_char period:3; - u_char valid:1; - } sync[8]; - u_char disc_sts; -}; - -struct bt_config { - u_char chan; -#define BUSDMA 0x00 -#define CHAN0 0x01 -#define CHAN5 0x20 -#define CHAN6 0x40 -#define CHAN7 0x80 - u_char intr; -#define INT9 0x01 -#define INT10 0x02 -#define INT11 0x04 -#define INT12 0x08 -#define INT14 0x20 -#define INT15 0x40 - u_char scsi_dev:3; /* XXX What about Wide Controllers? */ - u_char :5; -}; - - - -/* - * 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 - */ -struct bt_ext_info { - u_char bus_type; /* Host adapter bus type */ -#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 type */ -#define BT_BUS_TYPE_MCA 'M' /* Micro chanel? */ - u_char bios_addr; /* Bios Address-Not used */ - u_short max_seg; /* Max segment List */ - u_char num_mbx; /* Number of mailbox */ - int32_t mbx_base; /* mailbox base address */ - struct { - u_char resv1:1; /* ??? */ - u_char force:1; /* ON: force sync */ - 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; /* ??? */ - } s; - u_char firmid[3]; /* Firmware ver. & rev. w/o last char */ -}; - -#define BT_GET_BOARD_INFO 0x8b /* Get H/W ID and Revision */ -struct bt_board_info { - 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 */ -struct bt_sync_value { - u_char value[8]; /* Synchrnous value (value * 10 nsec) */ -}; - - -#define KVTOPHYS(x) vtophys(x) -#define PAGESIZ 4096 -#define INVALIDATE_CACHE {asm volatile( ".byte 0x0F ;.byte 0x08" ); } - -/***********debug values *************/ -#define BT_SHOWCCBS 0x01 -#define BT_SHOWINTS 0x02 -#define BT_SHOWCMDS 0x04 -#define BT_SHOWMISC 0x08 -static int bt_debug = 0; -SYSCTL_INT(_debug, OID_AUTO, bt_debug, CTLFLAG_RW, &bt_debug, 0, ""); - -static u_int32_t bt_adapter_info __P((int unit)); -static struct bt_ccb * - bt_ccb_phys_kv __P((struct bt_data *bt, physaddr ccb_phys)); -static int bt_cmd __P((struct bt_data *bt, int icnt, int ocnt, int wait, - u_char *retval, u_char opcode, ...)); -static void bt_done __P((struct bt_data *bt, struct bt_ccb *ccb)); -static void bt_free_ccb __P((struct bt_data *bt, struct bt_ccb *ccb, - int flags)); -static struct bt_ccb * - bt_get_ccb __P((struct bt_data *bt, int flags)); -static void bt_inquire_setup_information __P((struct bt_data *bt, - struct bt_ext_info *info)); -static void btminphys __P((struct buf *bp)); -static int bt_poll __P((struct bt_data *bt, struct scsi_xfer *xs, - struct bt_ccb *ccb)); -#ifdef UTEST -static void bt_print_active_ccbs __P((int unit)); -static void bt_print_ccb __P((struct bt_ccb *ccb)); -#endif -static int32_t bt_scsi_cmd __P((struct scsi_xfer *xs)); -static BT_MBO * bt_send_mbo __P((struct bt_data *bt, int flags, int cmd, - struct bt_ccb *ccb)); -static timeout_t - bt_timeout; - -u_long bt_unit = 0; -static int btprobing = 1; - -/* - * XXX - * Do our own re-probe protection until a configuration - * manager can do it for us. This ensures that we don't - * reprobe a card already found by the EISA or PCI probes. - */ -struct bt_found -{ - u_long port; - char probed; -}; - -static struct bt_found found[] = -{ - { 0x330, 0 }, - { 0x334, 0 }, - { 0x230, 0 }, - { 0x234, 0 }, - { 0x130, 0 }, - { 0x134, 0 } -}; - -static struct scsi_adapter bt_switch = -{ - bt_scsi_cmd, - btminphys, - 0, - 0, - bt_adapter_info, - "bt", - { 0, 0 } -}; - -/* the below structure is so we have a default dev struct for out link struct */ -static 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 */ - "bt", - 0, - { 0, 0 } -}; - -#define BT_RESET_TIMEOUT 1000 - -/* - * bt_cmd(bt, icnt, ocnt, wait, retval, opcode, ...) - * - * 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 ... - * ...: parameters to the command specified by opcode - * - * 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. - */ -static int -#ifdef __STDC__ -bt_cmd(struct bt_data *bt, int icnt, int ocnt, int wait, u_char *retval, - u_char opcode, ...) -#else -bt_cmd(bt, icnt, ocnt, wait, retval, opcode, va_alist) - struct bt_data *bt; - int icnt, ocnt, wait; - u_char *retval; - u_char opcode; - va_dcl -#endif -{ - va_list ap; - u_char data; - u_char oc; - int i; - int sts; - - /* - * multiply the wait argument by a big constant - * zero defaults to 1 - */ - if (wait) - wait *= 100000; - else - wait = 100000; - /* - * 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) { - i = 100000; /* 1 sec? */ - while (--i) { - sts = inb(BT_CTRL_STAT_PORT); - if (sts & BT_IDLE) { - break; - } - DELAY(10); - } - if (i == 0) { - if(!btprobing) - printf("bt%d: bt_cmd, host not idle(0x%x)\n", - bt->unit, sts); - return (ENXIO); - } - } - /* - * Now that it is idle, if we expect output, preflush the - * queue feeding to us. - */ - if (ocnt) { - while ((inb(BT_CTRL_STAT_PORT)) & BT_DF) - inb(BT_CMD_DATA_PORT); - } - /* - * Output the command and the number of arguments given - * for each byte, first check the port is empty. - */ - va_start(ap, opcode); - /* test icnt >= 0, to include the command in data sent */ - for (data = opcode; icnt >= 0; icnt--, data = (u_char)va_arg(ap, int)) { - sts = inb(BT_CTRL_STAT_PORT); - for (i = wait; i; i--) { - sts = inb(BT_CTRL_STAT_PORT); - if (!(sts & BT_CDF)) - break; - DELAY(10); - } - if (i == 0) { - if(!btprobing) - printf("bt%d: bt_cmd, cmd/data port full\n", - bt->unit); - outb(BT_CTRL_STAT_PORT, BT_SRST); - return (ENXIO); - } - outb(BT_CMD_DATA_PORT, data); - } - va_end(ap); - /* - * If we expect input, loop that many times, each time, - * looking for the data register to have valid data - */ - while (ocnt--) { - sts = inb(BT_CTRL_STAT_PORT); - for (i = wait; i; i--) { - sts = inb(BT_CTRL_STAT_PORT); - if (sts & BT_DF) - break; - DELAY(10); - } - if (i == 0) { - if(!btprobing) - printf("bt%d: bt_cmd, cmd/data port empty %d\n", - bt->unit, ocnt); - return (ENXIO); - } - oc = inb(BT_CMD_DATA_PORT); - if (retval) - *retval++ = oc; - } - /* - * Wait for the board to report a finised instruction - */ - i = 100000; /* 1 sec? */ - while (--i) { - sts = inb(BT_INTR_PORT); - if (sts & BT_HACC) { - break; - } - DELAY(10); - } - if (i == 0) { - if(!btprobing) - printf("bt%d: bt_cmd, host not finished(0x%x)\n", - bt->unit, sts); - return (ENXIO); - } - outb(BT_CTRL_STAT_PORT, BT_IRST); - return (0); -} - -struct bt_data * -bt_alloc(unit, iobase) - int unit; - u_long iobase; -{ - struct bt_data *bt; - int i; - - if (unit >= NBT) { - printf("bt: unit number (%d) too high\n", unit); - return NULL; - } - - /* - * Allocate a storage area for us - */ - if (btdata[unit]) { - printf("bt%d: memory already allocated\n", unit); - return NULL; - } - - /* - * Ensure that we haven't already been probed - */ - for (i=0; i < sizeof(found)/sizeof(struct bt_found); i++) { - if (found[i].port == iobase) { - if (found[i].probed) - return NULL; - else { - found[i].probed = 1; - break; - } - } - } - - bt = malloc(sizeof(struct bt_data), M_DEVBUF, M_NOWAIT); - if (!bt) { - printf("bt%d: cannot malloc!\n", unit); - return NULL; - } - bzero(bt, sizeof(struct bt_data)); - btdata[unit] = bt; - bt->unit = unit; - bt->bt_base = iobase; - - return(bt); -} - -void -bt_free(bt) - struct bt_data *bt; -{ - btdata[bt->unit] = NULL; - free(bt, M_DEVBUF); - return; -} - - -int -bt_attach(bt) - struct bt_data *bt; -{ - struct scsibus_data *scbus; - - btprobing = 0; - /* - * fill in the prototype scsi_link. - */ - bt->sc_link.adapter_unit = bt->unit; - bt->sc_link.adapter_targ = bt->bt_scsi_dev; - bt->sc_link.adapter_softc = bt; - bt->sc_link.adapter = &bt_switch; - bt->sc_link.device = &bt_dev; - bt->sc_link.flags = bt->bt_bounce ? SDEV_BOUNCE : 0; - - /* - * Prepare the scsibus_data area for the upperlevel - * scsi code. - */ - scbus = scsi_alloc_bus(); - /* XXX scbus->magtarg should be adjusted for Wide cards */ - if(!scbus) - return 0; - scbus->adapter_link = &bt->sc_link; - - /* - * ask the adapter what subunits are present - */ - scsi_attachdevs(scbus); - return 1; -} - -/* - * Return some information to the caller about the adapter and its - * capabilities. - */ -static u_int32_t -bt_adapter_info(unit) - int unit; -{ - return (2); /* 2 outstanding requests at a time per device */ -} - -/* - * Catch an interrupt from the adaptor - */ -void -bt_intr(arg) - void *arg; -{ - BT_MBI *wmbi; - struct bt_mbx *wmbx; - struct bt_ccb *ccb; - unsigned char stat; - int i, wait; - int found = 0; - struct bt_data *bt; - - bt = (struct bt_data *)arg; - -#ifdef UTEST - printf("bt_intr "); -#endif - /* - * First acknowlege the interrupt, Then if it's - * not telling about a completed operation - * just return. - */ - stat = inb(BT_INTR_PORT); - if((stat & BT_STAT_MASK) == 0) { - /* Shared interrupt */ - return; - } - - /* Mail Box out empty ? */ - if (stat & BT_MBOA) { - printf("bt%d: Available Free mbo post\n", bt->unit); - /* Disable MBO available interrupt */ - outb(BT_CMD_DATA_PORT, BT_MBO_INTR_EN); - wait = 100000; /* 1 sec enough? */ - for (i = wait; i; i--) { - if (!(inb(BT_CTRL_STAT_PORT) & BT_CDF)) - break; - DELAY(10); - } - if (i == 0) { - printf("bt%d: bt_intr, cmd/data port full\n", bt->unit); - outb(BT_CTRL_STAT_PORT, BT_SRST); - return; - } - outb(BT_CMD_DATA_PORT, 0x00); /* Disable */ - wakeup((caddr_t)&bt->bt_mbx); - outb(BT_CTRL_STAT_PORT, BT_IRST); - return; - } - if (!(stat & BT_MBIF)) { - outb(BT_CTRL_STAT_PORT, BT_IRST); - return; - } - /* - * If it IS then process the competed operation - */ - wmbx = &bt->bt_mbx; - wmbi = wmbx->tmbi; - AGAIN: - while (wmbi->stat != BT_MBI_FREE) { - ccb = bt_ccb_phys_kv(bt, (wmbi->ccb_addr)); - if (!ccb) { - wmbi->stat = BT_MBI_FREE; - printf("bt: BAD CCB ADDR!\n"); - continue; - } - found++; - if ((stat = wmbi->stat) != BT_MBI_OK) { - switch (stat) { - case BT_MBI_ABORT: -#ifdef UTEST - if (bt_debug & BT_SHOWMISC) - printf("abort "); -#endif - ccb->host_stat = BT_ABORTED; - break; - - case BT_MBI_UNKNOWN: - ccb = (struct bt_ccb *) 0; -#ifdef UTEST - if (bt_debug & BT_SHOWMISC) - printf("unknown ccb for abort"); -#endif - break; - - case BT_MBI_ERROR: - break; - - default: - panic("Impossible mbxi status"); - - } -#ifdef UTEST - if ((bt_debug & BT_SHOWCMDS) && ccb) { - u_char *cp; - cp = ccb->scsi_cmd; - printf("op=%x %x %x %x %x %x\n", - cp[0], cp[1], cp[2], - cp[3], cp[4], cp[5]); - printf("stat %x for mbi addr = 0x%08x\n" - ,wmbi->stat, wmbi); - printf("addr = 0x%x\n", ccb); - } -#endif - } - wmbi->stat = BT_MBI_FREE; - if (ccb) { - untimeout(bt_timeout, (caddr_t)ccb, - ccb->xfer->timeout_ch); - bt_done(bt, ccb); - } - /* Set the IN mail Box pointer for next */ bt_nextmbx(wmbi, wmbx, mbi); - } - if (!found) { - for (i = 0; i < BT_MBX_SIZE; i++) { - if (wmbi->stat != BT_MBI_FREE) { - found++; - break; - } - bt_nextmbx(wmbi, wmbx, mbi); - } - if (!found) { -#ifdef DEBUG - printf( - "bt%d: mbi at %p should be found, stat=%02x..resync\n", - bt->unit, wmbi, stat); -#endif - } else { - found = 0; - goto AGAIN; - } - } - wmbx->tmbi = wmbi; - outb(BT_CTRL_STAT_PORT, BT_IRST); -} - -/* - * A ccb is put onto the free list. - */ -static void -bt_free_ccb(bt, ccb, flags) - struct bt_data *bt; - struct bt_ccb *ccb; - int flags; -{ - unsigned int opri; - - opri = splbio(); - - ccb->next = bt->bt_ccb_free; - bt->bt_ccb_free = ccb; - ccb->flags = CCB_FREE; - /* - * If there were none, wake anybody waiting for one to come free, - * starting with queued entries. - */ - if (!ccb->next) { - wakeup((caddr_t)&bt->bt_ccb_free); - } - - splx(opri); -} - -/* - * Get a free ccb - * - * 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. - */ -static struct bt_ccb * -bt_get_ccb(bt, flags) - struct bt_data *bt; - int flags; -{ - unsigned opri; - struct bt_ccb *ccbp; - int hashnum; - - opri = splbio(); - /* - * 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), - M_TEMP, - M_NOWAIT)) { - bzero(ccbp, sizeof(struct bt_ccb)); - bt->numccbs++; - ccbp->flags = CCB_ACTIVE; - /* - * put in the phystokv hash table - * Never gets taken out. - */ - ccbp->hashkey = KVTOPHYS(ccbp); - hashnum = CCB_HASH(ccbp->hashkey); - ccbp->nexthash = bt->ccbhash[hashnum]; - bt->ccbhash[hashnum] = ccbp; - } else { - printf("bt%d: Can't malloc CCB\n", bt->unit); - } - goto gottit; - } else { - if (!(flags & SCSI_NOSLEEP)) { - tsleep((caddr_t)&bt->bt_ccb_free, PRIBIO, - "btccb", 0); - continue; - } - break; - } - } - if (ccbp) { - /* Get CCB from from free list */ - bt->bt_ccb_free = ccbp->next; - ccbp->flags = CCB_ACTIVE; - } - gottit: - splx(opri); - - return (ccbp); -} - -/* - * given a physical address, find the ccb that - * it corresponds to: - */ -static struct bt_ccb * -bt_ccb_phys_kv(bt, ccb_phys) - struct bt_data *bt; - physaddr ccb_phys; -{ - int hashnum = CCB_HASH(ccb_phys); - struct bt_ccb *ccbp = bt->ccbhash[hashnum]; - - while (ccbp) { - if (ccbp->hashkey == ccb_phys) - break; - ccbp = ccbp->nexthash; - } - return ccbp; -} - -/* - * Get a MBO and then Send it - */ -static BT_MBO * -bt_send_mbo(bt, flags, cmd, ccb) - struct bt_data *bt; - int flags; - int cmd; - struct bt_ccb *ccb; -{ - unsigned opri; - BT_MBO *wmbo; /* Mail Box Out pointer */ - struct bt_mbx *wmbx; /* Mail Box pointer specified unit */ - int i, wait; - - wmbx = &bt->bt_mbx; - - opri = splbio(); - - /* Get the Target OUT mail Box pointer and move to Next */ - wmbo = wmbx->tmbo; - 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); - for (i = wait; i; i--) { - if (!(inb(BT_CTRL_STAT_PORT) & BT_CDF)) - break; - DELAY(10); - } - if (i == 0) { - printf("bt%d: bt_send_mbo, cmd/data port full\n", bt->unit); - outb(BT_CTRL_STAT_PORT, BT_SRST); - return ((BT_MBO *) 0); - } - 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); - ccb->mbx = wmbo; - wmbo->cmd = cmd; - - /* Send it! */ - outb(BT_CMD_DATA_PORT, BT_START_SCSI); - - splx(opri); - - return (wmbo); -} - -/* - * 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 - */ -static void -bt_done(bt, ccb) - struct bt_data *bt; - struct bt_ccb *ccb; -{ - 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))) { - - s1 = &(ccb->scsi_sense); - s2 = &(xs->sense); - - if (ccb->host_stat) { - switch (ccb->host_stat) { - case BT_ABORTED: /* No response */ - SC_DEBUG(xs->sc_link, SDEV_DB3, - ("timeout reported back\n")); - xs->error = XS_TIMEOUT; - break; - case BT_SEL_TIMEOUT: - SC_DEBUG(xs->sc_link, SDEV_DB3, - ("selection timeout reported back\n")); - xs->error = XS_SELTIMEOUT; - break; - default: /* Other scsi protocol messes */ - xs->error = XS_DRIVER_STUFFUP; - SC_DEBUG(xs->sc_link, SDEV_DB3, - ("unexpected host_stat: %x\n", - ccb->host_stat)); - } - } else { - switch (ccb->target_stat) { - case 0x02: - *s2 = *s1; - xs->error = XS_SENSE; - break; - case 0x08: - xs->error = XS_BUSY; - break; - default: - SC_DEBUG(xs->sc_link, SDEV_DB3, - ("unexpected target_stat: %x\n", - ccb->target_stat)); - xs->error = XS_DRIVER_STUFFUP; - } - } - } else { /* All went correctly OR errors expected */ - xs->resid = 0; - } - xs->flags |= ITSDONE; - bt_free_ccb(bt, ccb, xs->flags); - scsi_done(xs); -} - -/* - * Start the board, ready for normal operation - */ -int -bt_init(bt) - struct bt_data* bt; -{ - unsigned char ad[4]; - volatile int i, sts; - struct bt_config conf; - struct bt_ext_info info; - 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); - - DELAY(10000); - - for (i = BT_RESET_TIMEOUT; i; i--) { - sts = inb(BT_CTRL_STAT_PORT); - if (sts == (BT_IDLE | BT_INIT)) - break; - DELAY(1000); - } - if (i == 0) { -#ifdef UTEST - printf("bt_init: No answer from board\n"); -#endif - return (ENXIO); - } - - DELAY(10000); - - /* - * Displaying Board ID and Hardware Revision - * 94/05/18 amurai@spec.co.jp - */ - i = bt_cmd(bt, 1, sizeof(binfo),0, - (u_char *)&binfo,BT_GET_BOARD_INFO,sizeof(binfo)); - if(i) - return i; - printf("bt%d: Bt%c%c%c%c/%c%d-", bt->unit, - binfo.id[0], - binfo.id[1], - binfo.id[2], - binfo.id[3], - binfo.ver[0], - (unsigned) binfo.ver[1] - ); - - /* - * 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(bt, 1, sizeof(info),0, (u_char *)&info, BT_INQUIRE_EXTENDED, - sizeof(info)); - switch (info.bus_type) { - case BT_BUS_TYPE_24bit: /* PC/AT 24 bit address bus */ - printf("ISA(24bit) bus\n"); - break; - case BT_BUS_TYPE_32bit: /* EISA/VLB/PCI 32 bit bus */ - printf("(32bit) bus\n"); - break; - case BT_BUS_TYPE_MCA: /* forget it right now */ - printf("MCA bus architecture..."); - printf("giving up\n"); - return (ENXIO); - break; - default: - printf("Unknown state..."); - printf("giving up\n"); - return (ENXIO); - break; - } - - if ( binfo.id[0] == '4' && binfo.id[1] == '4' && binfo.id[2] == '5' && - binfo.id[3] == 'S' ) { - printf("bt%d: Your card cannot DMA above 16MB boundary. Bounce buffering enabled.\n", bt->unit); - bt->bt_bounce++; - } else if ( binfo.id[0] == '5' ) { - printf("bt%d: This driver is designed for using 32 bit addressing\n" - "bt%d: mode firmware and EISA/PCI/VLB bus architectures\n" - "bt%d: Bounce-buffering will be used (and is necessary)\n" - "bt%d: if you have more than 16MBytes memory.\n", - bt->unit, - bt->unit, - bt->unit, - bt->unit); - bt->bt_bounce++; - } else if ( info.bus_type == BT_BUS_TYPE_24bit ) { - printf("bt%d: Your board should report a 32bit bus architecture type..\n" - "bt%d: The firmware on your board may have a problem with over\n" - "bt%d: 16MBytes memory handling with this driver.\n", - bt->unit, - bt->unit, - bt->unit); - bt->bt_bounce++; - } - - /* - * Assume we have a board at this stage - * setup dma channel from jumpers and save int - * level - */ - printf("bt%d: reading board settings, ", bt->unit); - - bt_cmd(bt, 0, sizeof(conf), 0, (u_char *)&conf, BT_CONF_GET); - switch (conf.chan) { - case BUSDMA: - bt->bt_dma = -1; - break; - case CHAN0: - outb(0x0b, 0x0c); - outb(0x0a, 0x00); - bt->bt_dma = 0; - break; - case CHAN5: - outb(0xd6, 0xc1); - outb(0xd4, 0x01); - bt->bt_dma = 5; - break; - case CHAN6: - outb(0xd6, 0xc2); - outb(0xd4, 0x02); - bt->bt_dma = 6; - break; - case CHAN7: - outb(0xd6, 0xc3); - outb(0xd4, 0x03); - bt->bt_dma = 7; - break; - default: - printf("illegal dma setting %x\n", conf.chan); - return (EIO); - } - if (bt->bt_dma == -1) - printf("busmastering, "); - else - printf("dma=%d, ", bt->bt_dma); - - switch (conf.intr) { - case INT9: - bt->bt_int = 9; - break; - case INT10: - bt->bt_int = 10; - break; - case INT11: - bt->bt_int = 11; - break; - case INT12: - bt->bt_int = 12; - break; - case INT14: - bt->bt_int = 14; - break; - case INT15: - bt->bt_int = 15; - break; - default: - printf("illegal int setting\n"); - return (EIO); - } - printf("int=%d\n", bt->bt_int); - - /* who are we on the scsi bus */ - bt->bt_scsi_dev = conf.scsi_dev; - /* - * Initialize mail box - */ - *((physaddr *) ad) = KVTOPHYS(&bt->bt_mbx); - bt_cmd(bt, 5, 0, 0, 0, BT_MBX_INIT_EXTENDED - ,BT_MBX_SIZE - ,ad[0] - ,ad[1] - ,ad[2] - ,ad[3]); - - /* - * 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->unit); - 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(bt, &info); - - - /* - * Note that we are going and return (to probe) - */ - return 0; -} - -static void -bt_inquire_setup_information(bt, info) - struct bt_data* bt; - struct bt_ext_info *info; -{ - struct bt_setup setup; - struct bt_sync_value sync; - char dummy[8]; - char sub_ver[3]; - struct bt_boardID bID; - int i; - - /* Inquire Installed Devices */ - bzero( &dummy[0], sizeof(dummy) ); - bt_cmd(bt, 0, sizeof(dummy), 100, &dummy[0], BT_DEV_GET); - - /* - * If board has a capbility of Syncrhonouse mode, - * Get a SCSI Synchronous value - */ - - if (info->s.force) { /* Assume fast sync capability */ - info->s.sync = 1; /* It's appear at 4.25? version */ - info->s.maxsync = 1; - } - if ( info->s.sync ) { - bt_cmd(bt, 1, sizeof(sync), 100, - (u_char *)&sync,BT_GET_SYNC_VALUE,sizeof(sync)); - } - - /* - * Inquire Board ID to board for firmware version - */ - bt_cmd(bt, 0, sizeof(bID), 0, (u_char *)&bID, BT_INQUIRE); - bt_cmd(bt, 0, 1, 0, &sub_ver[0], BT_INQUIRE_REV_THIRD ); - i = ((int)(bID.firm_revision-'0')) * 10 + (int)(bID.firm_version-'0'); - if ( i >= 33 ) { - bt_cmd(bt, 0, 1, 0, &sub_ver[1], BT_INQUIRE_REV_FOURTH ); - } else { - /* - * Below rev 3.3 firmware has a problem for issuing - * the BT_INQUIRE_REV_FOURTH command. - */ - sub_ver[1]='\0'; - } - sub_ver[2]='\0'; - if (sub_ver[1]==' ') - sub_ver[1]='\0'; - printf("bt%d: version %c.%c%s, ", - bt->unit, bID.firm_revision, bID.firm_version, sub_ver ); - - /* - * Obtain setup information from board. - */ - bt_cmd(bt, 1, sizeof(setup), 0, (u_char *)&setup, BT_SETUP_GET, - sizeof(setup)); - - if (setup.sync_neg && info->s.sync ) { - if ( info->s.maxsync ) { - printf("fast sync, "); /* Max 10MB/s */ - } else { - printf("sync, "); /* Max 5MB/s */ - } - } else { - if ( info->s.sync ) { - printf("async, "); /* Never try by board */ - } else { - printf("async only, "); /* Doesn't has a capability on board */ - } - } - if (setup.parity) { - printf("parity, "); - } else { - printf("no parity, "); - } - printf("%d mbxs, %d ccbs\n", setup.num_mbx, BT_CCB_MAX); - - /* - * Displayi SCSI negotiation value by each target. - * amurai@spec.co.jp - */ - for (i = 0; i < 8; i++) { - if (!setup.sync[i].valid ) - continue; - if ( (!setup.sync[i].offset && !setup.sync[i].period) - || !info->s.sync ) { - printf("bt%d: targ %d async\n", bt->unit, i); - } else { - printf("bt%d: targ %d sync rate=%2d.%02dMB/s(%dns), offset=%02d\n", - bt->unit, i, - 100 / sync.value[i], - (100 % sync.value[i]) * 100 / sync.value[i], - sync.value[i] * 10, - setup.sync[i].offset ); - } - } - - /* - * 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: Using Strict Round robin scheme\n", bt->unit); - bt_cmd(bt, 1, 0, 0, 0, BT_ROUND_ROBIN, BT_STRICT_ROUND_ROBIN); - } else { - printf("bt%d: Not using Strict Round robin scheme\n", bt->unit); - } - -} - -#ifndef min -#define min(x,y) (x < y ? x : y) -#endif /* min */ - -static void -btminphys(bp) - struct buf *bp; -{ - 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. - */ -static int32_t -bt_scsi_cmd(xs) - struct scsi_xfer *xs; -{ - struct bt_ccb *ccb; - struct bt_scat_gath *sg; - int seg; /* scatter gather seg being worked on */ - int thiskv; - physaddr thisphys, nextphys; - int bytes_this_seg, bytes_this_page, datalen, flags; - struct bt_data *bt; - - bt = (struct bt_data *)xs->sc_link->adapter_softc; - - 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 = xs->flags; - if (flags & ITSDONE) { - printf("bt%d: Already done?\n", bt->unit); - xs->flags &= ~ITSDONE; - } - if (!(flags & INUSE)) { - printf("bt%d: Not in use?\n", bt->unit); - xs->flags |= INUSE; - } - if (!(ccb = bt_get_ccb(bt, flags))) { - xs->error = XS_DRIVER_STUFFUP; - return (TRY_AGAIN_LATER); - } - SC_DEBUG(xs->sc_link, SDEV_DB3, - ("start ccb(%p)\n", ccb)); - /* - * Put all the arguments for the xfer in the ccb - */ - ccb->xfer = xs; - if (flags & SCSI_RESET) { - ccb->opcode = BT_RESET_CCB; - } else { - /* can't use S/G if zero length */ - ccb->opcode = (xs->datalen ? - BT_INIT_SCAT_GATH_CCB - : BT_INITIATOR_CCB); - } - ccb->target = xs->sc_link->target; - ccb->data_out = 0; - ccb->data_in = 0; - 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); - sg = ccb->scat_gath; - seg = 0; -#ifdef TFS - if (flags & SCSI_DATA_UIO) { - struct iovec *iovp; - - iovp = ((struct uio *) xs->data)->uio_iov; - datalen = ((struct uio *) xs->data)->uio_iovcnt; - xs->datalen = 0; - 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)); - sg++; - iovp++; - seg++; - datalen--; - } - } else -#endif /* TFS */ - { - /* - * Set up the scatter gather block - */ - - SC_DEBUG(xs->sc_link, SDEV_DB4, - ("%ld @%p:- ", xs->datalen, xs->data)); - datalen = xs->datalen; - thiskv = (int) xs->data; - thisphys = KVTOPHYS(thiskv); - - while ((datalen) && (seg < BT_NSEG)) { - bytes_this_seg = 0; - - /* put in the base address */ - sg->seg_addr = thisphys; - - SC_DEBUGN(xs->sc_link, SDEV_DB4, - ("0x%lx", thisphys)); - - /* do it at least once */ - nextphys = thisphys; - 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))) - + PAGESIZ; - bytes_this_page = nextphys - thisphys; - /**** or the data ****/ - bytes_this_page = min(bytes_this_page - ,datalen); - bytes_this_seg += bytes_this_page; - datalen -= bytes_this_page; - - /* get more ready for the next page */ - thiskv = (thiskv & (~(PAGESIZ - 1))) - + PAGESIZ; - if (datalen) - 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; - sg++; - seg++; - } - } - /* end of iov/kv decision */ - ccb->data_length = seg * sizeof(struct bt_scat_gath); - SC_DEBUGN(xs->sc_link, SDEV_DB4, ("\n")); - if (datalen) { - /* - * there's still data, must have run out of segs! - */ - printf("bt%d: bt_scsi_cmd, more than %d DMA segs\n", - bt->unit, BT_NSEG); - xs->error = XS_DRIVER_STUFFUP; - bt_free_ccb(bt, ccb, flags); - return (HAD_ERROR); - } - } else { /* No data xfer, use non S/G values */ - ccb->data_addr = (physaddr) 0; - ccb->data_length = 0; - } - ccb->link_id = 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(bt, flags, BT_MBO_START, ccb) == (BT_MBO *) 0) { - xs->error = XS_DRIVER_STUFFUP; - bt_free_ccb(bt, ccb, flags); - return (TRY_AGAIN_LATER); - } - /* - * Usually return SUCCESSFULLY QUEUED - */ - SC_DEBUG(xs->sc_link, SDEV_DB3, ("cmd_sent\n")); - if (!(flags & SCSI_NOMASK)) { - xs->timeout_ch = 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(bt, xs, ccb)); -} - -/* - * Poll a particular unit, looking for a particular xs - */ -static int -bt_poll(bt, xs, ccb) - struct bt_data* bt; - struct scsi_xfer *xs; - struct bt_ccb *ccb; -{ - int count = xs->timeout; - u_char stat; - - /* timeouts are in msec, so we loop in 1000 usec cycles */ - while (count) { - /* - * If we had interrupts enabled, would we - * have got an interrupt? - */ - stat = inb(BT_INTR_PORT); - if (stat & BT_ANY_INTR) { - bt_intr((void *)bt); - } - if (xs->flags & ITSDONE) { - break; - } - DELAY(1000); /* only happens in boot so ok */ - count--; - } - if (count == 0) { - /* - * 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(ccb); - - /* - * because we are polling, take out the timeout entry - * bt_timeout made - */ - untimeout(bt_timeout, (caddr_t)ccb, ccb->xfer->timeout_ch); - count = 2000; - while (count) { - /* - * Once again, wait for the int bit - */ - stat = inb(BT_INTR_PORT); - if (stat & BT_ANY_INTR) { - bt_intr((void *)bt); - } - if (xs->flags & ITSDONE) { - break; - } - DELAY(1000); /* only happens in boot so ok */ - count--; - } - if (count == 0) { - /* - * We timed out again... This is bad. Notice that - * this time there is no clock queue entry to remove. - */ - bt_timeout(ccb); - } - } - if (xs->error) - return (HAD_ERROR); - return (COMPLETE); -} - -static void -bt_timeout(void *arg1) -{ - struct bt_ccb * ccb = (struct bt_ccb *)arg1; - int unit; - struct bt_data *bt; - int s = splbio(); - - /* - * 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, ccb->xfer->timeout_ch); - - unit = ccb->xfer->sc_link->adapter_unit; - bt = btdata[unit]; - -#ifdef UTEST - bt_print_active_ccbs(bt); -#endif - - /* - * 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); - Debugger("bt742a"); - } - /* - * If it has been through before, then - * a previous abort has failed, don't - * try abort again - */ - if (ccb->flags == CCB_ABORTED) { - /* - * abort timed out - */ - printf("bt%d: Abort Operation has timed out\n", unit); - ccb->xfer->retries = 0; /* I MEAN IT ! */ - ccb->host_stat = BT_ABORTED; - bt_done(bt, ccb); - } else { - /* abort the operation that has timed out */ - printf("bt%d: Try to abort\n", unit); - bt_send_mbo(bt, ~SCSI_NOMASK, BT_MBO_ABORT, ccb); - /* 2 secs for the abort */ - ccb->flags = CCB_ABORTED; - ccb->xfer->timeout_ch = timeout(bt_timeout, (caddr_t)ccb, - 2 * hz); - } - splx(s); -} - -#ifdef UTEST -static void -bt_print_ccb(ccb) - struct bt_ccb *ccb; -{ - printf("ccb:%x op:%x cmdlen:%d senlen:%d\n" - ,ccb - ,ccb->opcode - ,ccb->scsi_cmd_length - ,ccb->req_sense_length); - printf(" datlen:%d hstat:%x tstat:%x flags:%x\n" - ,ccb->data_length - ,ccb->host_stat - ,ccb->target_stat - ,ccb->flags); -} - -static void -bt_print_active_ccbs(bt) - struct bt_data *bt; -{ - struct bt_ccb *ccb; - int i = 0; - - while (i < CCB_HASH_SIZE) { - ccb = bt->ccbhash[i]; - while (ccb) { - if (ccb->flags != CCB_FREE) - bt_print_ccb(ccb); - ccb = ccb->nexthash; - } - i++; - } -} -#endif /*UTEST */ diff --git a/sys/i386/scsi/btreg.h b/sys/i386/scsi/btreg.h deleted file mode 100644 index 8475fa5..0000000 --- a/sys/i386/scsi/btreg.h +++ /dev/null @@ -1,149 +0,0 @@ -/* - * 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 - * organizations 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. - * - * $Id: btreg.h,v 1.6 1997/02/22 09:38:43 peter Exp $ - */ - -#ifndef _BTREG_H_ -#define _BTREG_H_ - -#include "bt.h" - -/* - * Mail box defs etc. - * 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 BT_NSEG 33 /* - * Number of SG segments per command - * Max of 2048??? - */ - -typedef unsigned long int physaddr; - -struct bt_scat_gath { - unsigned long seg_len; - physaddr seg_addr; -}; - -typedef struct bt_mbx_out { - physaddr ccb_addr; - unsigned char dummy[3]; - unsigned char cmd; -} BT_MBO; - -typedef struct bt_mbx_in { - physaddr ccb_addr; - unsigned char btstat; - unsigned char sdstat; - unsigned char dummy; - unsigned char stat; -} BT_MBI; - -struct bt_mbx { - BT_MBO mbo[BT_MBX_SIZE]; -#define BT_MBO_FREE 0x0 /* MBO intry is free */ -#define BT_MBO_START 0x1 /* MBO activate entry */ -#define BT_MBO_ABORT 0x2 /* MBO abort entry */ - BT_MBI mbi[BT_MBX_SIZE]; -#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 */ - BT_MBO *tmbo; /* Target Mail Box out */ - BT_MBI *tmbi; /* Target Mail Box in */ -}; - - -struct bt_ccb { - unsigned char opcode; -#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 w/sg */ -#define BT_RESET_CCB 0x81 /* SCSI Bus reset */ - unsigned :3, data_in:1, data_out:1,:3; - unsigned char scsi_cmd_length; - unsigned char req_sense_length; - unsigned long data_length; - physaddr data_addr; - unsigned char dummy[2]; - unsigned char host_stat; -#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 */ - unsigned char target_stat; - unsigned char target; - unsigned char lun; - unsigned char scsi_cmd[12]; /* 12 bytes (bytes only) */ - unsigned char dummy2[1]; - unsigned char link_id; - physaddr link_addr; - physaddr sense_ptr; - struct scsi_sense_data scsi_sense; - struct bt_scat_gath scat_gath[BT_NSEG]; - struct bt_ccb *next; - struct scsi_xfer *xfer; /* the scsi_xfer for this cmd */ - struct bt_mbx_out *mbx; /* pointer to mail box */ - int flags; -#define CCB_FREE 0 -#define CCB_ACTIVE 1 -#define CCB_ABORTED 2 - struct bt_ccb *nexthash; /* if two hash the same */ - physaddr hashkey; /*physaddr of this ccb */ -}; - -struct bt_data { - int 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 */ - int bt_bounce; /* should we bounce? */ - int unit; /* The zero in bt0 */ - struct scsi_link sc_link; /* prototype for devs */ -}; - -extern struct bt_data *btdata[NBT]; - -extern u_long bt_unit; - -struct bt_data *bt_alloc __P((int unit, u_long iobase)); -void bt_free __P((struct bt_data *bt)); -void bt_intr __P((void *arg)); -int bt_init __P((struct bt_data *bt)); -int bt_attach __P((struct bt_data *bt)); - -#endif /* _BT_H_ */ diff --git a/sys/pci/aic7870.c b/sys/pci/aic7870.c deleted file mode 100644 index 0445576..0000000 --- a/sys/pci/aic7870.c +++ /dev/null @@ -1,997 +0,0 @@ -/* - * Product specific probe and attach routines for: - * 3940, 2940, aic7880, aic7870, aic7860 and aic7850 SCSI controllers - * - * Copyright (c) 1995-1997 Justin Gibbs. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification, immediately at the beginning of the file. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * Where this Software is combined with software released under the terms of - * the GNU Public License ("GPL") and the terms of the GPL would require the - * combined work to also be released under the terms of the GPL, the terms - * and conditions of this License will apply in addition to those of the - * GPL with the exception of any terms or conditions of this License that - * conflict with, or are expressly prohibited by, the GPL. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id: aic7870.c,v 1.55 1998/07/06 18:38:57 gibbs Exp $ - */ - -#if defined(__FreeBSD__) -#include "pci.h" -#endif -#if NPCI > 0 || defined(__NetBSD__) -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/queue.h> -#if defined(__NetBSD__) -#include <sys/device.h> -#include <machine/bus.h> -#include <machine/intr.h> -#endif /* defined(__NetBSD__) */ - -#include <scsi/scsiconf.h> - -#if defined(__FreeBSD__) - -#include <pci/pcireg.h> -#include <pci/pcivar.h> - -#include <machine/clock.h> - -#include <i386/scsi/aic7xxx.h> -#include <i386/scsi/93cx6.h> - -#include "aic7xxx_reg.h" - -#define PCI_BASEADR0 PCI_MAP_REG_START /* I/O Address */ -#define PCI_BASEADR1 PCI_MAP_REG_START + 4 /* Mem I/O Address */ - -#elif defined(__NetBSD__) - -#include <dev/pci/pcireg.h> -#include <dev/pci/pcivar.h> - -#include <dev/ic/aic7xxxreg.h> -#include <dev/ic/aic7xxxvar.h> -#include <dev/ic/smc93cx6var.h> - -#define bootverbose 1 -#define PCI_BASEADR0 PCI_MAPREG_START /* I/O Address */ -#define PCI_BASEADR1 PCI_MAPREG_START + 4 /* Mem I/O Address */ - -#endif /* defined(__NetBSD__) */ - -#define PCI_DEVICE_ID_ADAPTEC_398XU 0x83789004ul -#define PCI_DEVICE_ID_ADAPTEC_3940U 0x82789004ul -#define PCI_DEVICE_ID_ADAPTEC_2944U 0x84789004ul -#define PCI_DEVICE_ID_ADAPTEC_2940U 0x81789004ul -#define PCI_DEVICE_ID_ADAPTEC_2940AU 0x61789004ul -#define PCI_DEVICE_ID_ADAPTEC_398X 0x73789004ul -#define PCI_DEVICE_ID_ADAPTEC_3940 0x72789004ul -#define PCI_DEVICE_ID_ADAPTEC_2944 0x74789004ul -#define PCI_DEVICE_ID_ADAPTEC_2940 0x71789004ul -#define PCI_DEVICE_ID_ADAPTEC_AIC7880 0x80789004ul -#define PCI_DEVICE_ID_ADAPTEC_AIC7870 0x70789004ul -#define PCI_DEVICE_ID_ADAPTEC_AIC7860 0x60789004ul -#define PCI_DEVICE_ID_ADAPTEC_AIC7855 0x55789004ul -#define PCI_DEVICE_ID_ADAPTEC_AIC7850 0x50789004ul -#define PCI_DEVICE_ID_ADAPTEC_AIC7810 0x10789004ul - -#define DEVCONFIG 0x40 -#define MPORTMODE 0x00000400ul /* aic7870 only */ -#define RAMPSM 0x00000200ul /* aic7870 only */ -#define VOLSENSE 0x00000100ul -#define SCBRAMSEL 0x00000080ul -#define MRDCEN 0x00000040ul -#define EXTSCBTIME 0x00000020ul /* aic7870 only */ -#define EXTSCBPEN 0x00000010ul /* aic7870 only */ -#define BERREN 0x00000008ul -#define DACEN 0x00000004ul -#define STPWLEVEL 0x00000002ul -#define DIFACTNEGEN 0x00000001ul /* aic7870 only */ - -#define CSIZE_LATTIME 0x0c -#define CACHESIZE 0x0000003ful /* only 5 bits */ -#define LATTIME 0x0000ff00ul - -/* - * Define the format of the aic78X0 SEEPROM registers (16 bits). - */ - -struct seeprom_config { - -/* - * SCSI ID Configuration Flags - */ -#define CFXFER 0x0007 /* synchronous transfer rate */ -#define CFSYNCH 0x0008 /* enable synchronous transfer */ -#define CFDISC 0x0010 /* enable disconnection */ -#define CFWIDEB 0x0020 /* wide bus device */ -/* UNUSED 0x00C0 */ -#define CFSTART 0x0100 /* send start unit SCSI command */ -#define CFINCBIOS 0x0200 /* include in BIOS scan */ -#define CFRNFOUND 0x0400 /* report even if not found */ -/* UNUSED 0xf800 */ - u_int16_t device_flags[16]; /* words 0-15 */ - -/* - * BIOS Control Bits - */ -#define CFSUPREM 0x0001 /* support all removeable drives */ -#define CFSUPREMB 0x0002 /* support removeable drives for boot only */ -#define CFBIOSEN 0x0004 /* BIOS enabled */ -/* UNUSED 0x0008 */ -#define CFSM2DRV 0x0010 /* support more than two drives */ -/* UNUSED 0x0060 */ -#define CFEXTEND 0x0080 /* extended translation enabled */ -/* UNUSED 0xff00 */ - u_int16_t bios_control; /* word 16 */ - -/* - * Host Adapter Control Bits - */ -#define CFAUTOTERM 0x0001 /* Perform Auto termination */ -#define CFULTRAEN 0x0002 /* Ultra SCSI speed enable */ -#define CFSTERM 0x0004 /* SCSI low byte termination */ -#define CFWSTERM 0x0008 /* SCSI high byte termination */ -#define CFSPARITY 0x0010 /* SCSI parity */ -/* UNUSED 0x0020 */ -#define CFRESETB 0x0040 /* reset SCSI bus at boot */ -/* UNUSED 0xff80 */ - u_int16_t adapter_control; /* word 17 */ - -/* - * Bus Release, Host Adapter ID - */ -#define CFSCSIID 0x000f /* host adapter SCSI ID */ -/* UNUSED 0x00f0 */ -#define CFBRTIME 0xff00 /* bus release time */ - u_int16_t brtime_id; /* word 18 */ - -/* - * Maximum targets - */ -#define CFMAXTARG 0x00ff /* maximum targets */ -/* UNUSED 0xff00 */ - u_int16_t max_targets; /* word 19 */ - - u_int16_t res_1[11]; /* words 20-30 */ - u_int16_t checksum; /* word 31 */ -}; - -static void load_seeprom __P((struct ahc_softc *ahc, u_int8_t *sxfrctl1)); -static int acquire_seeprom __P((struct seeprom_descriptor *sd)); -static void release_seeprom __P((struct seeprom_descriptor *sd)); -static void write_brdctl __P((struct ahc_softc *ahc, u_int8_t value)); -static u_int8_t read_brdctl __P((struct ahc_softc *ahc)); - -static int aic3940_count; -static int aic398X_count; -static struct ahc_softc *first_398X; - -#if defined(__FreeBSD__) - -static char* aic7870_probe __P((pcici_t tag, pcidi_t type)); -static void aic7870_attach __P((pcici_t config_id, int unit)); - -static struct pci_device ahc_pci_driver = { - "ahc", - aic7870_probe, - aic7870_attach, - &ahc_unit, - NULL -}; - -DATA_SET (pcidevice_set, ahc_pci_driver); - -static char* -aic7870_probe (pcici_t tag, pcidi_t type) -{ - switch (type) { - case PCI_DEVICE_ID_ADAPTEC_398XU: - return ("Adaptec 398X Ultra SCSI RAID adapter"); - break; - case PCI_DEVICE_ID_ADAPTEC_3940U: - return ("Adaptec 3940 Ultra SCSI host adapter"); - break; - case PCI_DEVICE_ID_ADAPTEC_398X: - return ("Adaptec 398X SCSI RAID adapter"); - break; - case PCI_DEVICE_ID_ADAPTEC_3940: - return ("Adaptec 3940 SCSI host adapter"); - break; - case PCI_DEVICE_ID_ADAPTEC_2944U: - return ("Adaptec 2944 Ultra SCSI host adapter"); - break; - case PCI_DEVICE_ID_ADAPTEC_2940U: - return ("Adaptec 2940 Ultra SCSI host adapter"); - break; - case PCI_DEVICE_ID_ADAPTEC_2944: - return ("Adaptec 2944 SCSI host adapter"); - break; - case PCI_DEVICE_ID_ADAPTEC_2940: - return ("Adaptec 2940 SCSI host adapter"); - break; - case PCI_DEVICE_ID_ADAPTEC_2940AU: - return ("Adaptec 2940A Ultra SCSI host adapter"); - break; - case PCI_DEVICE_ID_ADAPTEC_AIC7880: - return ("Adaptec aic7880 Ultra SCSI host adapter"); - break; - case PCI_DEVICE_ID_ADAPTEC_AIC7870: - return ("Adaptec aic7870 SCSI host adapter"); - break; - case PCI_DEVICE_ID_ADAPTEC_AIC7860: - return ("Adaptec aic7860 SCSI host adapter"); - break; - case PCI_DEVICE_ID_ADAPTEC_AIC7855: - return ("Adaptec aic7855 SCSI host adapter"); - break; - case PCI_DEVICE_ID_ADAPTEC_AIC7850: - return ("Adaptec aic7850 SCSI host adapter"); - break; - case PCI_DEVICE_ID_ADAPTEC_AIC7810: - return ("Adaptec aic7810 RAID memory controller"); - break; - default: - break; - } - return (0); - -} - -#elif defined(__NetBSD__) - -int ahc_pci_probe __P((struct device *, void *, void *)); -void ahc_pci_attach __P((struct device *, struct device *, void *)); - -struct cfattach ahc_pci_ca = { - sizeof(struct ahc_softc), ahc_pci_probe, ahc_pci_attach -}; - -int -ahc_pci_probe(parent, match, aux) - struct device *parent; - void *match, *aux; -{ - struct pci_attach_args *pa = aux; - - switch (pa->pa_id) { - case PCI_DEVICE_ID_ADAPTEC_398XU: - case PCI_DEVICE_ID_ADAPTEC_3940U: - case PCI_DEVICE_ID_ADAPTEC_2944U: - case PCI_DEVICE_ID_ADAPTEC_2940U: - case PCI_DEVICE_ID_ADAPTEC_2940AU: - case PCI_DEVICE_ID_ADAPTEC_398X: - case PCI_DEVICE_ID_ADAPTEC_3940: - case PCI_DEVICE_ID_ADAPTEC_2944: - case PCI_DEVICE_ID_ADAPTEC_2940: - case PCI_DEVICE_ID_ADAPTEC_AIC7880: - case PCI_DEVICE_ID_ADAPTEC_AIC7870: - case PCI_DEVICE_ID_ADAPTEC_AIC7860: - case PCI_DEVICE_ID_ADAPTEC_AIC7855: - case PCI_DEVICE_ID_ADAPTEC_AIC7850: - case PCI_DEVICE_ID_ADAPTEC_AIC7810: - return 1; - } - return 0; -} -#endif /* defined(__NetBSD__) */ - -#if defined(__FreeBSD__) -static void -aic7870_attach(config_id, unit) - pcici_t config_id; - int unit; -#elif defined(__NetBSD__) -void -ahc_pci_attach(parent, self, aux) - struct device *parent, *self; - void *aux; -#endif -{ -#if defined(__FreeBSD__) - u_int16_t io_port; - struct ahc_softc *ahc; -#elif defined(__NetBSD__) - struct pci_attach_args *pa = aux; - struct ahc_softc *ahc = (void *)self; - int unit = ahc->sc_dev.dv_unit; - bus_io_addr_t iobase; - bus_io_size_t iosize; - bus_io_handle_t ioh; - pci_intr_handle_t ih; - const char *intrstr; -#endif - u_int32_t id; - u_int32_t command; - struct scb_data *shared_scb_data; - int opri; - ahc_type ahc_t = AHC_NONE; - ahc_flag ahc_f = AHC_FNONE; - vm_offset_t vaddr; - vm_offset_t paddr; - u_int8_t ultra_enb = 0; - u_int8_t our_id = 0; - u_int8_t sxfrctl1; - - shared_scb_data = NULL; - vaddr = NULL; - paddr = NULL; -#if defined(__FreeBSD__) - io_port = 0; - command = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG); -#ifdef AHC_ALLOW_MEMIO - if ((command & PCI_COMMAND_MEM_ENABLE) == 0 - || (pci_map_mem(config_id, PCI_BASEADR1, &vaddr, &paddr)) == 0) -#endif - if ((command & PCI_COMMAND_IO_ENABLE) == 0 - || (pci_map_port(config_id, PCI_BASEADR0, &io_port)) == 0) - return; -#elif defined(__NetBSD__) - /* XXX Memory mapped I/O?? */ - if (bus_io_map(pa->pa_bc, iobase, iosize, &ioh)) - if (pci_io_find(pa->pa_pc, pa->pa_tag, PCI_BASEADR0, &iobase, - &iosize)) - return; -#endif - -#if defined(__FreeBSD__) - switch ((id = pci_conf_read(config_id, PCI_ID_REG))) { -#elif defined(__NetBSD__) - switch (id = pa->pa_id) { -#endif - case PCI_DEVICE_ID_ADAPTEC_398XU: - case PCI_DEVICE_ID_ADAPTEC_398X: - if (id == PCI_DEVICE_ID_ADAPTEC_398XU) - ahc_t = AHC_398U; - else - ahc_t = AHC_398; - switch (aic398X_count) { - case 0: - break; - case 1: - ahc_f |= AHC_CHNLB; - break; - case 2: - ahc_f |= AHC_CHNLC; - break; - default: - break; - } - aic398X_count++; - if (first_398X != NULL) -#ifdef AHC_SHARE_SCBS - shared_scb_data = first_398X->scb_data; -#endif - if (aic398X_count == 3) { - /* - * This is the last device on this RAID - * controller, so reset our counts. - * XXX This won't work for the multiple 3980 - * controllers since they have only 2 channels, - * but I'm not even sure if Adaptec actually - * went through with their plans to produce - * this controller. - */ - aic398X_count = 0; - first_398X = NULL; - } - break; - case PCI_DEVICE_ID_ADAPTEC_3940U: - case PCI_DEVICE_ID_ADAPTEC_3940: - if (id == PCI_DEVICE_ID_ADAPTEC_3940U) - ahc_t = AHC_394U; - else - ahc_t = AHC_394; - if ((aic3940_count & 0x01) != 0) - /* Odd count implies second channel */ - ahc_f |= AHC_CHNLB; - aic3940_count++; - break; - case PCI_DEVICE_ID_ADAPTEC_2944U: - case PCI_DEVICE_ID_ADAPTEC_2940U: - ahc_t = AHC_294U; - break; - case PCI_DEVICE_ID_ADAPTEC_2944: - case PCI_DEVICE_ID_ADAPTEC_2940: - ahc_t = AHC_294; - break; - case PCI_DEVICE_ID_ADAPTEC_2940AU: - ahc_t = AHC_294AU; - break; - case PCI_DEVICE_ID_ADAPTEC_AIC7880: - ahc_t = AHC_AIC7880; - break; - case PCI_DEVICE_ID_ADAPTEC_AIC7870: - ahc_t = AHC_AIC7870; - break; - case PCI_DEVICE_ID_ADAPTEC_AIC7860: - ahc_t = AHC_AIC7860; - break; - case PCI_DEVICE_ID_ADAPTEC_AIC7855: - case PCI_DEVICE_ID_ADAPTEC_AIC7850: - ahc_t = AHC_AIC7850; - break; - case PCI_DEVICE_ID_ADAPTEC_AIC7810: - printf("RAID functionality unsupported\n"); - return; - default: - break; - } - - /* On all PCI adapters, we allow SCB paging */ - ahc_f |= AHC_PAGESCBS; -#if defined(__FreeBSD__) - if ((ahc = ahc_alloc(unit, io_port, vaddr, ahc_t, ahc_f, - shared_scb_data)) == NULL) - return; /* XXX PCI code should take return status */ -#else - ahc_construct(ahc, pa->pa_bc, ioh, ahc_t, ahc_f); -#endif - - /* Remeber how the card was setup in case there is no SEEPROM */ - our_id = ahc_inb(ahc, SCSIID) & OID; - if (ahc_t & AHC_ULTRA) - ultra_enb = ahc_inb(ahc, SXFRCTL0) & FAST20; - sxfrctl1 = ahc_inb(ahc, SXFRCTL1) & STPWEN; - -#if defined(__NetBSD__) - printf("\n"); -#endif - ahc_reset(ahc); - -#ifdef AHC_SHARE_SCBS - if (ahc_t & AHC_AIC7870) { -#if defined(__FreeBSD__) - u_int32_t devconfig = pci_conf_read(config_id, DEVCONFIG); -#elif defined(__NetBSD__) - u_int32_t devconfig = - pci_conf_read(pa->pa_pc, pa->pa_tag, DEVCONFIG); -#endif - if (devconfig & (RAMPSM)) { - /* XXX Assume 9bit SRAM and enable parity checking */ - devconfig |= EXTSCBPEN; - - /* XXX Assume fast SRAM and only enable 2 cycle - * access if we are sharing the SRAM across mutiple - * adapters (398X adapter). - */ - if ((devconfig & MPORTMODE) == 0) - /* Multi-user mode */ - devconfig |= EXTSCBTIME; - - devconfig &= ~SCBRAMSEL; -#if defined(__FreeBSD__) - pci_conf_write(config_id, DEVCONFIG, devconfig); -#elif defined(__NetBSD__) - pci_conf_write(pa->pa_pc, pa->pa_tag, - DEVCONFIG, devconfig); -#endif - } - } -#endif - -#if defined(__FreeBSD__) - if (!(pci_map_int(config_id, ahc_intr, (void *)ahc, &bio_imask))) { - ahc_free(ahc); - return; - } -#elif defined(__NetBSD__) - - if (pci_intr_map(pa->pa_pc, pa->pa_intrtag, pa->pa_intrpin, - pa->pa_intrline, &ih)) { - printf("%s: couldn't map interrupt\n", ahc->sc_dev.dv_xname); - ahc_free(ahc); - return; - } - intrstr = pci_intr_string(pa->pa_pc, ih); -#ifdef __OpenBSD__ - ahc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO, ahc_intr, ahc, - ahc->sc_dev.dv_xname); -#else - ahc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO, ahc_intr, ahc); -#endif - if (ahc->sc_ih == NULL) { - printf("%s: couldn't establish interrupt", - ahc->sc_dev.dv_xname); - if (intrstr != NULL) - printf(" at %s", intrstr); - printf("\n"); - ahc_free(ahc); - return; - } - if (intrstr != NULL) - printf("%s: interrupting at %s\n", ahc->sc_dev.dv_xname, - intrstr); -#endif - /* - * Protect ourself from spurrious interrupts during - * intialization. - */ - opri = splbio(); - - /* - * Do aic7880/aic7870/aic7860/aic7850 specific initialization - */ - { - u_int8_t sblkctl; - char *id_string; - - switch(ahc->type) { - case AHC_398U: - case AHC_394U: - case AHC_294U: - case AHC_AIC7880: - id_string = "aic7880 "; - load_seeprom(ahc, &sxfrctl1); - break; - case AHC_398: - case AHC_394: - case AHC_294: - case AHC_AIC7870: - id_string = "aic7870 "; - load_seeprom(ahc, &sxfrctl1); - break; - case AHC_294AU: - case AHC_AIC7860: - id_string = "aic7860 "; - load_seeprom(ahc, &sxfrctl1); - break; - case AHC_AIC7850: - id_string = "aic7850 "; - /* - * Use defaults, if the chip wasn't initialized by - * a BIOS. - */ - ahc->flags |= AHC_USEDEFAULTS; - break; - default: - printf("ahc: Unknown controller type. Ignoring.\n"); - ahc_free(ahc); - splx(opri); - return; - } - - /* - * Take the LED out of diagnostic mode - */ - sblkctl = ahc_inb(ahc, SBLKCTL); - ahc_outb(ahc, SBLKCTL, (sblkctl & ~(DIAGLEDEN|DIAGLEDON))); - - /* - * I don't know where this is set in the SEEPROM or by the - * BIOS, so we default to 100%. - */ - ahc_outb(ahc, DSPCISTATUS, DFTHRSH_100); - - if (ahc->flags & AHC_USEDEFAULTS) { - /* - * PCI Adapter default setup - * Should only be used if the adapter does not have - * an SEEPROM. - */ - /* See if someone else set us up already */ - u_int32_t i; - for (i = TARG_SCRATCH; i < 0x60; i++) { - if (ahc_inb(ahc, i) != 0x00) - break; - } - if (i == TARG_SCRATCH) { - /* - * Try looking for all ones. You can get - * either. - */ - for (i = TARG_SCRATCH; i < 0x60; i++) { - if (ahc_inb(ahc, i) != 0xff) - break; - } - } - if ((i != 0x60) && (our_id != 0)) { - printf("%s: Using left over BIOS settings\n", - ahc_name(ahc)); - ahc->flags &= ~AHC_USEDEFAULTS; - } else { - /* - * Assume only one connector and always turn - * on termination. - */ - our_id = 0x07; - sxfrctl1 = STPWEN; - } - ahc_outb(ahc, SCSICONF, - (our_id & 0x07)|ENSPCHK|RESET_SCSI); - /* In case we are a wide card */ - ahc_outb(ahc, SCSICONF + 1, our_id); - - if (ultra_enb == 0 - && (ahc->flags & AHC_USEDEFAULTS) == 0) { - /* - * If there wasn't a BIOS or the board - * wasn't in this mode to begin with, - * turn off ultra. - */ - ahc->type &= ~AHC_ULTRA; - } - } - - printf("%s: %s", ahc_name(ahc), id_string); - } - - /* - * Put our termination setting into sxfrctl1 now so that the - * generic initialization can see it. - */ - sxfrctl1 |= ahc_inb(ahc, SXFRCTL1); - ahc_outb(ahc, SXFRCTL1, sxfrctl1); - - if (ahc_init(ahc)){ - ahc_free(ahc); - splx(opri); - return; /* XXX PCI code should take return status */ - } - - if ((ahc->type & AHC_398) == AHC_398) { - /* Only set this once we've successfully probed */ - if (shared_scb_data == NULL) - first_398X = ahc; - } - splx(opri); - - ahc_attach(ahc); -} - -/* - * Read the SEEPROM. Return 0 on failure - */ -void -load_seeprom(ahc, sxfrctl1) - struct ahc_softc *ahc; - u_int8_t *sxfrctl1; -{ - struct seeprom_descriptor sd; - struct seeprom_config sc; - u_int16_t *scarray = (u_int16_t *)≻ - u_int8_t scsi_conf; - u_int8_t host_id; - int have_seeprom; - -#if defined(__FreeBSD__) - sd.sd_maddr = ahc->maddr; - if (sd.sd_maddr != NULL) - sd.sd_maddr += SEECTL; - sd.sd_iobase = ahc->baseport; - if (sd.sd_iobase != 0) - sd.sd_iobase += SEECTL; -#elif defined(__NetBSD__) - sd.sd_bc = ahc->sc_bc; - sd.sd_ioh = ahc->sc_ioh; - sd.sd_offset = SEECTL; -#endif - /* - * For some multi-channel devices, the c46 is simply too - * small to work. For the other controller types, we can - * get our information from either SEEPROM type. Set the - * type to start our probe with accordingly. - */ - if ((ahc->type & AHC_398) == AHC_398) - sd.sd_chip = C56_66; - else - sd.sd_chip = C46; - sd.sd_MS = SEEMS; - sd.sd_RDY = SEERDY; - sd.sd_CS = SEECS; - sd.sd_CK = SEECK; - sd.sd_DO = SEEDO; - sd.sd_DI = SEEDI; - - have_seeprom = acquire_seeprom(&sd); - if (have_seeprom) { - if (bootverbose) - printf("%s: Reading SEEPROM...", ahc_name(ahc)); - - for (;;) { - u_int start_addr; - - start_addr = ahc->flags & (AHC_CHNLB|AHC_CHNLC); - - have_seeprom = read_seeprom(&sd, (u_int16_t *)&sc, - start_addr, sizeof(sc)/2); - - if (have_seeprom) { - /* Check checksum */ - int i; - int maxaddr; - u_int16_t *scarray; - u_int16_t checksum; - - maxaddr = (sizeof(sc)/2) - 1; - checksum = 0; - scarray = (u_int16_t *)≻ - - for (i = 0; i < maxaddr; i++) - checksum = checksum + scarray[i]; - if (checksum == 0 || checksum != sc.checksum) { - if (bootverbose && sd.sd_chip == C56_66) - printf ("checksum error\n"); - have_seeprom = 0; - } else { - if (bootverbose) - printf("done.\n"); - break; - } - } - - if (sd.sd_chip == C56_66) - break; - sd.sd_chip = C56_66; - } - } - release_seeprom(&sd); - if (!have_seeprom) { - if (bootverbose) - printf("\n%s: No SEEPROM available\n", ahc_name(ahc)); - ahc->flags |= AHC_USEDEFAULTS; - } else { - /* - * Put the data we've collected down into SRAM - * where ahc_init will find it. - */ - int i; - int max_targ = sc.max_targets & CFMAXTARG; - - for (i = 0; i < max_targ; i++){ - u_char target_settings; - target_settings = (sc.device_flags[i] & CFXFER) << 4; - if (sc.device_flags[i] & CFSYNCH) - target_settings |= SOFS; - if (sc.device_flags[i] & CFWIDEB) - target_settings |= WIDEXFER; - if (sc.device_flags[i] & CFDISC) - ahc->discenable |= (0x01 << i); - ahc_outb(ahc, TARG_SCRATCH+i, target_settings); - } - ahc_outb(ahc, DISC_DSB, ~(ahc->discenable & 0xff)); - ahc_outb(ahc, DISC_DSB + 1, ~((ahc->discenable >> 8) & 0xff)); - - host_id = sc.brtime_id & CFSCSIID; - - scsi_conf = (host_id & 0x7); - if (sc.adapter_control & CFSPARITY) - scsi_conf |= ENSPCHK; - if (sc.adapter_control & CFRESETB) - scsi_conf |= RESET_SCSI; - - /* - * Update the settings in sxfrctl1 to match the - *termination settings - */ - *sxfrctl1 = 0; - if (sc.adapter_control & CFAUTOTERM) { - /* Play around with the memory port */ - have_seeprom = acquire_seeprom(&sd); - if (have_seeprom) { - u_int8_t brdctl; - u_int8_t seectl; - int internal50_present; - int internal68_present; - int external68_present; - int eprom_present; - int high_on; - int low_on; - - seectl = sd.sd_CS|sd.sd_MS; - SEEPROM_OUTB(&sd, seectl); - /* - * First read the status of our cables. - * Set the rom bank to 0 since the - * bank setting serves as a multiplexor - * for the cable detection logic. - * BRDDAT5 controls the bank switch. - */ - write_brdctl(ahc, 0); - - /* - * Now read the state of the internal - * connectors. BRDDAT6 is INT50 and - * BRDDAT7 is INT68. - */ - brdctl = read_brdctl(ahc); - internal50_present = !(brdctl & BRDDAT6); - internal68_present = !(brdctl & BRDDAT7) - && (max_targ > 8); - if (bootverbose) { - printf("internal50 cable %s present\n" - "internal68 cable %s present\n" - "brdctl == 0x%x\n", - internal50_present ? "is":"not", - internal68_present ? "is":"not", - brdctl); - } - - /* - * Set the rom bank to 1 and determine - * the other signals. - */ - write_brdctl(ahc, BRDDAT5); - - /* - * Now read the state of the external - * connectors. BRDDAT6 is EXT68 and - * BRDDAT7 is EPROMPS. - */ - brdctl = read_brdctl(ahc); - external68_present = !(brdctl & BRDDAT6); - eprom_present = brdctl & BRDDAT7; - if (bootverbose) { - printf("external cable %s present\n" - "eprom %s present\n" - "brdctl == 0x%x\n", - external68_present ? "is":"not", - eprom_present ? "is" : "not", - brdctl); - } - - /* - * Now set the termination based on what - * we found. BRDDAT6 controls wide - * termination enable. - */ - high_on = FALSE; - low_on = FALSE; - if ((max_targ > 8) - && ((external68_present == 0) - || (internal68_present == 0))) - high_on = TRUE; - - if (((internal50_present ? 1 : 0) - + (internal68_present ? 1 : 0) - + (external68_present ? 1 : 0)) <= 1) - low_on = TRUE; - - if ((internal50_present != 0) - && (internal68_present != 0) - && (external68_present != 0)) { - printf("Illegal cable configuration!!. " - "Only two connectors on the " - "adapter may be used at a " - "time!"); - } - - if (high_on == TRUE) - write_brdctl(ahc, BRDDAT6); - else - write_brdctl(ahc, 0); - - if (low_on == TRUE) - *sxfrctl1 |= STPWEN; - - if (bootverbose) { - printf("low byte termination %s, " - "high byte termination %s\n", - low_on ? "enabled":"disabled", - high_on ? "enabled":"disabled"); - } - } - release_seeprom(&sd); - } else { - if (sc.adapter_control & CFSTERM) - *sxfrctl1 |= STPWEN; - have_seeprom = acquire_seeprom(&sd); - if (have_seeprom) { - SEEPROM_OUTB(&sd, sd.sd_CS|sd.sd_MS); - if (sc.adapter_control & CFWSTERM) - write_brdctl(ahc, BRDDAT6); - else - write_brdctl(ahc, 0); - release_seeprom(&sd); - } else - printf("Unabled to configure high byte " - "termination!\n"); - - if (bootverbose) { - printf("low byte termination %s, " - "high byte termination %s\n", - sc.adapter_control & CFSTERM ? - "enabled":"disabled", - sc.adapter_control & CFWSTERM ? - "enabled":"disabled"); - } - } - - if (ahc->type & AHC_ULTRA) { - /* Should we enable Ultra mode? */ - if (!(sc.adapter_control & CFULTRAEN)) - /* Treat us as a non-ultra card */ - ahc->type &= ~AHC_ULTRA; - } - /* Set the host ID */ - ahc_outb(ahc, SCSICONF, scsi_conf); - /* In case we are a wide card */ - ahc_outb(ahc, SCSICONF + 1, host_id); - } -} - -static int -acquire_seeprom(sd) - struct seeprom_descriptor *sd; -{ - int wait; - - /* - * Request access of the memory port. When access is - * granted, SEERDY will go high. We use a 1 second - * timeout which should be near 1 second more than - * is needed. Reason: after the chip reset, there - * should be no contention. - */ - SEEPROM_OUTB(sd, sd->sd_MS); - wait = 1000; /* 1 second timeout in msec */ - while (--wait && ((SEEPROM_INB(sd) & sd->sd_RDY) == 0)) { - DELAY (1000); /* delay 1 msec */ - } - if ((SEEPROM_INB(sd) & sd->sd_RDY) == 0) { - SEEPROM_OUTB(sd, 0); - return (0); - } - return(1); -} - -static void -release_seeprom(sd) - struct seeprom_descriptor *sd; -{ - /* Release access to the memory port and the serial EEPROM. */ - SEEPROM_OUTB(sd, 0); -} - -static void -write_brdctl(ahc, value) - struct ahc_softc *ahc; - u_int8_t value; -{ - u_int8_t brdctl; - - brdctl = BRDCS|BRDSTB; - ahc_outb(ahc, BRDCTL, brdctl); - brdctl |= value; - ahc_outb(ahc, BRDCTL, brdctl); - brdctl &= ~BRDSTB; - ahc_outb(ahc, BRDCTL, brdctl); - brdctl &= ~BRDCS; - ahc_outb(ahc, BRDCTL, brdctl); -} - -static u_int8_t -read_brdctl(ahc) - struct ahc_softc *ahc; -{ - ahc_outb(ahc, BRDCTL, BRDRW|BRDCS); - return ahc_inb(ahc, BRDCTL); -} - -#endif /* NPCI > 0 */ diff --git a/sys/pci/bt9xx.c b/sys/pci/bt9xx.c deleted file mode 100644 index e50116e..0000000 --- a/sys/pci/bt9xx.c +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Product specific probe and attach routines for: - * Buslogic BT946 and BT956 SCSI controllers - * - * Copyright (c) 1995 Justin T. Gibbs - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice immediately at the beginning of the file, without modification, - * this list of conditions, and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Absolutely no warranty of function or purpose is made by the author - * Justin T. Gibbs. - * 4. Modifications may be freely made to this file if the above conditions - * are met. - * - * $Id: bt9xx.c,v 1.10 1997/02/22 09:44:00 peter Exp $ - */ - -#include "pci.h" -#if NPCI > 0 -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <scsi/scsiconf.h> -#include <pci/pcireg.h> -#include <pci/pcivar.h> -#include <i386/scsi/btreg.h> - -/* XXX Need more device IDs */ -#define PCI_DEVICE_ID_BUSLOGIC_946 0x1040104Bul -#define PCI_DEVICE_ID_BUSLOGIC_946_OLD 0x0140104Bul - -static char* bt_pci_probe __P((pcici_t tag, pcidi_t type)); -static void bt_pci_attach __P((pcici_t config_id, int unit)); - -static struct pci_device bt_pci_driver = { - "bt", - bt_pci_probe, - bt_pci_attach, - &bt_unit, - NULL -}; - -DATA_SET (pcidevice_set, bt_pci_driver); - -static char* -bt_pci_probe (pcici_t tag, pcidi_t type) -{ - switch(type) { - case PCI_DEVICE_ID_BUSLOGIC_946_OLD: - case PCI_DEVICE_ID_BUSLOGIC_946: - return ("Buslogic 946 SCSI host adapter"); - break; - default: - break; - } - return (0); - -} - -static void -bt_pci_attach(config_id, unit) - pcici_t config_id; - int unit; -{ - u_char reg; - u_long io_port; - unsigned opri = 0; - struct bt_data *bt; - - for(reg = PCI_MAP_REG_START; reg < PCI_MAP_REG_END; reg+=4) { - io_port = pci_conf_read(config_id, reg); - if ((io_port&~7)==0) continue; - if(io_port & PCI_MAP_IO) { - io_port &= ~PCI_MAP_IO; - break; - } - } - if(reg == PCI_MAP_REG_END) - return; - - if(!(bt = bt_alloc(unit, io_port))) - return; /* XXX PCI code should take return status */ - - if(!(pci_map_int(config_id, bt_intr, (void *)bt, &bio_imask))) { - bt_free(bt); - return; - } - /* - * Protect ourself from spurrious interrupts during - * intialization and attach. We should really rely - * on interrupts during attach, but we don't have - * access to our interrupts during ISA probes, so until - * that changes, we mask our interrupts during attach - * too. - */ - opri = splbio(); - - if(bt_init(bt)){ - bt_free(bt); - splx(opri); - return; /* XXX PCI code should take return status */ - } - - bt_attach(bt); - - splx(opri); - return; -} - -#endif /* NPCI > 0 */ diff --git a/sys/scsi/README b/sys/scsi/README deleted file mode 100644 index b9a626a..0000000 --- a/sys/scsi/README +++ /dev/null @@ -1,203 +0,0 @@ -WARNING: This file was not fully updated by dufault@hda.com when -changing the configuration. See the end for new notes. - -This release consists of the following files -(relative to the base of the source tree ) - -share/man/man4/scsi.4 <-useful general info -share/man/man4/uk.4 -share/man/man4/su.4 -share/man/man4/ch.4 -share/man/man4/cd.4 -share/man/man4/sd.4 -share/man/man4/st.4 <--READ THIS IF YOU USE TAPES! -sbin/scsi/procargs.c -sbin/scsi/scsi.c -sbin/scsi/scsi.1 -sbin/scsi/Makefile -sbin/st/Makefile -sbin/st/st.1 -sbin/st/st.c -sys/sys/chio.h -sys/sys/cdio.h -sys/sys/mtio.h -sys/sys/scsiio.h -sys/i386/conf/EXAMPLE -sys/i386/isa/ultra14f.c <-runs 14f and 34f -sys/i386/isa/ultra_all.c.beta <-beta version, runs 14f,24f and 34f -sys/i386/isa/bt742a.c -sys/i386/isa/aha1742.c -sys/i386/isa/aha1542.c -sys/scsi/syspatches -sys/scsi/syspatches/conf.c -sys/scsi/syspatches/user_scsi.diffs -sys/scsi/syspatches/MAKEDEV.diff -sys/scsi/syspatches/isa.c.patch -sys/scsi/syspatches/README -sys/scsi/uk.c -sys/scsi/su.c -sys/scsi/st.c -sys/scsi/sd.c -sys/scsi/ch.c -sys/scsi/cd.c -sys/scsi/scsi_ioctl.c -sys/scsi/scsi_base.c -sys/scsi/scsiconf.c -sys/scsi/scsi_tape.h -sys/scsi/scsi_disk.h -sys/scsi/scsi_changer.h -sys/scsi/scsi_cd.h -sys/scsi/scsi_all.h -sys/scsi/scsi_debug.h -sys/scsi/scsiconf.h -sys/scsi/README <--this file - -notice sys/scsi/sg.c and sys/sys/sgio.h have been removed - - ----------------------------------------------------------------- -This scsi system is designed to allow the re-use of top end drivers -such as disk and tape drivers, with different scsi adapters. - -As of writing this document, There are top end drivers working for: ----------------------------------------------------------------- -generic scsi disk -generic scsi tape -cd-rom (plays music under the xcplayer (?) program) -AEG Character recognition devices * -Calera Character recognition devices * -Generic scsi-II scanners * -Exabyte tape changer device. -GENERIC SCSI DEVICES (user generated scsi commands) ----------------------------------------------------------------- - - -There are also working bottom end drivers for: ----------------------------------------------------------------- -adaptec 1542 (and 1742 in 1542 mode) -bustec 742a (apparently works for VESA version (445S?))(and 747?) -adaptec 174x (note NOT 27xx) -Ultrastore 14f (works for 34f (VESA version)) -Ultrastore 24f RSN (Beta version included here) ----------------------------------------------------------------- - - -################## Using the scsi system ################## -------------minor numbers--------------- -This scsi system does not allocate minor numbers to devices depending -on their SCSI IDs is any way. A devices minor number is dependant -on the order in which it was found. -e.g. the first tape found will become st0 (minor number 0) - the second found will become st1 (minor number 16) - the third will become st2 (minor 32) - etc. - -These devices could be on the same scsi bus or different scsi busses. -That would not change their minor numbers. - -THE EXCEPTION TO THIS IS IN THE GENERIC SCSI DRIVER. in which case -the following mapping applies: - -BB TTT LLL B= scsi bus number, T = target number, L = LUN. - -It is possible to run two different TYPES of scsi adapters at the -same time and have st0 on one and st1 on another. (for example) - -There is a scheme supported in which scsi devices can be 'wired in' even -if they are not present or powered on at probe time. (see scsiconf.c) -In addition, the scsi(1) command allows the operator ask for a -reprobe at any time. Newly found devices will be configured in. Any -device that does not map to a known device type is attached to the -'unknown' (uk) driver. - - ---------------making devices------------ -A changed version of /dev/MAKEDEV is supplied that -can be used to make devices sd[01234] and st[01234] - -e.g. -cd /dev -sh MAKEDEV sd0 sd1 sd2 st0 st1 cd0 - -see st(1) and st(4) for info on tape devices. - ---------------file layout------------------- -Originally I had all scsi definitions in one file: scsi.h -I have since moved definitions of commands so that all -definitions needed for a particular type of device are -found together in the include file of that name. -This approximatly follows the layout of their definition -in the SCSI-2 spec. -As such they are: - -scsi_all.h general commands for all devices --- CHAPTER 7 -scsi-disk.h commands relevant to disk --- CHAPTER 8 -scsi-tape.h commands for scsi tapes --- CHAPTER 9 -scsi-cd.h commands for cd-roms (and audio) --- CHAPTER 13 -scsi-changer.h commands medium changer devices --- CHAPTER 16 - ----------ioctl definitions------------- -User accessable structures (e.g. ioctl definitions) have been -placed in sys/cdio, sys/sgio and sys/chio (based after sys/mtio for -the ioctls for mag tapes (including st). -General scsi ioctls are found in sys/scsiio.h. - ------------cd-rom----------------- -The cd rom driver ha been tested by a number of people and -grefen@convex.com has completed the audio play -functions. -(xcdplayer was available from the 'from_ref' directory on agate) - -At this time it is possible audio play is broken on cdroms and I will -be unable to fix it until I get one to test. -***IMPORTANT*** -Cdrom audio is only suported at all for cdroms that use SCSI2 audio -definitions. - --------------media changer--------------- -Once again courtesy of grefen@convex.com (in germany) -I have not tested this but he assures me it's ready for testing. -If anyone has an exabyte tape changer or similar, -contact the author for information regarding the control interface -and program. - -WARNING: This has not been tested for a LONG TIME! - - ----------recent changes----------- -Removed all bitfields from machine independent sections to make -it possible for them to be used on big-endian architectures. - -Removed scsi specific timeouts in favour of system timeout handling. - -Many structures (getting more all the time) now dynamically allocated. - -Addition of code in the tape driver to recognise models of drive that -have particular problems so they can be handled specially. - -many bug-fixes and cleanups. - ----------even more recent changes:-------- - -rewrote almost the entire thing.. - - - -------Mon Oct 11 22:20:25 WST 1993------ - -Code is now all KNF (or close to it). - -A new structure has been introduced.. -Called scsi_link, one of these exists for every bus/target/lun -that has a driver attached to it. -It has links to the adapter and to the driver, as well as status -information of global interest. (e.g. if the device is in use). -The use of this new structure has allowed the compaction of a -lot of duplicated code into a single copy (now in scsi_base.c) -and makes more simple the USER level scsi implimentation. - -------Tue Feb 28 07:43:17 EST 1995----- -dufault@hda.com: Redid configuration to support wired devices. -All driver entries now get bounced directly into the routines in -"scsi_driver" via a set of functions generated by the SCSI_ENTRIES macro -in scsi_conf.h. This lets us put the common code in a single place. diff --git a/sys/scsi/cd.c b/sys/scsi/cd.c deleted file mode 100644 index 750746f..0000000 --- a/sys/scsi/cd.c +++ /dev/null @@ -1,1419 +0,0 @@ -/* - * 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. - * - * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 - * - * $Id: cd.c,v 1.98 1998/08/17 19:09:36 bde Exp $ - */ - -#include "opt_bounce.h" -#include "opt_devfs.h" -#include "opt_scsi.h" - -#define SPLCD splbio -#define ESUCCESS 0 -#include <sys/param.h> -#include <sys/dkbad.h> -#include <sys/systm.h> -#include <sys/conf.h> -#include <sys/buf.h> -#include <sys/cdio.h> -#include <sys/disklabel.h> -#include <sys/diskslice.h> -#include <sys/dkstat.h> -#include <sys/kernel.h> -#ifdef DEVFS -#include <sys/devfsext.h> -#endif /*DEVFS*/ - -#include <scsi/scsi_all.h> -#include <scsi/scsi_cd.h> -#include <scsi/scsi_disk.h> /* rw_big and start_stop come from there */ -#include <scsi/scsiconf.h> -#include <scsi/scsi_debug.h> -#include <scsi/scsi_driver.h> - -#include "ioconf.h" - -static errval cd_get_parms __P((int, int)); -static u_int32_t cd_size __P((int unit, int flags)); -static d_strategy_t cdstrategy1; -static errval cd_get_mode __P((u_int32_t, struct cd_mode_data *, u_int32_t)); -static errval cd_set_mode __P((u_int32_t unit, struct cd_mode_data *)); -static errval cd_read_toc __P((u_int32_t, u_int32_t, u_int32_t, struct cd_toc_entry *, - u_int32_t)); - -static errval cd_pause __P((u_int32_t, u_int32_t)); -static errval cd_reset __P((u_int32_t)); -static errval cd_play_msf __P((u_int32_t, u_int32_t, u_int32_t, u_int32_t, u_int32_t, u_int32_t, u_int32_t)); -static errval cd_play __P((u_int32_t, u_int32_t, u_int32_t)); -#ifdef notyet -static errval cd_play_big __P((u_int32_t unit, u_int32_t blk, u_int32_t len)); -#endif -static errval cd_play_tracks __P((u_int32_t, u_int32_t, u_int32_t, u_int32_t, u_int32_t)); -static errval cd_read_subchannel __P((u_int32_t, u_int32_t, u_int32_t, int, struct cd_sub_channel_info *, u_int32_t)); - -static d_open_t cdopen; -static d_read_t cdread; -static d_close_t cdclose; -static d_ioctl_t cdioctl; -static d_strategy_t cdstrategy; - -#define CDEV_MAJOR 15 -#define BDEV_MAJOR 6 -static struct cdevsw cd_cdevsw = { - cdopen, cdclose, cdread, nowrite, - cdioctl, nostop, nullreset, nodevtotty, - seltrue, nommap, cdstrategy, "cd", - NULL, -1, nodump, nopsize, - D_DISK, 0, -1 }; - -static int32_t cdstrats, cdqueues; - -#define CDUNIT(dev) dkunit(dev) - -/* XXX introduce a dkmodunit() macro for this. */ -#define CDSETUNIT(DEV, U) \ - makedev(major(DEV), dkmakeminor((U), dkslice(DEV), dkpart(DEV))) - -#define CDOUTSTANDING 2 -#define CDRETRIES 1 -#define LEADOUT 0xaa /* leadout toc entry */ - -#define PARTITION(dev) dkpart(dev) - -static void cdstart(u_int32_t unit, u_int32_t flags); - -struct scsi_data { - u_int32_t flags; -#define CDINIT 0x04 /* device has been init'd */ - struct cd_parms { - u_int32_t blksize; - u_long disksize; /* total number sectors */ - } params; - struct diskslices *dk_slices; /* virtual drives */ - struct buf_queue_head buf_queue; - int dkunit; -#ifdef DEVFS - void *b_devfs_token; - void *c_devfs_token; - void *ctl_devfs_token; -#endif -}; - -static int cdunit(dev_t dev) { return CDUNIT(dev); } -static dev_t cdsetunit(dev_t dev, int unit) { return CDSETUNIT(dev, unit); } - -static errval cd_open(dev_t dev, int flags, int fmt, struct proc *p, - struct scsi_link *sc_link); -static errval cd_ioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, - struct proc *p, struct scsi_link *sc_link); -static errval cd_close(dev_t dev, int flag, int fmt, struct proc *p, - struct scsi_link *sc_link); -static void cd_strategy(struct buf *bp, struct scsi_link *sc_link); - -SCSI_DEVICE_ENTRIES(cd) - -static struct scsi_device cd_switch = -{ - NULL, /* use default error handler */ - cdstart, /* we have a queue, which is started by this */ - NULL, /* we do not have an async handler */ - NULL, /* use default 'done' routine */ - "cd", /* we are to be refered to by this name */ - 0, /* no device specific flags */ - {0, 0}, - 0, /* Link flags */ - cdattach, - "CD-ROM", - cdopen, - sizeof(struct scsi_data), - T_READONLY, - cdunit, - cdsetunit, - cd_open, - cd_ioctl, - cd_close, - cd_strategy, -}; - -#define CD_STOP 0 -#define CD_START 1 -#define CD_EJECT -2 - -static __inline void -cd_registerdev(int unit) -{ - if(dk_ndrive < DK_NDRIVE) { - sprintf(dk_names[dk_ndrive], "cd%d", unit); - dk_wpms[dk_ndrive] = (150*1024/2); - SCSI_DATA(&cd_switch, unit)->dkunit = dk_ndrive++; - } else { - SCSI_DATA(&cd_switch, unit)->dkunit = -1; - } -} - -/* - * The routine called by the low level scsi routine when it discovers - * A device suitable for this driver - */ -static int -cdattach(struct scsi_link *sc_link) -{ - u_int32_t unit; - struct cd_parms *dp; - struct scsi_data *cd = sc_link->sd; -#ifdef DEVFS - int mynor; -#endif - - unit = sc_link->dev_unit; - dp = &(cd->params); - - bufq_init(&cd->buf_queue); - if (sc_link->opennings > CDOUTSTANDING) - sc_link->opennings = CDOUTSTANDING; - /* - * Use the subdriver to request information regarding - * the drive. We cannot use interrupts yet, so the - * request must specify this. - * - * XXX dufault@hda.com: - * Need to handle this better in the case of no record. Rather than - * a state driven sense handler I think we should make it so that - * the command can get the sense back so that it can selectively log - * errors. - */ - if (sc_link->quirks & CD_Q_NO_TOUCH) { - dp->disksize = 0; - } else { - cd_get_parms(unit, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT); - } - if (dp->disksize) { - printf("cd present [%lu x %lu byte records]", - cd->params.disksize, (u_long)cd->params.blksize); - } else { - printf("can't get the size"); - } - - cd->flags |= CDINIT; - cd_registerdev(unit); -#ifdef DEVFS - mynor = dkmakeminor(unit, WHOLE_DISK_SLICE, RAW_PART); - cd->b_devfs_token = devfs_add_devswf(&cd_cdevsw, mynor, DV_BLK, - UID_ROOT, GID_OPERATOR, 0640, - "cd%d", unit); - cd->c_devfs_token = devfs_add_devswf(&cd_cdevsw, mynor, DV_CHR, - UID_ROOT, GID_OPERATOR, 0640, - "rcd%d", unit); - mynor = dkmakeminor(unit, 0, 0); /* XXX */ - cd->ctl_devfs_token = devfs_add_devswf(&cd_cdevsw, - mynor | SCSI_CONTROL_MASK, - DV_CHR, - UID_ROOT, GID_WHEEL, 0600, - "rcd%d.ctl", unit); -#endif - - return 0; -} - -/* - * open the device. Make sure the partition info is a up-to-date as can be. - */ -static errval -cd_open(dev_t dev, int flags, int fmt, struct proc *p, - struct scsi_link *sc_link) -{ - errval errcode = 0; - u_int32_t unit; - struct disklabel label; - struct scsi_data *cd; - int n; - - unit = CDUNIT(dev); - - cd = sc_link->sd; - /* - * Make sure the device has been initialised - */ - if ((cd == NULL) || (!(cd->flags & CDINIT))) - return (ENXIO); - - SC_DEBUG(sc_link, SDEV_DB1, - ("cd_open: dev=0x%lx (unit %lu,partition %d)\n", - (u_long)dev, (u_long)unit, PARTITION(dev))); - /* - * Check that it is still responding and ok. - * if the media has been changed this will result in a - * "unit attention" error which the error code will - * disregard because the SDEV_OPEN flag is not yet set. - * Makes sure that we know it if the media has been changed.. - */ - scsi_test_unit_ready(sc_link, SCSI_SILENT); - - /* - * If it's been invalidated, then forget the label. - */ - if (!(sc_link->flags & SDEV_MEDIA_LOADED) && cd->dk_slices != NULL) { - /* - * If somebody still has it open, then forbid re-entry. - */ - if (dsisopen(cd->dk_slices)) { - SC_DEBUG(sc_link, SDEV_DB2, - ("unit attn, but openparts?\n")); - return (ENXIO); - } - - dsgone(&cd->dk_slices); - } - - /* - * Start the drive, and take notice of error returns. - * Some (arguably broken) drives go crazy on this attempt, we can - * handle it. - */ - if ((sc_link->quirks & CD_Q_NO_START) == 0) { - scsi_start_unit(sc_link, CD_START); - SC_DEBUG(sc_link, SDEV_DB3, ("'start' attempted ")); - } - sc_link->flags |= SDEV_OPEN; /* unit attn errors are now errors */ - - /* - * Some drives take a long time to become ready after a disk swap - * and report 'Not Ready' rather than 'Unit in the Process of Getting - * Ready' while doing so; attempts to mount during this period will - * return ENXIO. Give them some time to come up. - */ - for (n = 0; scsi_test_unit_ready(sc_link, SCSI_SILENT) && n != 12; n++) - tsleep(cd, PRIBIO | PCATCH, "cdrdy", hz); - - /* If still not ready, give up */ - if (scsi_test_unit_ready(sc_link, SCSI_SILENT) != 0) { - SC_DEBUG(sc_link, SDEV_DB3, ("not ready\n")); - errcode = ENXIO; - goto bad; - } - SC_DEBUG(sc_link, SDEV_DB3, ("Device present\n")); - scsi_prevent(sc_link, PR_PREVENT, SCSI_SILENT); - /* - * Load the physical device parameters - */ - if (cd_get_parms(unit, 0)) { - errcode = ENXIO; - goto bad; - } - SC_DEBUG(sc_link, SDEV_DB3, ("Params loaded ")); - - /* - * Build prototype label for whole disk. - * Should put manufacturer and model in d_typename and d_packname. - * Should take information about different data tracks from the - * TOC and put it in the partition table. - */ - bzero(&label, sizeof label); - label.d_type = DTYPE_SCSI; - strncpy(label.d_typename, "scsi cd_rom", sizeof(label.d_typename)); - label.d_secsize = cd->params.blksize; - label.d_secperunit = cd->params.disksize; - label.d_flags = D_REMOVABLE; - /* - * Make partition 'a' cover the whole disk. This is a temporary - * compatibility hack. The 'a' partition should not exist, so - * the slice code won't create it. The slice code will make - * partition (RAW_PART + 'a') cover the whole disk and fill in - * some more defaults. - */ - label.d_partitions[0].p_size = label.d_secperunit; - label.d_partitions[0].p_fstype = FS_OTHER; - - /* Initialize slice tables. */ - errcode = dsopen("cd", dev, fmt, DSO_NOLABELS | DSO_ONESLICE, - &cd->dk_slices, &label, cdstrategy1, - (ds_setgeom_t *)NULL, &cd_cdevsw); - if (errcode != 0) - goto bad; - SC_DEBUG(sc_link, SDEV_DB3, ("Slice tables initialized ")); - - SC_DEBUG(sc_link, SDEV_DB3, ("open complete\n")); - sc_link->flags |= SDEV_MEDIA_LOADED; - return 0; - - bad: - /* - * if we would have been the only open - * then leave things back as they were - */ - if (!dsisopen(cd->dk_slices)) { - sc_link->flags &= ~SDEV_OPEN; - scsi_prevent(sc_link, PR_ALLOW, SCSI_SILENT); - } - return (errcode); -} - -/* - * close the device.. only called if we are the LAST - * occurence of an open device - */ -static errval -cd_close(dev_t dev, int flag, int fmt, struct proc *p, - struct scsi_link *sc_link) -{ - struct scsi_data *cd; - - cd = sc_link->sd; - SC_DEBUG(sc_link, SDEV_DB2, ("cd%d: closing part %d\n", - CDUNIT(dev), PARTITION(dev))); - dsclose(dev, fmt, cd->dk_slices); - if (!dsisopen(cd->dk_slices)) { - scsi_prevent(sc_link, PR_ALLOW, SCSI_SILENT); - sc_link->flags &= ~SDEV_OPEN; - } - return (0); -} - - -static int -cdread(dev_t dev, struct uio *uio, int ioflag) -{ - return (physio(cdstrategy, NULL, dev, 1, minphys, uio)); -} - -/* - * Actually translate the requested transfer into one the physical driver can - * understand. The transfer is described by a buf and will include only one - * physical transfer. - */ -static void -cd_strategy(struct buf *bp, struct scsi_link *sc_link) -{ - u_int32_t opri; - u_int32_t unit = CDUNIT((bp->b_dev)); - struct scsi_data *cd = sc_link->sd; - - cdstrats++; - /* - * If the device has been made invalid, error out - * maybe the media changed - */ - if (!(sc_link->flags & SDEV_MEDIA_LOADED)) { - bp->b_error = EIO; - goto bad; - } - /* - * can't ever write to a CD - */ - if ((bp->b_flags & B_READ) == 0) { - bp->b_error = EROFS; - goto bad; - } - - /* - * Do bounds checking, adjust transfer, and set b_pblkno. - */ - if (dscheck(bp, cd->dk_slices) <= 0) - goto done; - - opri = SPLCD(); - - /* - * Use a bounce buffer if necessary - */ -#ifdef BOUNCE_BUFFERS - if (sc_link->flags & SDEV_BOUNCE) - vm_bounce_alloc(bp); -#endif - - /* - * Place it in the queue of disk activities for this disk - */ - bufq_insert_tail(&cd->buf_queue, bp); - - /* - * Tell the device to get going on the transfer if it's - * not doing anything, otherwise just wait for completion - */ - cdstart(unit, 0); - - splx(opri); - return; - bad: - bp->b_flags |= B_ERROR; - done: - - /* - * Correctly set the buf to indicate a completed xfer - */ - bp->b_resid = bp->b_bcount; - biodone(bp); - return; -} - -static void -cdstrategy1(struct buf *bp) -{ - /* - * XXX - do something to make cdstrategy() but not this block while - * we're doing dsinit() and dsioctl(). - */ - cdstrategy(bp); -} - -/* - * cdstart looks to see if there is a buf waiting for the device - * and that the device is not already busy. If both are true, - * It deques the buf and creates a scsi command to perform the - * transfer in the buf. The transfer request will call scsi_done - * on completion, which will in turn call this routine again - * so that the next queued transfer is performed. - * The bufs are queued by the strategy routine (cdstrategy) - * - * This routine is also called after other non-queued requests - * have been made of the scsi driver, to ensure that the queue - * continues to be drained. - * - * must be called at the correct (highish) spl level - * cdstart() is called at SPLCD from cdstrategy and scsi_done - */ -static void -cdstart(unit, flags) - u_int32_t unit; - u_int32_t flags; -{ - register struct buf *bp = 0; - struct scsi_rw_big cmd; - u_int32_t blkno, nblk; - struct scsi_link *sc_link = SCSI_LINK(&cd_switch, unit); - struct scsi_data *cd = sc_link->sd; - - SC_DEBUG(sc_link, SDEV_DB2, ("cdstart%lu ", (u_long)unit)); - /* - * See if there is a buf to do and we are not already - * doing one - */ - if (!sc_link->opennings) { - return; /* no room for us, unit already underway */ - } - if (sc_link->flags & SDEV_WAITING) { /* is room, but a special waits */ - return; /* give the special that's waiting a chance to run */ - } - - bp = bufq_first(&cd->buf_queue); - if (bp == NULL) { /* yes, an assign */ - return; - } - bufq_remove(&cd->buf_queue, bp); - - /* - * Should reject all queued entries if SDEV_MEDIA_LOADED is not true. - */ - if (!(sc_link->flags & SDEV_MEDIA_LOADED)) { - goto bad; /* no I/O.. media changed or something */ - } - /* - * We have a buf, now we should make a command - */ - blkno = bp->b_pblkno; - nblk = bp->b_bcount / cd->params.blksize; - - /* - * Fill out the scsi command - */ - bzero(&cmd, sizeof(cmd)); - cmd.op_code = READ_BIG; - cmd.addr_3 = (blkno & 0xff000000UL) >> 24; - cmd.addr_2 = (blkno & 0xff0000) >> 16; - cmd.addr_1 = (blkno & 0xff00) >> 8; - cmd.addr_0 = blkno & 0xff; - cmd.length2 = (nblk & 0xff00) >> 8; - cmd.length1 = (nblk & 0xff); - - /* - * Call the routine that chats with the adapter. - * Note: we cannot sleep as we may be an interrupt - */ - if (scsi_scsi_cmd(sc_link, - (struct scsi_generic *) &cmd, - sizeof(cmd), - (u_char *) bp->b_data, - bp->b_bcount, - CDRETRIES, - 30000, - bp, - flags | ((bp->b_flags & B_READ) ? - SCSI_DATA_IN : SCSI_DATA_OUT)) - != SUCCESSFULLY_QUEUED) { - bad: - printf("cd%lu: oops not queued\n", (u_long)unit); - bp->b_error = EIO; - bp->b_flags |= B_ERROR; - biodone(bp); - return; - } - cdqueues++; - if(cd->dkunit >= 0) { - dk_xfer[cd->dkunit]++; - dk_seek[cd->dkunit]++; /* don't know */ - dk_wds[cd->dkunit] += bp->b_bcount >> 6; - } -} - -/* - * Perform special action on behalf of the user. - * Knows about the internals of this device - */ -static errval -cd_ioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p, - struct scsi_link *sc_link) -{ - errval error; - u_int32_t unit; - register struct scsi_data *cd; - - /* - * Find the device that the user is talking about - */ - cd = sc_link->sd; - SC_DEBUG(sc_link, SDEV_DB2, ("cdioctl 0x%lx ", cmd)); - - /* - * If the device is not valid.. abandon ship - */ - if (!(sc_link->flags & SDEV_MEDIA_LOADED)) - return (EIO); - - if (cmd == DIOCSBAD) - return (EINVAL); /* XXX */ -#if 0 - /* Wait until we have exclusive access to the device. */ - /* XXX this is how sd does it. How did we work without this? */ - error = scsi_device_lock(sc_link); - if (error) - return error; -#endif - error = dsioctl("cd", dev, cmd, addr, flag, &cd->dk_slices, - cdstrategy1, (ds_setgeom_t *)NULL); - scsi_device_unlock(sc_link); - if (error != ENOIOCTL) - return (error); - if (PARTITION(dev) != RAW_PART) - return (ENOTTY); - error = 0; - unit = CDUNIT(dev); - switch (cmd) { - case CDIOCPLAYTRACKS: - { - struct ioc_play_track *args - = (struct ioc_play_track *) addr; - struct cd_mode_data data; - error = cd_get_mode(unit, &data, AUDIO_PAGE); - if (error) - break; - data.page.audio.flags &= ~CD_PA_SOTC; - data.page.audio.flags |= CD_PA_IMMED; - error = cd_set_mode(unit, &data); - if (error) - break; - if (sc_link->quirks & CD_Q_BCD_TRACKS) { - args->start_track = bin2bcd(args->start_track); - args->end_track = bin2bcd(args->end_track); - } - return (cd_play_tracks(unit - ,args->start_track - ,args->start_index - ,args->end_track - ,args->end_index - )); - } - break; - case CDIOCPLAYMSF: - { - struct ioc_play_msf *args - = (struct ioc_play_msf *) addr; - struct cd_mode_data data; - error = cd_get_mode(unit, &data, AUDIO_PAGE); - if (error) - break; - data.page.audio.flags &= ~CD_PA_SOTC; - data.page.audio.flags |= CD_PA_IMMED; - error = cd_set_mode(unit, &data); - if (error) - break; - return (cd_play_msf(unit - ,args->start_m - ,args->start_s - ,args->start_f - ,args->end_m - ,args->end_s - ,args->end_f - )); - } - break; - case CDIOCPLAYBLOCKS: - { - struct ioc_play_blocks *args - = (struct ioc_play_blocks *) addr; - struct cd_mode_data data; - error = cd_get_mode(unit, &data, AUDIO_PAGE); - if (error) - break; - data.page.audio.flags &= ~CD_PA_SOTC; - data.page.audio.flags |= CD_PA_IMMED; - error = cd_set_mode(unit, &data); - if (error) - break; - return (cd_play(unit, args->blk, args->len)); - - } - break; - case CDIOCREADSUBCHANNEL: - { - struct ioc_read_subchannel *args - = (struct ioc_read_subchannel *) addr; - struct cd_sub_channel_info data; - u_int32_t len = args->data_len; - if (len > sizeof(data) || - len < sizeof(struct cd_sub_channel_header)) { - error = EINVAL; - break; - } - if (sc_link->quirks & CD_Q_BCD_TRACKS) - args->track = bin2bcd(args->track); - error = cd_read_subchannel(unit, args->address_format, - args->data_format, args->track, &data, len); - if (error) - break; - if (sc_link->quirks & CD_Q_BCD_TRACKS) - data.what.track_info.track_number = - bcd2bin(data.what.track_info.track_number); - len = min(len, ((data.header.data_len[0] << 8) + - data.header.data_len[1] + - sizeof(struct cd_sub_channel_header))); - if (copyout(&data, args->data, len) != 0) { - error = EFAULT; - } - } - break; - case CDIOREADTOCHEADER: - { - struct ioc_toc_header th; - error = cd_read_toc(unit, 0, 0, - (struct cd_toc_entry *)&th, sizeof th); - if (error) - break; - if (sc_link->quirks & CD_Q_BCD_TRACKS) { - /* we are going to have to convert the BCD - * encoding on the cd to what is expected - */ - th.starting_track = bcd2bin(th.starting_track); - th.ending_track = bcd2bin(th.ending_track); - } - NTOHS(th.len); - bcopy(&th, addr, sizeof th); - } - break; - case CDIOREADTOCENTRYS: - { - struct { - struct ioc_toc_header header; - struct cd_toc_entry entries[100]; - } data; - struct { - struct ioc_toc_header header; - struct cd_toc_entry entry; - } lead; - struct ioc_read_toc_entry *te = - (struct ioc_read_toc_entry *) addr; - struct ioc_toc_header *th; - u_int32_t len, readlen, idx, num; - u_int32_t starting_track = te->starting_track; - - if ( te->data_len < sizeof(struct cd_toc_entry) - || (te->data_len % sizeof(struct cd_toc_entry)) != 0 - || te->address_format != CD_MSF_FORMAT - && te->address_format != CD_LBA_FORMAT - ) { - error = EINVAL; - break; - } - - th = &data.header; - error = cd_read_toc(unit, 0, 0, - (struct cd_toc_entry *)th, sizeof (*th)); - if (error) - break; - - if (sc_link->quirks & CD_Q_BCD_TRACKS) { - /* we are going to have to convert the BCD - * encoding on the cd to what is expected - */ - th->starting_track = - bcd2bin(th->starting_track); - th->ending_track = bcd2bin(th->ending_track); - } - - if (starting_track == 0) - starting_track = th->starting_track; - else if (starting_track == LEADOUT) - starting_track = th->ending_track + 1; - else if (starting_track < th->starting_track || - starting_track > th->ending_track + 1) { - error = EINVAL; - break; - } - - /* calculate reading length without leadout entry */ - readlen = (th->ending_track - starting_track + 1) * - sizeof(struct cd_toc_entry); - - /* and with leadout entry */ - len = readlen + sizeof(struct cd_toc_entry); - if (te->data_len < len) { - len = te->data_len; - if (readlen > len) - readlen = len; - } - if (len > sizeof(data.entries)) { - error = EINVAL; - break; - } - num = len / sizeof(struct cd_toc_entry); - - if (readlen > 0) { - error = cd_read_toc(unit, te->address_format, - starting_track, - (struct cd_toc_entry *)&data, - readlen + sizeof (*th)); - if (error) - break; - } - - /* make leadout entry if needed */ - idx = starting_track + num - 1; - if (sc_link->quirks & CD_Q_BCD_TRACKS) - th->ending_track = bcd2bin(th->ending_track); - if (idx == th->ending_track + 1) { - error = cd_read_toc(unit, te->address_format, - LEADOUT, - (struct cd_toc_entry *)&lead, - sizeof(lead)); - if (error) - break; - data.entries[idx - starting_track] = lead.entry; - } - - if (sc_link->quirks & CD_Q_BCD_TRACKS) { - for (idx = 0; idx < num - 1; idx++) { - data.entries[idx].track = - bcd2bin(data.entries[idx].track); - } - } - - error = copyout(data.entries, te->data, len); - } - break; - case CDIOREADTOCENTRY: - { - struct { - struct ioc_toc_header header; - struct cd_toc_entry entry; - } data; - struct ioc_read_toc_single_entry *te = - (struct ioc_read_toc_single_entry *) addr; - struct ioc_toc_header *th; - u_int32_t track; - - if (te->address_format != CD_MSF_FORMAT - && te->address_format != CD_LBA_FORMAT) { - error = EINVAL; - break; - } - - th = &data.header; - error = cd_read_toc(unit, 0, 0, - (struct cd_toc_entry *)th, sizeof (*th)); - if (error) - break; - - if (sc_link->quirks & CD_Q_BCD_TRACKS) { - /* we are going to have to convert the BCD - * encoding on the cd to what is expected - */ - th->starting_track = - bcd2bin(th->starting_track); - th->ending_track = bcd2bin(th->ending_track); - } - - track = te->track; - if (track == 0) - track = th->starting_track; - else if (track == LEADOUT) - /* OK */; - else if (track < th->starting_track || - track > th->ending_track + 1) { - error = EINVAL; - break; - } - - error = cd_read_toc(unit, te->address_format, - track, - (struct cd_toc_entry *)&data, - sizeof data); - if (error) - break; - - if (sc_link->quirks & CD_Q_BCD_TRACKS) - data.entry.track = bcd2bin(data.entry.track); - - bcopy(&data.entry, &te->entry, - sizeof(struct cd_toc_entry)); - } - break; - case CDIOCSETPATCH: - { - struct ioc_patch *arg = (struct ioc_patch *) addr; - struct cd_mode_data data; - error = cd_get_mode(unit, &data, AUDIO_PAGE); - if (error) - break; - data.page.audio.port[LEFT_PORT].channels = arg->patch[0]; - data.page.audio.port[RIGHT_PORT].channels = arg->patch[1]; - data.page.audio.port[2].channels = arg->patch[2]; - data.page.audio.port[3].channels = arg->patch[3]; - error = cd_set_mode(unit, &data); - if (error) - break; /* eh? */ - } - break; - case CDIOCGETVOL: - { - struct ioc_vol *arg = (struct ioc_vol *) addr; - struct cd_mode_data data; - error = cd_get_mode(unit, &data, AUDIO_PAGE); - if (error) - break; - arg->vol[LEFT_PORT] = data.page.audio.port[LEFT_PORT].volume; - arg->vol[RIGHT_PORT] = data.page.audio.port[RIGHT_PORT].volume; - arg->vol[2] = data.page.audio.port[2].volume; - arg->vol[3] = data.page.audio.port[3].volume; - } - break; - case CDIOCSETVOL: - { - struct ioc_vol *arg = (struct ioc_vol *) addr; - struct cd_mode_data data; - error = cd_get_mode(unit, &data, AUDIO_PAGE); - if (error) - break; - data.page.audio.port[LEFT_PORT].channels = CHANNEL_0; - data.page.audio.port[LEFT_PORT].volume = arg->vol[LEFT_PORT]; - data.page.audio.port[RIGHT_PORT].channels = CHANNEL_1; - data.page.audio.port[RIGHT_PORT].volume = arg->vol[RIGHT_PORT]; - data.page.audio.port[2].volume = arg->vol[2]; - data.page.audio.port[3].volume = arg->vol[3]; - error = cd_set_mode(unit, &data); - if (error) - break; - } - break; - case CDIOCSETMONO: - { - struct cd_mode_data data; - error = cd_get_mode(unit, &data, AUDIO_PAGE); - if (error) - break; - data.page.audio.port[LEFT_PORT].channels = LEFT_CHANNEL | RIGHT_CHANNEL; - data.page.audio.port[RIGHT_PORT].channels = LEFT_CHANNEL | RIGHT_CHANNEL; - data.page.audio.port[2].channels = 0; - data.page.audio.port[3].channels = 0; - error = cd_set_mode(unit, &data); - if (error) - break; - } - break; - case CDIOCSETSTEREO: - { - struct cd_mode_data data; - error = cd_get_mode(unit, &data, AUDIO_PAGE); - if (error) - break; - data.page.audio.port[LEFT_PORT].channels = LEFT_CHANNEL; - data.page.audio.port[RIGHT_PORT].channels = RIGHT_CHANNEL; - data.page.audio.port[2].channels = 0; - data.page.audio.port[3].channels = 0; - error = cd_set_mode(unit, &data); - if (error) - break; - } - break; - case CDIOCSETMUTE: - { - struct cd_mode_data data; - error = cd_get_mode(unit, &data, AUDIO_PAGE); - if (error) - break; - data.page.audio.port[LEFT_PORT].channels = 0; - data.page.audio.port[RIGHT_PORT].channels = 0; - data.page.audio.port[2].channels = 0; - data.page.audio.port[3].channels = 0; - error = cd_set_mode(unit, &data); - if (error) - break; - } - break; - case CDIOCSETLEFT: - { - struct cd_mode_data data; - error = cd_get_mode(unit, &data, AUDIO_PAGE); - if (error) - break; - data.page.audio.port[LEFT_PORT].channels = LEFT_CHANNEL; - data.page.audio.port[RIGHT_PORT].channels = LEFT_CHANNEL; - data.page.audio.port[2].channels = 0; - data.page.audio.port[3].channels = 0; - error = cd_set_mode(unit, &data); - if (error) - break; - } - break; - case CDIOCSETRIGHT: - { - struct cd_mode_data data; - error = cd_get_mode(unit, &data, AUDIO_PAGE); - if (error) - break; - data.page.audio.port[LEFT_PORT].channels = RIGHT_CHANNEL; - data.page.audio.port[RIGHT_PORT].channels = RIGHT_CHANNEL; - data.page.audio.port[2].channels = 0; - data.page.audio.port[3].channels = 0; - error = cd_set_mode(unit, &data); - if (error) - break; - } - break; - case CDIOCRESUME: - error = cd_pause(unit, 1); - break; - case CDIOCPAUSE: - error = cd_pause(unit, 0); - break; - case CDIOCSTART: - error = scsi_start_unit(sc_link, 0); - break; - case CDIOCSTOP: - error = scsi_stop_unit(sc_link, 0, 0); - break; - case CDIOCEJECT: - error = scsi_stop_unit(sc_link, 1, 0); - break; - case CDIOCALLOW: - error = scsi_prevent(sc_link, PR_ALLOW, 0); - break; - case CDIOCPREVENT: - error = scsi_prevent(sc_link, PR_PREVENT, 0); - break; - case CDIOCSETDEBUG: - sc_link->flags |= (SDEV_DB1 | SDEV_DB2); - break; - case CDIOCCLRDEBUG: - sc_link->flags &= ~(SDEV_DB1 | SDEV_DB2); - break; - case CDIOCRESET: - return (cd_reset(unit)); - break; - default: - error = scsi_do_ioctl(dev, cmd, addr, flag, p, sc_link); - break; - } - return (error); -} - -/* - * Find out from the device what its capacity is - */ -static u_int32_t -cd_size(unit, flags) - int unit; - int flags; -{ - struct scsi_read_cd_cap_data rdcap; - struct scsi_read_cd_capacity scsi_cmd; - u_int32_t size; - u_int32_t blksize; - struct scsi_link *sc_link = SCSI_LINK(&cd_switch, unit); - struct scsi_data *cd = sc_link->sd; - - /* - * make up a scsi command and ask the scsi driver to do - * it for you. - */ - bzero(&scsi_cmd, sizeof(scsi_cmd)); - scsi_cmd.op_code = READ_CD_CAPACITY; - - /* - * If the command works, interpret the result as a 4 byte - * number of blocks and a blocksize - */ - if (scsi_scsi_cmd(sc_link, - (struct scsi_generic *) &scsi_cmd, - sizeof(scsi_cmd), - (u_char *) & rdcap, - sizeof(rdcap), - CDRETRIES, - 20000, /* might be a disk-changer */ - NULL, - SCSI_DATA_IN | flags) != 0) { - return (0); - } else { - size = rdcap.addr_0 + 1; - size += rdcap.addr_1 << 8; - size += rdcap.addr_2 << 16; - size += rdcap.addr_3 << 24; - blksize = rdcap.length_0; - blksize += rdcap.length_1 << 8; - blksize += rdcap.length_2 << 16; - blksize += rdcap.length_3 << 24; - } - if (blksize < 512) - blksize = 2048; /* some drives lie ! */ - if (size < 100) - size = 400000; /* ditto */ - SC_DEBUG(sc_link, SDEV_DB3, ("cd%d: %lu %lu byte blocks\n", - unit, (u_long)size, (u_long)blksize)); - cd->params.disksize = size; - cd->params.blksize = blksize; - return (size); -} - -/* - * Get the requested page into the buffer given - */ -static errval -cd_get_mode(unit, data, page) - u_int32_t unit; - struct cd_mode_data *data; - u_int32_t page; -{ - struct scsi_mode_sense scsi_cmd; - errval retval; - - bzero(&scsi_cmd, sizeof(scsi_cmd)); - bzero(data, sizeof(*data)); - scsi_cmd.op_code = MODE_SENSE; - scsi_cmd.page = page; - scsi_cmd.length = sizeof(*data) & 0xff; - retval = scsi_scsi_cmd(SCSI_LINK(&cd_switch, unit), - (struct scsi_generic *) &scsi_cmd, - sizeof(scsi_cmd), - (u_char *) data, - sizeof(*data), - CDRETRIES, - 20000, /* should be immed */ - NULL, - SCSI_DATA_IN); - return (retval); -} - -/* - * Get the requested page into the buffer given - */ -static errval -cd_set_mode(unit, data) - u_int32_t unit; - struct cd_mode_data *data; -{ - struct scsi_mode_select scsi_cmd; - - bzero(&scsi_cmd, sizeof(scsi_cmd)); - scsi_cmd.op_code = MODE_SELECT; - scsi_cmd.byte2 |= SMS_PF; - scsi_cmd.length = sizeof(*data) & 0xff; - data->header.data_length = 0; - /* - * SONY drives do not allow a mode select with a medium_type - * value that has just been returned by a mode sense; use a - * medium_type of 0 (Default) instead. - */ - data->header.medium_type = 0; - return (scsi_scsi_cmd(SCSI_LINK(&cd_switch, unit), - (struct scsi_generic *) &scsi_cmd, - sizeof(scsi_cmd), - (u_char *) data, - sizeof(*data), - CDRETRIES, - 20000, /* should be immed */ - NULL, - SCSI_DATA_OUT)); -} - -/* - * Get scsi driver to send a "start playing" command - */ -static errval -cd_play(unit, blk, len) - u_int32_t unit, blk, len; -{ - struct scsi_play scsi_cmd; - - bzero(&scsi_cmd, sizeof(scsi_cmd)); - scsi_cmd.op_code = PLAY; - scsi_cmd.blk_addr[0] = (blk >> 24) & 0xff; - scsi_cmd.blk_addr[1] = (blk >> 16) & 0xff; - scsi_cmd.blk_addr[2] = (blk >> 8) & 0xff; - scsi_cmd.blk_addr[3] = blk & 0xff; - scsi_cmd.xfer_len[0] = (len >> 8) & 0xff; - scsi_cmd.xfer_len[1] = len & 0xff; - return (scsi_scsi_cmd(SCSI_LINK(&cd_switch, unit), - (struct scsi_generic *) &scsi_cmd, - sizeof(scsi_cmd), - 0, - 0, - CDRETRIES, - 200000, /* should be immed */ - NULL, - 0)); -} - -#ifdef notyet -/* - * Get scsi driver to send a "start playing" command - */ -static errval -cd_play_big(unit, blk, len) - u_int32_t unit, blk, len; -{ - struct scsi_play_big scsi_cmd; - - bzero(&scsi_cmd, sizeof(scsi_cmd)); - scsi_cmd.op_code = PLAY_BIG; - scsi_cmd.blk_addr[0] = (blk >> 24) & 0xff; - scsi_cmd.blk_addr[1] = (blk >> 16) & 0xff; - scsi_cmd.blk_addr[2] = (blk >> 8) & 0xff; - scsi_cmd.blk_addr[3] = blk & 0xff; - scsi_cmd.xfer_len[0] = (len >> 24) & 0xff; - scsi_cmd.xfer_len[1] = (len >> 16) & 0xff; - scsi_cmd.xfer_len[2] = (len >> 8) & 0xff; - scsi_cmd.xfer_len[3] = len & 0xff; - return (scsi_scsi_cmd(SCSI_LINK(&cd_switch, unit), - (struct scsi_generic *) &scsi_cmd, - sizeof(scsi_cmd), - 0, - 0, - CDRETRIES, - 20000, /* should be immed */ - NULL, - 0)); -} -#endif - -/* - * Get scsi driver to send a "start playing" command - */ -static errval -cd_play_tracks(unit, strack, sindex, etrack, eindex) - u_int32_t unit, strack, sindex, etrack, eindex; -{ - struct scsi_play_track scsi_cmd; - - bzero(&scsi_cmd, sizeof(scsi_cmd)); - scsi_cmd.op_code = PLAY_TRACK; - scsi_cmd.start_track = strack; - scsi_cmd.start_index = sindex; - scsi_cmd.end_track = etrack; - scsi_cmd.end_index = eindex; - return (scsi_scsi_cmd(SCSI_LINK(&cd_switch, unit), - (struct scsi_generic *) &scsi_cmd, - sizeof(scsi_cmd), - 0, - 0, - CDRETRIES, - 20000, /* should be immed */ - NULL, - 0)); -} - -/* - * Get scsi driver to send a "play msf" command - */ -static errval -cd_play_msf(unit, startm, starts, startf, endm, ends, endf) - u_int32_t unit, startm, starts, startf, endm, ends, endf; -{ - struct scsi_play_msf scsi_cmd; - - bzero(&scsi_cmd, sizeof(scsi_cmd)); - scsi_cmd.op_code = PLAY_MSF; - scsi_cmd.start_m = startm; - scsi_cmd.start_s = starts; - scsi_cmd.start_f = startf; - scsi_cmd.end_m = endm; - scsi_cmd.end_s = ends; - scsi_cmd.end_f = endf; - - return (scsi_scsi_cmd(SCSI_LINK(&cd_switch, unit), - (struct scsi_generic *) &scsi_cmd, - sizeof(scsi_cmd), - 0, - 0, - CDRETRIES, - 2000, - NULL, - 0)); -} - -/* - * Get scsi driver to send a "start up" command - */ -static errval -cd_pause(unit, go) - u_int32_t unit, go; -{ - struct scsi_pause scsi_cmd; - - bzero(&scsi_cmd, sizeof(scsi_cmd)); - scsi_cmd.op_code = PAUSE; - scsi_cmd.resume = go; - - return (scsi_scsi_cmd(SCSI_LINK(&cd_switch, unit), - (struct scsi_generic *) &scsi_cmd, - sizeof(scsi_cmd), - 0, - 0, - CDRETRIES, - 2000, - NULL, - 0)); -} - -/* - * Get scsi driver to send a "RESET" command - */ -static errval -cd_reset(unit) - u_int32_t unit; -{ - return scsi_reset_target(SCSI_LINK(&cd_switch, unit)); -} - -/* - * Read subchannel - */ -static errval -cd_read_subchannel(unit, mode, format, track, data, len) - u_int32_t unit, mode, format; - int track; - struct cd_sub_channel_info *data; - u_int32_t len; -{ - struct scsi_read_subchannel scsi_cmd; - - bzero(&scsi_cmd, sizeof(scsi_cmd)); - - scsi_cmd.op_code = READ_SUBCHANNEL; - if (mode == CD_MSF_FORMAT) - scsi_cmd.byte2 |= CD_MSF; - scsi_cmd.byte3 = SRS_SUBQ; - scsi_cmd.subchan_format = format; - scsi_cmd.track = track; - scsi_cmd.data_len[0] = (len) >> 8; - scsi_cmd.data_len[1] = (len) & 0xff; - return (scsi_scsi_cmd(SCSI_LINK(&cd_switch, unit), - (struct scsi_generic *) &scsi_cmd, - sizeof(struct scsi_read_subchannel), - (u_char *) data, - len, - CDRETRIES, - 5000, - NULL, - SCSI_DATA_IN)); -} - -/* - * Read table of contents - */ -static errval -cd_read_toc(unit, mode, start, data, len) - u_int32_t unit, mode, start; - struct cd_toc_entry *data; - u_int32_t len; -{ - struct scsi_read_toc scsi_cmd; - u_int32_t ntoc; - - bzero(&scsi_cmd, sizeof(scsi_cmd)); - /*if(len!=sizeof(struct ioc_toc_header)) - * ntoc=((len)-sizeof(struct ioc_toc_header))/sizeof(struct cd_toc_entry); - * else */ - ntoc = len; - - scsi_cmd.op_code = READ_TOC; - if (mode == CD_MSF_FORMAT) - scsi_cmd.byte2 |= CD_MSF; - scsi_cmd.from_track = start; - scsi_cmd.data_len[0] = (ntoc) >> 8; - scsi_cmd.data_len[1] = (ntoc) & 0xff; - return (scsi_scsi_cmd(SCSI_LINK(&cd_switch, unit), - (struct scsi_generic *) &scsi_cmd, - sizeof(struct scsi_read_toc), - (u_char *) data, - len, - CDRETRIES, - 5000, - NULL, - SCSI_DATA_IN)); -} - -#define b2tol(a) (((unsigned)(a##_1) << 8) + (unsigned)a##_0 ) - -/* - * Get the scsi driver to send a full inquiry to the device and use the - * results to fill out the disk parameter structure. - */ -static errval -cd_get_parms(unit, flags) - int unit; - int flags; -{ - struct scsi_link *sc_link = SCSI_LINK(&cd_switch, unit); - - /* - * First check if we have it all loaded - */ - if (sc_link->flags & SDEV_MEDIA_LOADED) - return (0); - /* - * give a number of sectors so that sec * trks * cyls - * is <= disk_size - */ - if (cd_size(unit, flags)) { - sc_link->flags |= SDEV_MEDIA_LOADED; - return (0); - } else { - return (ENXIO); - } -} - -static cd_devsw_installed = 0; - -static void cd_drvinit(void *unused) -{ - - if( ! cd_devsw_installed ) { - cdevsw_add_generic(BDEV_MAJOR, CDEV_MAJOR, &cd_cdevsw); - cd_devsw_installed = 1; - } -} - -SYSINIT(cddev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,cd_drvinit,NULL) - - diff --git a/sys/scsi/ch.c b/sys/scsi/ch.c deleted file mode 100644 index 9b970fb..0000000 --- a/sys/scsi/ch.c +++ /dev/null @@ -1,750 +0,0 @@ -/* - * Copyright (c) 1996 Jason R. Thorpe <thorpej@and.com> - * All rights reserved. - * - * Partially based on an autochanger driver written by Stefan Grefen - * and on an autochanger driver written by the Systems Programming Group - * at the University of Utah Computer Science Department. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgements: - * This product includes software developed by Jason R. Thorpe - * for And Communications, http://www.and.com/ - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id: ch.c,v 1.47 1998/06/17 14:13:13 bde Exp $ - */ - -#include "opt_devfs.h" -#include "opt_bounce.h" - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/chio.h> -#include <sys/conf.h> -#include <sys/kernel.h> -#include <sys/malloc.h> -#ifdef DEVFS -#include <sys/devfsext.h> -#endif /*DEVFS*/ -#ifdef BOUNCE_BUFFERS -#include <sys/buf.h> -#endif - -#include <scsi/scsi_changer.h> -#include <scsi/scsiconf.h> -#include <scsi/scsi_driver.h> - -#include "ioconf.h" - -#define CHRETRIES 2 -#define CHUNIT(x) (minor((x))) -#define CHSETUNIT(x, y) makedev(major(x), y) - -struct ch_softc { - /* - * Human-readable external name. FreeBSD doesn't have a - * generic hook for this, so we make it look NetBSD-like. See - * comment in chattach(). - */ - struct { - char dv_xname[16]; - } sc_dev; - - /* - * Pointer back to the scsi_link. See comment in chattach(). - */ - struct scsi_link *sc_link; - - int sc_picker; /* current picker */ - - /* - * The following information is obtained from the - * element address assignment page. - */ - int sc_firsts[4]; /* firsts, indexed by CHET_* */ - int sc_counts[4]; /* counts, indexed by CHET_* */ - - /* - * The following mask defines the legal combinations - * of elements for the MOVE MEDIUM command. - */ - u_int8_t sc_movemask[4]; - - /* - * As above, but for EXCHANGE MEDIUM. - */ - u_int8_t sc_exchangemask[4]; - - int flags; /* misc. info */ -#ifdef DEVFS - void *c_devfs_token; - void *ctl_devfs_token; -#endif -}; - -/* sc_flags */ -#define CHF_ROTATE 0x01 /* picker can rotate */ - -static d_open_t chopen; -static d_close_t chclose; -static d_ioctl_t chioctl; - -#define CDEV_MAJOR 17 -static struct cdevsw ch_cdevsw = - { chopen, chclose, noread, nowrite, /*17*/ - chioctl, nostop, nullreset, nodevtotty,/* ch */ - seltrue, nommap, nostrat, "ch", NULL, -1 }; - -/* - * SCSI glue. - */ - -/* - * Under FreeBSD, this macro sets up a bunch of trampoline - * functions that indirect through the SCSI subsystem. - */ -SCSI_DEVICE_ENTRIES(ch) - -static int chunit __P((dev_t)); -static dev_t chsetunit __P((dev_t, int)); - -/* So, like, why not "int"? */ -static errval ch_devopen __P((dev_t, int, int, struct proc *, - struct scsi_link *)); -static errval ch_devioctl __P((dev_t, u_long, caddr_t, int, struct proc *, - struct scsi_link *)); -static errval ch_devclose __P((dev_t, int, int, struct proc *, - struct scsi_link *)); - -static struct scsi_device ch_switch = { - NULL, /* (*err_handler) */ - NULL, /* (*start) */ - NULL, /* (*async) */ - NULL, /* (*done) */ - "ch", /* name */ - 0, /* flags */ - { 0, 0 }, /* spare[2] */ - 0, /* link_flags */ - chattach, /* (*attach) */ - "Medium-Changer", /* desc */ - chopen, /* (*open) */ - sizeof(struct ch_softc), /* sizeof_scsi_data */ - T_CHANGER, /* type */ - chunit, /* (*getunit) */ - chsetunit, /* (*setunit) */ - ch_devopen, /* (*dev_open) */ - ch_devioctl, /* (*dev_ioctl) */ - ch_devclose, /* (*dev_close) */ -}; - -static int ch_move __P((struct ch_softc *, struct changer_move *)); -static int ch_exchange __P((struct ch_softc *, struct changer_exchange *)); -static int ch_position __P((struct ch_softc *, struct changer_position *)); -static int ch_usergetelemstatus __P((struct ch_softc *, int, u_int8_t *)); -static int ch_getelemstatus __P((struct ch_softc *, int, int, caddr_t, size_t)); -static int ch_get_params __P((struct ch_softc *, int)); - -static errval -chattach(link) - struct scsi_link *link; -{ - struct ch_softc *sc = (struct ch_softc *)(link->sd); - u_int32_t unit = link->dev_unit; - - /* - * FreeBSD doesn't have any common way of carrying - * around a device's external name (i.e. <name><unit>), - * so emulate the structure used by NetBSD to keep the - * diffs lower. - */ - bzero(sc->sc_dev.dv_xname, sizeof(sc->sc_dev.dv_xname)); - sprintf(sc->sc_dev.dv_xname, "%s%d", ch_switch.name, unit); - - /* - * FreeBSD gets "softc" info for a device from the - * scsi_link argument passed to indirect entry point functions. - * NetBSD get scsi_link info from softcs that are - * obtained from indexes passed to direct entry point functions. - * We emulate the NetBSD behavior here to keep the diffs - * lower. - */ - sc->sc_link = link; - - /* - * Get information about the device. Note we can't use - * interrupts yet. - */ - if (ch_get_params(sc, SCSI_NOSLEEP|SCSI_NOMASK)) - printf("offline"); - else { - printf("%d slot%s, %d drive%s, %d picker%s", - sc->sc_counts[CHET_ST], (sc->sc_counts[CHET_ST] > 1) ? - "s" : "", - sc->sc_counts[CHET_DT], (sc->sc_counts[CHET_DT] > 1) ? - "s" : "", - sc->sc_counts[CHET_MT], (sc->sc_counts[CHET_MT] > 1) ? - "s" : ""); - if (sc->sc_counts[CHET_IE]) - printf(", %d portal%s", sc->sc_counts[CHET_IE], - (sc->sc_counts[CHET_IE] > 1) ? "s" : ""); - if (bootverbose) { - printf("\n"); /* This will probably look ugly ... bummer. */ - printf("%s: move mask: 0x%x 0x%x 0x%x 0x%x\n", - sc->sc_dev.dv_xname, - sc->sc_movemask[CHET_MT], sc->sc_movemask[CHET_ST], - sc->sc_movemask[CHET_IE], sc->sc_movemask[CHET_DT]); - printf("%s: exchange mask: 0x%x 0x%x 0x%x 0x%x\n", - sc->sc_dev.dv_xname, - sc->sc_exchangemask[CHET_MT], sc->sc_exchangemask[CHET_ST], - sc->sc_exchangemask[CHET_IE], sc->sc_exchangemask[CHET_DT]); - } - } - - /* Default the current picker. */ - sc->sc_picker = sc->sc_firsts[CHET_MT]; - -#ifdef DEVFS - sc->c_devfs_token = devfs_add_devswf(&ch_cdevsw, unit << 4, DV_CHR, - UID_ROOT, GID_OPERATOR, 0600, - "ch%d", unit); - sc->ctl_devfs_token = devfs_add_devswf(&ch_cdevsw, - (unit << 4) | SCSI_CONTROL_MASK, - DV_CHR, - UID_ROOT, GID_OPERATOR, 0600, - "ch%d.ctl", unit); -#endif - return (0); -} - -static errval -ch_devopen(dev, flags, fmt, p, link) - dev_t dev; - int flags, fmt; - struct proc *p; - struct scsi_link *link; -{ - struct ch_softc *sc = (struct ch_softc *)(link->sd); - errval error = 0; - int unit; - - unit = CHUNIT(dev); - - /* - * Only allow one open at a time. - */ - if (link->flags & SDEV_OPEN) - return (EBUSY); - - link->flags |= SDEV_OPEN; - - /* - * Absorb any unit attention errors. Ignore "not ready" - * since this might occur if e.g. a tape isn't actually - * loaded in the drive. - */ - (void)scsi_test_unit_ready(link, SCSI_SILENT); - - /* - * Make sure our parameters are up to date. - */ - if (error = ch_get_params(sc, 0)) - goto bad; - - return (0); - - bad: - link->flags &= ~SDEV_OPEN; - return (error); -} - -static errval -ch_devclose(dev, flags, fmt, p, link) - dev_t dev; - int flags, fmt; - struct proc *p; - struct scsi_link *link; -{ - - link->flags &= ~SDEV_OPEN; - return (0); -} - -static errval -ch_devioctl(dev, cmd, data, flags, p, link) - dev_t dev; - u_long cmd; - caddr_t data; - int flags; - struct proc *p; - struct scsi_link *link; -{ - struct ch_softc *sc = (struct ch_softc *)(link->sd); - caddr_t elemdata; - int error = 0; - - switch (cmd) { - case CHIOMOVE: - error = ch_move(sc, (struct changer_move *)data); - break; - - case CHIOEXCHANGE: - error = ch_exchange(sc, (struct changer_exchange *)data); - break; - - case CHIOPOSITION: - error = ch_position(sc, (struct changer_position *)data); - break; - - case CHIOGPICKER: - *(int *)data = sc->sc_picker - sc->sc_firsts[CHET_MT]; - break; - - case CHIOSPICKER: { - int new_picker = *(int *)data; - - if (new_picker > (sc->sc_counts[CHET_MT] - 1)) - return (EINVAL); - sc->sc_picker = sc->sc_firsts[CHET_MT] + new_picker; - break; } - - case CHIOGPARAMS: { - struct changer_params *cp = (struct changer_params *)data; - - cp->cp_curpicker = sc->sc_picker - sc->sc_firsts[CHET_MT]; - cp->cp_npickers = sc->sc_counts[CHET_MT]; - cp->cp_nslots = sc->sc_counts[CHET_ST]; - cp->cp_nportals = sc->sc_counts[CHET_IE]; - cp->cp_ndrives = sc->sc_counts[CHET_DT]; - break; } - - case CHIOGSTATUS: { - struct changer_element_status *ces = - (struct changer_element_status *)data; - - error = ch_usergetelemstatus(sc, ces->ces_type, ces->ces_data); - break; } - - /* Implement prevent/allow? */ - - default: - error = scsi_do_ioctl(dev, cmd, data, flags, p, link); - break; - } - - return (error); -} - -static int -ch_move(sc, cm) - struct ch_softc *sc; - struct changer_move *cm; -{ - struct scsi_move_medium cmd; - u_int16_t fromelem, toelem; - - /* - * Check arguments. - */ - if ((cm->cm_fromtype > CHET_DT) || (cm->cm_totype > CHET_DT)) - return (EINVAL); - if ((cm->cm_fromunit > (sc->sc_counts[cm->cm_fromtype] - 1)) || - (cm->cm_tounit > (sc->sc_counts[cm->cm_totype] - 1))) - return (ENODEV); - - /* - * Check the request against the changer's capabilities. - */ - if ((sc->sc_movemask[cm->cm_fromtype] & (1 << cm->cm_totype)) == 0) - return (EINVAL); - - /* - * Calculate the source and destination elements. - */ - fromelem = sc->sc_firsts[cm->cm_fromtype] + cm->cm_fromunit; - toelem = sc->sc_firsts[cm->cm_totype] + cm->cm_tounit; - - /* - * Build the SCSI command. - */ - bzero(&cmd, sizeof(cmd)); - cmd.opcode = MOVE_MEDIUM; - scsi_uto2b(sc->sc_picker, cmd.tea); - scsi_uto2b(fromelem, cmd.src); - scsi_uto2b(toelem, cmd.dst); - if (cm->cm_flags & CM_INVERT) - cmd.flags |= MOVE_MEDIUM_INVERT; - - /* - * Send command to changer. - */ - return (scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd, - sizeof(cmd), NULL, 0, CHRETRIES, 100000, NULL, 0)); -} - -static int -ch_exchange(sc, ce) - struct ch_softc *sc; - struct changer_exchange *ce; -{ - struct scsi_exchange_medium cmd; - u_int16_t src, dst1, dst2; - - /* - * Check arguments. - */ - if ((ce->ce_srctype > CHET_DT) || (ce->ce_fdsttype > CHET_DT) || - (ce->ce_sdsttype > CHET_DT)) - return (EINVAL); - if ((ce->ce_srcunit > (sc->sc_counts[ce->ce_srctype] - 1)) || - (ce->ce_fdstunit > (sc->sc_counts[ce->ce_fdsttype] - 1)) || - (ce->ce_sdstunit > (sc->sc_counts[ce->ce_sdsttype] - 1))) - return (ENODEV); - - /* - * Check the request against the changer's capabilities. - */ - if (((sc->sc_exchangemask[ce->ce_srctype] & - (1 << ce->ce_fdsttype)) == 0) || - ((sc->sc_exchangemask[ce->ce_fdsttype] & - (1 << ce->ce_sdsttype)) == 0)) - return (EINVAL); - - /* - * Calculate the source and destination elements. - */ - src = sc->sc_firsts[ce->ce_srctype] + ce->ce_srcunit; - dst1 = sc->sc_firsts[ce->ce_fdsttype] + ce->ce_fdstunit; - dst2 = sc->sc_firsts[ce->ce_sdsttype] + ce->ce_sdstunit; - - /* - * Build the SCSI command. - */ - bzero(&cmd, sizeof(cmd)); - cmd.opcode = EXCHANGE_MEDIUM; - scsi_uto2b(sc->sc_picker, cmd.tea); - scsi_uto2b(src, cmd.src); - scsi_uto2b(dst1, cmd.fdst); - scsi_uto2b(dst2, cmd.sdst); - if (ce->ce_flags & CE_INVERT1) - cmd.flags |= EXCHANGE_MEDIUM_INV1; - if (ce->ce_flags & CE_INVERT2) - cmd.flags |= EXCHANGE_MEDIUM_INV2; - - /* - * Send command to changer. - */ - return (scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd, - sizeof(cmd), NULL, 0, CHRETRIES, 100000, NULL, 0)); -} - -static int -ch_position(sc, cp) - struct ch_softc *sc; - struct changer_position *cp; -{ - struct scsi_position_to_element cmd; - u_int16_t dst; - - /* - * Check arguments. - */ - if (cp->cp_type > CHET_DT) - return (EINVAL); - if (cp->cp_unit > (sc->sc_counts[cp->cp_type] - 1)) - return (ENODEV); - - /* - * Calculate the destination element. - */ - dst = sc->sc_firsts[cp->cp_type] + cp->cp_unit; - - /* - * Build the SCSI command. - */ - bzero(&cmd, sizeof(cmd)); - cmd.opcode = POSITION_TO_ELEMENT; - scsi_uto2b(sc->sc_picker, cmd.tea); - scsi_uto2b(dst, cmd.dst); - if (cp->cp_flags & CP_INVERT) - cmd.flags |= POSITION_TO_ELEMENT_INVERT; - - /* - * Send command to changer. - */ - return (scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd, - sizeof(cmd), NULL, 0, CHRETRIES, 100000, NULL, 0)); -} - -/* - * Perform a READ ELEMENT STATUS on behalf of the user, and return to - * the user only the data the user is interested in (i.e. an array of - * flags bytes). - */ -static int -ch_usergetelemstatus(sc, chet, uptr) - struct ch_softc *sc; - int chet; - u_int8_t *uptr; -{ - struct read_element_status_header *st_hdr; - struct read_element_status_page_header *pg_hdr; - struct read_element_status_descriptor *desc; - caddr_t data = NULL; -#ifdef BOUNCE_BUFFERS - int datasize = 0; -#endif - size_t size, desclen; - int avail, i, error = 0; - u_int8_t *user_data = NULL; - - /* - * If there are no elements of the requested type in the changer, - * the request is invalid. - */ - if (sc->sc_counts[chet] == 0) - return (EINVAL); - - /* - * Request one descriptor for the given element type. This - * is used to determine the size of the descriptor so that - * we can allocate enough storage for all of them. We assume - * that the first one can fit into 1k. - */ -#ifdef BOUNCE_BUFFERS - data = (caddr_t)vm_bounce_kva_alloc(btoc(1024)); - if (!data) - return (ENOMEM); - datasize = 1024; -#else - data = (caddr_t)malloc(1024, M_DEVBUF, M_WAITOK); -#endif - if (error = ch_getelemstatus(sc, sc->sc_firsts[chet], 1, data, 1024)) - goto done; - - st_hdr = (struct read_element_status_header *)data; - pg_hdr = (struct read_element_status_page_header *)((char *)st_hdr + - sizeof(struct read_element_status_header)); - desclen = scsi_2btou(pg_hdr->edl); - - size = sizeof(struct read_element_status_header) + - sizeof(struct read_element_status_page_header) + - (desclen * sc->sc_counts[chet]); - - /* - * Reallocate storage for descriptors and get them from the - * device. - */ -#ifdef BOUNCE_BUFFERS - vm_bounce_kva_alloc_free((vm_offset_t)data, btoc(datasize)); - data = (caddr_t)vm_bounce_kva_alloc(btoc(size)); - if (!data) { - error = ENOMEM; - goto done; - } - datasize = size; -#else - free(data, M_DEVBUF); - data = (caddr_t)malloc(size, M_DEVBUF, M_WAITOK); -#endif - if (error = ch_getelemstatus(sc, sc->sc_firsts[chet], - sc->sc_counts[chet], data, size)) - goto done; - - /* - * Fill in the user status array. - */ - st_hdr = (struct read_element_status_header *)data; - avail = scsi_2btou(st_hdr->count); - if (avail != sc->sc_counts[chet]) - printf("%s: warning, READ ELEMENT STATUS avail != count\n", - sc->sc_dev.dv_xname); - - user_data = (u_int8_t *)malloc(avail, M_DEVBUF, M_WAITOK); - - desc = (struct read_element_status_descriptor *)((char *)data + - sizeof(struct read_element_status_header) + - sizeof(struct read_element_status_page_header)); - for (i = 0; i < avail; ++i) { - user_data[i] = desc->flags1; - desc = (struct read_element_status_descriptor *) - ((char *)desc + desclen); - } - - /* Copy flags array out to userspace. */ - error = copyout(user_data, uptr, avail); - - done: -#ifdef BOUNCE_BUFFERS - if (data != NULL) - vm_bounce_kva_alloc_free((vm_offset_t)data, btoc(datasize)); -#else - if (data != NULL) - free(data, M_DEVBUF); -#endif - if (user_data != NULL) - free(user_data, M_DEVBUF); - return (error); -} - -static int -ch_getelemstatus(sc, first, count, data, datalen) - struct ch_softc *sc; - int first, count; - caddr_t data; - size_t datalen; -{ - struct scsi_read_element_status cmd; - - /* - * Build SCSI command. - */ - bzero(&cmd, sizeof(cmd)); - cmd.opcode = READ_ELEMENT_STATUS; - scsi_uto2b(first, cmd.sea); - scsi_uto2b(count, cmd.count); - scsi_uto3b(datalen, cmd.len); - - /* - * Send command to changer. - */ - return (scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd, - sizeof(cmd), (u_char *)data, datalen, CHRETRIES, 100000, NULL, SCSI_DATA_IN)); -} - - -/* - * Ask the device about itself and fill in the parameters in our - * softc. - */ -static int -ch_get_params(sc, scsiflags) - struct ch_softc *sc; - int scsiflags; -{ - struct scsi_mode_sense cmd; - struct scsi_mode_sense_data { - struct scsi_mode_header header; - union { - struct page_element_address_assignment ea; - struct page_transport_geometry_parameters tg; - struct page_device_capabilities cap; - } pages; - } sense_data; - int error, from; - u_int8_t *moves, *exchanges; - - /* - * Grab info from the element address assignment page. - */ - bzero(&cmd, sizeof(cmd)); - bzero(&sense_data, sizeof(sense_data)); - cmd.op_code = MODE_SENSE; - cmd.byte2 |= 0x08; /* disable block descriptors */ - cmd.page = 0x1d; - cmd.length = (sizeof(sense_data) & 0xff); - error = scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd, - sizeof(cmd), (u_char *)&sense_data, sizeof(sense_data), CHRETRIES, - 6000, NULL, scsiflags | SCSI_DATA_IN); - if (error) { - printf("%s: could not sense element address page\n", - sc->sc_dev.dv_xname); - return (error); - } - - sc->sc_firsts[CHET_MT] = scsi_2btou(sense_data.pages.ea.mtea); - sc->sc_counts[CHET_MT] = scsi_2btou(sense_data.pages.ea.nmte); - sc->sc_firsts[CHET_ST] = scsi_2btou(sense_data.pages.ea.fsea); - sc->sc_counts[CHET_ST] = scsi_2btou(sense_data.pages.ea.nse); - sc->sc_firsts[CHET_IE] = scsi_2btou(sense_data.pages.ea.fieea); - sc->sc_counts[CHET_IE] = scsi_2btou(sense_data.pages.ea.niee); - sc->sc_firsts[CHET_DT] = scsi_2btou(sense_data.pages.ea.fdtea); - sc->sc_counts[CHET_DT] = scsi_2btou(sense_data.pages.ea.ndte); - - /* XXX ask for page trasport geom */ - - /* - * Grab info from the capabilities page. - */ - bzero(&cmd, sizeof(cmd)); - bzero(&sense_data, sizeof(sense_data)); - cmd.op_code = MODE_SENSE; - cmd.byte2 |= 0x08; /* disable block descriptors */ - cmd.page = 0x1f; - cmd.length = (sizeof(sense_data) & 0xff); - error = scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd, - sizeof(cmd), (u_char *)&sense_data, sizeof(sense_data), CHRETRIES, - 6000, NULL, scsiflags | SCSI_DATA_IN); - if (error) { - printf("%s: could not sense capabilities page\n", - sc->sc_dev.dv_xname); - return (error); - } - - bzero(sc->sc_movemask, sizeof(sc->sc_movemask)); - bzero(sc->sc_exchangemask, sizeof(sc->sc_exchangemask)); - moves = &sense_data.pages.cap.move_from_mt; - exchanges = &sense_data.pages.cap.exchange_with_mt; - for (from = CHET_MT; from <= CHET_DT; ++from) { - sc->sc_movemask[from] = moves[from]; - sc->sc_exchangemask[from] = exchanges[from]; - } - - sc->sc_link->flags |= SDEV_MEDIA_LOADED; - return (0); -} - -static int -chunit(dev) - dev_t dev; -{ - - return (CHUNIT(dev)); -} - -static dev_t -chsetunit(dev, unit) - dev_t dev; - int unit; -{ - - return (CHSETUNIT(dev, unit)); -} - - -static ch_devsw_installed = 0; - -static void -ch_drvinit(void *unused) -{ - dev_t dev; - - if( ! ch_devsw_installed ) { - dev = makedev(CDEV_MAJOR, 0); - cdevsw_add(&dev,&ch_cdevsw, NULL); - ch_devsw_installed = 1; - } -} - -SYSINIT(chdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,ch_drvinit,NULL) diff --git a/sys/scsi/od.c b/sys/scsi/od.c deleted file mode 100644 index 5943b50..0000000 --- a/sys/scsi/od.c +++ /dev/null @@ -1,966 +0,0 @@ -/* - * Copyright (c) 1995,1996 Shunsuke Akiyama. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Shunsuke Akiyama. - * 4. Neither the name of the author nor the names of any co-contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY Shunsuke Akiyama AND CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL Shunsuke Akiyama OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * $Id: od.c,v 1.45 1998/07/30 15:16:05 bde Exp $ - */ - -/* - * Compile option defines: - */ - -/* - * If drive returns sense key as 0x02 with vendor specific additional - * sense code (ASC) and additional sense code qualifier (ASCQ), or - * illegal ASC and ASCQ. This cause an error (NOT READY) and retrying. - * To suppress this, uncomment following. - * Or put "options OD_BOGUS_NOT_READY" entry into your kernel - * configuration file. - * -#define OD_BOGUS_NOT_READY - */ - -/* - * For an automatic spindown, try this. Again, preferrably as an - * option in your config file. - * WARNING! Use at your own risk. Joerg's ancient SONY SMO drive - * groks it fine, while Shunsuke's Fujitsu chokes on it and times - * out. -#define OD_AUTO_TURNOFF - */ - -#include "opt_bounce.h" -#include "opt_devfs.h" -#include "opt_scsi.h" -#include "opt_od.h" - -#define SPLOD splbio -#include <sys/param.h> -#include <sys/kernel.h> -#include <sys/dkbad.h> -#include <sys/systm.h> -#include <sys/conf.h> -#include <sys/buf.h> -#include <sys/cdio.h> -#include <sys/dkstat.h> -#include <sys/disklabel.h> -#include <sys/diskslice.h> -#ifdef DEVFS -#include <sys/devfsext.h> -#endif /*DEVFS*/ -#include <scsi/scsi_disk.h> -#include <scsi/scsiconf.h> -#include <scsi/scsi_debug.h> -#include <scsi/scsi_driver.h> - -#include "ioconf.h" - -static u_int32_t odstrats, odqueues; - -#define SECSIZE 512 /* default sector size */ -#define ODOUTSTANDING 4 -#define OD_RETRIES 4 - -#define PARTITION(dev) dkpart(dev) -#define ODUNIT(dev) dkunit(dev) - -/* XXX introduce a dkmodunit() macro for this. */ -#define ODSETUNIT(DEV, U) \ - makedev(major(DEV), dkmakeminor((U), dkslice(DEV), dkpart(DEV))) - -struct scsi_data { - u_int32_t flags; -#define ODINIT 0x04 /* device has been init'd */ - struct disk_parms { - u_char heads; /* Number of heads */ - u_int16_t cyls; /* Number of cylinders (fictitious) */ - u_int16_t sectors; /* Number of sectors/track */ - u_int16_t secsiz; /* Number of bytes/sector */ - u_int32_t disksize; /* total number sectors */ - u_int16_t rpm; /* medium rotation rate */ - } params; - struct diskslices *dk_slices; /* virtual drives */ - struct buf_queue_head buf_queue; - int dkunit; /* disk stats unit number */ -#ifdef DEVFS - /* Eventually move all these to common disk struct. */ - void *b_devfs_token; - void *c_devfs_token; - void *ctl_devfs_token; -#endif -}; - -static errval od_get_parms __P((int unit, int flags)); -#ifdef notyet -static errval od_reassign_blocks __P((int unit, int block)); -#endif -static u_int32_t od_size __P((int unit, int flags)); -static int od_sense_handler __P((struct scsi_xfer *)); -static void odstart __P((u_int32_t, u_int32_t)); -static void odstrategy1 __P((struct buf *)); - -static dev_t odsetunit(dev_t dev, int unit) { return ODSETUNIT(dev, unit); } -static int odunit(dev_t dev) { return ODUNIT(dev); } - -static errval od_open __P((dev_t dev, int mode, int fmt, struct proc *p, - struct scsi_link *sc_link)); -static errval od_ioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, - struct proc *p, struct scsi_link *sc_link); -static errval od_close __P((dev_t dev, int fflag, int fmt, struct proc *p, - struct scsi_link *sc_link)); -static void od_strategy(struct buf *bp, struct scsi_link *sc_link); - -static d_open_t odopen; -static d_read_t odread; -static d_write_t odwrite; -static d_close_t odclose; -static d_ioctl_t odioctl; -static d_strategy_t odstrategy; - -#define CDEV_MAJOR 70 -#define BDEV_MAJOR 20 -static struct cdevsw od_cdevsw = { - odopen, odclose, odread, odwrite, - odioctl, nostop, nullreset, nodevtotty, - seltrue, nommap, odstrategy, "od", - NULL, -1, nodump, nopsize, - D_DISK, 0, -1 }; - -/* - * Actually include the interface routines - */ -SCSI_DEVICE_ENTRIES(od) - -static struct scsi_device od_switch = -{ - od_sense_handler, - odstart, /* have a queue, served by this */ - NULL, /* have no async handler */ - NULL, /* Use default 'done' routine */ - "od", - 0, - {0, 0}, - 0, /* Link flags */ - odattach, - "Optical", - odopen, - sizeof(struct scsi_data), - T_OPTICAL, - odunit, - odsetunit, - od_open, - od_ioctl, - od_close, - od_strategy, -}; - -static __inline void -od_registerdev(int unit) -{ - if(dk_ndrive < DK_NDRIVE) { - sprintf(dk_names[dk_ndrive], "od%d", unit); - dk_wpms[dk_ndrive] = (4*1024*1024/2); /* 4MB/sec */ - SCSI_DATA(&od_switch, unit)->dkunit = dk_ndrive++; - } else { - SCSI_DATA(&od_switch, unit)->dkunit = -1; - } -} - - -/* - * The routine called by the low level scsi routine when it discovers - * a device suitable for this driver. - */ -static errval -odattach(struct scsi_link *sc_link) -{ - u_int32_t unit; - struct disk_parms *dp; -#ifdef DEVFS - int mynor; -#endif - - struct scsi_data *od = sc_link->sd; - - unit = sc_link->dev_unit; - - dp = &(od->params); - - if (sc_link->opennings > ODOUTSTANDING) - sc_link->opennings = ODOUTSTANDING; - - bufq_init(&od->buf_queue); - /* - * Use the subdriver to request information regarding - * the drive. We cannot use interrupts yet, so the - * request must specify this. - */ - scsi_start_unit(sc_link, SCSI_NOSLEEP | SCSI_NOMASK - | SCSI_ERR_OK | SCSI_SILENT); - od_get_parms(unit, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT); - /* - * if we don't have actual parameters, assume 512 bytes/sec - * (could happen on removable media - MOD) - * -- this avoids the division below from falling over - */ - if(dp->secsiz == 0) dp->secsiz = SECSIZE; - if (dp->disksize != 0) { - printf("%luMB (%lu %u byte sectors)", - (u_long)(dp->disksize / ((1024L * 1024L) / dp->secsiz)), - (u_long)dp->disksize, dp->secsiz); - } else { - printf("od not present"); - } - -#ifndef SCSI_REPORT_GEOMETRY - if ( (sc_link->flags & SDEV_BOOTVERBOSE) ) -#endif - { - sc_print_addr(sc_link); - printf("with approximate %d cyls, %d heads, and %d sectors/track", - dp->cyls, dp->heads, dp->sectors); - } -#ifdef OD_AUTO_TURNOFF - scsi_stop_unit(sc_link, 0, SCSI_ERR_OK | SCSI_SILENT); -#endif /* OD_AUTO_TURNOFF */ - - od->flags |= ODINIT; - od_registerdev(unit); - -#ifdef DEVFS - mynor = dkmakeminor(unit, WHOLE_DISK_SLICE, RAW_PART); - od->b_devfs_token = devfs_add_devswf(&od_cdevsw, mynor, DV_BLK, - UID_ROOT, GID_OPERATOR, 0640, - "od%d", unit); - od->c_devfs_token = devfs_add_devswf(&od_cdevsw, mynor, DV_CHR, - UID_ROOT, GID_OPERATOR, 0640, - "rod%d", unit); - mynor = dkmakeminor(unit, 0, 0); /* XXX */ - od->ctl_devfs_token = devfs_add_devswf(&od_cdevsw, - mynor | SCSI_CONTROL_MASK, - DV_CHR, - UID_ROOT, GID_WHEEL, 0600, - "rod%d.ctl", unit); -#endif - - return 0; -} - -/* - * open the device. Make sure the partition info is a up-to-date as can be. - */ -static errval -od_open(dev, mode, fmt, p, sc_link) - dev_t dev; - int mode; - int fmt; - struct proc *p; - struct scsi_link *sc_link; -{ - errval errcode = 0; - u_int32_t unit; - struct disklabel label; - struct scsi_data *od; - - unit = ODUNIT(dev); - od = sc_link->sd; - - /* - * Make sure the disk has been initialized - * At some point in the future, get the scsi driver - * to look for a new device if we are not initted - */ - if ((!od) || (!(od->flags & ODINIT))) { - return ENXIO; - } - - SC_DEBUG(sc_link, SDEV_DB1, - ("od_open: dev=0x%lx (unit %lu, partition %d)\n", - (u_long)dev, (u_long)unit, PARTITION(dev))); - - /* - * Try to start the drive, and try to clear "Unit Attention" - * condition, when media had been changed before. - * This operation also clears the SDEV_MEDIA_LOADED flag in its - * error handling routine. - */ - scsi_start_unit(sc_link, SCSI_SILENT); - scsi_prevent(sc_link, PR_PREVENT, SCSI_ERR_OK | SCSI_SILENT); - - /* - * Make sure the drive is ready. - */ - scsi_test_unit_ready(sc_link, 0); - - SC_DEBUG(sc_link, SDEV_DB3, ("'start' attempted ")); - - sc_link->flags |= SDEV_OPEN; /* unit attn becomes an err now */ - /* - * If it's been invalidated, then forget the label. - */ - if (!(sc_link->flags & SDEV_MEDIA_LOADED)) { - /* - * If somebody still has it open, then forbid re-entry. - */ - if (dsisopen(od->dk_slices)) { - errcode = ENXIO; - goto bad; - } - - if (od->dk_slices != NULL) - dsgone(&od->dk_slices); - } - - /* - * This time actually take notice of error returns - */ - if (scsi_test_unit_ready(sc_link, SCSI_SILENT) != 0) { - SC_DEBUG(sc_link, SDEV_DB3, ("not ready\n")); - errcode = ENXIO; - goto bad; - } - SC_DEBUG(sc_link, SDEV_DB3, ("device present\n")); - - /* - * Load the physical device parameters - */ - errcode = od_get_parms(unit, 0); /* sets SDEV_MEDIA_LOADED */ - if (errcode) { - goto bad; - } - switch (od->params.secsiz) { - case SECSIZE : - case 1024 : - case 2048 : - break; - default : - printf("od%lu: Can't deal with %u bytes logical blocks\n", - (u_long)unit, od->params.secsiz); - Debugger("od"); - errcode = ENXIO; - goto bad; - } - SC_DEBUG(sc_link, SDEV_DB3, ("params loaded ")); - - /* Build label for whole disk. */ - bzero(&label, sizeof label); - label.d_type = DTYPE_SCSI; - label.d_secsize = od->params.secsiz; - label.d_nsectors = od->params.sectors; - label.d_ntracks = od->params.heads; - label.d_ncylinders = od->params.cyls; - label.d_secpercyl = od->params.heads * od->params.sectors; - label.d_rpm = od->params.rpm; /* maybe wrong */ - if (label.d_secpercyl == 0) - label.d_secpercyl = 64*32; - /* XXX as long as it's not 0 - * - readdisklabel divides by it (?) - */ - label.d_secperunit = od->params.disksize; - - /* Initialize slice tables. */ - errcode = dsopen("od", dev, fmt, 0, &od->dk_slices, &label, odstrategy1, - (ds_setgeom_t *)NULL, &od_cdevsw); - if (errcode != 0) - goto bad; - SC_DEBUG(sc_link, SDEV_DB3, ("Slice tables initialized ")); - - SC_DEBUG(sc_link, SDEV_DB3, ("open %lu %lu\n", - (u_long)odstrats, (u_long)odqueues)); - - return 0; - -bad: - if (!dsisopen(od->dk_slices)) { - scsi_prevent(sc_link, PR_ALLOW, SCSI_ERR_OK | SCSI_SILENT); -#ifdef OD_AUTO_TURNOFF - scsi_stop_unit(sc_link, 0, SCSI_ERR_OK | SCSI_SILENT); -#endif /* OD_AUTO_TURNOFF */ - sc_link->flags &= ~SDEV_OPEN; - } - return errcode; -} - -/* - * close the device.. only called if we are the LAST occurence of an open - * device. Convenient now but usually a pain. - */ -static errval -od_close(dev, fflag, fmt, p, sc_link) - dev_t dev; - int fflag; - int fmt; - struct proc *p; - struct scsi_link *sc_link; -{ - struct scsi_data *od; - - od = sc_link->sd; - dsclose(dev, fmt, od->dk_slices); - if (!dsisopen(od->dk_slices)) { - scsi_prevent(sc_link, PR_ALLOW, SCSI_SILENT | SCSI_ERR_OK); -#ifdef OD_AUTO_TURNOFF - scsi_stop_unit(sc_link, 0, SCSI_ERR_OK | SCSI_SILENT); -#endif /* OD_AUTO_TURNOFF */ - sc_link->flags &= ~SDEV_OPEN; - } - return 0; -} - -static int -odread(dev_t dev, struct uio *uio, int ioflag) -{ - return (physio(odstrategy, NULL, dev, 1, minphys, uio)); -} - -static int -odwrite(dev_t dev, struct uio *uio, int ioflag) -{ - return (physio(odstrategy, NULL, dev, 0, minphys, uio)); -} - -/* - * Actually translate the requested transfer into one the physical driver - * can understand. The transfer is described by a buf and will include - * only one physical transfer. - */ -static void -od_strategy(struct buf *bp, struct scsi_link *sc_link) -{ - u_int32_t opri; - struct scsi_data *od; - u_int32_t unit; - - odstrats++; - unit = ODUNIT((bp->b_dev)); - od = sc_link->sd; - - /* - * If the device has been made invalid, error out - */ - if (!(sc_link->flags & SDEV_MEDIA_LOADED)) { - bp->b_error = EIO; - goto bad; - } - - /* - * Do bounds checking, adjust transfer, and set b_pblkno. - */ - if (dscheck(bp, od->dk_slices) <= 0) - goto done; /* XXX check b_resid */ - - opri = SPLOD(); - - /* - * Use a bounce buffer if necessary - */ -#ifdef BOUNCE_BUFFERS - if (sc_link->flags & SDEV_BOUNCE) - vm_bounce_alloc(bp); -#endif - - /* - * Place it in the queue of disk activities for this disk - */ - bufq_insert_tail(&od->buf_queue, bp); - - /* - * Tell the device to get going on the transfer if it's - * not doing anything, otherwise just wait for completion - */ - odstart(unit, 0); - - splx(opri); - return /*0*/; -bad: - bp->b_flags |= B_ERROR; -done: - - /* - * Correctly set the buf to indicate a completed xfer - */ - bp->b_resid = bp->b_bcount; - biodone(bp); - return /*0*/; -} - -static void -odstrategy1(struct buf *bp) -{ - /* - * XXX - do something to make odstrategy() but not this block while - * we're doing dsinit() and dsioctl(). - */ - odstrategy(bp); -} - -/* - * odstart looks to see if there is a buf waiting for the device - * and that the device is not already busy. If both are true, - * It dequeues the buf and creates a scsi command to perform the - * transfer in the buf. The transfer request will call scsi_done - * on completion, which will in turn call this routine again - * so that the next queued transfer is performed. - * The bufs are queued by the strategy routine (odstrategy) - * - * This routine is also called after other non-queued requests - * have been made of the scsi driver, to ensure that the queue - * continues to be drained. - * - * must be called at the correct (highish) spl level - * odstart() is called at SPLOD from odstrategy and scsi_done - */ -static void -odstart(u_int32_t unit, u_int32_t flags) -{ - register struct scsi_link *sc_link = SCSI_LINK(&od_switch, unit); - register struct scsi_data *od = sc_link->sd; - struct buf *bp = 0; - struct scsi_rw_big cmd; - u_int32_t blkno, nblk; - u_int32_t secsize; - - SC_DEBUG(sc_link, SDEV_DB2, ("odstart ")); - /* - * Check if the device has room for another command - */ - while (sc_link->opennings) { - - /* - * there is excess capacity, but a special waits - * It'll need the adapter as soon as we clear out of the - * way and let it run (user level wait). - */ - if (sc_link->flags & SDEV_WAITING) { - return; - } - /* - * See if there is a buf with work for us to do.. - */ - bp = bufq_first(&od->buf_queue); - if (bp == NULL) { /* yes, an assign */ - return; - } - bufq_remove(&od->buf_queue, bp); - - /* - * If the device has become invalid, abort all the - * reads and writes until all files have been closed and - * re-openned - */ - if (!(sc_link->flags & SDEV_MEDIA_LOADED)) { - goto bad; - } - /* - * We have a buf, now we know we are going to go through - * With this thing.. - */ - secsize = od->params.secsiz; - blkno = bp->b_pblkno; - if (bp->b_bcount & (secsize - 1)) - { - goto bad; - } - nblk = bp->b_bcount / secsize; - - /* - * Fill out the scsi command - */ - cmd.op_code = (bp->b_flags & B_READ) - ? READ_BIG : WRITE_BIG; - scsi_uto4b(blkno, &cmd.addr_3); - scsi_uto2b(nblk, &cmd.length2); - cmd.byte2 = cmd.reserved = cmd.control = 0; - /* - * Call the routine that chats with the adapter. - * Note: we cannot sleep as we may be an interrupt - */ - if (scsi_scsi_cmd(sc_link, - (struct scsi_generic *) &cmd, - sizeof(cmd), - (u_char *) bp->b_data, - bp->b_bcount, - OD_RETRIES, - 100000, - bp, - flags | ((bp->b_flags & B_READ) ? - SCSI_DATA_IN : SCSI_DATA_OUT)) - == SUCCESSFULLY_QUEUED) { - odqueues++; - if(od->dkunit >= 0) { - dk_xfer[od->dkunit]++; - dk_seek[od->dkunit]++; /* don't know */ - dk_wds[od->dkunit] += bp->b_bcount >> 6; - } - } else { -bad: - printf("od%lu: oops not queued\n", (u_long)unit); - bp->b_error = EIO; - bp->b_flags |= B_ERROR; - biodone(bp); - } - } -} - -/* - * Perform special action on behalf of the user - * Knows about the internals of this device - */ -static errval -od_ioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p, - struct scsi_link *sc_link) -{ - /* struct od_cmd_buf *args; */ - errval error; - struct scsi_data *od; - - /* - * Find the device that the user is talking about - */ - od = sc_link->sd; - SC_DEBUG(sc_link, SDEV_DB1, ("odioctl (0x%lx)", cmd)); - - /* - * If the device is not valid.. abandon ship - */ - if (!(sc_link->flags & SDEV_MEDIA_LOADED)) - return EIO; - - switch (cmd) { - case DIOCSBAD: - error = EINVAL; - break; - case CDIOCEJECT: - error = scsi_stop_unit(sc_link, 1, 0); - sc_link->flags &= ~SDEV_MEDIA_LOADED; - break; - case CDIOCALLOW: - error = scsi_prevent(sc_link, PR_ALLOW, 0); - break; - case CDIOCPREVENT: - error = scsi_prevent(sc_link, PR_PREVENT, 0); - break; - default: - error = dsioctl("od", dev, cmd, addr, flag, &od->dk_slices, - odstrategy1, (ds_setgeom_t *)NULL); - if (error == ENOIOCTL) { - if (PARTITION(dev) != RAW_PART) { - error = ENOTTY; - } else { - error = scsi_do_ioctl(dev, cmd, addr, - flag, p, sc_link); - } - } - break; - } - return error; -} - -/* - * Find out from the device what its capacity is - */ -static u_int32_t -od_size(unit, flags) - int unit, flags; -{ - struct scsi_read_cap_data rdcap; - struct scsi_read_capacity rdcap_cmd; - struct scsi_link *sc_link = SCSI_LINK(&od_switch, unit); - struct scsi_data *od = sc_link->sd; - struct scsi_mode_sense mdsense_cmd; - struct scsi_mode_sense_data { - struct scsi_mode_header header; - struct blk_desc blk_desc; - union disk_pages pages; - } scsi_sense; - - /* - * make up a scsi command and ask the scsi driver to do - * it for you. - */ - bzero(&rdcap_cmd, sizeof(rdcap_cmd)); - rdcap_cmd.op_code = READ_CAPACITY; - - /* - * If the command works, interpret the result as a 4 byte - * number of blocks - */ - if (scsi_scsi_cmd(sc_link, - (struct scsi_generic *) &rdcap_cmd, - sizeof(rdcap_cmd), - (u_char *) & rdcap, - sizeof(rdcap), - OD_RETRIES, - 10000, - NULL, - flags | SCSI_DATA_IN) != 0) { - return 0; - } else { - od->params.disksize = scsi_4btou(&rdcap.addr_3) + 1; - od->params.secsiz = scsi_4btou(&rdcap.length_3); - } - - /* - * do a "mode sense page 4" (rigid disk drive geometry) - */ - bzero(&mdsense_cmd, sizeof(mdsense_cmd)); - mdsense_cmd.op_code = MODE_SENSE; - mdsense_cmd.page = 4; - mdsense_cmd.length = 0x20; - /* - * If the command worked, use the results to fill out - * the parameter structure - */ - if (scsi_scsi_cmd(sc_link, - (struct scsi_generic *) &mdsense_cmd, - sizeof(mdsense_cmd), - (u_char *) & scsi_sense, - sizeof(scsi_sense), - OD_RETRIES, - 10000, - NULL, - flags | SCSI_SILENT | SCSI_DATA_IN) != 0) { - - /* default to a fictitious geometry */ - od->params.heads = 64; - } else { - SC_DEBUG(sc_link, SDEV_DB3, - ("%lu cyls, %d heads, %lu rpm\n", - (u_long)scsi_3btou(&scsi_sense.pages.rigid_geometry.ncyl_2), - scsi_sense.pages.rigid_geometry.nheads, - (u_long)scsi_2btou( - &scsi_sense.pages.rigid_geometry.medium_rot_rate_1))); - - od->params.heads = scsi_sense.pages.rigid_geometry.nheads; - if (od->params.heads == 0) - od->params.heads = 64; /* fictitious */ - od->params.rpm = - scsi_2btou(&scsi_sense.pages.rigid_geometry.medium_rot_rate_1); - } - - /* - * do a "mode sense page 3" (format device) - */ - bzero(&mdsense_cmd, sizeof(mdsense_cmd)); - mdsense_cmd.op_code = MODE_SENSE; - mdsense_cmd.page = 3; - mdsense_cmd.length = 0x20; - /* - * If the command worked, use the results to fill out - * the parameter structure - */ - if (scsi_scsi_cmd(sc_link, - (struct scsi_generic *) &mdsense_cmd, - sizeof(mdsense_cmd), - (u_char *) & scsi_sense, - sizeof(scsi_sense), - OD_RETRIES, - 10000, - NULL, - flags | SCSI_SILENT | SCSI_DATA_IN) != 0) { - - /* default to a fictitious geometry */ - od->params.sectors = 32; - } else { - SC_DEBUG(sc_link, SDEV_DB3, - ("%d secs\n", - scsi_2btou(&scsi_sense.pages.disk_format.ph_sec_t_1))); - - od->params.sectors = - scsi_2btou(&scsi_sense.pages.disk_format.ph_sec_t_1); - if (od->params.sectors == 0) - od->params.sectors = 32; /* fictitious */ - } - - return od->params.disksize; -} - -#ifdef notyet -/* - * Tell the device to map out a defective block - */ -static errval -od_reassign_blocks(unit, block) - int unit, block; -{ - struct scsi_reassign_blocks scsi_cmd; - struct scsi_reassign_blocks_data rbdata; - struct scsi_link *sc_link = SCSI_LINK(&od_switch, unit); - - bzero(&scsi_cmd, sizeof(scsi_cmd)); - bzero(&rbdata, sizeof(rbdata)); - scsi_cmd.op_code = REASSIGN_BLOCKS; - - rbdata.length_msb = 0; - rbdata.length_lsb = sizeof(rbdata.defect_descriptor[0]); - scsi_uto4b(block, &rbdata.defect_descriptor[0].dlbaddr_3); - - return scsi_scsi_cmd(sc_link, - (struct scsi_generic *) &scsi_cmd, - sizeof(scsi_cmd), - (u_char *) & rbdata, - sizeof(rbdata), - OD_RETRIES, - 20000, - NULL, - SCSI_DATA_OUT); -} -#endif - -/* - * Get the scsi driver to send a full inquiry to the - * device and use the results to fill out the disk - * parameter structure. - */ -static errval -od_get_parms(unit, flags) - int unit, flags; -{ - struct scsi_link *sc_link = SCSI_LINK(&od_switch, unit); - struct scsi_data *od = sc_link->sd; - struct disk_parms *disk_parms = &od->params; - u_int32_t sectors; - errval retval; - - /* - * First check if we have it all loaded - */ - if (sc_link->flags & SDEV_MEDIA_LOADED) - return 0; - - /* - * Use fictitious geometry, this depends on the size of medium. - */ - sectors = od_size(unit, flags); - /* od_size() sets secsiz, disksize, sectors, and heads */ - - /* fictitious number of cylinders, so that C*H*S <= total */ - if (disk_parms->sectors != 0 && disk_parms->heads != 0) { - disk_parms->cyls = - sectors / (disk_parms->sectors * disk_parms->heads); - } else { - disk_parms->cyls = 0; - } - - if (sectors != 0) { - sc_link->flags |= SDEV_MEDIA_LOADED; - retval = 0; - } else { - retval = ENXIO; - } - return retval; -} - -/* - * sense handler: Called to determine what to do when the - * device returns a CHECK CONDITION. - */ - -static int -od_sense_handler(struct scsi_xfer *xs) -{ - struct scsi_sense_data *sense; - struct scsi_sense_extended *ext; - int asc, ascq; - - sense = &(xs->sense); - ext = (struct scsi_sense_extended *)&(sense->ext.extended); - - /* I don't know what the heck to do with a deferred error, - * so I'll just kick it back to the caller. - */ - if ((sense->error_code & SSD_ERRCODE) == 0x71) - return SCSIRET_CONTINUE; - -#ifdef OD_BOGUS_NOT_READY - if (((sense->error_code & SSD_ERRCODE) == 0x70) && - ((sense->ext.extended.flags & SSD_KEY) == 0x02)) - /* No point in retrying Not Ready */ - return SCSIRET_CONTINUE; -#endif - - if (((sense->error_code & SSD_ERRCODE) == 0x70) && - ((sense->ext.extended.flags & SSD_KEY) == 0x04)) - /* No point in retrying Hardware Failure */ - return SCSIRET_CONTINUE; - - if (((sense->error_code & SSD_ERRCODE) == 0x70) && - ((sense->ext.extended.flags & SSD_KEY) == 0x05)) - /* No point in retrying Illegal Requests */ - return SCSIRET_CONTINUE; - - asc = (ext->extra_len >= 5) ? ext->add_sense_code : 0; - ascq = (ext->extra_len >= 6) ? ext->add_sense_code_qual : 0; - - if (asc == 0x11 || asc == 0x30 || asc == 0x31 || asc == 0x53 - || asc == 0x5a) { - /* Unrecovered errors */ - return SCSIRET_CONTINUE; - } - if (asc == 0x21 && ascq == 0) { - /* Logical block address out of range */ - return SCSIRET_CONTINUE; - } - if (asc == 0x27 && ascq == 0) { - /* Write protected */ - return SCSIRET_CONTINUE; - } - if (asc == 0x28 && ascq == 0) { - /* Not ready to ready transition */ - /* (medium may have changed) */ - return SCSIRET_CONTINUE; - } - if (asc == 0x3a && ascq == 0) { - /* Medium not present */ - return SCSIRET_CONTINUE; - } - - /* Retry all disk errors. - */ - scsi_sense_print(xs); - if (xs->retries) - printf(", retries:%d\n", xs->retries); - else - printf(", FAILURE\n"); - - return SCSIRET_DO_RETRY; -} - -static od_devsw_installed = 0; - -static void od_drvinit(void *unused) -{ - - if( ! od_devsw_installed ) { - cdevsw_add_generic(BDEV_MAJOR, CDEV_MAJOR, &od_cdevsw); - od_devsw_installed = 1; - } -} - -SYSINIT(oddev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,od_drvinit,NULL) diff --git a/sys/scsi/pt.c b/sys/scsi/pt.c deleted file mode 100644 index c2a2a18..0000000 --- a/sys/scsi/pt.c +++ /dev/null @@ -1,326 +0,0 @@ -/* - * pt: Processor Type driver. - * - * Copyright (C) 1995, HD Associates, Inc. - * PO Box 276 - * Pepperell, MA 01463 - * 508 433 5266 - * dufault@hda.com - * - * This code is contributed to the University of California at Berkeley: - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id: pt.c,v 1.29 1998/07/04 22:30:24 julian Exp $ - */ - -#include "opt_bounce.h" -#include "opt_devfs.h" -#include "opt_scsi.h" - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/buf.h> -#include <sys/conf.h> -#include <sys/kernel.h> -#ifdef DEVFS -#include <sys/devfsext.h> -#endif /*DEVFS*/ -#include <scsi/scsiconf.h> -#include <scsi/scsi_debug.h> -#include <scsi/scsi_driver.h> - -#include "ioconf.h" - -struct scsi_data { - struct buf_queue_head buf_queue; -#ifdef DEVFS - void *devfs_data_tok; - void *devfs_ctl_tok; -#endif -}; - -static d_open_t ptopen; -static d_read_t ptread; -static d_write_t ptwrite; -static d_close_t ptclose; -static d_ioctl_t ptioctl; -static d_strategy_t ptstrategy; - -#define CDEV_MAJOR 61 -static struct cdevsw pt_cdevsw = - { ptopen, ptclose, ptread, ptwrite, /*61*/ - ptioctl, nostop, nullreset, nodevtotty,/* pt */ - seltrue, nommap, ptstrategy, "pt", NULL, -1 }; - -SCSI_DEVICE_ENTRIES(pt) - -static void ptstart(u_int32_t unit, u_int32_t flags); -static void pt_strategy(struct buf *bp, struct scsi_link *sc_link); -static int pt_sense(struct scsi_xfer *scsi_xfer); - -static struct scsi_device pt_switch = -{ - pt_sense, - ptstart, /* we have a queue, and this is how we service it */ - NULL, - NULL, - "pt", - 0, - {0, 0}, - SDEV_ONCE_ONLY, /* Only one open allowed */ - ptattach, - "Processor", - ptopen, - sizeof(struct scsi_data), - T_PROCESSOR, - 0, - 0, - 0, - 0, - 0, - pt_strategy, -}; - -static errval -ptattach(struct scsi_link *sc_link) -{ - struct scsi_data *pt = sc_link->sd; - - bufq_init(&pt->buf_queue); - -#ifdef DEVFS - pt->devfs_data_tok = devfs_add_devswf(&pt_cdevsw, - sc_link->dev_unit, - DV_CHR, - UID_ROOT, GID_WHEEL, 0600, - "pt%d", sc_link->dev_unit); - pt->devfs_ctl_tok = devfs_add_devswf(&pt_cdevsw, - sc_link->dev_unit | SCSI_CONTROL_MASK, - DV_CHR, - UID_ROOT, GID_WHEEL, 0600, - "pt%d.ctl", sc_link->dev_unit); -#endif - return 0; -} - -/* - * ptstart looks to see if there is a buf waiting for the device - * and that the device is not already busy. If both are true, - * It dequeues the buf and creates a scsi command to perform the - * transfer required. The transfer request will call scsi_done - * on completion, which will in turn call this routine again - * so that the next queued transfer is performed. - * The bufs are queued by the strategy routine (ptstrategy) - * - * This routine is also called after other non-queued requests - * have been made of the scsi driver, to ensure that the queue - * continues to be drained. - * ptstart() is called at splbio - */ -static void -ptstart(unit, flags) - u_int32_t unit; - u_int32_t flags; -{ - struct scsi_link *sc_link = SCSI_LINK(&pt_switch, unit); - struct scsi_data *pt = sc_link->sd; - register struct buf *bp = 0; - struct - { -#define PROCESSOR_SEND 0x0A -#define PROCESSOR_RECEIVE 0x08 - u_char op_code; - u_char byte2; - u_char len[3]; - u_char control; - } cmd; - - - SC_DEBUG(sc_link, SDEV_DB2, ("ptstart ")); - /* - * See if there is a buf to do and we are not already - * doing one - */ - while (sc_link->opennings != 0) { - - /* if a special awaits, let it proceed first */ - if (sc_link->flags & SDEV_WAITING) { - sc_link->flags &= ~SDEV_WAITING; - wakeup((caddr_t)sc_link); - return; - } - - bp = bufq_first(&pt->buf_queue); - if (bp == NULL) { /* yes, an assign */ - return; - } - bufq_remove(&pt->buf_queue, bp); - - /* - * Fill out the scsi command - */ - bzero(&cmd, sizeof(cmd)); - if ((bp->b_flags & B_READ) == B_WRITE) { - cmd.op_code = PROCESSOR_SEND; - flags |= SCSI_DATA_OUT; - } else { - cmd.op_code = PROCESSOR_RECEIVE; - flags |= SCSI_DATA_IN; - } - - scsi_uto3b(bp->b_bcount, cmd.len); - /* - * go ask the adapter to do all this for us - */ - if (scsi_scsi_cmd(sc_link, - (struct scsi_generic *) &cmd, - sizeof(cmd), - (u_char *) bp->b_data, - bp->b_bcount, - 0, - 10000, - bp, - flags) == SUCCESSFULLY_QUEUED) { - } else { - printf("pt%lu: oops not queued\n", (u_long)unit); - bp->b_flags |= B_ERROR; - bp->b_error = EIO; - biodone(bp); - } - } /* go back and see if we can cram more work in.. */ -} - -static int -ptread( dev_t dev, struct uio *uio, int ioflag) -{ - return (physio(ptstrategy, NULL, dev, 1, minphys, uio)); -} - -static int -ptwrite ( dev_t dev, struct uio *uio, int ioflag) -{ - return (physio(ptstrategy, NULL, dev, 0, minphys, uio)); -} - -static void -pt_strategy(struct buf *bp, struct scsi_link *sc_link) -{ - unsigned char unit; - u_int32_t opri; - struct scsi_data *pt; - - unit = minor((bp->b_dev)); - pt = sc_link->sd; - - opri = splbio(); - - /* - * Use a bounce buffer if necessary - */ -#ifdef BOUNCE_BUFFERS - if (sc_link->flags & SDEV_BOUNCE) - vm_bounce_alloc(bp); -#endif - - /* - * Place it in the queue of activities for this tape - * at the end (a bit silly because we only have one user.. - * (but it could fork() )) - */ - bufq_insert_tail(&pt->buf_queue, bp); - - /* - * Tell the device to get going on the transfer if it's - * not doing anything, otherwise just wait for completion - * (All a bit silly if we're only allowing 1 open but..) - */ - ptstart(unit, 0); - - splx(opri); - return; -} - -/* - * sense handler: Called to determine what to do when the - * device returns a CHECK CONDITION. - * - * For the processor type devices we try to handle the "info" field. - */ - -static int -pt_sense(struct scsi_xfer *xs) -{ - struct scsi_sense_data *sense = &(xs->sense); - struct buf *bp; - - long resid; - - if ((sense->error_code & SSD_ERRCODE_VALID) == 0 || - (sense->ext.extended.flags & SSD_ILI) == 0) { - return SCSIRET_CONTINUE; /* let the default handler handle it */ - } - - resid = ntohl(*((int32_t *) sense->ext.extended.info)); - - bp = xs->bp; - - if (resid < 0) { - /* It synthesized data in order to fill our request. - * Move resid back to cover this. - */ - xs->resid = -resid; - xs->flags |= SCSI_RESID_VALID; - return 0; - } - else { - /* It wanted to send more data. We can't really do anything - * about this. - */ - return SCSIRET_CONTINUE; - } -} - -static pt_devsw_installed = 0; - -static void -pt_drvinit(void *unused) -{ - dev_t dev; - - if ( ! pt_devsw_installed ) { - dev = makedev(CDEV_MAJOR, 0); - cdevsw_add(&dev,&pt_cdevsw, NULL); - pt_devsw_installed = 1; - } -} - -SYSINIT(ptdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,pt_drvinit,NULL) - - diff --git a/sys/scsi/scsi_all.h b/sys/scsi/scsi_all.h deleted file mode 100644 index f12ac72..0000000 --- a/sys/scsi/scsi_all.h +++ /dev/null @@ -1,351 +0,0 @@ -/* - * Largely written by Julian Elischer (julian@tfs.com) - * for TRW Financial Systems. - * - * 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. - * - * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 - * - * $Id: scsi_all.h,v 1.15 1997/02/22 09:44:27 peter Exp $ - */ - -/* - * SCSI general interface description - */ - -#ifndef _SCSI_SCSI_ALL_H -#define _SCSI_SCSI_ALL_H 1 -/* - * SCSI command format - */ - -/* - * Define dome bits that are in ALL (or a lot of) scsi commands - */ -#define SCSI_CTL_LINK 0x01 -#define SCSI_CTL_FLAG 0x02 -#define SCSI_CTL_VENDOR 0xC0 -#define SCSI_CMD_LUN 0xA0 /* these two should not be needed */ -#define SCSI_CMD_LUN_SHIFT 5 /* LUN in the cmd is no longer SCSI */ - - -struct scsi_generic -{ - u_char opcode; - u_char bytes[11]; -}; - -struct scsi_test_unit_ready -{ - u_char op_code; - u_char byte2; - u_char unused[3]; - u_char control; -}; - -struct scsi_send_diag -{ - u_char op_code; - u_char byte2; -#define SSD_UOL 0x01 -#define SSD_DOL 0x02 -#define SSD_SELFTEST 0x04 -#define SSD_PF 0x10 - u_char unused[1]; - u_char paramlen[2]; - u_char control; -}; - -struct scsi_sense -{ - u_char op_code; - u_char byte2; - u_char unused[2]; - u_char length; - u_char control; -}; - -struct scsi_inquiry -{ - u_char op_code; - u_char byte2; - u_char unused[2]; - u_char length; - u_char control; -}; - -struct scsi_mode_sense -{ - u_char op_code; - u_char byte2; -#define SMS_DBD 0x08 - u_char page; -#define SMS_PAGE_CODE 0x3F -#define SMS_PAGE_CTRL 0xC0 -#define SMS_PAGE_CTRL_CURRENT 0x00 -#define SMS_PAGE_CTRL_CHANGEABLE 0x40 -#define SMS_PAGE_CTRL_DEFAULT 0x80 -#define SMS_PAGE_CTRL_SAVED 0xC0 - u_char unused; - u_char length; - u_char control; -}; - -struct scsi_mode_sense_big -{ - u_char op_code; - u_char byte2; /* same bits as small version */ - u_char page; /* same bits as small version */ - u_char unused[4]; - u_char length[2]; - u_char control; -}; - -struct scsi_mode_select -{ - u_char op_code; - u_char byte2; -#define SMS_SP 0x01 -#define SMS_PF 0x10 - u_char unused[2]; - u_char length; - u_char control; -}; - -struct scsi_mode_select_big -{ - u_char op_code; - u_char byte2; /* same bits as small version */ - u_char unused[5]; - u_char length[2]; - u_char control; -}; - -struct scsi_reserve -{ - u_char op_code; - u_char byte2; - u_char unused[2]; - u_char length; - u_char control; -}; - -struct scsi_release -{ - u_char op_code; - u_char byte2; - u_char unused[2]; - u_char length; - u_char control; -}; - -struct scsi_prevent -{ - u_char op_code; - u_char byte2; - u_char unused[2]; - u_char how; - u_char control; -}; -#define PR_PREVENT 0x01 -#define PR_ALLOW 0x00 - -struct scsi_changedef -{ - u_char op_code; - u_char byte2; - u_char unused1; - u_char how; - u_char unused[4]; - u_char datalen; - u_char control; -}; -#define SC_SCSI_1 0x01 -#define SC_SCSI_2 0x03 - -/* - * Opcodes - */ - -#define TEST_UNIT_READY 0x00 -#define REQUEST_SENSE 0x03 -#define INQUIRY 0x12 -#define MODE_SELECT 0x15 -#define MODE_SENSE 0x1a -#define START_STOP 0x1b -#define RESERVE 0x16 -#define RELEASE 0x17 -#define PREVENT_ALLOW 0x1e -#define POSITION_TO_ELEMENT 0x2b -#define CHANGE_DEFINITION 0x40 -#define MODE_SENSE_BIG 0x54 -#define MODE_SELECT_BIG 0x55 -#define MOVE_MEDIUM 0xa5 -#define READ_ELEMENT_STATUS 0xb8 - - -/* - * sense data format - */ -#define T_DIRECT 0 -#define T_SEQUENTIAL 1 -#define T_PRINTER 2 -#define T_PROCESSOR 3 -#define T_WORM 4 -#define T_READONLY 5 -#define T_SCANNER 6 -#define T_OPTICAL 7 -#define T_CHANGER 8 -#define T_COMM 9 -#define T_ASC0 10 -#define T_ASC1 11 -#define T_TARGET 12 -#define T_UNKNOWN 13 -#define T_NTYPES 14 - -#define T_NODEVICE 0x1F - -#define T_REMOV 1 -#define T_FIXED 0 - -struct scsi_inquiry_data -{ - u_char device; -#define SID_TYPE 0x1F -#define SID_QUAL 0xE0 -#define SID_QUAL_LU_OK 0x00 -#define SID_QUAL_LU_OFFLINE 0x20 -#define SID_QUAL_RSVD 0x40 -#define SID_QUAL_BAD_LU 0x60 - u_char dev_qual2; -#define SID_QUAL2 0x7F -#define SID_REMOVABLE 0x80 - u_char version; -#define SID_ANSII 0x07 -#define SID_ECMA 0x38 -#define SID_ISO 0xC0 - u_char response_format; - u_char additional_length; - u_char unused[2]; - u_char flags; -#define SID_SftRe 0x01 -#define SID_CmdQue 0x02 -#define SID_Linked 0x08 -#define SID_Sync 0x10 -#define SID_WBus16 0x20 -#define SID_WBus32 0x40 -#define SID_RelAdr 0x80 - char vendor[8]; - char product[16]; - char revision[4]; - u_char extra[8]; -}; - - -struct scsi_sense_data -{ -/* 1*/ u_char error_code; /* same bits as new version */ - union - { - struct - { -/* 2*/ u_char blockhi; -/* 3*/ u_char blockmed; -/* 4*/ u_char blocklow; - } unextended; - struct - { -/* 2*/ u_char segment; -/* 3*/ u_char flags; /* same bits as new version */ -/* 7*/ u_char info[4]; -/* 8*/ u_char extra_len; - /* allocate enough room to hold new stuff - ( by increasing 16 to 24 below) */ -/*32*/ u_char extra_bytes[24]; - } extended; - }ext; -}; /* total of 32 bytes */ - -struct scsi_sense_extended -{ -/* 2*/ u_char segment; -/* 3*/ u_char flags; -#define SSD_KEY 0x0F -#define SSD_ILI 0x20 -#define SSD_EOM 0x40 -#define SSD_FILEMARK 0x80 -/* 7*/ u_char info[4]; -/* 8*/ u_char extra_len; -/*12*/ u_char cmd_spec_info[4]; -/*13*/ u_char add_sense_code; -/*14*/ u_char add_sense_code_qual; -/*15*/ u_char fru; -/*16*/ u_char sense_key_spec_1; -#define SSD_SCS_VALID 0x80 -/*17*/ u_char sense_key_spec_2; -/*18*/ u_char sense_key_spec_3; -/*32*/ u_char extra_bytes[14]; -}; - -struct scsi_sense_data_new -{ -/* 1*/ u_char error_code; -#define SSD_ERRCODE 0x7F -#define SSD_ERRCODE_VALID 0x80 - union - { - struct /* this is deprecated, the standard says "DON'T"*/ - { -/* 2*/ u_char blockhi; -/* 3*/ u_char blockmed; -/* 4*/ u_char blocklow; - } unextended; - - struct scsi_sense_extended extended; - } ext; -}; /* total of 32 bytes */ - -struct blk_desc -{ - u_char density; - u_char nblocks[3]; - u_char reserved; - u_char blklen[3]; -}; - -struct scsi_mode_header -{ - u_char data_length; /* Sense data length */ - u_char medium_type; - u_char dev_spec; - u_char blk_desc_len; -}; - -struct scsi_mode_header_big -{ - u_char data_length[2]; /* Sense data length */ - u_char medium_type; - u_char dev_spec; - u_char unused[2]; - u_char blk_desc_len[2]; -}; - - -/* - * Status Byte - */ -#define SCSI_OK 0x00 -#define SCSI_CHECK 0x02 -#define SCSI_BUSY 0x08 -#define SCSI_INTERM 0x10 -#define SCSI_RSVD 0x18 -#define SCSI_QUEUE_FULL 0x28 -#endif /*_SCSI_SCSI_ALL_H*/ diff --git a/sys/scsi/scsi_base.c b/sys/scsi/scsi_base.c deleted file mode 100644 index 67d01b8..0000000 --- a/sys/scsi/scsi_base.c +++ /dev/null @@ -1,1370 +0,0 @@ -/* - * Written By Julian ELischer - * Copyright julian Elischer 1993. - * Permission is granted to use or redistribute this file in any way as long - * as this notice remains. Julian Elischer does not guarantee that this file - * is totally correct for any given task and users of this file must - * accept responsibility for any damage that occurs from the application of this - * file. - * - * Written by Julian Elischer (julian@dialix.oz.au) - * $Id: scsi_base.c,v 1.57 1998/07/11 07:45:57 bde Exp $ - */ - -#include "opt_bounce.h" -#include "opt_scsi.h" - -#define SPLSD splbio -#define ESUCCESS 0 -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/buf.h> -#include <sys/malloc.h> -#include <sys/proc.h> - -#include <machine/clock.h> - -#include <vm/vm.h> -#include <vm/vm_param.h> -#include <vm/pmap.h> - -#include <scsi/scsi_disk.h> -#include <scsi/scsiconf.h> -#include <scsi/scsi_debug.h> - -static errval sc_err1(struct scsi_xfer *); -static errval scsi_interpret_sense(struct scsi_xfer *); -static struct scsi_xfer *get_xs( struct scsi_link *sc_link, u_int32_t flags); -static void free_xs(struct scsi_xfer *xs, struct scsi_link *sc_link, - u_int32_t flags); -#ifdef SCSIDEBUG -static void show_mem(unsigned char *address, u_int32_t num); -static void show_scsi_xs (struct scsi_xfer *); -#endif - -#ifdef notyet -static int scsi_sense_qualifiers (struct scsi_xfer *, int *, int *); -#endif - -static struct scsi_xfer *next_free_xs; - -/* - * Get a scsi transfer structure for the caller. Charge the structure - * to the device that is referenced by the sc_link structure. If the - * sc_link structure has no 'credits' then the device already has the - * maximum number or outstanding operations under way. In this stage, - * wait on the structure so that when one is freed, we are awoken again - * If the SCSI_NOSLEEP flag is set, then do not wait, but rather, return - * a NULL pointer, signifying that no slots were available - * Note in the link structure, that we are waiting on it. - */ - -static struct scsi_xfer * -get_xs(sc_link, flags) - struct scsi_link *sc_link; /* who to charge the xs to */ - u_int32_t flags; /* if this call can sleep */ -{ - struct scsi_xfer *xs; - u_int32_t s; - - SC_DEBUG(sc_link, SDEV_DB3, ("get_xs\n")); - s = splbio(); - while (!sc_link->opennings) { - SC_DEBUG(sc_link, SDEV_DB3, ("sleeping\n")); - if (flags & SCSI_NOSLEEP) { - splx(s); - return 0; - } - sc_link->flags |= SDEV_WAITING; - tsleep((caddr_t)sc_link, PRIBIO, "scsiget", 0); - } - sc_link->active++; - sc_link->opennings--; - if ( (xs = next_free_xs) ) { - next_free_xs = xs->next; - splx(s); - } else { - splx(s); - SC_DEBUG(sc_link, SDEV_DB3, ("making\n")); - xs = malloc(sizeof(*xs), M_TEMP, - ((flags & SCSI_NOSLEEP) ? M_NOWAIT : M_WAITOK)); - if (xs == NULL) { - sc_print_addr(sc_link); - printf("cannot allocate scsi xs\n"); - return (NULL); - } - callout_handle_init(&xs->timeout_ch); - } - SC_DEBUG(sc_link, SDEV_DB3, ("returning\n")); - xs->sc_link = sc_link; - return (xs); -} - -/* - * Given a scsi_xfer struct, and a device (referenced through sc_link) - * return the struct to the free pool and credit the device with it - * If another process is waiting for an xs, do a wakeup, let it proceed - */ -static void -free_xs(xs, sc_link, flags) - struct scsi_xfer *xs; - struct scsi_link *sc_link; /* who to credit for returning it */ - u_int32_t flags; -{ - xs->next = next_free_xs; - next_free_xs = xs; - - SC_DEBUG(sc_link, SDEV_DB3, ("free_xs\n")); - /* if was 0 and someone waits, wake them up */ - sc_link->active--; - if ((!sc_link->opennings++) && (sc_link->flags & SDEV_WAITING)) { - sc_link->flags &= ~SDEV_WAITING; - wakeup((caddr_t)sc_link); /* remember, it wakes them ALL up */ - } else { - if (sc_link->device->start) { - SC_DEBUG(sc_link, SDEV_DB2, ("calling private start()\n")); - (*(sc_link->device->start)) (sc_link->dev_unit, flags); - } - } -} - -/* XXX dufault: Replace "sd_size" with "scsi_read_capacity" - * when bde is done with sd.c - */ -/* - * Find out from the device what its capacity is. - */ -u_int32_t -scsi_read_capacity(sc_link, blk_size, flags) - struct scsi_link *sc_link; - u_int32_t *blk_size; - u_int32_t flags; -{ - struct scsi_read_cap_data rdcap; - struct scsi_read_capacity scsi_cmd; - u_int32_t size; - - /* - * make up a scsi command and ask the scsi driver to do - * it for you. - */ - bzero(&scsi_cmd, sizeof(scsi_cmd)); - scsi_cmd.op_code = READ_CAPACITY; - - /* - * If the command works, interpret the result as a 4 byte - * number of blocks - */ - if (scsi_scsi_cmd(sc_link, - (struct scsi_generic *) &scsi_cmd, - sizeof(scsi_cmd), - (u_char *) & rdcap, - sizeof(rdcap), - 4, - 5000000, /* WORMs tend to take a HUGE amount of time */ - NULL, - flags | SCSI_DATA_IN) != 0) { - - sc_print_addr(sc_link); - printf("could not get size\n"); - return (0); - } else { - size = scsi_4btou(&rdcap.addr_3) + 1; - if (blk_size) - *blk_size = scsi_4btou(&rdcap.length_3); - } - return (size); -} - -errval -scsi_reset_target(sc_link) - struct scsi_link *sc_link; -{ - return (scsi_scsi_cmd(sc_link, - 0, - 0, - 0, - 0, - 1, - 2000, - NULL, - SCSI_RESET)); -} - -errval -scsi_target_mode(sc_link, on_off) - struct scsi_link *sc_link; - int on_off; -{ - struct scsi_generic scsi_cmd; - bzero(&scsi_cmd, sizeof(scsi_cmd)); - scsi_cmd.opcode = SCSI_OP_TARGET; - scsi_cmd.bytes[0] = (on_off) ? 1 : 0; - - return (scsi_scsi_cmd(sc_link, - &scsi_cmd, - sizeof(scsi_cmd), - 0, - 0, - 1, - 2000, - NULL, - SCSI_ESCAPE)); -} - -/* - * Get scsi driver to send a "are you ready?" command - */ -errval -scsi_test_unit_ready(sc_link, flags) - struct scsi_link *sc_link; - u_int32_t flags; -{ - struct scsi_test_unit_ready scsi_cmd; - - bzero(&scsi_cmd, sizeof(scsi_cmd)); - scsi_cmd.op_code = TEST_UNIT_READY; - - return (scsi_scsi_cmd(sc_link, - (struct scsi_generic *) &scsi_cmd, - sizeof(scsi_cmd), - 0, - 0, - 2, - 100000, - NULL, - flags)); -} - -#ifdef SCSI_2_DEF -/* - * Do a scsi operation, asking a device to run as SCSI-II if it can. - */ -errval -scsi_change_def(sc_link, flags) - struct scsi_link *sc_link; - u_int32_t flags; -{ - struct scsi_changedef scsi_cmd; - - bzero(&scsi_cmd, sizeof(scsi_cmd)); - scsi_cmd.op_code = CHANGE_DEFINITION; - scsi_cmd.how = SC_SCSI_2; - - return (scsi_scsi_cmd(sc_link, - (struct scsi_generic *) &scsi_cmd, - sizeof(scsi_cmd), - 0, - 0, - 2, - 100000, - NULL, - flags)); -} -#endif /* SCSI_2_DEF */ - -/* - * Do a scsi operation asking a device what it is - * Use the scsi_cmd routine in the switch table. - */ -errval -scsi_inquire(sc_link, inqbuf, flags) - struct scsi_link *sc_link; - struct scsi_inquiry_data *inqbuf; - u_int32_t flags; -{ - struct scsi_inquiry scsi_cmd; - - bzero(&scsi_cmd, sizeof(scsi_cmd)); - scsi_cmd.op_code = INQUIRY; - scsi_cmd.length = sizeof(struct scsi_inquiry_data); - - return (scsi_scsi_cmd(sc_link, - (struct scsi_generic *) &scsi_cmd, - sizeof(scsi_cmd), - (u_char *) inqbuf, - sizeof(struct scsi_inquiry_data), - 2, - 100000, - NULL, - SCSI_DATA_IN | flags)); -} - -/* - * Prevent or allow the user to remove the media - */ -errval -scsi_prevent(sc_link, type, flags) - struct scsi_link *sc_link; - u_int32_t type, flags; -{ - struct scsi_prevent scsi_cmd; - - bzero(&scsi_cmd, sizeof(scsi_cmd)); - scsi_cmd.op_code = PREVENT_ALLOW; - scsi_cmd.how = type; - return (scsi_scsi_cmd(sc_link, - (struct scsi_generic *) &scsi_cmd, - sizeof(scsi_cmd), - 0, - 0, - 2, - 5000, - NULL, - flags)); -} - -/* - * Get scsi driver to send a "start up" command - */ -errval -scsi_start_unit(sc_link, flags) - struct scsi_link *sc_link; - u_int32_t flags; -{ - struct scsi_start_stop scsi_cmd; - - bzero(&scsi_cmd, sizeof(scsi_cmd)); - scsi_cmd.op_code = START_STOP; - scsi_cmd.how = SSS_START; - - return (scsi_scsi_cmd(sc_link, - (struct scsi_generic *) &scsi_cmd, - sizeof(scsi_cmd), - 0, - 0, - 2, - 30000, - NULL, - flags)); -} - -/* - * Get scsi driver to send a "stop" command - */ -errval -scsi_stop_unit(sc_link, eject, flags) - struct scsi_link *sc_link; - u_int32_t eject; - u_int32_t flags; -{ - struct scsi_start_stop scsi_cmd; - - bzero(&scsi_cmd, sizeof(scsi_cmd)); - scsi_cmd.op_code = START_STOP; - if (eject) { - scsi_cmd.how = SSS_LOEJ; - } - - return (scsi_scsi_cmd(sc_link, - (struct scsi_generic *) &scsi_cmd, - sizeof(scsi_cmd), - 0, - 0, - 2, - 10000, - NULL, - flags)); -} - -/* - * This routine is called by the scsi interrupt when the transfer is complete. - */ -void -scsi_done(xs) - struct scsi_xfer *xs; -{ - struct scsi_link *sc_link = xs->sc_link; - struct buf *bp = xs->bp; - errval retval; - - SC_DEBUG(sc_link, SDEV_DB2, ("scsi_done\n")); -#ifdef SCSIDEBUG - if (sc_link->flags & SDEV_DB1) - { - show_scsi_cmd(xs); - } -#endif /*SCSIDEBUG */ - /* - * If it's a user level request, bypass all usual completion processing, - * let the user work it out.. We take reponsibility for freeing the - * xs when the user returns. (and restarting the device's queue). - */ - if (xs->flags & SCSI_USER) { - SC_DEBUG(sc_link, SDEV_DB3, ("calling user done()\n")); - scsi_user_done(xs); /* to take a copy of the sense etc. */ - SC_DEBUG(sc_link, SDEV_DB3, ("returned from user done()\n ")); - - free_xs(xs, sc_link, SCSI_NOSLEEP); /* restarts queue too */ - SC_DEBUG(sc_link, SDEV_DB3, ("returning to adapter\n")); - return; - } - /* - * If the device has its own done routine, call it first. - * If it returns a legit error value, return that, otherwise - * it wants us to continue with normal processing. - */ - - if (sc_link->device->done) { - SC_DEBUG(sc_link, SDEV_DB2, ("calling private done()\n")); - retval = (*sc_link->device->done) (xs); - if (retval == -1) { - free_xs(xs, sc_link, SCSI_NOSLEEP); /*XXX */ - return; /* it did it all, finish up */ - } - /* XXX: This isn't used anywhere. Do you have plans for it, - * Julian? (dufault@hda.com). - * This allows a private 'done' handler to - * resubmit the command if it wants to retry, - * In this case the xs must NOT be freed. (julian) - */ - if (retval == -2) { - return; /* it did it all, finish up */ - } - SC_DEBUG(sc_link, SDEV_DB3, ("continuing with generic done()\n")); - } - if ((bp = xs->bp) == NULL) { - /* - * if it's a normal upper level request, then ask - * the upper level code to handle error checking - * rather than doing it here at interrupt time - */ - wakeup((caddr_t)xs); - return; - } - /* - * Go and handle errors now. - * If it returns SCSIRET_DO_RETRY then we should RETRY - */ - if ((retval = sc_err1(xs)) == SCSIRET_DO_RETRY) { - if ((*(sc_link->adapter->scsi_cmd)) (xs) - == SUCCESSFULLY_QUEUED) { /* don't wake the job, ok? */ - return; - } - xs->flags |= ITSDONE; - } - - free_xs(xs, sc_link, SCSI_NOSLEEP); /* does a start if needed */ - biodone(bp); -} - -/* - * ask the scsi driver to perform a command for us. - * tell it where to read/write the data, and how - * long the data is supposed to be. If we have a buf - * to associate with the transfer, we need that too. - */ -errval -scsi_scsi_cmd(sc_link, scsi_cmd, cmdlen, data_addr, datalen, - retries, timeout, bp, flags) - struct scsi_link *sc_link; - struct scsi_generic *scsi_cmd; - u_int32_t cmdlen; - u_char *data_addr; - u_int32_t datalen; - u_int32_t retries; - u_int32_t timeout; - struct buf *bp; - u_int32_t flags; -{ - struct scsi_xfer *xs; - errval retval; - u_int32_t s; - struct proc *p = curproc; - int iskstack = 0; /* 0 = "ok", 1 = copied from kernel stack */ - - /* - * Illegal command lengths will wedge host adapter software. - * Reject zero length commands and assert all defined commands - * are the correct length. - */ - if ((flags & (SCSI_RESET | SCSI_ESCAPE)) == 0) - { - if (cmdlen == 0) { - retval = EFAULT; - goto bad_with_biodone; - } else { - static u_int8_t sizes[] = {6, 10, 10, 0, 0, 12, 0, 0 }; - u_int8_t size = sizes[((scsi_cmd->opcode) >> 5)]; - if (size && (size != cmdlen)) { - retval = EIO; - goto bad_with_biodone; - } - } - } - - SC_DEBUG(sc_link, SDEV_DB2, ("scsi_cmd\n")); - - xs = get_xs(sc_link, flags); - if (!xs) { - retval = ENOMEM; - goto bad_with_biodone; - } - /* - * Fill out the scsi_xfer structure. We don't know whose context - * the cmd is in, so copy it. - */ - bcopy(scsi_cmd, &(xs->cmdstore), cmdlen); - xs->flags = INUSE | flags; - xs->sc_link = sc_link; - xs->retries = retries; - xs->timeout = timeout; - xs->cmd = &xs->cmdstore; - xs->cmdlen = cmdlen; - xs->data = data_addr; - xs->datalen = datalen; - xs->resid = 0; - xs->bp = bp; -/*XXX*/ /*use constant not magic number */ - if (datalen && (caddr_t) data_addr < (caddr_t) KERNBASE) { - /* XXX: should panic */ - printf("scsi_scsi_cmd(): data target is user space!\n"); -#ifdef SCSIDEBUG - show_scsi_cmd(xs); -#endif /* SCSIDEBUG */ - retval = EFAULT; - goto bad; - } - /* XXX theoretically.. in !BOUNCE_BUFFERS, we can still get to all - * process's kstack's, *BUT* we can swap a process. We really don't - * need to take a fault in that situation. Besides, the permanent - * KVM space will go away and only the current process will be - * reachable once the kthreading is finished. - */ - if (datalen && p != NULL && - (caddr_t)data_addr > (caddr_t)p->p_addr && - (caddr_t)data_addr < (caddr_t)p->p_addr + UPAGES * PAGE_SIZE) - iskstack = 1; - /* if we are doing a scsi command to/from per-proc kstack, copy it.. */ - if (iskstack) { - if (bp) { - printf("Data buffered space not in kernel context\n"); -#ifdef SCSIDEBUG - show_scsi_cmd(xs); -#endif /* SCSIDEBUG */ - retval = EFAULT; - goto bad; - } -#ifdef BOUNCE_BUFFERS - xs->data = (caddr_t) vm_bounce_kva_alloc(btoc(datalen)); -#else - xs->data = malloc(datalen, M_TEMP, M_WAITOK); -#endif - /* I think waiting is ok *//*XXX */ - switch ((int)(flags & (SCSI_DATA_IN | SCSI_DATA_OUT))) { - case 0: - printf("No direction flags, assuming both\n"); -#ifdef SCSIDEBUG - show_scsi_cmd(xs); -#endif /* SCSIDEBUG */ - case SCSI_DATA_IN | SCSI_DATA_OUT: /* weird */ - case SCSI_DATA_OUT: - bcopy(data_addr, xs->data, datalen); - break; - case SCSI_DATA_IN: - bzero(xs->data, datalen); - } - } -retry: - xs->error = XS_NOERROR; -#ifdef PARANOID - if (datalen && ((caddr_t) xs->data < (caddr_t) KERNBASE)) { - printf("It's still wrong!\n"); - } -#endif /*PARANOID*/ -#ifdef SCSIDEBUG - if (sc_link->flags & SDEV_DB3) show_scsi_xs(xs); -#endif /* SCSIDEBUG */ - /* - * Do the transfer. If we are polling we will return: - * COMPLETE, Was poll, and scsi_done has been called - * TRY_AGAIN_LATER, Adapter short resources, try again - * - * if under full steam (interrupts) it will return: - * SUCCESSFULLY_QUEUED, will do a wakeup when complete - * TRY_AGAIN_LATER, (as for polling) - * After the wakeup, we must still check if it succeeded - * - * If we have a bp however, all the error proccessing - * and the buffer code both expect us to return straight - * to them, so as soon as the command is queued, return - */ - - retval = (*(sc_link->adapter->scsi_cmd)) (xs); - - switch (retval) { - case SUCCESSFULLY_QUEUED: - if (bp) { - return 0; /* will sleep (or not) elsewhere */ - } - s = splbio(); - while (!(xs->flags & ITSDONE)) { - tsleep((caddr_t)xs, PRIBIO + 1, "scsicmd", 0); - } - splx(s); - /* fall through to check success of completed command */ - case COMPLETE: /* Polling command completed ok */ -/*XXX*/ case HAD_ERROR: /* Polling command completed with error */ - SC_DEBUG(sc_link, SDEV_DB3, ("back in cmd()\n")); - if ((retval = sc_err1(xs)) == SCSIRET_DO_RETRY) - goto retry; - break; - - case TRY_AGAIN_LATER: /* adapter resource shortage */ - SC_DEBUG(sc_link, SDEV_DB3, ("will try again \n")); - /* should sleep 1 sec here */ - if (xs->retries--) { - xs->flags &= ~ITSDONE; - goto retry; - } - default: - retval = EIO; - } - /* - * If we had to copy the data out of the user's context, - * then do the other half (copy it back or whatever) - * and free the memory buffer - */ - if (iskstack) { - switch ((int)(flags & (SCSI_DATA_IN | SCSI_DATA_OUT))) { - case 0: - case SCSI_DATA_IN | SCSI_DATA_OUT: /* weird */ - case SCSI_DATA_IN: - bcopy(xs->data, data_addr, datalen); - break; - } -bad_with_alloc: -#ifdef BOUNCE_BUFFERS - vm_bounce_kva_alloc_free((vm_offset_t) xs->data, - btoc(datalen)); -#else - free(xs->data, M_TEMP); -#endif - } - /* - * we have finished with the xfer stuct, free it and - * check if anyone else needs to be started up. - */ -bad: - s = splbio(); - free_xs(xs, sc_link, flags); /* includes the 'start' op */ - splx(s); -bad_with_biodone: - if (bp && retval) { - bp->b_error = retval; - bp->b_flags |= B_ERROR; - biodone(bp); - } - return (retval); -} - -static errval -sc_done(struct scsi_xfer *xs, int code) -{ - /* - * If it has a buf, we might be working with - * a request from the buffer cache or some other - * piece of code that requires us to process - * errors at interrupt time. We have probably - * been called by scsi_done() - */ - struct buf *bp; - - if (code == SCSIRET_DO_RETRY) { - if (xs->retries--) { - xs->error = XS_NOERROR; - xs->flags &= ~ITSDONE; - return SCSIRET_DO_RETRY; - } - code = EIO; /* Too many retries */ - } - - /* - * an EOF condition results in a VALID resid.. - */ - if(xs->flags & SCSI_EOF) { - xs->resid = xs->datalen; - xs->flags |= SCSI_RESID_VALID; - } - - bp = xs->bp; - if (code != ESUCCESS) { - if (bp) { - bp->b_error = 0; - bp->b_flags |= B_ERROR; - bp->b_error = code; - bp->b_resid = bp->b_bcount; - SC_DEBUG(xs->sc_link, SDEV_DB3, - ("scsi_interpret_sense (bp) returned %d\n", code)); - } else { - SC_DEBUG(xs->sc_link, SDEV_DB3, - ("scsi_interpret_sense (no bp) returned %d\n", code)); - } - } - else { - if (bp) { - - bp->b_error = 0; - - /* XXX: We really shouldn't need this SCSI_RESID_VALID flag. - * If we initialize it to 0 and only touch it if we have - * a value then we can leave out the test. - */ - - if (xs->flags & SCSI_RESID_VALID) { - bp->b_resid = xs->resid; - bp->b_flags |= B_ERROR; - } else { - bp->b_resid = 0; - } - } - } - - return code; -} - -/* - * submit a scsi command, given the command.. used for retries - * and callable from timeout() - */ -#ifdef NOTYET -errval scsi_submit(xs) - struct scsi_xfer *xs; -{ - struct scsi_link *sc_link = xs->sc_link; - int retval; - - retval = (*(sc_link->adapter->scsi_cmd)) (xs); - - return retval; -} - -/* - * Retry a scsi command, given the command, and a delay. - */ -errval scsi_retry(xs,delay) - struct scsi_xfer *xs; - int delay; -{ - if(delay) - { - timeout(((void())*)scsi_submit,xs,hz*delay); - return(0); - } - else - { - return(scsi_submit(xs)); - } -} -#endif - -/* - * handle checking for errors.. - * called at interrupt time from scsi_done() and - * at user time from scsi_scsi_cmd(), depending on whether - * there was a bp (basically, if there is a bp, there may be no - * associated process at the time. (it could be an async operation)) - * lower level routines shouldn't know about xs->bp.. we are the lowest. - */ -static errval -sc_err1(xs) - struct scsi_xfer *xs; -{ - SC_DEBUG(xs->sc_link, SDEV_DB3, ("sc_err1,err = 0x%lx \n", - (u_long)xs->error)); - - switch ((int)xs->error) { - case XS_SENSE: - return sc_done(xs, scsi_interpret_sense(xs)); - - case XS_NOERROR: - return sc_done(xs, ESUCCESS); - - case XS_BUSY: - /* should somehow arange for a 1 sec delay here (how?)[jre] - * tsleep(&localvar, priority, "foo", hz); - * that's how! [unknown] - * no, we could be at interrupt context.. use - * timeout(scsi_resubmit,xs,hz); [jre] (not implimenteed yet) - */ - DELAY(1000); - case XS_TIMEOUT: - return sc_done(xs, SCSIRET_DO_RETRY); - - /* fall through */ - case XS_SELTIMEOUT: - case XS_DRIVER_STUFFUP: - return sc_done(xs, EIO); - - default: - sc_print_addr(xs->sc_link); - printf("unknown error category from scsi driver\n"); - return sc_done(xs, EIO); - } -} - -#ifdef notyet -static int -scsi_sense_qualifiers(xs, asc, ascq) - struct scsi_xfer *xs; - int *asc; - int *ascq; -{ - struct scsi_sense_data_new *sense; - struct scsi_sense_extended *ext; - - sense = (struct scsi_sense_data_new *)&(xs->sense); - - ext = &(sense->ext.extended); - - if (ext->extra_len < 5) - return 0; - - *asc = (ext->extra_len >= 5) ? ext->add_sense_code : 0; - *ascq = (ext->extra_len >= 6) ? ext->add_sense_code_qual : 0; - - return 1; -} - -#endif - -/* - * scsi_sense_print will decode the sense data into human - * readable form. Sense handlers can use this to generate - * a report. This NOW DOES send the closing "\n". - */ -void scsi_sense_print(xs) - struct scsi_xfer *xs; -{ - struct scsi_sense_data_new *sense; - struct scsi_sense_extended *ext; - u_int32_t key; - u_int32_t info; - int asc, ascq; - - /* This sense key text now matches what is in the SCSI spec - * (Yes, even the capitals) - * so that it is easier to look through the spec to find the - * appropriate place. - */ - static char *sense_key_text[] = - { - "NO SENSE", "RECOVERED ERROR", - "NOT READY", "MEDIUM ERROR", - "HARDWARE FAILURE", "ILLEGAL REQUEST", - "UNIT ATTENTION", "DATA PROTECT", - "BLANK CHECK", "Vendor Specific", - "COPY ABORTED", "ABORTED COMMAND", - "EQUAL", "VOLUME OVERFLOW", - "MISCOMPARE", "RESERVED" - }; - - sc_print_start(xs->sc_link); - - sense = (struct scsi_sense_data_new *)&(xs->sense); - ext = &(sense->ext.extended); - - key = ext->flags & SSD_KEY; - - switch (sense->error_code & SSD_ERRCODE) { - case 0x71: /* deferred error */ - printf("Deferred Error: "); - - /* DROP THROUGH */ - - case 0x70: - - printf("%s", sense_key_text[key]); - info = (ext->info[0] << 24) | (ext->info[1] << 16) - | (ext->info[2] << 8) | ext->info[3]; - - if (sense->error_code & SSD_ERRCODE_VALID) { - - switch ((int)key) { - case 0x2: /* NOT READY */ - case 0x5: /* ILLEGAL REQUEST */ - case 0x6: /* UNIT ATTENTION */ - case 0x7: /* DATA PROTECT */ - break; - case 0x8: /* BLANK CHECK */ - printf(" req sz: %lu (decimal)", (u_long)info); - break; - default: - if (info) { - if (sense->ext.extended.flags & SSD_ILI) { - printf( - " ILI (length mismatch): %ld", - (u_long)info); - } - else { - printf(" info:%#lx", - (u_long)info); - } - } - } - } - else if (info) - printf(" info?:%#lx", (u_long)info); - - if (ext->extra_len >= 4) { - if (bcmp(ext->cmd_spec_info, "\0\0\0\0", 4)) { - printf(" csi:%x,%x,%x,%x", - ext->cmd_spec_info[0], - ext->cmd_spec_info[1], - ext->cmd_spec_info[2], - ext->cmd_spec_info[3]); - } - } - - asc = (ext->extra_len >= 5) ? ext->add_sense_code : 0; - ascq = (ext->extra_len >= 6) ? ext->add_sense_code_qual : 0; - - if (asc || ascq) - { - char *desc = scsi_sense_desc(asc, ascq); - printf(" asc:%x,%x", asc, ascq); - - if (strlen(desc) > 40) - sc_print_addr(xs->sc_link);; - - printf(" %s", desc); - } - - if (ext->extra_len >= 7 && ext->fru) { - printf(" field replaceable unit: %x", ext->fru); - } - - if (ext->extra_len >= 10 && - (ext->sense_key_spec_1 & SSD_SCS_VALID)) { - printf(" sks:%x,%x", ext->sense_key_spec_1, - (ext->sense_key_spec_2 | - ext->sense_key_spec_3)); - } - break; - - /* - * Not code 70, just report it - */ - default: - printf("error code %d", - sense->error_code & SSD_ERRCODE); - if (sense->error_code & SSD_ERRCODE_VALID) { - printf(" at block no. %ld (decimal)", - (((unsigned long)sense->ext.unextended.blockhi) << 16) + - (((unsigned long)sense->ext.unextended.blockmed) << 8) + - ((unsigned long)sense->ext.unextended.blocklow)); - } - } - - printf("\n"); - sc_print_finish(); -} - -/* - * Look at the returned sense and act on the error, determining - * the unix error number to pass back. (0 = report no error) - * - * THIS IS THE DEFAULT SENSE HANDLER - */ -static errval -scsi_interpret_sense(xs) - struct scsi_xfer *xs; -{ - struct scsi_sense_data_new *sense; - struct scsi_sense_extended *ext; - struct scsi_link *sc_link = xs->sc_link; - u_int32_t key; - u_int32_t silent; - errval errcode; - int error_code, asc, ascq; - - /* - * If the flags say errs are ok, then always return ok. - * XXX: What if it is a deferred error? - */ - if (xs->flags & SCSI_ERR_OK) - return (ESUCCESS); - - sense = (struct scsi_sense_data_new *)&(xs->sense); - ext = &(sense->ext.extended); -#ifdef SCSIDEBUG - if (sc_link->flags & SDEV_DB1) { - - u_int32_t count = 0; - printf("code%x valid%x ", - sense->error_code & SSD_ERRCODE, - sense->error_code & SSD_ERRCODE_VALID ? 1 : 0); - printf("seg%x key%x ili%x eom%x fmark%x\n", - ext->segment, - ext->flags & SSD_KEY, - ext->flags & SSD_ILI ? 1 : 0, - ext->flags & SSD_EOM ? 1 : 0, - ext->flags & SSD_FILEMARK ? 1 : 0); - printf("info: %x %x %x %x followed by %d extra bytes\n", - ext->info[0], - ext->info[1], - ext->info[2], - ext->info[3], - ext->extra_len); - printf("extra: "); - while (count < ext->extra_len) { - printf("%x ", ext->extra_bytes[count++]); - } - printf("\n"); - } - #endif /*SCSIDEBUG */ - /* - * If the device has its own sense handler, call it first. - * If it returns a legit errno value, return that, otherwise - * it should return either DO_RETRY or CONTINUE to either - * request a retry or continue with default sense handling. - */ - if (sc_link->device->err_handler) { - SC_DEBUG(sc_link, SDEV_DB2, - ("calling private err_handler()\n")); - errcode = (*sc_link->device->err_handler) (xs); - - SC_DEBUG(sc_link, SDEV_DB2, - ("private err_handler() returned %d\n",errcode)); - if (errcode >= 0) { - SC_DEBUG(sc_link, SDEV_DB2, - ("SCSI_EOF = %d\n",(xs->flags & SCSI_EOF)?1:0)); - SC_DEBUG(sc_link, SDEV_DB2, - ("SCSI_RESID_VALID = %d\n", - (xs->flags & SCSI_RESID_VALID)?1:0)); - - if(xs->flags & SCSI_EOF) { - xs->resid = xs->datalen; - xs->flags |= SCSI_RESID_VALID; - } - return errcode; /* valid errno value */ - } - - switch(errcode) { - case SCSIRET_DO_RETRY: /* Requested a retry */ - return errcode; - - case SCSIRET_CONTINUE: /* Continue with default sense processing */ - break; - - default: - sc_print_addr(xs->sc_link); - printf("unknown return code %d from sense handler.\n", - errcode); - - return errcode; - } - } - - /* otherwise use the default */ - silent = xs->flags & SCSI_SILENT; - key = ext->flags & SSD_KEY; - error_code = sense->error_code & SSD_ERRCODE; - asc = (ext->extra_len >= 5) ? ext->add_sense_code : 0; - ascq = (ext->extra_len >= 6) ? ext->add_sense_code_qual : 0; - - /* - * Retry while the device is returning a ``Logical unit - * is in the process of becoming ready.'' (until it either - * eventually yields an error, or finally succeeds). - */ - if (error_code == 0x70 /* current error */ && - (int)key == 0x2 /* not ready */ && - asc == 4 && ascq == 1 /* logical unit i i t p o b r */) - return (SCSIRET_DO_RETRY); - - if (!silent) { - scsi_sense_print(xs); - } - - switch (error_code) { - case 0x71: /* deferred error */ - /* Print even if silent (not silent was already done) - */ - if (silent) { - scsi_sense_print(xs); - } - - /* XXX: - * This error doesn't relate to the command associated - * with this request sense. A deferred error is an error - * for a command that has already returned GOOD status (see 7.2.14.2). - * - * By my reading of that section, it looks like the current command - * has been cancelled, we should now clean things up (hopefully - * recovering any lost data) and then - * retry the current command. There are two easy choices, both - * wrong: - * 1. Drop through (like we had been doing), thus treating this as - * if the error were for the current command and return and stop - * the current command. - * 2. Issue a retry (like I made it do) thus hopefully recovering - * the current transfer, and ignoring the fact that we've dropped - * a command. - * - * These should probably be handled in a device specific - * sense handler or punted back up to a user mode daemon - */ - return SCSIRET_DO_RETRY; - - /* - * If it's code 70, use the extended stuff and interpret the key - */ - case 0x70: - - switch ((int)key) { - case 0x0: /* NO SENSE */ - case 0x1: /* RECOVERED ERROR */ - case 0xc: /* EQUAL */ - if(xs->flags & SCSI_EOF) { - xs->resid = xs->datalen; - xs->flags |= SCSI_RESID_VALID; - } - return (ESUCCESS); - case 0x2: /* NOT READY */ - sc_link->flags &= ~SDEV_MEDIA_LOADED; - return (EBUSY); - case 0x5: /* ILLEGAL REQUEST */ - return (EINVAL); - case 0x6: /* UNIT ATTENTION */ - sc_link->flags &= ~SDEV_MEDIA_LOADED; - if (sc_link->flags & SDEV_OPEN) { - return (EIO); - } else { - return 0; - } - case 0x7: /* DATA PROTECT */ - return (EACCES); - case 0xd: /* VOLUME OVERFLOW */ - return (ENOSPC); - case 0x8: /* BLANK CHECK */ - xs->flags |= SCSI_EOF; /* force EOF on tape read */ - return (ESUCCESS); - default: - return (EIO); - } - /* - * Not code 70, return EIO - */ - default: - return (EIO); - } -} - -/* - * Utility routines often used in SCSI stuff - */ - -/* - * convert a physical address to 3 bytes, - * MSB at the lowest address, - * LSB at the highest. - */ -void -scsi_uto3b(val, bytes) - u_int32_t val; - u_char *bytes; -{ - *bytes++ = (val & 0xff0000) >> 16; - *bytes++ = (val & 0xff00) >> 8; - *bytes = val & 0xff; -} - -u_int32_t -scsi_3btou(bytes) - u_char *bytes; -{ - u_int32_t rc; - rc = (*bytes++ << 16); - rc += (*bytes++ << 8); - rc += *bytes; - return rc; -} - -int32_t -scsi_3btoi(bytes) - u_char *bytes; -{ - u_int32_t rc = scsi_3btou(bytes); - - if (rc & 0x00800000) - rc |= 0xff000000; - - return (int32_t) rc; -} - -void -scsi_uto2b(val, bytes) - u_int32_t val; - u_char *bytes; -{ - *bytes++ = (val & 0xff00) >> 8; - *bytes = val & 0xff; -} - -u_int32_t -scsi_2btou(bytes) - u_char *bytes; -{ - u_int32_t rc; - rc = (*bytes++ << 8); - rc += *bytes; - return rc; -} - -void -scsi_uto4b(val, bytes) - u_int32_t val; - u_char *bytes; -{ - *bytes++ = (val & 0xff000000) >> 24; - *bytes++ = (val & 0xff0000) >> 16; - *bytes++ = (val & 0xff00) >> 8; - *bytes = val & 0xff; -} - -u_int32_t -scsi_4btou(bytes) - u_char *bytes; -{ - u_int32_t rc; - rc = (*bytes++ << 24); - rc += (*bytes++ << 16); - rc += (*bytes++ << 8); - rc += *bytes; - return rc; -} - -static int sc_printing; - -void -sc_print_init() -{ - sc_printing++; -} - -void -sc_print_start(sc_link) - struct scsi_link *sc_link; -{ - sc_print_addr(sc_link); - sc_printing++; -} -void -sc_print_finish() -{ - sc_printing--; -} - -static void -id_put(int id, char *after) -{ - switch(id) - { - case SCCONF_UNSPEC: - break; - - case SCCONF_ANY: - printf("?"); - break; - - default: - printf("%d", id); - break; - } - - printf("%s", after); -} - -/* - * sc_print_addr: Print out the scsi_link structure's address info. - * This should handle any circumstance, even the transitory ones - * during system configuration. - */ - -void -sc_print_addr(sc_link) - struct scsi_link *sc_link; -{ - if (sc_printing) - printf("\n"); - - if (sc_link->device == 0) { - printf("nodevice at "); - } - else if (strcmp(sc_link->device->name, "probe") != 0) { - printf("%s", sc_link->device->name); - id_put(sc_link->dev_unit, ": "); - return; - } - - printf("scbus"); - id_put(sc_link->scsibus, " "); - - printf("target "); - id_put(sc_link->target, " "); - printf("lun "); - id_put(sc_link->lun, ": "); -} - -#ifdef SCSIDEBUG -/* - * Given a scsi_xfer, dump the request, in all its glory - */ -static void -show_scsi_xs(xs) - struct scsi_xfer *xs; -{ - printf("xs(%p): ", (void *)xs); - printf("flg(0x%lx)", (u_long)xs->flags); - printf("sc_link(%p)", (void *)xs->sc_link); - printf("retr(0x%x)", xs->retries); - printf("timo(0x%lx)", (long)xs->timeout); - printf("cmd(%p)", (void *)xs->cmd); - printf("len(0x%lx)", (long)xs->cmdlen); - printf("data(%p)", (void *)xs->data); - printf("len(0x%lx)", (long)xs->datalen); - printf("res(0x%lx)", (long)xs->resid); - printf("err(0x%lx)", (long)xs->error); - printf("bp(%p)", (void *)xs->bp); - show_scsi_cmd(xs); -} - -void -show_scsi_cmd(struct scsi_xfer *xs) -{ - u_char *b = (u_char *) xs->cmd; - int i = 0; - - sc_print_addr(xs->sc_link); - printf("command: "); - - if (!(xs->flags & SCSI_RESET)) { - while (i < xs->cmdlen) { - if (i) - printf(","); - printf("%x", b[i++]); - } - printf("-[%ld bytes]\n", (long)xs->datalen); - if (xs->datalen) - show_mem(xs->data, min(64, xs->datalen)); - } else { - printf("-RESET-\n"); - } -} - -static void -show_mem(address, num) - unsigned char *address; - u_int32_t num; -{ - u_int32_t y; - printf("------------------------------"); - for (y = 0; y < num; y += 1) { - if (!(y % 16)) - printf("\n%03ld: ", (long)y); - printf("%02x ", *address++); - } - printf("\n------------------------------\n"); -} -#endif /*SCSIDEBUG */ diff --git a/sys/scsi/scsi_cd.h b/sys/scsi/scsi_cd.h deleted file mode 100644 index 26e366b..0000000 --- a/sys/scsi/scsi_cd.h +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Written by Julian Elischer (julian@tfs.com) - * for TRW Financial Systems. - * - * 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. - * - * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 - * - * $Id: scsi_cd.h,v 1.10 1997/02/22 09:44:28 peter Exp $ - */ -#ifndef _SCSI_SCSI_CD_H -#define _SCSI_SCSI_CD_H 1 - -/* - * Define two bits always in the same place in byte 2 (flag byte) - */ -#define CD_RELADDR 0x01 -#define CD_MSF 0x02 - -/* - * SCSI command format - */ - -struct scsi_pause -{ - u_char op_code; - u_char byte2; - u_char unused[6]; - u_char resume; - u_char control; -}; -#define PA_PAUSE 1 -#define PA_RESUME 0 - -struct scsi_play_msf -{ - u_char op_code; - u_char byte2; - u_char unused; - u_char start_m; - u_char start_s; - u_char start_f; - u_char end_m; - u_char end_s; - u_char end_f; - u_char control; -}; - -struct scsi_play_track -{ - u_char op_code; - u_char byte2; - u_char unused[2]; - u_char start_track; - u_char start_index; - u_char unused1; - u_char end_track; - u_char end_index; - u_char control; -}; - -struct scsi_play -{ - u_char op_code; - u_char byte2; - u_char blk_addr[4]; - u_char unused; - u_char xfer_len[2]; - u_char control; -}; - -struct scsi_play_big -{ - u_char op_code; - u_char byte2; /* same as above */ - u_char blk_addr[4]; - u_char xfer_len[4]; - u_char unused; - u_char control; -}; - -struct scsi_play_rel_big -{ - u_char op_code; - u_char byte2; /* same as above */ - u_char blk_addr[4]; - u_char xfer_len[4]; - u_char track; - u_char control; -}; - -struct scsi_read_header -{ - u_char op_code; - u_char byte2; - u_char blk_addr[4]; - u_char unused; - u_char data_len[2]; - u_char control; -}; - -struct scsi_read_subchannel -{ - u_char op_code; - u_char byte2; - u_char byte3; -#define SRS_SUBQ 0x40 - u_char subchan_format; - u_char unused[2]; - u_char track; - u_char data_len[2]; - u_char control; -}; - -struct scsi_read_toc -{ - u_char op_code; - u_char byte2; - u_char unused[4]; - u_char from_track; - u_char data_len[2]; - u_char control; -}; - -struct scsi_read_cd_capacity -{ - u_char op_code; - u_char byte2; - u_char addr_3; /* Most Significant */ - u_char addr_2; - u_char addr_1; - u_char addr_0; /* Least Significant */ - u_char unused[3]; - u_char control; -}; - -/* - * Opcodes - */ - -#define READ_CD_CAPACITY 0x25 /* slightly different from disk */ -#define READ_SUBCHANNEL 0x42 /* cdrom read Subchannel */ -#define READ_TOC 0x43 /* cdrom read TOC */ -#define READ_HEADER 0x44 /* cdrom read header */ -#define PLAY 0x45 /* cdrom play 'play audio' mode */ -#define PLAY_MSF 0x47 /* cdrom play Min,Sec,Frames mode */ -#define PLAY_TRACK 0x48 /* cdrom play track/index mode */ -#define PLAY_TRACK_REL 0x49 /* cdrom play track/index mode */ -#define PAUSE 0x4b /* cdrom pause in 'play audio' mode */ -#define PLAY_BIG 0xa5 /* cdrom pause in 'play audio' mode */ -#define PLAY_TRACK_REL_BIG 0xa9 /* cdrom play track/index mode */ - - - -struct scsi_read_cd_cap_data -{ - u_char addr_3; /* Most significant */ - u_char addr_2; - u_char addr_1; - u_char addr_0; /* Least significant */ - u_char length_3; /* Most significant */ - u_char length_2; - u_char length_1; - u_char length_0; /* Least significant */ -}; - -union cd_pages -{ - struct audio_page - { - u_char page_code; -#define CD_PAGE_CODE 0x3F -#define AUDIO_PAGE 0x0e -#define CD_PAGE_PS 0x80 - u_char param_len; - u_char flags; -#define CD_PA_SOTC 0x02 -#define CD_PA_IMMED 0x04 - u_char unused[2]; - u_char format_lba; -#define CD_PA_FORMAT_LBA 0x0F -#define CD_PA_APR_VALID 0x80 - u_char lb_per_sec[2]; - struct port_control - { - u_char channels; -#define CHANNEL 0x0F -#define CHANNEL_0 1 -#define CHANNEL_1 2 -#define CHANNEL_2 4 -#define CHANNEL_3 8 -#define LEFT_CHANNEL CHANNEL_0 -#define RIGHT_CHANNEL CHANNEL_1 - u_char volume; - } port[4]; -#define LEFT_PORT 0 -#define RIGHT_PORT 1 - }audio; -}; - -struct cd_mode_data -{ - struct scsi_mode_header header; - struct blk_desc blk_desc; - union cd_pages page; -}; -#endif /*_SCSI_SCSI_CD_H*/ - diff --git a/sys/scsi/scsi_changer.h b/sys/scsi/scsi_changer.h deleted file mode 100644 index be24baf..0000000 --- a/sys/scsi/scsi_changer.h +++ /dev/null @@ -1,400 +0,0 @@ -/* - * Copyright (c) 1996 Jason R. Thorpe <thorpej@and.com> - * All rights reserved. - * - * Partially based on an autochanger driver written by Stefan Grefen - * and on an autochanger driver written by the Systems Programming Group - * at the University of Utah Computer Science Department. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgements: - * This product includes software developed by Jason R. Thorpe - * for And Communications, http://www.and.com/ - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id: scsi_changer.h,v 1.9 1997/02/22 09:44:29 peter Exp $ - */ - -/* - * SCSI changer interface description - */ - -/* - * Partially derived from software written by Stefan Grefen - * (grefen@goofy.zdv.uni-mainz.de soon grefen@convex.com) - * based on the SCSI System by written Julian Elischer (julian@tfs.com) - * for TRW Financial Systems. - * - * 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. - * - * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 - */ - -#ifndef _SCSI_SCSI_CHANGER_H -#define _SCSI_SCSI_CHANGER_H 1 - -/* - * SCSI command format - */ - -/* - * Exchange the medium in the source element with the medium - * located at the destination element. - */ -struct scsi_exchange_medium { - u_int8_t opcode; -#define EXCHANGE_MEDIUM 0xa6 - u_int8_t byte2; - u_int8_t tea[2]; /* transport element address */ - u_int8_t src[2]; /* source address */ - u_int8_t fdst[2]; /* first destination address */ - u_int8_t sdst[2]; /* second destination address */ - u_int8_t flags; -#define EXCHANGE_MEDIUM_INV1 0x01 -#define EXCHANGE_MEDIUM_INV2 0x02 - u_int8_t control; -}; - -/* - * Cause the medium changer to check all elements for medium and any - * other status relevant to the element. - */ -struct scsi_initialize_elememt_status { - u_int8_t opcode; -#define INITIALIZE_ELEMENT_STATUS 0x07 - u_int8_t byte2; - u_int8_t reserved[3]; - u_int8_t control; -}; - -/* - * Request the changer to move a unit of media from the source element - * to the destination element. - */ -struct scsi_move_medium { - u_int8_t opcode; -#define MOVE_MEDIUM 0xa5 - u_int8_t byte2; - u_int8_t tea[2]; /* transport element address */ - u_int8_t src[2]; /* source element address */ - u_int8_t dst[2]; /* destination element address */ - u_int8_t reserved[2]; - u_int8_t flags; -#define MOVE_MEDIUM_INVERT 0x01 - u_int8_t control; -}; - -/* - * Position the specified transport element (picker) in front of - * the destination element specified. - */ -struct scsi_position_to_element { - u_int8_t opcode; -#define POSITION_TO_ELEMENT 0x2b - u_int8_t byte2; - u_int8_t tea[2]; /* transport element address */ - u_int8_t dst[2]; /* destination element address */ - u_int8_t reserved[2]; - u_int8_t flags; -#define POSITION_TO_ELEMENT_INVERT 0x01 - u_int8_t control; -}; - -/* - * Request that the changer report the status of its internal elements. - */ -struct scsi_read_element_status { - u_int8_t opcode; -#define READ_ELEMENT_STATUS 0xb8 - u_int8_t byte2; -#define READ_ELEMENT_STATUS_VOLTAG 0x10 /* report volume tag info */ - /* ...next 4 bits are an element type code... */ - u_int8_t sea[2]; /* starting element address */ - u_int8_t count[2]; /* number of elements */ - u_int8_t reserved0; - u_int8_t len[3]; /* length of data buffer */ - u_int8_t reserved1; - u_int8_t control; -}; - -struct scsi_request_volume_element_address { - u_int8_t opcode; -#define REQUEST_VOLUME_ELEMENT_ADDRESS 0xb5 - u_int8_t byte2; -#define REQUEST_VOLUME_ELEMENT_ADDRESS_VOLTAG 0x10 - /* ...next 4 bits are an element type code... */ - u_int8_t eaddr[2]; /* element address */ - u_int8_t count[2]; /* number of elements */ - u_int8_t reserved0; - u_int8_t len[3]; /* length of data buffer */ - u_int8_t reserved1; - u_int8_t control; -}; - -/* XXX scsi_release */ - -/* - * Data returned by READ ELEMENT STATUS consists of an 8-byte header - * followed by one or more read_element_status_pages. - */ -struct read_element_status_header { - u_int8_t fear[2]; /* first element address reported */ - u_int8_t count[2]; /* number of elements available */ - u_int8_t reserved; - u_int8_t nbytes[3]; /* byte count of all pages */ -}; - -struct read_element_status_page_header { - u_int8_t type; /* element type code; see type codes below */ - u_int8_t flags; -#define READ_ELEMENT_STATUS_AVOLTAG 0x40 -#define READ_ELEMENT_STATUS_PVOLTAG 0x80 - u_int8_t edl[2]; /* element descriptor length */ - u_int8_t reserved; - u_int8_t nbytes[3]; /* byte count of all descriptors */ -}; - -struct read_element_status_descriptor { - u_int8_t eaddr[2]; /* element address */ - u_int8_t flags1; - -#define READ_ELEMENT_STATUS_FULL 0x01 -#define READ_ELEMENT_STATUS_IMPEXP 0x02 -#define READ_ELEMENT_STATUS_EXCEPT 0x04 -#define READ_ELEMENT_STATUS_ACCESS 0x08 -#define READ_ELEMENT_STATUS_EXENAB 0x10 -#define READ_ELEMENT_STATUS_INENAB 0x20 - -#define READ_ELEMENT_STATUS_MT_MASK1 0x05 -#define READ_ELEMENT_STATUS_ST_MASK1 0x0c -#define READ_ELEMENT_STATUS_IE_MASK1 0x3f -#define READ_ELEMENT_STATUS_DT_MASK1 0x0c - - u_int8_t reserved0; - u_int8_t sense_code; - u_int8_t sense_qual; - - /* - * dt_scsi_flags and dt_scsi_addr are valid only on data transport - * elements. These bytes are undefined for all other element types. - */ - u_int8_t dt_scsi_flags; - -#define READ_ELEMENT_STATUS_DT_LUNMASK 0x07 -#define READ_ELEMENT_STATUS_DT_LUVALID 0x10 -#define READ_ELEMENT_STATUS_DT_IDVALID 0x20 -#define READ_ELEMENT_STATUS_DT_NOTBUS 0x80 - - u_int8_t dt_scsi_addr; - - u_int8_t reserved1; - - u_int8_t flags2; -#define READ_ELEMENT_STATUS_INVERT 0x40 -#define READ_ELEMENT_STATUS_SVALID 0x80 - u_int8_t ssea[2]; /* source storage element address */ - - /* - * bytes 12-47: Primary volume tag information. - * (field omitted if PVOLTAG = 0) - * - * bytes 48-83: Alternate volume tag information. - * (field omitted if AVOLTAG = 0) - * - * bytes 84-87: Reserved (moved up if either of the above fields - * are omitted) - * - * bytes 88-end: Vendor-specific: (moved up if either of the - * above fields are missing) - */ -}; - -/* XXX add data returned by REQUEST VOLUME ELEMENT ADDRESS */ - -/* Element type codes */ -#define ELEMENT_TYPE_MASK 0x0f /* Note: these aren't bits */ -#define ELEMENT_TYPE_ALL 0x00 -#define ELEMENT_TYPE_MT 0x01 -#define ELEMENT_TYPE_ST 0x02 -#define ELEMENT_TYPE_IE 0x03 -#define ELEMENT_TYPE_DT 0x04 - -/* - * XXX The following definitions should be common to all SCSI device types. - */ -#define PGCODE_MASK 0x3f /* valid page number bits in pg_code */ -#define PGCODE_PS 0x80 /* indicates page is savable */ - -/* - * Device capabilities page. - * - * This page defines characteristics of the elemenet types in the - * medium changer device. - * - * Note in the definitions below, the following abbreviations are - * used: - * MT Medium transport element (picker) - * ST Storage transport element (slot) - * IE Import/export element (portal) - * DT Data tranfer element (tape/disk drive) - */ -struct page_device_capabilities { - u_int8_t pg_code; /* page code (0x1f) */ - u_int8_t pg_length; /* page length (0x12) */ - - /* - * The STOR_xx bits indicate that an element of a given - * type may provide independent storage for a unit of - * media. The top four bits of this value are reserved. - */ - u_int8_t stor; -#define STOR_MT 0x01 -#define STOR_ST 0x02 -#define STOR_IE 0x04 -#define STOR_DT 0x08 - - u_int8_t reserved0; - - /* - * The MOVE_TO_yy bits indicate the changer supports - * moving a unit of medium from an element of a given type to an - * element of type yy. This is used to determine if a given - * MOVE MEDIUM command is legal. The top four bits of each - * of these values are reserved. - */ - u_int8_t move_from_mt; - u_int8_t move_from_st; - u_int8_t move_from_ie; - u_int8_t move_from_dt; -#define MOVE_TO_MT 0x01 -#define MOVE_TO_ST 0x02 -#define MOVE_TO_IE 0x04 -#define MOVE_TO_DT 0x08 - - u_int8_t reserved1[2]; - - /* - * Similar to above, but for EXCHANGE MEDIUM. - */ - u_int8_t exchange_with_mt; - u_int8_t exchange_with_st; - u_int8_t exchange_with_ie; - u_int8_t exchange_with_dt; -#define EXCHANGE_WITH_MT 0x01 -#define EXCHANGE_WITH_ST 0x02 -#define EXCHANGE_WITH_IE 0x04 -#define EXCHANGE_WITH_DT 0x08 -}; - -/* - * Medium changer elemement address assignment page. - * - * Some of these fields can be a little confusing, so an explanation - * is in order. - * - * Each component within a a medium changer apparatus is called an - * "element". - * - * The "medium transport element address" is the address of the first - * picker (robotic arm). "Number of medium transport elements" tells - * us how many pickers exist in the changer. - * - * The "first storage element address" is the address of the first - * slot in the tape or disk magazine. "Number of storage elements" tells - * us how many slots exist in the changer. - * - * The "first import/export element address" is the address of the first - * medium portal accessible both by the medium changer and an outside - * human operator. This is where the changer might deposit tapes destined - * for some vault. The "number of import/export elements" tells us - * not many of these portals exist in the changer. NOTE: this number may - * be 0. - * - * The "first data transfer element address" is the address of the first - * tape or disk drive in the changer. "Number of data transfer elements" - * tells us how many drives exist in the changer. - */ -struct page_element_address_assignment { - u_int8_t pg_code; /* page code (0x1d) */ - u_int8_t pg_length; /* page length (0x12) */ - - /* Medium transport element address */ - u_int8_t mtea[2]; - - /* Number of medium transport elements */ - u_int8_t nmte[2]; - - /* First storage element address */ - u_int8_t fsea[2]; - - /* Number of storage elements */ - u_int8_t nse[2]; - - /* First import/export element address */ - u_int8_t fieea[2]; - - /* Number of import/export elements */ - u_int8_t niee[2]; - - /* First data transfer element address */ - u_int8_t fdtea[2]; - - /* Number of data trafer elements */ - u_int8_t ndte[2]; - - u_int8_t reserved[2]; -}; - -/* - * Transport geometry parameters page. - * - * Defines whether each medium transport element is a member of a set of - * elements that share a common robotics subsystem and whether the element - * is capable of media rotation. One transport geometry descriptor is - * transferred for each medium transport element, beginning with the first - * medium transport element (other than the default transport element address - * of 0). - */ -struct page_transport_geometry_parameters { - u_int8_t pg_code; /* page code (0x1e) */ - u_int8_t pg_length; /* page length; variable */ - - /* Transport geometry descriptor(s) are here. */ - - u_int8_t misc; -#define CAN_ROTATE 0x01 - - /* Member number in transport element set. */ - u_int8_t member; -}; - -#endif /* _SCSI_SCSI_CHANGER_H */ diff --git a/sys/scsi/scsi_debug.h b/sys/scsi/scsi_debug.h deleted file mode 100644 index a362f5d..0000000 --- a/sys/scsi/scsi_debug.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Use - * options SCSIDEBUG - * - * in the kernel config file to get these macros into effect. - */ - -/* - * Written by Julian Elischer (julian@tfs.com) - * - * $Id$ - */ -#ifndef _SCSI_SCSI_DEBUG_H -#define _SCSI_SCSI_DEBUG_H 1 - -/* - * These are the new debug bits. (Sat Oct 2 12:46:46 WST 1993) - * the following DEBUG bits are defined to exist in the flags word of - * the scsi_link structure. - */ -#define SDEV_DB1 0x10 /* scsi commands, errors, data */ -#define SDEV_DB2 0x20 /* routine flow tracking */ -#define SDEV_DB3 0x40 /* internal to routine flows */ -#define SDEV_DB4 0x80 /* level 4 debugging for this dev */ - -/* target and LUN we want to debug */ -#define DEBUGTARG 9 /*9 = dissable*/ -#define DEBUGLUN 0 -#define DEBUGLEVEL (SDEV_DB1|SDEV_DB2) - -/* - * This is the usual debug macro for use with the above bits - */ -#ifdef SCSIDEBUG -#define SC_DEBUG(sc_link,Level,Printstuff) \ - if((sc_link)->flags & (Level)) \ - { \ - printf("%s%d(%s%d:%d:%d): ", \ - sc_link->device->name, \ - sc_link->dev_unit, \ - sc_link->adapter->name, \ - sc_link->adapter_unit, \ - sc_link->target, \ - sc_link->lun); \ - printf Printstuff; \ - } -#define SC_DEBUGN(sc_link,Level,Printstuff) \ - if((sc_link)->flags & (Level)) \ - { \ - printf Printstuff; \ - } -#else -#define SC_DEBUG(A,B,C) /* not included */ -#define SC_DEBUGN(A,B,C) /* not included */ -#endif - -#endif /*_SCSI_SCSI_DEBUG_H*/ -/* END OF FILE */ - diff --git a/sys/scsi/scsi_disk.h b/sys/scsi/scsi_disk.h deleted file mode 100644 index a33e4e7..0000000 --- a/sys/scsi/scsi_disk.h +++ /dev/null @@ -1,221 +0,0 @@ -/* - * SCSI interface description - */ - -/* - * Some lines of this file come from a file of the name "scsi.h" - * distributed by OSF as part of mach2.5, - * so the following disclaimer has been kept. - * - * Copyright 1990 by Open Software Foundation, - * Grenoble, FRANCE - * - * All Rights Reserved - * - * Permission to use, copy, modify, and distribute this software and - * its documentation for any purpose and without fee is hereby granted, - * provided that the above copyright notice appears in all copies and - * that both the copyright notice and this permission notice appear in - * supporting documentation, and that the name of OSF or Open Software - * Foundation not be used in advertising or publicity pertaining to - * distribution of the software without specific, written prior - * permission. - * - * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, - * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, - * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION - * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -/* - * Largely written by Julian Elischer (julian@tfs.com) - * for TRW Financial Systems. - * - * 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. - * - * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 - * - * $Id$ - */ - -/* - * SCSI command format - */ - -#ifndef _SCSI_SCSI_DISK_H -#define _SCSI_SCSI_DISK_H 1 - -struct scsi_reassign_blocks -{ - u_char op_code; - u_char byte2; - u_char unused[3]; - u_char control; -}; - -struct scsi_rw -{ - u_char op_code; - u_char addr_2; /* Most significant */ -#define SRW_TOPADDR 0x1F /* only 5 bits here */ - u_char addr_1; - u_char addr_0; /* least significant */ - u_char length; - u_char control; -}; - -struct scsi_rw_big -{ - u_char op_code; - u_char byte2; -#define SRWB_RELADDR 0x01 - u_char addr_3; /* Most significant */ - u_char addr_2; - u_char addr_1; - u_char addr_0; /* least significant */ - u_char reserved; - u_char length2; - u_char length1; - u_char control; -}; - -struct scsi_read_capacity -{ - u_char op_code; - u_char byte2; - u_char addr_3; /* Most Significant */ - u_char addr_2; - u_char addr_1; - u_char addr_0; /* Least Significant */ - u_char unused[3]; - u_char control; -}; - -struct scsi_start_stop -{ - u_char op_code; - u_char byte2; - u_char unused[2]; - u_char how; -#define SSS_START 0x01 -#define SSS_LOEJ 0x02 - u_char control; -}; - - - -/* - * Opcodes - */ - -#define REASSIGN_BLOCKS 0x07 -#define READ_COMMAND 0x08 -#define WRITE_COMMAND 0x0a -#define MODE_SELECT 0x15 -#define MODE_SENSE 0x1a -#define START_STOP 0x1b -#define PREVENT_ALLOW 0x1e -#define READ_CAPACITY 0x25 -#define READ_BIG 0x28 -#define WRITE_BIG 0x2a - - - -struct scsi_read_cap_data -{ - u_char addr_3; /* Most significant */ - u_char addr_2; - u_char addr_1; - u_char addr_0; /* Least significant */ - u_char length_3; /* Most significant */ - u_char length_2; - u_char length_1; - u_char length_0; /* Least significant */ -}; - -struct scsi_reassign_blocks_data -{ - u_char reserved[2]; - u_char length_msb; - u_char length_lsb; - struct - { - u_char dlbaddr_3; /* defect logical block address (MSB) */ - u_char dlbaddr_2; - u_char dlbaddr_1; - u_char dlbaddr_0; /* defect logical block address (LSB) */ - } defect_descriptor[1]; -}; - -union disk_pages /* this is the structure copied from osf */ -{ - struct page_disk_format { - u_char pg_code; /* page code (should be 3) */ -#define DISK_PGCODE 0x3F /* only 6 bits valid */ - u_char pg_length; /* page length (should be 0x16) */ - u_char trk_z_1; /* tracks per zone (MSB) */ - u_char trk_z_0; /* tracks per zone (LSB) */ - u_char alt_sec_1; /* alternate sectors per zone (MSB) */ - u_char alt_sec_0; /* alternate sectors per zone (LSB) */ - u_char alt_trk_z_1; /* alternate tracks per zone (MSB) */ - u_char alt_trk_z_0; /* alternate tracks per zone (LSB) */ - u_char alt_trk_v_1; /* alternate tracks per volume (MSB) */ - u_char alt_trk_v_0; /* alternate tracks per volume (LSB) */ - u_char ph_sec_t_1; /* physical sectors per track (MSB) */ - u_char ph_sec_t_0; /* physical sectors per track (LSB) */ - u_char bytes_s_1; /* bytes per sector (MSB) */ - u_char bytes_s_0; /* bytes per sector (LSB) */ - u_char interleave_1;/* interleave (MSB) */ - u_char interleave_0;/* interleave (LSB) */ - u_char trk_skew_1; /* track skew factor (MSB) */ - u_char trk_skew_0; /* track skew factor (LSB) */ - u_char cyl_skew_1; /* cylinder skew (MSB) */ - u_char cyl_skew_0; /* cylinder skew (LSB) */ - u_char flags; /* various */ -#define DISK_FMT_SURF 0x10 -#define DISK_FMT_RMB 0x20 -#define DISK_FMT_HSEC 0x40 -#define DISK_FMT_SSEC 0x80 - u_char reserved21; - u_char reserved22; - u_char reserved23; - } disk_format; - struct page_rigid_geometry { - u_char pg_code; /* page code (should be 4) */ - u_char pg_length; /* page length (should be 0x16) */ - u_char ncyl_2; /* number of cylinders (MSB) */ - u_char ncyl_1; /* number of cylinders */ - u_char ncyl_0; /* number of cylinders (LSB) */ - u_char nheads; /* number of heads */ - u_char st_cyl_wp_2; /* starting cyl., write precomp (MSB) */ - u_char st_cyl_wp_1; /* starting cyl., write precomp */ - u_char st_cyl_wp_0; /* starting cyl., write precomp (LSB) */ - u_char st_cyl_rwc_2;/* starting cyl., red. write cur (MSB)*/ - u_char st_cyl_rwc_1;/* starting cyl., red. write cur */ - u_char st_cyl_rwc_0;/* starting cyl., red. write cur (LSB)*/ - u_char driv_step_1; /* drive step rate (MSB) */ - u_char driv_step_0; /* drive step rate (LSB) */ - u_char land_zone_2; /* landing zone cylinder (MSB) */ - u_char land_zone_1; /* landing zone cylinder */ - u_char land_zone_0; /* landing zone cylinder (LSB) */ - u_char rpl; /* rotational position locking (2 bits) */ - u_char rot_offset; /* rotational offset */ - u_char reserved19; - u_char medium_rot_rate_1; /* medium rotation rate (RPM) (MSB) */ - u_char medium_rot_rate_0; /* medium rotation rate (RPM) (LSB) */ - u_char reserved22; - u_char reserved23; - } rigid_geometry; -} ; -#endif /* _SCSI_SCSI_DISK_H*/ diff --git a/sys/scsi/scsi_driver.c b/sys/scsi/scsi_driver.c deleted file mode 100644 index 69f2278..0000000 --- a/sys/scsi/scsi_driver.c +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright (C) 1995, HD Associates, Inc. - * PO Box 276 - * Pepperell, MA 01463 - * 508 433 5266 - * dufault@hda.com - * - * This code is contributed to the University of California at Berkeley: - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id: scsi_driver.c,v 1.26 1997/09/02 20:06:34 bde Exp $ - * - */ - -#include "opt_scsi.h" - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/buf.h> - -#include <scsi/scsiconf.h> -#include <scsi/scsi_debug.h> -#include <scsi/scsi_driver.h> - -#define GETUNIT(DEVICE, DEV) \ - ((DEVICE)->getunit) ? (*(DEVICE)->getunit)((DEV)) \ - : (minor((DEV)) & ~SCSI_CONTROL_MASK) - -/* scsi_device_attach: Attach a SCSI device. This routine will - * print out the device address, what it is, then call the type - * attach function and when that returns print a newline. If the - * type attach will make LOT's of noise it should print a leading - * newline and then the address using sc_print_addr. See "sd.c". - */ -int scsi_device_attach(struct scsi_link *sc_link) -{ - errval errcode; - dev_t dev; - struct scsi_device *device = sc_link->device; - - if (bootverbose) - sc_link->flags |= SDEV_BOOTVERBOSE; - - SC_DEBUG(sc_link, SDEV_DB2, - ("%s%dattach: ", device->name, sc_link->dev_unit)); - - /* Print _sane_ probe info! */ - printf("%s%d at scbus%d target %d lun %d\n", - sc_link->device->name, sc_link->dev_unit, - sc_link->scsibus, sc_link->target, sc_link->lun); -#ifndef SCSIDEBUG - scsi_print_info(sc_link); -#endif - - printf("%s%d: %s ", device->name, sc_link->dev_unit, device->desc); - /* - * XXX some SCSI adapter drivers print out things while the - * device-specific attach routine is running. The result is - * something of a mess. This hack at least keeps it so each - * line will begin with foodev0:. - */ - sc_print_init(); - - dev = scsi_dev_lookup(device->open); - - sc_link->dev = (device->setunit ? - (*device->setunit)(dev, sc_link->dev_unit) : - makedev(major(dev), sc_link->dev_unit) ); - - errcode = (device->attach) ? (*(device->attach))(sc_link) : 0; - - printf("\n"); - sc_print_finish(); - - if (errcode == 0) - sc_link->flags |= device->link_flags; - - return errcode; -} - -int -scsi_open(dev_t dev, int flags, int fmt, struct proc *p, -struct scsi_device *device) -{ - errval errcode; - u_int32_t unit; - struct scsi_link *sc_link; - - if (device == 0) - return ENXIO; - - unit = GETUNIT(device, dev); - sc_link = SCSI_LINK(device, unit); - - /* - * Check the unit is legal - */ - if (sc_link == 0 || (sc_link->sd == 0 && !(sc_link->flags & SDEV_UK))) - return ENXIO; - - /* If it is a "once only" device that is already open return EBUSY. - */ - if ((sc_link->flags & SDEV_ONCE_ONLY) && (sc_link->flags & SDEV_IS_OPEN)) - return EBUSY; - - /* For the control device (user ioctl's only) don't call the open - * entry. - */ - if (SCSI_CONTROL(dev) || (device->dev_open == 0)) - { - scsi_test_unit_ready(sc_link, SCSI_SILENT); - errcode = 0; - } - else - errcode = (*device->dev_open)(dev, flags, fmt, p, sc_link); - - if (!errcode ) sc_link->flags |= SDEV_IS_OPEN; - - SC_DEBUG(sc_link, SDEV_DB1, ("%sopen: dev=0x%lx (unit %lu) result %d\n", - device->name, (u_long)dev, (u_long)unit, errcode)); - - return errcode; -} - -int -scsi_close(dev_t dev, int flags, int fmt, struct proc *p, -struct scsi_device *device) -{ - errval errcode; - struct scsi_link *sc_link = SCSI_LINK(device, GETUNIT(device, dev)); - - SC_DEBUG(sc_link, SDEV_DB1, ("%sclose: Closing device\n", device->name)); - - if (SCSI_CONTROL(dev) || (device->dev_close == 0)) - errcode = 0; - else - errcode = (*device->dev_close)(dev, flags, fmt, p, sc_link); - - sc_link->flags &= ~SDEV_IS_OPEN; - - return errcode; -} - -int -scsi_ioctl(dev_t dev, u_int32_t cmd, caddr_t arg, int flags, struct proc *p, -struct scsi_device *device) -{ - errval errcode; - struct scsi_link *sc_link = SCSI_LINK(device, GETUNIT(device, dev)); - - if (SCSI_CONTROL(dev) || (device->dev_ioctl == 0)) - errcode = scsi_do_ioctl(dev, cmd, arg, flags, p, sc_link); - else - errcode = (*device->dev_ioctl)(dev, cmd, arg, flags, p, sc_link); - - return errcode; -} - -void -scsi_minphys(struct buf *bp, struct scsi_device *device) -{ - struct scsi_link *sc_link = SCSI_LINK(device, GETUNIT(device, bp->b_dev)); - (*sc_link->adapter->scsi_minphys)(bp); -} - -void -scsi_strategy(struct buf *bp, struct scsi_device *device) -{ - u_int32_t unit = GETUNIT(device, bp->b_dev); - struct scsi_link *sc_link = SCSI_LINK(device, unit); - - SC_DEBUG(sc_link, SDEV_DB2, ("\n%sstrategy ", device->name)); - SC_DEBUG(sc_link, SDEV_DB1, ("%ld bytes @ blk%ld\n", - bp->b_bcount, (long)bp->b_blkno)); - - if (SCSI_CONTROL(bp->b_dev) || (device->dev_strategy == 0)) - { - bp->b_resid = bp->b_bcount; - bp->b_error = EIO; - bp->b_flags |= B_ERROR; - biodone(bp); - } - else - { - bp->b_resid = 0; - bp->b_error = 0; - - if (bp->b_bcount == 0) - biodone(bp); - else - { - (*sc_link->adapter->scsi_minphys)(bp); - (*device->dev_strategy)(bp, sc_link); - } - } -} - -int scsi_device_lock(struct scsi_link *sc_link) -{ - int error; - while (sc_link->flags & SDEV_XLOCK) { - sc_link->flags |= SDEV_WANT; - error = tsleep(&sc_link->flags, PRIBIO | PCATCH, "sdevlk",0); - if (error) - return error; - } - sc_link->flags |= SDEV_XLOCK; - return 0; -} - -void scsi_device_unlock(struct scsi_link *sc_link) -{ - sc_link->flags &= ~SDEV_XLOCK; - if (sc_link->flags & SDEV_WANT) { - sc_link->flags &= ~SDEV_WANT; - wakeup(&sc_link->flags); - } -} diff --git a/sys/scsi/scsi_driver.h b/sys/scsi/scsi_driver.h deleted file mode 100644 index 50f4851..0000000 --- a/sys/scsi/scsi_driver.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 1995, HD Associates, Inc. - * PO Box 276 - * Pepperell, MA 01463 - * 508 433 5266 - * dufault@hda.com - * - * This code is contributed to the University of California at Berkeley: - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id: scsi_driver.h,v 1.12 1997/06/25 19:07:42 tegge Exp $ - * - */ -#ifndef _SCSI__DRIVER_H_ -#define _SCSI__DRIVER_H_ - -#ifdef KERNEL - -struct scsi_link; -struct scsi_device; -struct buf; -struct proc; - -int scsi_device_attach __P((struct scsi_link *)); -int scsi_device_lock __P((struct scsi_link *)); -void scsi_device_unlock __P((struct scsi_link *)); - -int scsi_open __P((dev_t, int, int, struct proc *, struct scsi_device *)); -int scsi_close __P((dev_t, int, int, struct proc *, struct scsi_device *)); -int scsi_ioctl __P((dev_t, u_int32_t, caddr_t, int, struct proc *, - struct scsi_device *)); -void scsi_strategy __P((struct buf *, struct scsi_device *)); -void scsi_minphys __P((struct buf *, struct scsi_device *)); - -#endif /* KERNEL */ - -#endif /* _SCSI__DRIVER_H_ */ diff --git a/sys/scsi/scsi_generic.h b/sys/scsi/scsi_generic.h deleted file mode 100644 index 2cd6f6c..0000000 --- a/sys/scsi/scsi_generic.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Contributed by HD Associates (contact: dufault@hda.com) - * Copyright (c) 1992, 1993 HD Associates - * - * Berkeley style copyright. I've just snarfed it out of stdio.h: - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * from: @(#)stdio.h 5.17 (Berkeley) 6/3/91 - * $Id$ - */ - -/* generic SCSI header file. We use the same minor number format - * as on SGI except that the flag bits aren't available because they - * are used as the board index. - * - * The minor number format is: - * FF UUU III (FFUU UIII) - * - * Where: - * FF is the board index - * UUU are the LUN - * III is the SCSI ID (controller) - */ - -#ifndef _SCSI_GENERIC_H_ -#define _SCSI_GENERIC_H_ - -#define G_SCSI_FLAG(DEV) (((DEV) & 0xC0) >> 6) -#define G_SCSI_UNIT(DEV) G_SCSI_FLAG(DEV) -#define G_SCSI_LUN(DEV) (((DEV) & 0x38) >> 3) -#define G_SCSI_ID(DEV) ((DEV) & 0x7) - -#define G_SCSI_MINOR(FLAG, LUN, ID) \ - (((FLAG) << 6) | ((LUN) << 3) | (ID)) - -#endif /* _SCSI_GENERIC_H_ */ diff --git a/sys/scsi/scsi_ioctl.c b/sys/scsi/scsi_ioctl.c deleted file mode 100644 index c63de3a..0000000 --- a/sys/scsi/scsi_ioctl.c +++ /dev/null @@ -1,406 +0,0 @@ -/* - * Copyright (C) 1992, 1993, 1994, HD Associates, Inc. - * PO Box 276 - * Pepperell, MA 01463 - * 508 433 5266 - * dufault@hda.com - * - * This code is contributed to the University of California at Berkeley: - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - *End copyright - * - * $Id: scsi_ioctl.c,v 1.31 1998/06/07 17:12:49 dfr Exp $ - * - * - */ - -#include "opt_bounce.h" -#include "opt_scsi.h" - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/malloc.h> -#include <sys/buf.h> - -#define b_screq b_driver1 /* a patch in buf.h */ -#define b_sc_link b_driver2 /* a patch in buf.h */ - -#include <sys/fcntl.h> -#include <sys/proc.h> -#include <sys/uio.h> - -#include <scsi/scsiconf.h> -#include <scsi/scsi_debug.h> -#include <sys/scsiio.h> - -static void scsierr(struct buf *, int); /* XXX ??? */ - -/* - * We let the user interpret his own sense in the generic scsi world. - * This routine is called at interrupt time if the SCSI_USER bit was set - * in the flags passed to scsi_scsi_cmd(). No other completion processing - * takes place, even if we are running over another device driver. - * The lower level routines that call us here, will free the xs and restart - * the device's queue if such exists. - */ -#ifndef min -#define min(A,B) ((A<B) ? A : B ) -#endif - -void scsi_user_done(xs) -struct scsi_xfer *xs; -{ - - struct buf *bp; - scsireq_t *screq; - - bp = xs->bp; - if(!bp) { /* ALL user requests must have a buf */ - sc_print_addr(xs->sc_link); - printf("User command with no buf\n"); - return ; - } - screq = bp->b_screq; - if (!screq) { /* Is it one of ours? (the SCSI_USER bit says it is) */ - sc_print_addr(xs->sc_link); - printf("User command with no request\n"); - return ; - } - - SC_DEBUG(xs->sc_link,SDEV_DB2,("user-done\n")); - screq->retsts = 0; - screq->status = xs->status; - switch((int)xs->error) { - case XS_NOERROR: - SC_DEBUG(xs->sc_link,SDEV_DB3,("no error\n")); - if (xs->flags & SCSI_RESID_VALID) - screq->datalen_used = xs->datalen - xs->resid; - else - screq->datalen_used = xs->datalen; - screq->retsts = SCCMD_OK; - break; - - case XS_SENSE: - SC_DEBUG(xs->sc_link,SDEV_DB3,("have sense\n")); - screq->senselen_used = min(sizeof(xs->sense),SENSEBUFLEN); - bcopy(&xs->sense,screq->sense,screq->senselen); - screq->retsts = SCCMD_SENSE; - break; - - case XS_DRIVER_STUFFUP: - sc_print_addr(xs->sc_link); - printf("host adapter code inconsistency\n"); - screq->retsts = SCCMD_UNKNOWN; - break; - - case XS_TIMEOUT: - SC_DEBUG(xs->sc_link,SDEV_DB3,("timeout\n")); - screq->retsts = SCCMD_TIMEOUT; - break; - - case XS_BUSY: - SC_DEBUG(xs->sc_link,SDEV_DB3,("busy\n")); - screq->retsts = SCCMD_BUSY; - break; - - default: - sc_print_addr(xs->sc_link); - printf("unknown error category from host adapter code\n"); - screq->retsts = SCCMD_UNKNOWN; - break; - } - biodone(bp); /* we're waiting on it in scsistrategy() */ - return; /* it'll free the xs and restart any queue */ -} - - -/* Pseudo strategy function - * Called by scsi_do_ioctl() via physio/physstrat if there is to - * be data transfered, and directly if there is no data transfer. - * - * Can't be used with block devices or raw_read/raw_write directly - * from the cdevsw/bdevsw tables because they couldn't have added - * the screq structure. [JRE] - */ -static void -scsistrategy(struct buf *bp) -{ - errval err; - struct scsi_link *sc_link = bp->b_sc_link; - scsireq_t *screq; - u_int32_t flags = 0; - int s; - - - if(!sc_link) { - printf("user_strat: No link pointer\n"); - scsierr(bp,EINVAL); - return; - } - SC_DEBUG(sc_link,SDEV_DB2,("user_strategy\n")); - screq = bp->b_screq; - if(!screq) { - sc_print_addr(sc_link); - printf("No request block\n"); - scsierr(bp,EINVAL); - return; - } - - /* We're in trouble if physio tried to break up the - * transfer: - */ - if (bp->b_bcount != screq->datalen) { - sc_print_addr(sc_link); - printf("physio split the request.. cannot proceed\n"); - scsierr(bp, EIO); - return; - } - - if (screq->timeout == 0) { - scsierr(bp, EINVAL); - return; - } - - if (screq->cmdlen > sizeof(struct scsi_generic)) { - sc_print_addr(sc_link); - printf("cmdlen too big "); - scsierr(bp, EFAULT); - return; - } - - - if (screq->flags & SCCMD_READ) - flags |= SCSI_DATA_IN; - - if (screq->flags & SCCMD_WRITE) - flags |= SCSI_DATA_OUT; - - if (screq->flags & SCCMD_TARGET) - flags |= SCSI_TARGET; - - if (screq->flags & SCCMD_ESCAPE) - flags |= SCSI_ESCAPE; - -#ifdef BOUNCE_BUFFERS - if (sc_link->flags & SDEV_BOUNCE) - vm_bounce_alloc(bp); -#endif - - err = scsi_scsi_cmd(sc_link, - (struct scsi_generic *)screq->cmd, - screq->cmdlen, - (u_char *)bp->b_data, - screq->datalen, - 0, /* user must do the retries *//* ignored */ - screq->timeout, - bp, - flags | SCSI_USER); - - - - /*because there is a bp, scsi_scsi_cmd will return immediatly*/ - if (err) - { - scsierr(bp, err); - return; - } - SC_DEBUG(sc_link,SDEV_DB3,("about to sleep\n")); - s = splbio(); - while(!(bp->b_flags & B_DONE)) - { - tsleep((caddr_t)bp, PRIBIO, "scsistrat", 0); - } - splx(s); - SC_DEBUG(sc_link,SDEV_DB3,("back from sleep\n")); - return; -} - -/* - * Something (e.g. another driver) has called us - * with an sc_link for a target/lun/adapter, and a scsi - * specific ioctl to perform, better try. - * If user-level type command, we must still be running - * in the context of the calling process - */ -errval scsi_do_ioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, -struct proc *p, struct scsi_link *sc_link) -{ - errval ret = 0; - - /* If we can't write the device we can't permit much: - */ - - if (cmd != SCIOCIDENTIFY && cmd != SCIOCGETDEVINFO&& !(flags & FWRITE)) - return EACCES; - - SC_DEBUG(sc_link,SDEV_DB2, ("scsi_do_ioctl(0x%lx)\n", cmd)); - switch(cmd) - { - case SCIOCCOMMAND: - { - /* - * You won't believe this, but the arg copied in - * from the user space, is on the kernel stack - * for this process, so we can't write - * to it at interrupt time.. - * we need to copy it in and out! - * Make a static copy using malloc! - */ - scsireq_t *screq2 = (scsireq_t *)addr; - scsireq_t *screq = (scsireq_t *)addr; - int rwflag = (screq->flags & SCCMD_READ) ? B_READ : B_WRITE; - struct buf *bp; - caddr_t d_addr; - int len; - -#if 0 /* XXX dufault@hda.com: This looks too rev dependent. Do it always? */ - if((unsigned int)screq < (unsigned int)KERNBASE) -#endif - { - screq = malloc(sizeof(scsireq_t),M_TEMP,M_WAITOK); - bcopy(screq2,screq,sizeof(scsireq_t)); - } - bp = malloc(sizeof (struct buf),M_TEMP,M_WAITOK); - bzero(bp,sizeof(struct buf)); - d_addr = screq->databuf; - bp->b_bcount = len = screq->datalen; - bp->b_screq = screq; - bp->b_sc_link = sc_link; - if (len) { - struct uio auio; - struct iovec aiov; - long cnt; - - aiov.iov_base = d_addr; - aiov.iov_len = len; - auio.uio_iov = &aiov; - auio.uio_iovcnt = 1; - - auio.uio_resid = len; - if (auio.uio_resid < 0) - return (EINVAL); - - auio.uio_rw = (rwflag == B_READ) ? UIO_READ : UIO_WRITE; - auio.uio_segflg = UIO_USERSPACE; - auio.uio_procp = curproc; - cnt = len; - ret = physio(scsistrategy, bp, dev, rwflag, - minphys, &auio); - } else { - /* if no data, no need to translate it.. */ - bp->b_data = 0; - bp->b_dev = dev; - bp->b_flags |= B_BUSY; - - scsistrategy(bp); - ret = bp->b_error; - } - free(bp,M_TEMP); -#if 0 /* XXX dufault@hda.com: This looks too rev dependent. Do it always? */ - if((unsigned int)screq2 < (unsigned int)KERNBASE) -#endif - { - bcopy(screq,screq2,sizeof(scsireq_t)); - free(screq,M_TEMP); - } - break; - } - case SCIOCDEBUG: - { - int level = *((int *)addr); - SC_DEBUG(sc_link,SDEV_DB3,("debug set to %d\n",level)); - sc_link->flags &= ~SDEV_DBX; /*clear debug bits */ - if(level & 1) sc_link->flags |= SDEV_DB1; - if(level & 2) sc_link->flags |= SDEV_DB2; - if(level & 4) sc_link->flags |= SDEV_DB3; - if(level & 8) sc_link->flags |= SDEV_DB4; - ret = 0; - break; - } - case SCIOCREPROBE: - { - struct scsi_addr *sca = (struct scsi_addr *) addr; - - ret = scsi_probe_busses(sca->scbus,sca->target,sca->lun); - break; - } - case SCIOCRECONFIG: - case SCIOCDECONFIG: - ret = EINVAL; - break; - - case SCIOCIDENTIFY: - { - struct scsi_addr *sca = (struct scsi_addr *) addr; - sca->scbus = sc_link->scsibus; - sca->target = sc_link->target; - sca->lun = sc_link->lun; - break; - } - case SCIOCGETDEVINFO: - { - struct scsi_devinfo *scd = (struct scsi_devinfo *)addr; - struct scsi_link *scl; - scl = scsi_link_get(scd->addr.scbus, scd->addr.target, - scd->addr.lun); - if (scl != 0) { - scd->dev = scl->dev; - /* XXX buffers better be big enough... */ - sprintf(scd->devname, "%s%d", - scl->device->name, scl->dev_unit); - sprintf(scd->adname, "%s%d:%d", - scl->adapter->name, scl->adapter_unit, - scl->adapter_bus); - ret = 0; - } else { - ret = ENXIO; - } - break; - } - - default: - ret = ENOTTY; - break; - } - - return ret; -} - -void -scsierr(bp,err) - struct buf *bp; - int err; -{ - bp->b_flags |= B_ERROR; - bp->b_error = err; - biodone(bp); - return; -} - diff --git a/sys/scsi/scsi_message.h b/sys/scsi/scsi_message.h deleted file mode 100644 index 7163d49..0000000 --- a/sys/scsi/scsi_message.h +++ /dev/null @@ -1,37 +0,0 @@ -/* Messages (1 byte) */ /* I/T (M)andatory or (O)ptional */ -#define MSG_CMDCOMPLETE 0x00 /* M/M */ -#define MSG_EXTENDED 0x01 /* O/O */ -#define MSG_SAVEDATAPOINTER 0x02 /* O/O */ -#define MSG_RESTOREPOINTERS 0x03 /* O/O */ -#define MSG_DISCONNECT 0x04 /* O/O */ -#define MSG_INITIATOR_DET_ERR 0x05 /* M/M */ -#define MSG_ABORT 0x06 /* O/M */ -#define MSG_MESSAGE_REJECT 0x07 /* M/M */ -#define MSG_NOOP 0x08 /* M/M */ -#define MSG_PARITY_ERROR 0x09 /* M/M */ -#define MSG_LINK_CMD_COMPLETE 0x0a /* O/O */ -#define MSG_LINK_CMD_COMPLETEF 0x0b /* O/O */ -#define MSG_BUS_DEV_RESET 0x0c /* O/M */ -#define MSG_ABORT_TAG 0x0d /* O/O */ -#define MSG_CLEAR_QUEUE 0x0e /* O/O */ -#define MSG_INIT_RECOVERY 0x0f /* O/O */ -#define MSG_REL_RECOVERY 0x10 /* O/O */ -#define MSG_TERM_IO_PROC 0x11 /* O/O */ - -/* Messages (2 byte) */ -#define MSG_SIMPLE_Q_TAG 0x20 /* O/O */ -#define MSG_HEAD_OF_Q_TAG 0x21 /* O/O */ -#define MSG_ORDERED_Q_TAG 0x22 /* O/O */ -#define MSG_IGN_WIDE_RESIDUE 0x23 /* O/O */ - -/* Identify message */ /* M/M */ -#define MSG_IDENTIFYFLAG 0x80 -#define MSG_IDENTIFY(lun, disc) (((disc) ? 0xc0 : MSG_IDENTIFYFLAG) | (lun)) -#define MSG_ISIDENTIFY(m) ((m) & MSG_IDENTIFYFLAG) - -/* Extended messages (opcode and length) */ -#define MSG_EXT_SDTR 0x01 -#define MSG_EXT_SDTR_LEN 0x03 - -#define MSG_EXT_WDTR 0x03 -#define MSG_EXT_WDTR_LEN 0x02 diff --git a/sys/scsi/scsi_sense.c b/sys/scsi/scsi_sense.c deleted file mode 100644 index 3dfc0ef..0000000 --- a/sys/scsi/scsi_sense.c +++ /dev/null @@ -1,309 +0,0 @@ -#include "opt_scsi.h" - -#include <sys/param.h> - -#include <scsi/scsiconf.h> - -/* XXX There should be a way for a type driver to have its own - * private senses and add them when it is added. - */ - -#if !defined(NO_SCSI_SENSE) - -#include "sd.h" -#include "st.h" -#define NSPRINT 0 -#include "pt.h" -#include "worm.h" -#include "cd.h" -#define NSCAN 0 -#include "od.h" -#include "ch.h" -#define NCOMM 0 - -static struct -{ - u_char asc; - u_char ascq; - char *desc; -} tab[] = { -#if (NCH > 0) - {0x28, 0x01, "Import or export element accessed" }, - {0x21, 0x01, "Invalid element address" }, - {0x3b, 0x0d, "Medium destination element full" }, - {0x3b, 0x0e, "Medium source element empty" }, -#endif -#if (NOD > 0) - {0x58, 0x00, "Generation does not exist" }, - {0x59, 0x00, "Updated block read" }, -#endif -#if (NSCAN > 0) - {0x2c, 0x02, "Invalid combination of windows specified" }, - {0x60, 0x00, "Lamp failure" }, - {0x61, 0x02, "Out of focus" }, - {0x3b, 0x0c, "Position past beginning of medium" }, - {0x3b, 0x0b, "Position past end of medium" }, - {0x3b, 0x0a, "Read past beginning of medium" }, - {0x3b, 0x09, "Read past end of medium" }, - {0x62, 0x00, "Scan head positioning error" }, - {0x2c, 0x01, "Too many windows specified" }, - {0x61, 0x01, "Unable to acquire video" }, - {0x61, 0x00, "Video acquisition error" }, -#endif -#if (NCD > 0) - {0x00, 0x11, "Audio play operation in progress" }, - {0x00, 0x12, "Audio play operation paused" }, - {0x00, 0x14, "Audio play operation stopped due to error" }, - {0x00, 0x13, "Audio play operation successfully completed" }, - {0x63, 0x00, "End of user area encountered on this track" }, - {0x64, 0x00, "Illegal mode for this track" }, - {0x00, 0x15, "No current audio status to return" }, - {0x18, 0x03, "Recovered data with CIRC" }, - {0x18, 0x04, "Recovered data with L-EC" }, - {0x57, 0x00, "Unable to recover table-of-contents" }, -#endif -#if (NWORM > 0)||(NOD > 0) - {0x11, 0x07, "Data resynchronization error" }, -#endif -#if (NWORM > 0)||(NCD > 0)||(NOD > 0) - {0x11, 0x06, "Circ unrecovered error" }, - {0x09, 0x02, "Focus servo failure" }, - {0x11, 0x05, "L-EC uncorrectable error" }, - {0x17, 0x04, "Recovered data with retries and/or CIRC applied" }, - {0x09, 0x03, "Spindle servo failure" }, - {0x09, 0x01, "Tracking servo failure" }, -#endif -#if (NPT > 0) - {0x54, 0x00, "SCSI to host system interface failure" }, - {0x55, 0x00, "System resource failure" }, -#endif -#if (NSPRINT > 0) - {0x3b, 0x07, "Failed to sense bottom-of-form" }, - {0x3b, 0x06, "Failed to sense top-of-form" }, - {0x3b, 0x05, "Paper jam" }, - {0x36, 0x00, "Ribbon, ink, or toner failure" }, - {0x3b, 0x04, "Slew failure" }, - {0x3b, 0x03, "Tape or electronic vertical forms unit not ready" }, -#endif -#if (NST > 0) - {0x14, 0x04, "Block sequence error" }, - {0x52, 0x00, "Cartridge fault" }, - {0x14, 0x03, "End-of-data not found" }, - {0x03, 0x02, "Excessive write errors" }, - {0x00, 0x01, "Filemark detected" }, - {0x14, 0x02, "Filemark or setmark not found" }, - {0x11, 0x08, "Incomplete block read" }, - {0x11, 0x09, "No gap found" }, - {0x03, 0x01, "No write current" }, - {0x2d, 0x00, "Overwrite error on update in place" }, - {0x50, 0x02, "Position error related to timing" }, - {0x3b, 0x08, "Reposition error" }, - {0x00, 0x03, "Setmark detected" }, - {0x33, 0x00, "Tape length error" }, - {0x3b, 0x01, "Tape position error at beginning-of-medium" }, - {0x3b, 0x02, "Tape position error at end-of-medium" }, - {0x53, 0x01, "Unload tape failure" }, - {0x50, 0x00, "Write append error" }, - {0x50, 0x01, "Write append position error" }, -#endif -#if (NST > 0)||(NOD > 0) - {0x51, 0x00, "Erase failure" }, -#endif -#if (NST > 0)||(NSCAN > 0) - {0x00, 0x04, "Beginning-of-partition/medium detected" }, - {0x00, 0x05, "End-of-data detected" }, - {0x00, 0x02, "End-of-partition/medium detected" }, - {0x0c, 0x00, "Write error" }, -#endif -#if (NST > 0)||(NSPRINT > 0) - {0x3b, 0x00, "Sequential positioning error" }, -#endif -#if (NSD > 0) - {0x41, 0x00, "Data path failure (should use 40 nn)" }, - {0x22, 0x00, "Illegal function (should use 20 00, 24 00, or 26 00)" }, - {0x42, 0x00, "Power-on or self-test failure (should use 40 nn)" }, - {0x40, 0x00, "Ram failure (should use 40 nn)" }, -#endif -#if (NSD > 0)||(NOD > 0) - {0x19, 0x00, "Defect list error" }, - {0x19, 0x03, "Defect list error in grown list" }, - {0x19, 0x02, "Defect list error in primary list" }, - {0x19, 0x01, "Defect list not available" }, - {0x1c, 0x00, "Defect list not found" }, - {0x1c, 0x02, "Grown defect list not found" }, - {0x1c, 0x01, "Primary defect list not found" }, - {0x5c, 0x00, "RPL status change" }, - {0x5c, 0x02, "Spindles not synchronized" }, - {0x5c, 0x01, "Spindles synchronized" }, -#endif -#if (NSD > 0)||(NWORM > 0)||(NOD > 0) - {0x13, 0x00, "Address mark not found for data field" }, - {0x12, 0x00, "Address mark not found for id field" }, - {0x16, 0x00, "Data synchronization mark error" }, - {0x32, 0x01, "Defect list update failure" }, - {0x10, 0x00, "Id CRC or ECC error" }, - {0x1d, 0x00, "Miscompare during verify operation" }, - {0x32, 0x00, "No defect spare location available" }, - {0x01, 0x00, "No index/sector signal" }, - {0x17, 0x06, "Recovered data without ECC - data auto-reallocated" }, - {0x17, 0x07, "Recovered data without ECC - recommend reassignment" }, - {0x17, 0x08, "Recovered data without ECC - recommend rewrite" }, - {0x1e, 0x00, "Recovered ID with ECC correction" }, - {0x11, 0x04, "Unrecovered read error - auto reallocate failed" }, - {0x11, 0x0b, "Unrecovered read error - recommend reassignment" }, - {0x11, 0x0c, "Unrecovered read error - recommend rewrite the data" }, - {0x0c, 0x02, "Write error - auto reallocation failed" }, - {0x0c, 0x01, "Write error recovered with auto reallocation" }, -#endif -#if (NSD > 0)||(NWORM > 0)||(NCD > 0)||(NOD > 0) - {0x18, 0x02, "Recovered data - data auto-reallocated" }, - {0x18, 0x05, "Recovered data - recommend reassignment" }, - {0x18, 0x06, "Recovered data - recommend rewrite" }, - {0x17, 0x05, "Recovered data using previous sector id" }, - {0x18, 0x01, "Recovered data with error correction & retries applied" }, -#endif -#if (NSD > 0)||(NWORM > 0)||(NCD > 0)||(NOD > 0)||(NCH > 0) - {0x06, 0x00, "No reference position found" }, - {0x02, 0x00, "No seek complete" }, -#endif -#if (NSD > 0)||(NSPRINT > 0)||(NOD > 0) - {0x31, 0x01, "Format command failed" }, -#endif -#if (NSD > 0)||(NST > 0) - {0x30, 0x03, "Cleaning cartridge installed" }, -#endif -#if (NSD > 0)||(NST > 0)||(NOD > 0) - {0x11, 0x0a, "Miscorrected error" }, -#endif -#if (NSD > 0)||(NST > 0)||(NWORM > 0)||(NOD > 0) - {0x31, 0x00, "Medium format corrupted" }, - {0x5a, 0x03, "Operator selected write permit" }, - {0x5a, 0x02, "Operator selected write protect" }, - {0x27, 0x00, "Write protected" }, -#endif -#if (NSD > 0)||(NST > 0)||(NWORM > 0)||(NSCAN > 0)||(NOD > 0) - {0x11, 0x02, "Error too long to correct" }, - {0x11, 0x03, "Multiple read errors" }, - {0x11, 0x01, "Read retries exhausted" }, -#endif -#if (NSD > 0)||(NST > 0)||(NWORM > 0)||(NCD > 0)||(NOD > 0) - {0x30, 0x02, "Cannot read medium - incompatible format" }, - {0x30, 0x01, "Cannot read medium - unknown format" }, - {0x15, 0x02, "Positioning error detected by read of medium" }, - {0x14, 0x01, "Record not found" }, - {0x18, 0x00, "Recovered data with error correction applied" }, - {0x17, 0x03, "Recovered data with negative head offset" }, - {0x17, 0x02, "Recovered data with positive head offset" }, - {0x09, 0x00, "Track following error" }, -#endif -#if (NSD > 0)||(NST > 0)||(NWORM > 0)||(NCD > 0)||(NOD > 0)||(NCH > 0) - {0x30, 0x00, "Incompatible medium installed" }, - {0x21, 0x00, "Logical block address out of range" }, - {0x53, 0x02, "Medium removal prevented" }, - {0x5a, 0x01, "Operator medium removal request" }, -#endif -#if (NSD > 0)||(NST > 0)||(NWORM > 0)||(NCD > 0)||(NSCAN > 0)||(NOD > 0) - {0x17, 0x00, "Recovered data with no error correction applied" }, - {0x17, 0x01, "Recovered data with retries" }, - {0x11, 0x00, "Unrecovered read error" }, -#endif -#if (NSD > 0)||(NST > 0)||(NSPRINT > 0)||(NOD > 0) - {0x04, 0x04, "Logical unit not ready, format in progress" }, -#endif -#if (NSD > 0)||(NST > 0)||(NSPRINT > 0)||(NWORM > 0)||(NSCAN > 0)||(NOD > 0) - {0x03, 0x00, "Peripheral device write fault" }, -#endif -#if (NSD > 0)||(NST > 0)||(NSPRINT > 0)||(NWORM > 0)||(NCD > 0)||(NSCAN > 0)||(NOD > 0) - {0x14, 0x00, "Recorded entity not found" }, -#endif -#if (NSD > 0)||(NST > 0)||(NSPRINT > 0)||(NWORM > 0)||(NCD > 0)||(NSCAN > 0)||(NOD > 0)||(NCH > 0) - {0x15, 0x01, "Mechanical positioning error" }, - {0x53, 0x00, "Media load or eject failed" }, - {0x3a, 0x00, "Medium not present" }, - {0x07, 0x00, "Multiple peripheral devices selected" }, - {0x15, 0x00, "Random positioning error" }, -#endif -#if (NSD > 0)||(NST > 0)||(NSPRINT > 0)||(NWORM > 0)||(NCD > 0)||(NSCAN > 0)||(NOD > 0)||(NCH > 0)||(ncomm > 0) - {0x2a, 0x02, "Log parameters changed" }, - {0x08, 0x00, "Logical unit communication failure" }, - {0x08, 0x02, "Logical unit communication parity error" }, - {0x08, 0x01, "Logical unit communication time-out" }, - {0x2a, 0x01, "Mode parameters changed" }, - {0x2a, 0x00, "Parameters changed" }, - {0x37, 0x00, "Rounded parameter" }, - {0x39, 0x00, "Saving parameters not supported" }, -#endif -#if (NSD > 0)||(NST > 0)||(NSPRINT > 0)||(NPT > 0)||(NWORM > 0)||(NCD > 0)||(NSCAN > 0)||(NOD > 0)||(ncomm > 0) - {0x2b, 0x00, "Copy cannot execute since host cannot disconnect" }, -#endif -#if (NSD > 0)||(NST > 0)||(NSPRINT > 0)||(NPT > 0)||(NWORM > 0)||(NCD > 0)||(NSCAN > 0)||(NOD > 0)||(NCH > 0) - {0x5b, 0x02, "Log counter at maximum" }, - {0x5b, 0x00, "Log exception" }, - {0x5b, 0x03, "Log list codes exhausted" }, - {0x5a, 0x00, "Operator request or state change input (unspecified)" }, - {0x5b, 0x01, "Threshold condition met" }, -#endif - {0x3f, 0x02, "Changed operating definition" }, - {0x4a, 0x00, "Command phase error" }, - {0x2c, 0x00, "Command sequence error" }, - {0x2f, 0x00, "Commands cleared by another initiator" }, - {0x4b, 0x00, "Data phase error" }, -/* {0x40, 0xnn, "Diagnostic failure on component nn (80h-ffh)" }, */ - {0x0a, 0x00, "Error log overflow" }, - {0x00, 0x06, "I/O process terminated" }, - {0x48, 0x00, "Initiator detected error message received" }, - {0x3f, 0x03, "Inquiry data has changed" }, - {0x44, 0x00, "Internal target failure" }, - {0x3d, 0x00, "Invalid bits in identify message" }, - {0x20, 0x00, "Invalid command operation code" }, - {0x24, 0x00, "Invalid field in CDB" }, - {0x26, 0x00, "Invalid field in parameter list" }, - {0x49, 0x00, "Invalid message error" }, - {0x05, 0x00, "Logical unit does not respond to selection" }, - {0x4c, 0x00, "Logical unit failed self-configuration" }, - {0x3e, 0x00, "Logical unit has not self-configured yet" }, - {0x04, 0x01, "Logical unit is in process of becoming ready" }, - {0x04, 0x00, "Logical unit not ready, cause not reportable" }, - {0x04, 0x02, "Logical unit not ready, initializing command required" }, - {0x04, 0x03, "Logical unit not ready, manual intervention required" }, - {0x25, 0x00, "Logical unit not supported" }, - {0x43, 0x00, "Message error" }, - {0x3f, 0x01, "Microcode has been changed" }, - {0x00, 0x00, "No additional sense information" }, - {0x28, 0x00, "Not ready to ready transition, medium may have changed" }, - {0x4e, 0x00, "Overlapped commands attempted" }, - {0x1a, 0x00, "Parameter list length error" }, - {0x26, 0x01, "Parameter not supported" }, - {0x26, 0x02, "Parameter value invalid" }, - {0x29, 0x00, "Power on, reset, or bus device reset occurred" }, - {0x47, 0x00, "SCSI parity error" }, - {0x45, 0x00, "Select or reselect failure" }, - {0x1b, 0x00, "Synchronous data transfer error" }, - {0x3f, 0x00, "Target operating conditions have changed" }, - {0x26, 0x03, "Threshold parameters not supported" }, - {0x46, 0x00, "Unsuccessful soft reset" }, -}; - -char *scsi_sense_desc(int asc, int ascq) -{ - int i; - - if (asc >= 0x80 && asc <= 0xff) - return "Vendor Specific ASC"; - - if (ascq >= 0x80 && ascq <= 0xff) - return "Vendor Specific ASCQ"; - - for (i = 0; i < sizeof(tab) / sizeof(tab[0]); i++) - if (tab[i].asc == asc && tab[i].ascq == ascq) - return tab[i].desc; - - return ""; -} - -#else /* NO_SCSI_SENSE */ -char *scsi_sense_desc(int asc, int ascq) -{ - return ""; -} -#endif diff --git a/sys/scsi/scsi_tape.h b/sys/scsi/scsi_tape.h deleted file mode 100644 index 5b16574..0000000 --- a/sys/scsi/scsi_tape.h +++ /dev/null @@ -1,247 +0,0 @@ -/* - * SCSI tape interface description - */ - -/* - * Written by Julian Elischer (julian@tfs.com) - * for TRW Financial Systems. - * - * 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. - * - */ - -/* - * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 - * - * $Id$ - */ -#ifndef SCSI_SCSI_TAPE_H -#define SCSI_SCSI_TAPE_H 1 - - - -/* - * SCSI command formats - */ - - -struct scsi_rw_tape -{ - u_char op_code; - u_char byte2; -#define SRWT_FIXED 0x01 - u_char len[3]; - u_char control; -}; - -struct scsi_space -{ - u_char op_code; - u_char byte2; -#define SS_CODE 0x03 - u_char number[3]; - u_char control; -}; -#define SP_BLKS 0 -#define SP_FILEMARKS 1 -#define SP_SEQ_FILEMARKS 2 -#define SP_EOM 3 - -struct scsi_write_filemarks -{ - u_char op_code; - u_char byte2; - u_char number[3]; - u_char control; -}; - -struct scsi_rewind -{ - u_char op_code; - u_char byte2; -#define SR_IMMED 0x01 - u_char unused[3]; - u_char control; -}; - -/* -** Tape erase - AKL: Andreas Klemm <andreas@knobel.gun.de> -*/ -struct scsi_erase -{ - u_char op_code; - u_char byte2; -#define SE_LONG 0x01 /* - ** Archive Viper 2525 doesn't allow short - ** erase, other tapes possibly don't allow - ** that, too. - */ -#define SE_IMMED 0x02 - u_char unused[3]; - u_char control; -}; - -struct scsi_load -{ - u_char op_code; - u_char byte2; -#define SL_IMMED 0x01 - u_char unused[2]; - u_char how; - u_char control; -}; -#define LD_UNLOAD 0 -#define LD_LOAD 1 -#define LD_RETEN 2 - - -struct scsi_blk_limits -{ - u_char op_code; - u_char byte2; - u_char unused[3]; - u_char control; -}; - -/* - * Opcodes - */ - -#define REWIND 0x01 -#define READ_BLK_LIMITS 0x05 -#define READ_COMMAND_TAPE 0x08 -#define WRITE_COMMAND_TAPE 0x0a -#define WRITE_FILEMARKS 0x10 -#define SPACE 0x11 -#define ERASE 0x19 -#define LOAD_UNLOAD 0x1b - - - -struct scsi_blk_limits_data -{ - u_char reserved; - u_char max_length_2; /* Most significant */ - u_char max_length_1; - u_char max_length_0; /* Least significant */ - u_char min_length_1; /* Most significant */ - u_char min_length_0; /* Least significant */ -}; - -/* defines for the device specific byte in the mode select/sense header */ -#define SMH_DSP_SPEED 0x0F -#define SMH_DSP_BUFF_MODE 0x70 -#define SMH_DSP_BUFF_MODE_OFF 0x00 -#define SMH_DSP_BUFF_MODE_ON 0x10 -#define SMH_DSP_BUFF_MODE_MLTI 0x20 -#define SMH_DSP_WRITE_PROT 0x80 - -/* A special for the CIPHER ST150S(old drive) */ -struct blk_desc_cipher -{ - u_char density; - u_char nblocks[3]; - u_char reserved; - u_char blklen[3]; - u_char other; -#define ST150_SEC 0x01 /* soft error count */ -#define SR150_AUI 0x02 /* autoload inhibit */ -}; - -/* - * This structure defines the various mode pages that tapes know about. - */ -#define PAGE_HEADERLEN 2 -struct tape_pages -{ - u_char pg_code; /* page code */ -#define ST_PAGE_CONFIGURATION 0x10 -#define ST_PAGE_MEDIUM_PART 0x11 -#define ST_PAGE_MEDIUM_PART2 0x12 -#define ST_PAGE_MEDIUM_PART3 0x13 -#define ST_PAGE_MEDIUM_PART4 0x14 -#define ST_P_CODE 0x3F /* page code */ -#define ST_P_PS 0x80 /* page savable */ - u_char pg_length; /* page length */ - union - { - struct - { - u_char active_format; /* active format for density*/ -#define ST_P_CAP 0x40 /* change active Partition */ -#define ST_P_CAF 0x20 /* change active format */ -#define ST_P_AF 0x1F /* active format */ - u_char active_partition; /* */ - u_char write_buffer_full_ratio; /* highwater writing*/ - u_char read_buffer_empty_ratio; /* lowwater reading*/ - u_char write_delay_high; /* # 100mSecs before flush*/ - u_char write_delay_low; /* of buffer to the media */ - u_char flags1; /* various single bit flags */ -#define ST_P_DBR 0x80 /* supports data-buffer recovery */ -#define ST_P_BIS 0x40 /* supports Block_ID */ -#define ST_P_RSmk 0x20 /* Reports setmarks during reads and spaces */ -#define ST_P_AVC 0x10 /* Supports Automatic Velocity Control */ -#define ST_P_SOCF 0x0C /* Stop On Consecutive Filemarks, */ -#define ST_P_RBO 0x02 /* Recoverd Buffered Data order, 1 = LIFO */ -#define ST_P_REW 0x01 /* Report Early Warning (see SEW) */ - u_char gap_size; /*I/B gap, 1=min 0=default */ - u_char flags2; /* various single bit flags */ -#define ST_P_EOD 0xE0 /* What is and EOD....*/ -#define ST_P_EOD_DEF 0x00 /* Drive's default */ -#define ST_P_EOD_FMT 0x20 /* define by format */ -#define ST_P_EOD_SOCF 0x40 /* define by SOCF (above) */ -#define ST_P_EEG 0x10 /* use EOD above */ -#define ST_P_SEW 0x04 /* Synchronise at Early warning.. flush buffers*/ - u_char early_warn_high;/* buf size at early warning */ - u_char early_warn_med; /* after early warning, only */ - u_char early_warn_low; /* buufer this much data */ - u_char data_compress_alg; /* 0 = off, 1 = default */ - u_char reserved; /* The standard says so */ - } configuration; - struct - { -#define ST_MAXPARTS 16 /*for now*/ - u_char max_add_parts; /* that drive allows */ - u_char parts_defined; /* max min(ST_MAXPARTS,max_add_parts) */ - u_char flags; -#define ST_P_FDP 0x80 -#define ST_P_SDP 0x40 -#define ST_P_IDP 0x20 -#define ST_P_PSUM 0x18 /* units of part defs.. */ -#define ST_P_PSUM_BYTES 0x0 /* units of part defs.. */ -#define ST_P_PSUM_KBYTES 0x08 /* units of part defs.. */ -#define ST_P_PSUM_MBYTES 0x10 /* units of part defs.. */ - u_char medium_format_recog; -#define ST_P_REC_NONE 0x00 -#define ST_P_REC_FMT 0x01 /* can recognise format of new media */ -#define ST_P_REC_PART 0x02 /* can recognise partitions of new media */ -#define ST_P_REC_FMT_PART 0x03 /* can recognise format and parts */ - u_char reserved1; - u_char reserved2; - struct - { - u_char high; - u_char low; - }part[ST_MAXPARTS]; - } medium_partition; - struct - { - struct - { - u_char high; - u_char low; - }part[ST_MAXPARTS]; - } medium_partition_extra; - }pages; -}; - - -#endif /*SCSI_SCSI_TAPE_H*/ diff --git a/sys/scsi/scsi_worm.h b/sys/scsi/scsi_worm.h deleted file mode 100644 index 6f8fc61..0000000 --- a/sys/scsi/scsi_worm.h +++ /dev/null @@ -1,128 +0,0 @@ -#ifndef _SCSI_SCSI_WORM_H -#define _SCSI_SCSI_WORM_H - -#define PAGE_HEADERLEN 2 - -/* - * Opcodes - */ - -#define REZERO_UNIT 0x01 /* re-init; XXX belongs to scsi_all? */ -#define SYNCHRONIZE_CACHE 0x35 /* flush write buffer, close wr chn */ -#define FIRST_WRITEABLE_ADDR 0xe2 /* return first available LBA */ -#define RESERVE_TRACK 0xe4 /* reserve a track for later write */ -#define READ_TRACK_INFORMATION 0xe5 /* get info for a particular track */ -#define WRITE_TRACK 0xe6 /* open the write channel */ -#define LOAD_UNLOAD 0xe7 /* resembles part of START_STOP */ -#define FIXATION 0xe9 /* write leadin/leadout */ -#define WRITE_SESSION 0xed /* guide to write a new session */ -#define READ_SESSION_INFO 0xee /* read leadin/leadout lengths */ - -struct scsi_rezero_unit -{ - u_char op_code; - u_char byte2; - u_char reserved[3]; - u_char control; -}; - -struct scsi_synchronize_cache -{ - u_char op_code; - u_char byte2; - u_char reserved[7]; - u_char control; -}; - -/* struct scsi_first_writeable_address; */ - -struct scsi_reserve_track -{ - u_char op_code; - u_char byte2; - u_char reserved[3]; - u_char reserve_length_3; /* MSB */ - u_char reserve_length_2; - u_char reserve_length_1; - u_char reserve_length_0; /* LSB */ - u_char control; -}; - -/* struct scsi_read_track_information; */ - -struct scsi_write_track -{ - u_char op_code; - u_char byte2; - u_char reserved[3]; - u_char track_number; /* 0 means: use next available */ - u_char mode; -#define WORM_TRACK_MODE_RAW 0x08 -#define WORM_TRACK_MODE_AUDIO 0x04 -#define WORM_TRACK_MODE_MODE1 0x01 /* also audio with preemphasis */ -#define WORM_TRACK_MODE_MODE2 0x02 - u_char transfer_length_1; /* number of blocks to transfer, MSB */ - u_char transfer_length_0; /* LSB */ - u_char control; -#define WORM_TRACK_CONTROL_MIX 0x40 /* mixed mode blocks */ -}; - -struct scsi_load_unload -{ - u_char op_code; - u_char byte2; - u_char reserved[6]; - u_char load; -#define WORM_LOAD_MEDIUM 0x01 - u_char control; -}; - -struct scsi_fixation -{ - u_char op_code; - u_char byte2; - u_char reserved[6]; - u_char action; -#define WORM_FIXATION_ONP 0x08 /* open next program area (new session) */ -#define WORM_TOC_TYPE_AUDIO 0x00 -#define WORM_TOC_TYPE_CDROM 0x01 -#define WORM_TOC_TYPE_CDROM_1 0x02 /* CD-ROM, first track mode 1 (?) */ -#define WORM_TOC_TYPE_CDROM_2 0x03 /* CD-ROM, first track mode 2 */ -#define WORM_TOC_TYPE_CDI 0x04 - u_char control; -}; - -struct scsi_write_session -{ - u_char op_code; - u_char byte2; - u_char reserved[4]; - u_char action; /* see scsi_fixation above */ -#define WORM_LOFP_MODE_MODE1 0x10 -#define WORM_LOFP_MODE_MODE2 0x20 - u_char transfer_length_2; /* number of blocks to transfer, MSB */ - u_char transfer_length_1; /* LSB */ - u_char control; -}; - -struct scsi_read_session_info -{ - u_char op_code; - u_char byte2; - u_char reserved[6]; - u_char transfer_length; - u_char control; -}; - -struct scsi_first_writable_address -{ - u_char op_code; - u_char byte2; - u_char track_number; - u_char mode; - u_char reserved[4]; - u_char transfer_length; - u_char control; -}; - -#endif /* _SCSI_SCSI_WORM_H */ diff --git a/sys/scsi/scsiconf.c b/sys/scsi/scsiconf.c deleted file mode 100644 index f805edc..0000000 --- a/sys/scsi/scsiconf.c +++ /dev/null @@ -1,1573 +0,0 @@ -/* - * 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. - * - * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 - * - * New configuration setup: dufault@hda.com - * - * $Id: scsiconf.c,v 1.107 1998/07/28 09:03:37 phk Exp $ - */ - -#include "opt_scsi.h" - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/malloc.h> -#include <sys/conf.h> -#ifdef PC98 -#include <sys/device.h> -#endif - -#include <machine/clock.h> - -#include "sd.h" -#include "st.h" -#include "cd.h" -#include "ch.h" -#include "od.h" -#include "pt.h" -#include "worm.h" - -#include "sctarg.h" - -#include <scsi/scsiconf.h> -#include <scsi/scsi_debug.h> -#include <scsi/scsi_driver.h> - -static struct extend_array *extend_new __P((void)); -static void extend_release __P((struct extend_array *ea, int index)); -static void *extend_set __P((struct extend_array *ea, int index, void *value)); - -/* - * XXX SCSI_DEVICE_ENTRIES() generates extern switches but it should - * generate static switches except for this. Separate macros are - * probably required for the extern and static parts. - */ -extern struct scsi_device uk_switch; - -/*********************************************************************** - * Extensible arrays: Use a realloc like implementation to permit - * the arrays to be extend. These are set up to be moved out - * of this file if needed elsewhere. - */ -struct extend_array -{ - int nelem; - void **ps; -}; - -static void make_readable __P((char *to, char *from, size_t n)); -static int match __P((char *pattern, char *name)); -static int scsi_bus_conf __P((struct scsi_link *sc_link_proto)); - -static void * -extend_alloc(size_t s) -{ - void *p = malloc(s, M_DEVBUF, M_NOWAIT); - if (!p) - panic("extend_alloc: malloc failed."); - return p; -} - -static void -extend_free(void *p) { free(p, M_DEVBUF); } - -/* EXTEND_CHUNK: Number of extend slots to allocate whenever we need a new - * one. - */ -#ifndef EXTEND_CHUNK - #define EXTEND_CHUNK 8 -#endif - -static struct extend_array * -extend_new(void) -{ - struct extend_array *p = extend_alloc(sizeof(*p)); - if (p) { - p->nelem = 0; - p->ps = 0; - } - - return p; -} - -static void * -extend_set(struct extend_array *ea, int index, void *value) -{ - if (index >= ea->nelem) { - void **space; - space = extend_alloc(sizeof(void *) * (index + EXTEND_CHUNK)); - bzero(space, sizeof(void *) * (index + EXTEND_CHUNK)); - - /* Make sure we have something to copy before we copy it */ - if (ea->nelem) { - bcopy(ea->ps, space, sizeof(void *) * ea->nelem); - extend_free(ea->ps); - } - - ea->ps = space; - ea->nelem = index + EXTEND_CHUNK; - } - if (ea->ps[index]) { - printf("extend_set: entry %d already has storage.\n", index); - return 0; - } - else - ea->ps[index] = value; - - return value; -} - -void * -extend_get(struct extend_array *ea, int index) -{ - if (ea == NULL || index >= ea->nelem || index < 0) - return NULL; - return ea->ps[index]; -} - -static void -extend_release(struct extend_array *ea, int index) -{ - void *p = extend_get(ea, index); - if (p) { - ea->ps[index] = 0; - } -} - -/*********************************************************************** - * This extend_array holds an array of "scsibus_data" pointers. - * One of these is allocated and filled in for each scsi bus. - * it holds pointers to allow the scsi bus to get to the driver - * that is running each LUN on the bus - * it also has a template entry which is the prototype struct - * supplied by the adapter driver, this is used to initialise - * the others, before they have the rest of the fields filled in - */ - -static struct extend_array *scbusses; - -/* - * The structure of known drivers for autoconfiguration - */ -struct scsidevs { - u_int32_t type; - u_int32_t driver; /* normally the same as type */ - boolean removable; - char *manufacturer; - char *model; - char *version; - char *devname; - char flags; /* 1 show my comparisons during boot(debug) */ - u_int16_t quirks; - void *devmodes; -}; - -#define SC_SHOWME 0x01 -#define SC_ONE_LU 0x00 -#define SC_MORE_LUS 0x02 - -static struct scsidevs unknowndev = - { - T_UNKNOWN, T_UNKNOWN, 0, "*", "*", "*", - "uk", SC_MORE_LUS - }; -static st_modes mode_tandberg3600 = - { - {0, 0, 0}, /* minor 0,1,2,3 */ - {0, ST_Q_FORCE_VAR_MODE, QIC_525}, /* minor 4,5,6,7 */ - {0, 0, QIC_150}, /* minor 8,9,10,11 */ - {0, 0, QIC_120} /* minor 12,13,14,15 */ - }; -static st_modes mode_tandberg4200 = - { - {0, 0, 0}, /* minor 0,1,2,3 */ - {0, ST_Q_FORCE_VAR_MODE, 0}, /* minor 4,5,6,7 */ - {0, 0, QIC_150}, /* minor 8,9,10,11 */ - {0, 0, QIC_120} /* minor 12,13,14,15 */ - }; -static st_modes mode_archive2525 = - { - {0, ST_Q_SNS_HLP, 0}, /* minor 0,1,2,3 */ - {0, ST_Q_SNS_HLP, QIC_525}, /* minor 4,5,6,7 */ - {0, 0, QIC_150}, /* minor 8,9,10,11 */ - {0, 0, QIC_120} /* minor 12,13,14,15 */ - }; -static st_modes mode_archive150 = - { - {0, 0, 0}, /* minor 0,1,2,3 */ - {0, 0, QIC_150}, /* minor 4,5,6,7 */ - {0, 0, QIC_120}, /* minor 8,9,10,11 */ - {0, 0, QIC_24} /* minor 12,13,14,15 */ - }; -static st_modes mode_wangtek5525 = - { - {0, 0, 0}, /* minor 0,1,2,3 */ - {0, ST_Q_BLKSIZ, QIC_525}, /* minor 4,5,6,7 */ - {0, 0, QIC_150}, /* minor 8,9,10,11 */ - {0, 0, QIC_120} /* minor 12,13,14,15 */ - }; -static st_modes mode_wangdat1300 = - { - {0, 0, 0}, /* minor 0,1,2,3 */ - {512, ST_Q_FORCE_FIXED_MODE, DDS}, /* minor 4,5,6,7 */ - {1024, ST_Q_FORCE_FIXED_MODE, DDS}, /* minor 8,9,10,11 */ - {0, ST_Q_FORCE_VAR_MODE, DDS} /* minor 12,13,14,15 */ - }; -static st_modes mode_unktape = - { - {0, 0, 0}, /* minor 0,1,2,3 */ - {512, ST_Q_FORCE_FIXED_MODE, QIC_24}, /* minor 4,5,6,7 */ - {0, ST_Q_FORCE_VAR_MODE, HALFINCH_1600}, /* minor 8,9,10,11 */ - {0, ST_Q_FORCE_VAR_MODE, HALFINCH_6250} /* minor 12,13,14,15 */ - }; - -static int worm_mode_philips = WORM_Q_PHILIPS; -static int worm_mode_plasmon = WORM_Q_PLASMON; - -/*********************************************************************** - * A list of known devices and their "quirks". Matching is based - * first on device type, then on the manufacturer, model, and revision - * strings returned by the device. The returned strings are fixed lengths - * of 8, 16 and 4 bytes respectively. In the matching pattern, a - * question mark (?) matches any single character and a trailing - * asterisk (*) matches remaining characters. For patterns shorter - * than their respective fields, trailing spaces are implied. - */ - -static struct scsidevs knowndevs[] = -{ -#if NOD > 0 - { - T_OPTICAL, T_OPTICAL, T_REMOV, "MATSHITA", "PD-1 LF-1*", "*", - "od", SC_MORE_LUS - }, - { - T_DIRECT, T_OPTICAL, T_REMOV, "SONY", "SMO-*", "*", - "od", SC_MORE_LUS - }, - { - T_DIRECT, T_OPTICAL, T_REMOV, "MOST", "RMD-5200-S", "*", - "od", SC_ONE_LU - }, - { - T_DIRECT, T_OPTICAL, T_REMOV, "RICOH", "RO-*", "*", - "od", SC_ONE_LU - }, -#endif /* NOD */ -#if NSD > 0 - { - T_DIRECT, T_DIRECT, T_FIXED, "EMULEX", "MD21*" , "*", - "sd", SC_MORE_LUS - }, - { - T_DIRECT, T_DIRECT, T_FIXED, "IFT", "*" , "*", - "sd", SC_MORE_LUS - }, -#endif /* NSD */ -#if NST > 0 - { - T_SEQUENTIAL, T_SEQUENTIAL, T_REMOV, "TANDBERG", " TDC 3600", "*", - "st", SC_ONE_LU, ST_Q_NEEDS_PAGE_0, mode_tandberg3600 - }, - { - T_SEQUENTIAL, T_SEQUENTIAL, T_REMOV, "TANDBERG", " TDC 42*", "*", - "st", SC_ONE_LU, ST_Q_SNS_HLP|ST_Q_NO_1024, mode_tandberg4200 - }, - { - T_SEQUENTIAL, T_SEQUENTIAL, T_REMOV, "ARCHIVE", "VIPER 2525*", "-005", - "st", SC_ONE_LU, 0, mode_archive2525 - }, - { - T_SEQUENTIAL, T_SEQUENTIAL, T_REMOV, "ARCHIVE", "VIPER 150 *", "*", - "st", SC_ONE_LU, ST_Q_NEEDS_PAGE_0, mode_archive150 - }, - { - T_SEQUENTIAL, T_SEQUENTIAL, T_REMOV, "WANGTEK", "5525ES*", "*", - "st", SC_ONE_LU, 0, mode_wangtek5525 - }, - { - T_SEQUENTIAL, T_SEQUENTIAL, T_REMOV, "WangDAT", "Model 1300", "*", - "st", SC_ONE_LU, 0, mode_wangdat1300 - }, - { - T_SEQUENTIAL, T_SEQUENTIAL, T_REMOV, "DEC", "DLT2700", "*", - "st", SC_MORE_LUS, 0 - }, - { - T_SEQUENTIAL, T_SEQUENTIAL, T_REMOV, "Quantum", "DLT*", "*", - "st", SC_MORE_LUS, 0 - }, - { - T_SEQUENTIAL, T_SEQUENTIAL, T_REMOV, "SUN", "DLT*", "*", - "st", SC_MORE_LUS, 0 - }, - { - T_SEQUENTIAL, T_SEQUENTIAL, T_REMOV, "HP", "C1553A*", "*", - "st", SC_MORE_LUS, 0 - }, - { - T_SEQUENTIAL, T_SEQUENTIAL, T_REMOV, "HP", "C1557A", "*", - "st", SC_MORE_LUS, 0 - }, - { - T_SEQUENTIAL, T_SEQUENTIAL, T_REMOV, "ARCHIVE", "Python 28849-*", "*", - "st", SC_MORE_LUS, 0 - }, - { - T_SEQUENTIAL, T_SEQUENTIAL, T_REMOV, "ARCHIVE", "4586XX 28887-*", "*", - "st", SC_MORE_LUS, 0 - }, - { - T_SEQUENTIAL, T_SEQUENTIAL, T_REMOV, "SONY", "TSL-7000", "*", - "st", SC_MORE_LUS, 0 - }, -#endif /* NST */ -#if NCH > 0 - /* - * The <ARCHIVE, Python 28849-XXX, 4.98> is a SCSI changer device - * with an Archive Python DAT drive built-in. The tape appears - * at LUN 0 and the changer at LUN 1. - * This entry should not be needed at all. - */ - { - T_CHANGER, T_CHANGER, T_REMOV, "ARCHIVE", "Python 28849-*", "*", - "ch", SC_MORE_LUS - }, - { - T_CHANGER, T_CHANGER, T_REMOV, "ARCHIVE", "4586XX 28887-*", "*", - "ch", SC_MORE_LUS - }, - { - T_CHANGER, T_CHANGER, T_REMOV, "SONY", "TSL-7000", "*", - "ch", SC_MORE_LUS - }, -#endif /* NCH */ -#if NCD > 0 -#ifndef UKTEST /* make cdroms unrecognised to test the uk driver */ - /* - * CDU-8003A aka Apple CDROM-300. - */ - { - T_READONLY, T_READONLY, T_REMOV, "SONY", "CD-ROM CDU-8003A", "1.9a", - "cd", SC_ONE_LU - }, - { - T_READONLY, T_READONLY, T_REMOV, "SONY", "CD-ROM CDU-8012", "3.1a", - "cd", SC_ONE_LU - }, - { - T_READONLY, T_READONLY, T_REMOV, "PIONEER", "CD-ROM DRM-6??*" ,"*", - "cd", SC_MORE_LUS, CD_Q_NO_TOUCH - }, - { - T_READONLY, T_READONLY, T_REMOV, "NRC", "MBR-7*" ,"*", - "cd", SC_MORE_LUS - }, - { - T_READONLY, T_READONLY, T_REMOV, "CHINON", "CD-ROM CDS-535","*", - "cd", SC_ONE_LU, CD_Q_BCD_TRACKS - }, - /* - * Note: My drive with v1.0 firmware "forgets" to generate scsi parity - * when answering probes.. :-( EVIL!! You need to disable scsi parity - * checking in order to find out that it answers to all 7 LUNS. :-( - * -Peter - */ - { - T_READONLY, T_READONLY, T_REMOV, "NEC", "CD-ROM DRIVE:55","*", - "cd", SC_ONE_LU - }, - /* - * Same with the OEM version of this drive (1.0 firmware). - * -Paul - */ - { - T_READONLY, T_READONLY, T_REMOV, "NEC", "CD-ROM DRIVE:210","*", - "cd", SC_ONE_LU - }, - /* - * Doobe-doo-be doooo - * -Mary - */ - { - T_READONLY, T_READONLY, T_REMOV, "MEDIAVIS", "RENO CD-ROMX2A","*", - "cd", SC_ONE_LU, CD_Q_NO_START - }, - { - T_READONLY, T_READONLY, T_REMOV, "NAKAMICH", "MJ-*" ,"*", - "cd", SC_MORE_LUS - }, - /* yet another changer */ - { - T_READONLY, T_READONLY, T_REMOV, "REGAL", "CDC-4*" ,"*", - "cd", SC_MORE_LUS - }, - /* IODATA CD-C68E 6 CD changer */ - { - T_READONLY, T_READONLY, T_REMOV, "IODATA", "CD-C68E" ,"*", - "cd", SC_MORE_LUS - }, -#endif /* !UKTEST */ -#endif /* NCD */ -#if NWORM > 0 - { - T_READONLY, T_WORM, T_REMOV, "HP", "C4324/C4325", "*", - "worm", SC_ONE_LU, 0, &worm_mode_philips - }, - { - T_READONLY, T_WORM, T_REMOV, "HP", "CD-Writer 6020", "*", - "worm", SC_ONE_LU, 0, &worm_mode_philips - }, - { - /* That's the Philips drive, in case anybody wonders... */ - T_READONLY, T_WORM, T_REMOV, "IMS", "CDD2000*", "*", - "worm", SC_ONE_LU, 0, &worm_mode_philips - }, - { - /* Here's another Philips drive... */ - T_READONLY, T_WORM, T_REMOV, "PHILIPS", "CDD2*", "*", - "worm", SC_ONE_LU, 0, &worm_mode_philips - }, - /* - * The Plasmon's are dual-faced: they appear as T_WORM if the - * drive is empty, or a CD-R medium is in the drive, and they - * announce theirselves as T_READONLY if a CD-ROM (or fixated - * CD-R) is there. We need both entries here, so the worm_mode - * hook will be properly filled in. - */ - { - T_READONLY, T_WORM, T_REMOV, "PLASMON", "RF41*", "*", - "worm", SC_ONE_LU, 0, &worm_mode_plasmon - }, - { - T_WORM, T_WORM, T_REMOV, "PLASMON", "RF41*", "*", - "worm", SC_ONE_LU, 0, &worm_mode_plasmon - }, -#endif /* NWORM */ -#if NPT > 0 - /* - * Some of the Epson scanners erroneously respond to more than - * one LUN. - */ - { - T_PROCESSOR, T_PROCESSOR, T_FIXED, "EPSON SC", "*", "*", - "pt", SC_ONE_LU - }, -#endif /* NPT */ - - /* - * Wildcard entries. Keep them down here below all device - * specific entries, so the above ones can override the type - * driver if necessary. - */ -#if NOD > 0 - { - T_OPTICAL, T_OPTICAL, T_REMOV, "*", "*", "*", - "od", SC_ONE_LU - }, -#endif /* NOD */ -#if NSD > 0 - { - T_DIRECT, T_DIRECT, T_FIXED, "HP", "C372*", "*", - "sd", SC_ONE_LU, SD_Q_NO_TAGS - }, - { - T_DIRECT, T_DIRECT, T_REMOV, "iomega", "jaz*", "*", - "sd", SC_ONE_LU, SD_Q_NO_TAGS - }, - { - T_DIRECT, T_DIRECT, T_FIXED, "*", "*", "*", - "sd", SC_ONE_LU - }, - { - T_DIRECT, T_DIRECT, T_REMOV, "*", "*", "*", - "sd", SC_ONE_LU - }, -#endif /* NSD */ -#if NST > 0 - { - T_SEQUENTIAL, T_SEQUENTIAL, T_REMOV, "*", "*", "*", - "st", SC_ONE_LU, 0, mode_unktape - }, -#endif /* NST */ -#if NCH > 0 - /* - * Due to the way media changers are working, they are most - * likely always on a different LUN than the transfer element - * device. Thus, it should be safe to always probe all LUNs - * on them. - */ - { - T_CHANGER, T_CHANGER, T_REMOV, "*", "*", "*", - "ch", SC_MORE_LUS - }, -#endif /* NCH */ -#if NCD > 0 && !defined(UKTEST) - { - T_READONLY, T_READONLY, T_REMOV, "*", "*", "*", - "cd", SC_ONE_LU - }, -#endif /* NCD */ -#if NWORM > 0 - { - T_WORM, T_WORM, T_REMOV, "*", "*", "*", - "worm", SC_ONE_LU - }, -#endif /* NWORM */ - { - 0 - } -}; - -/* - * Declarations - */ -static struct scsidevs *scsi_probedev __P((struct scsi_link *sc_link, - boolean *maybe_more, int *type_p)); -static struct scsidevs *scsi_selectdev __P((u_int32_t qualifier, u_int32_t type, - boolean remov, char *manu, char *model, - char *rev)); - -/* XXX dufault@hda.com - * This scsi_device doesn't have the scsi_data_size. - * This is used during probe. - */ -static struct scsi_device probe_switch = -{ - NULL, - NULL, - NULL, - NULL, - "probe", -}; - -static int free_bus; /* First bus not wired down */ - -static struct scsi_device *device_list; -static int next_free_type = T_NTYPES; - -/* Register new functions at the head of the list. That allows - * you to replace a standard driver with a new one. - * - * You can't register the exact device (the same in memory structure) - * more than once - the list links are part of the structure. That is - * prevented. - * - * Custom devices should always be registered as type "-1". Then - * the next available type number will be allocated for it. - * - * Be careful not to register a type as 0 unless you really mean to - * replace the disk driver. - * - * This is usually called only by the "device_init" function generated - * automatically in the SCSI_DEVICE_ENTRIES macro. - */ - -void -scsi_device_register(struct scsi_device *sd) -{ - /* Not only is it pointless to add the same device more than once - * but it will also screw up the list. - */ - struct scsi_device *is_there; - for (is_there = device_list; is_there; is_there = is_there->next) - if (is_there == sd) - return; - - if (sd->type == -1) - sd->type = next_free_type++; - - sd->next = device_list; - device_list = sd; - - if (sd->links == 0) - sd->links = extend_new(); -} - -static struct scsi_device * -scsi_device_lookup(int type) -{ - struct scsi_device *sd; - - for (sd = device_list; sd; sd = sd->next) - if (sd->type == type) - return sd; - - return &uk_switch; -} - -static struct scsi_device * -scsi_device_lookup_by_name(char *name) -{ - struct scsi_device *sd; - - for (sd = device_list; sd; sd = sd->next) - if (strcmp(sd->name, name) == 0) - return sd; - - return &uk_switch; -} - -/* Macro that lets us know something is specified. - */ -#define IS_SPECIFIED(ARG) (ARG != SCCONF_UNSPEC && ARG != SCCONF_ANY) - -/* scsi_init: Do all the one time processing. This initializes the - * type drivers and initializes the configuration. - */ -static void -scsi_init(void) -{ - static int done = 0; - if(!done) { - int i; - - done = 1; - - scbusses = extend_new(); - - /* First call all type initialization functions. - */ - ukinit(); /* We always have the unknown device. */ - - for (i = 0; scsi_tinit[i]; i++) - (*scsi_tinit[i])(); - - /* Lowest free bus for auto-configure is one - * more than the first one not - * specified in config: - */ - for (i = 0; scsi_cinit[i].driver; i++) - if (IS_SPECIFIED(scsi_cinit[i].scbus) && - free_bus <= scsi_cinit[i].scbus) - free_bus = scsi_cinit[i].scbus + 1; - - /* Lowest free unit for each type for auto-configure is one - * more than the first one not specified in the config file: - */ - for (i = 0; scsi_dinit[i].name; i++) { - struct scsi_device_config *sdc = scsi_dinit + i; - struct scsi_device *sd = - scsi_device_lookup_by_name(sdc->name); - - /* This is a little tricky: We don't want "sd 4" to match as - * a wired down device, but we do want "sd 4 target 5" or - * even "sd 4 scbus 1" to match. - */ - if (IS_SPECIFIED(sdc->unit) && - (IS_SPECIFIED(sdc->target) || IS_SPECIFIED(sdc->cunit)) && - sd->free_unit <= sdc->unit) - sd->free_unit = sdc->unit + 1; - } - } -} - -/* scsi_bus_conf: Figure out which bus this is. If it is wired in config - * use that. Otherwise use the next free one. - */ -static int -scsi_bus_conf(sc_link_proto) - struct scsi_link *sc_link_proto; -{ - int i; - int bus; - - /* Which bus is this? Try to find a match in the "scsi_cinit" - * table. If it isn't wired down auto-configure it at the - * next available bus. - */ - - bus = SCCONF_UNSPEC; - for (i = 0; scsi_cinit[i].driver; i++) { - if (IS_SPECIFIED(scsi_cinit[i].scbus)) - { - if (!strcmp(sc_link_proto->adapter->name, scsi_cinit[i].driver) - &&(sc_link_proto->adapter_unit == scsi_cinit[i].unit)) - { - if (IS_SPECIFIED(scsi_cinit[i].bus)) { - if (sc_link_proto->adapter_bus==scsi_cinit[i].bus){ - bus = scsi_cinit[i].scbus; - break; - } - } - else if (sc_link_proto->adapter_bus == 0) { - /* Backwards compatibility for single bus cards */ - bus = scsi_cinit[i].scbus; - break; - } - else { - printf("Ambiguous scbus configuration for %s%d " - "bus %d, cannot wire down. The kernel " - "config entry for scbus%d should specify " - "a controller bus.\n" - "Scbus will be assigned dynamically.\n", - sc_link_proto->adapter->name, - sc_link_proto->adapter_unit, - sc_link_proto->adapter_bus, - sc_link_proto->adapter_bus ); - break; - } - } - } - } - - - if (bus == SCCONF_UNSPEC) - bus = free_bus++; - else if (bootverbose) - printf("Choosing drivers for scbus configured at %d\n", bus); - - return bus; -} - -/* scsi_assign_unit: Look through the structure generated by config. - * See if there is a fixed assignment for this unit. If there isn't, - * assign the next free unit. - */ -static int -scsi_assign_unit(struct scsi_link *sc_link) -{ - int i; - int found; -#ifdef PC98 - struct cfdata cf; - cf.cf_flags = 0; -#endif - - found = 0; - for (i = 0; scsi_dinit[i].name; i++) { - if ((strcmp(sc_link->device->name, scsi_dinit[i].name) == 0) && - sc_link->target == scsi_dinit[i].target && - ( - (sc_link->lun == scsi_dinit[i].lun) || - (sc_link->lun == 0 && scsi_dinit[i].lun == SCCONF_UNSPEC) - ) && - sc_link->scsibus == scsi_dinit[i].cunit) { - sc_link->dev_unit = scsi_dinit[i].unit; - found = 1; -#ifdef PC98 - cf.cf_flags = scsi_dinit[i].flags; -#endif - if (bootverbose) - printf("%s is configured at %d\n", - sc_link->device->name, sc_link->dev_unit); - break; - } - } - - if (!found) - sc_link->dev_unit = sc_link->device->free_unit++; - -#ifdef PC98 - if (!found) { - for (i = 0; scsi_dinit[i].name; i++) { - if ((strcmp(sc_link->device->name, scsi_dinit[i].name) == 0) && - (scsi_dinit[i].target == SCCONF_UNSPEC)) - cf.cf_flags = scsi_dinit[i].flags; - } - } - if (sc_link->adapter->open_target_lu) - (*(sc_link->adapter->open_target_lu))(sc_link, &cf); -#endif - - return sc_link->dev_unit; -} - - -#if NSCTARG > 0 -/* The SCSI target configuration is simpler. If an entry is present - * we just return the bus, target and lun for that unit. - */ -static void -scsi_sctarg_lookup(char *name, int unit, int *target, int *lun, int *bus) -{ - int i; - - *bus = SCCONF_UNSPEC; - *target = SCCONF_UNSPEC; - *lun = SCCONF_UNSPEC; - - for (i = 0; scsi_dinit[i].name; i++) { - if ((strcmp(name, scsi_dinit[i].name) == 0) && - unit == scsi_dinit[i].unit) - { - *bus = scsi_dinit[i].cunit; - *target = scsi_dinit[i].target; - *lun = scsi_dinit[i].lun; - } - } -} -#endif /* NSCTARG > 0 */ - -void -scsi_configure_start(void) -{ - scsi_init(); -} - -#if NSCTARG > 0 -static errval scsi_attach_sctarg __P((void)); -#endif - -void -scsi_configure_finish(void) -{ - -#if NSCTARG > 0 - scsi_attach_sctarg(); -#endif - -} - -/* - * scsi_attachdevs is the routine called by the adapter boards - * to get all their devices configured in. - */ -void -scsi_attachdevs(scbus) - struct scsibus_data *scbus; -{ - int scsibus; - struct scsi_link *sc_link_proto = scbus->adapter_link; - - if ( (scsibus = scsi_bus_conf(sc_link_proto)) == -1) { - return; - } - /* - * if the adapter didn't give us this, set a default - * (compatibility with old adapter drivers) - */ - if(!(sc_link_proto->opennings)) { - sc_link_proto->opennings = 1; - } - sc_link_proto->scsibus = scsibus; - /* - * Allocate our target-lun space. - */ - scbus->sc_link = (struct scsi_link *(*)[][8])malloc( - sizeof(struct scsi_link *[scbus->maxtarg + 1][8]), - M_TEMP, M_NOWAIT); - if(scbus == 0 || scbus->sc_link == 0 - || extend_set(scbusses, scsibus, scbus) == 0) { - panic("scsi_attachdevs: malloc"); - } - bzero(scbus->sc_link, sizeof(struct scsi_link*[scbus->maxtarg + 1][8])); -#if defined(SCSI_DELAY) && SCSI_DELAY > 2 - printf("%s%d: waiting for scsi devices to settle\n", - sc_link_proto->adapter->name, sc_link_proto->adapter_unit); -#else /* SCSI_DELAY > 2 */ -#undef SCSI_DELAY -#define SCSI_DELAY 2 -#endif /* SCSI_DELAY */ - DELAY(1000000 * SCSI_DELAY); - scsi_probe_bus(scsibus,-1,-1); -} - -/* - * Probe the requested scsi bus. It must be already set up. - * -1 requests all set up scsi busses. - * targ and lun optionally narrow the search if not -1 - */ -errval -scsi_probe_busses(int bus, int targ, int lun) -{ - if (bus == -1) { - for(bus = 0; bus < scbusses->nelem; bus++) { - scsi_probe_bus(bus, targ, lun); - } - return 0; - } else { - return scsi_probe_bus(bus, targ, lun); - } -} - -/* scsi_alloc_unit: Register a scsi_data pointer for a given - * unit in a given scsi_device structure. - * - * XXX dufault@hda.com: I still don't like the way this reallocs stuff - - * but at least now it is collected in one place instead of existing - * in multiple type drivers. I'd like it better if we had it do a - * second pass after it knew the sizes of everything and set up everything - * at once. - */ -static int -scsi_alloc_unit(struct scsi_link *sc_link) -{ - u_int32_t unit; - struct scsi_data *sd; - struct scsi_device *dsw; - - unit = sc_link->dev_unit; - dsw = sc_link->device; - - /* - * allocate the per unit data area - */ - if (dsw->sizeof_scsi_data) - { - sd = malloc(dsw->sizeof_scsi_data, M_DEVBUF, M_NOWAIT); - if (!sd) { - printf("%s%lu: malloc failed for scsi_data\n", - sc_link->device->name, (u_long)unit); - return 0; - } - bzero(sd, dsw->sizeof_scsi_data); - } - else - sd = 0; - - sc_link->sd = sd; - - if (extend_set(dsw->links, unit, (void *)sc_link) == 0) { - printf("%s%lu: Can't store link pointer.\n", - sc_link->device->name, (u_long)unit); - free(sd, M_DEVBUF); - return 0; - } - - return 1; -} - -static void -scsi_free_unit(struct scsi_link *sc_link) -{ - if (sc_link->sd) - { - free(sc_link->sd, M_DEVBUF); - sc_link->sd = 0; - } - extend_release(sc_link->device->links, sc_link->dev_unit); -} - -#if NSCTARG > 0 - -/* XXX: It is a bug that the sc_link has this information - * about the adapter in it. The sc_link should refer to - * a structure that is host adpater specific. That will also - * pull all knowledge of an sc_link out of the adapter drivers. - */ - -errval -scsi_set_bus(int bus, struct scsi_link *sc_link) -{ - struct scsi_link *ad_link; - struct scsibus_data *scsibus_data; - - if (bus < 0 || bus > scbusses->nelem) { - return ENXIO; - } - - scsibus_data = (struct scsibus_data *)extend_get(scbusses, bus); - - if(!scsibus_data) { - return ENXIO; - } - - ad_link = scsibus_data->adapter_link; - - sc_link->adapter_unit = ad_link->adapter_unit; - sc_link->adapter_targ = ad_link->adapter_targ; - sc_link->adapter = ad_link->adapter; - sc_link->device = ad_link->device; - sc_link->flags = ad_link->flags; - - return 0; -} - -/* - * Allocate and attach as many SCSI target devices as configured. - * There are two ways that you can configure the target device: - * 1. In the configuration file. That is handled here. - * 2. Via the minor number. That takes precedence over the config file. - */ -static errval -scsi_attach_sctarg() -{ - struct scsi_link *sc_link = NULL; - int dev_unit; - struct scsi_device *sctarg = scsi_device_lookup(T_TARGET); - - if (sctarg == 0) { - return ENXIO; - } - - for (dev_unit = 0; dev_unit < NSCTARG; dev_unit++) { - - int target, lun, bus; - - /* If we don't have a link block allocate one. - */ - if (!sc_link) { - sc_link = malloc(sizeof(*sc_link), M_TEMP, M_NOWAIT); - } - - scsi_sctarg_lookup(sctarg->name, dev_unit, &target, &lun, &bus); - - if (IS_SPECIFIED(bus)) { - struct scsibus_data *scsibus_data; - - if (bus < 0 || bus > scbusses->nelem) { - printf("%s%d: configured on illegal bus %d.\n", - sctarg->name, dev_unit, bus); - continue; - } - - scsibus_data = (struct scsibus_data *)extend_get(scbusses, bus); - - if(!scsibus_data) { - printf("%s%d: no bus %d.\n", sctarg->name, dev_unit, bus); - continue; - } - - *sc_link = *scsibus_data->adapter_link; /* struct copy */ - sc_link->target = target; - sc_link->lun = lun; - } - else { - /* This will be configured in the open routine. - */ - sc_link->scsibus = SCCONF_UNSPEC; - sc_link->target = SCCONF_UNSPEC; - sc_link->lun = SCCONF_UNSPEC; - } - - sc_link->quirks = 0; - sc_link->device = sctarg; - sc_link->dev_unit = dev_unit; - - if (scsi_alloc_unit(sc_link)) { - - if (scsi_device_attach(sc_link) == 0) { - sc_link = NULL; /* it's been used */ - } - else - scsi_free_unit(sc_link); - } - } - - if (sc_link) { - free(sc_link, M_TEMP); - } - - return 0; -} -#endif /* NSCTARG > 0 */ - -/* - * Allocate a scsibus_data structure - * The target/lun area is dynamically allocated in scsi_attachdevs after - * the controller driver has a chance to update the maxtarg field. - */ -struct scsibus_data* -scsi_alloc_bus() -{ - struct scsibus_data *scbus; - /* - * Prepare the scsibus_data area for the upperlevel - * scsi code. - */ - scbus = malloc(sizeof(struct scsibus_data), M_TEMP, M_NOWAIT); - if(!scbus) { - printf("scsi_alloc_bus: - cannot malloc!\n"); - return NULL; - } - bzero(scbus, sizeof(struct scsibus_data)); - /* Setup the defaults */ - scbus->maxtarg = 7; - scbus->maxlun = 7; - return scbus; -} - -/* - * Probe the requested scsi bus. It must be already set up. - * targ and lun optionally narrow the search if not -1 - */ -errval -scsi_probe_bus(int bus, int targ, int lun) -{ - struct scsibus_data *scsibus_data ; - int maxtarg,mintarg,maxlun,minlun; - struct scsi_link *sc_link_proto; - u_int8_t scsi_addr ; - struct scsidevs *bestmatch = NULL; - struct scsi_link *sc_link = NULL; - boolean maybe_more; - int type; - - if ((bus < 0 ) || ( bus >= scbusses->nelem)) { - return ENXIO; - } - scsibus_data = (struct scsibus_data *)extend_get(scbusses, bus); - if(!scsibus_data) return ENXIO; - sc_link_proto = scsibus_data->adapter_link; - scsi_addr = sc_link_proto->adapter_targ; - if(targ == -1){ - maxtarg = scsibus_data->maxtarg; - mintarg = 0; - } else { - if((targ < 0 ) || (targ > scsibus_data->maxtarg)) return EINVAL; - maxtarg = mintarg = targ; - } - - if(lun == -1){ - maxlun = scsibus_data->maxlun; - minlun = 0; - } else { - if((lun < 0 ) || (lun > scsibus_data->maxlun)) return EINVAL; - maxlun = minlun = lun; - } - - printf("scbus%d at %s%d bus %d\n", - sc_link_proto->scsibus, sc_link_proto->adapter->name, - sc_link_proto->adapter_unit, sc_link_proto->adapter_bus); - - for ( targ = mintarg;targ <= maxtarg; targ++) { - maybe_more = 0; /* by default only check 1 lun */ - if (targ == scsi_addr) { - continue; - } - for ( lun = minlun; lun <= maxlun ;lun++) { - /* - * The spot appears to already have something - * linked in, skip past it. Must be doing a 'reprobe' - */ - if((*scsibus_data->sc_link)[targ][lun]) - {/* don't do this one, but check other luns */ - maybe_more = 1; - continue; - } - /* - * If we presently don't have a link block - * then allocate one to use while probing - */ - if (!sc_link) { - sc_link = malloc(sizeof(*sc_link), M_TEMP, M_NOWAIT); - } - *sc_link = *sc_link_proto; /* struct copy */ - sc_link->device = &probe_switch; - sc_link->target = targ; - sc_link->lun = lun; - sc_link->quirks = 0; - bestmatch = scsi_probedev(sc_link, &maybe_more, &type); - if (bestmatch) { - sc_link->quirks = bestmatch->quirks; - sc_link->devmodes = bestmatch->devmodes; - } else { - sc_link->quirks = 0; - sc_link->devmodes = NULL; - } - if (bestmatch) { /* FOUND */ - sc_link->device = scsi_device_lookup(type); - - (void)scsi_assign_unit(sc_link); - - if (scsi_alloc_unit(sc_link)) { - - if (scsi_device_attach(sc_link) == 0) { - (*scsibus_data->sc_link)[targ][lun] = sc_link; - sc_link = NULL; /* it's been used */ - } - else - scsi_free_unit(sc_link); - } - } - - if (!(maybe_more)) { /* nothing suggests we'll find more */ - break; /* nothing here, skip to next targ */ - } - /* otherwise something says we should look further */ - } - } - if (sc_link) { - free(sc_link, M_TEMP); - } - return 0; -} - -/* Return the scsi_link for this device, if any. - */ -struct scsi_link * -scsi_link_get(bus, targ, lun) - int bus; - int targ; - int lun; -{ - struct scsibus_data *scsibus_data = - (struct scsibus_data *)extend_get(scbusses, bus); - return (scsibus_data) ? (*scsibus_data->sc_link)[targ][lun] : 0; -} - -/* make_readable: Make the inquiry data readable. Anything less than a ' ' - * is made a '?' and trailing spaces are removed. - */ -static void -make_readable(to, from, n) - char *to; - char *from; - size_t n; -{ - int i; - - for (i = 0; from[i] && i < n - 1; i++) { - if (from[i] < ' ') - to[i]='?'; - else - to[i] = from[i]; - } - - while (i && to[i - 1] == ' ') - i--; - - to[i] = 0; -} - -#ifndef SCSIDEBUG -void scsi_print_info(sc_link) - struct scsi_link *sc_link; -{ - int dtype = 0; - char *desc; - char *qtype; - struct scsi_inquiry_data *inqbuf; - u_int32_t len, qualifier, type; - boolean remov; - char manu[8 + 1]; - char model[16 + 1]; - char version[4 + 1]; - - inqbuf = &sc_link->inqbuf; - - type = inqbuf->device & SID_TYPE; - qualifier = inqbuf->device & SID_QUAL; - remov = inqbuf->dev_qual2 & SID_REMOVABLE; - - switch ((int)qualifier) { - case SID_QUAL_LU_OK: - qtype = ""; - break; - - case SID_QUAL_LU_OFFLINE: - qtype = "Supported device currently not connected"; - break; - - default: - dtype = 1; - qtype = "Vendor specific peripheral qualifier"; - break; - } - - if ((inqbuf->version & SID_ANSII) > 0) { - if ((len = inqbuf->additional_length - + ((char *) inqbuf->unused - - (char *) inqbuf)) - > (sizeof(struct scsi_inquiry_data) - 1)) - len = sizeof(struct scsi_inquiry_data) - 1; - desc = inqbuf->vendor; - desc[len - (desc - (char *) inqbuf)] = 0; - make_readable(manu, inqbuf->vendor, sizeof(manu)); - make_readable(model, inqbuf->product, sizeof(model)); - make_readable(version, inqbuf->revision, sizeof(version)); - } else { - /* - * If not advanced enough, use default values - */ - desc = "early protocol device"; - make_readable(manu, "unknown", sizeof(manu)); - make_readable(model, "unknown", sizeof(model)); - make_readable(version, "????", sizeof(version)); - } - - printf("%s%d: ", sc_link->device->name, - sc_link->dev_unit); - printf("<%s %s %s> ", manu, model, version ); - printf("type %lu %sSCSI %d", - (u_long)type, remov ? "removable " : "fixed ", - inqbuf->version & SID_ANSII); - if (qtype[0]) { - sc_print_addr(sc_link); - printf(" qualifier %lu: %s", (u_long)qualifier, qtype); - } - - printf("\n"); -} -#endif - -/* - * given a target and lu, ask the device what - * it is, and find the correct driver table - * entry. - */ -static struct scsidevs * -scsi_probedev(sc_link, maybe_more, type_p) - boolean *maybe_more; - struct scsi_link *sc_link; - int *type_p; -{ -#ifdef SCSIDEBUG - u_int8_t target = sc_link->target; - u_int8_t lu = sc_link->lun; -#endif - struct scsidevs *bestmatch = (struct scsidevs *) 0; - int dtype = 0; - char *desc; - char *qtype; - struct scsi_inquiry_data *inqbuf; - u_int32_t len, qualifier, type; - boolean remov; - char manu[8 + 1]; - char model[16 + 1]; - char version[4 + 1]; - - inqbuf = &sc_link->inqbuf; - - bzero(inqbuf, sizeof(*inqbuf)); - /* - * Ask the device what it is - */ -#ifdef SCSIDEBUG - if ((target == DEBUGTARG) && (lu == DEBUGLUN)) - sc_link->flags |= (DEBUGLEVEL); - else - sc_link->flags &= ~(SDEV_DB1 | SDEV_DB2 | SDEV_DB3 | SDEV_DB4); -#endif /* SCSIDEBUG */ - /* catch unit attn */ - scsi_test_unit_ready(sc_link, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT); -#ifdef DOUBTFULL - switch (scsi_test_unit_ready(sc_link, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT)) { - case 0: /* said it WAS ready */ - case EBUSY: /* replied 'NOT READY' but WAS present, continue */ - case ENXIO: - break; - case EIO: /* device timed out */ - case EINVAL: /* Lun not supported */ - default: - return (struct scsidevs *) 0; - - } -#endif /*DOUBTFULL*/ -#ifdef SCSI_2_DEF - /* some devices need to be told to go to SCSI2 */ - /* However some just explode if you tell them this.. leave it out */ - scsi_change_def(sc_link, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT); -#endif /*SCSI_2_DEF */ - - /* Now go ask the device all about itself */ - if (scsi_inquire(sc_link, inqbuf, SCSI_NOSLEEP | SCSI_NOMASK) != 0) { - return (struct scsidevs *) 0; - } - - /* - * note what BASIC type of device it is - */ - type = inqbuf->device & SID_TYPE; - qualifier = inqbuf->device & SID_QUAL; - remov = inqbuf->dev_qual2 & SID_REMOVABLE; - - /* - * Any device qualifier that has the top bit set (qualifier&4 != 0) - * is vendor specific and will match in the default of this switch. - */ - - switch ((int)qualifier) { - case SID_QUAL_LU_OK: - qtype = ""; - break; - - case SID_QUAL_LU_OFFLINE: - qtype = "Supported device currently not connected"; - break; - - case SID_QUAL_RSVD: /* Peripheral qualifier reserved in SCSI-2 spec */ - *maybe_more = 1; - return (struct scsidevs *) 0; - - case SID_QUAL_BAD_LU: /* Target can not support a device on this unit */ - /* - * Check for a non-existent unit. If the device is returning - * this much, then we must set the flag that has - * the searchers keep looking on other luns. - */ - *maybe_more = 1; - return (struct scsidevs *) 0; - - default: - dtype = 1; - qtype = "Vendor specific peripheral qualifier"; - *maybe_more = 1; - break; - } - - if (dtype == 0) { - if (type == T_NODEVICE) { - *maybe_more = 1; - return (struct scsidevs *) 0; - } - dtype = 1; - } - /* - * Then if it's advanced enough, more detailed - * information - */ - if ((inqbuf->version & SID_ANSII) > 0) { - if ((len = inqbuf->additional_length - + ((char *) inqbuf->unused - - (char *) inqbuf)) - > (sizeof(struct scsi_inquiry_data) - 1)) - len = sizeof(struct scsi_inquiry_data) - 1; - desc = inqbuf->vendor; - desc[len - (desc - (char *) inqbuf)] = 0; - make_readable(manu, inqbuf->vendor, sizeof(manu)); - make_readable(model, inqbuf->product, sizeof(model)); - make_readable(version, inqbuf->revision, sizeof(version)); - } else { - /* - * If not advanced enough, use default values - */ - desc = "early protocol device"; - make_readable(manu, "unknown", sizeof(manu)); - make_readable(model, "unknown", sizeof(model)); - make_readable(version, "????", sizeof(version)); - type = T_UNKNOWN; - } - -#ifdef SCSIDEBUG - sc_print_start(sc_link); - - printf("<%s %s %s> ", manu, model, version ); - printf("type %lu %sSCSI %d" - ,(u_long)type - ,remov ? "removable " : "fixed " - ,inqbuf->version & SID_ANSII - ); - if (qtype[0]) { - sc_print_addr(sc_link); - printf(" qualifier %lu: %s", (u_long)qualifier, qtype); - } - - printf("\n"); - sc_print_finish(); -#endif - /* - * Try make as good a match as possible with - * available sub drivers - */ - bestmatch = (scsi_selectdev( - qualifier, type, remov ? T_REMOV : T_FIXED, manu, model, version)); - if ((bestmatch) && (bestmatch->flags & SC_MORE_LUS)) { - *maybe_more = 1; - } - - /* If the device is unknown then we should be trying to look up a - * type driver based on the inquiry type. - */ - if (bestmatch == &unknowndev) - *type_p = type; - else - *type_p = - bestmatch->driver; - return bestmatch; -} - -/* Try to find the major number for a device during attach. - */ -dev_t -scsi_dev_lookup(d_open) - d_open_t *d_open; -{ - int i; - - dev_t d = NODEV; - - for (i = 0; i < nchrdev; i++) - if (cdevsw[i] && cdevsw[i]->d_open == d_open) - { - d = makedev(i, 0); - break; - } - - return d; -} - -/* - * Compare name with pattern, return 0 on match. - * Short pattern matches trailing blanks in name, - * wildcard '*' in pattern matches rest of name - */ -static int -match(pattern, name) - char *pattern; - char *name; -{ - char c; - while (c = *pattern++) - { - if (c == '*') return 0; - if ((c == '?') && (*name > ' ')) continue; - if (c != *name++) return 1; - } - while (c = *name++) - { - if (c != ' ') return 1; - } - return 0; -} - -/* - * Try make as good a match as possible with - * available sub drivers - */ -static struct scsidevs * -scsi_selectdev(qualifier, type, remov, manu, model, rev) - u_int32_t qualifier, type; - boolean remov; - char *manu, *model, *rev; -{ - struct scsidevs *bestmatch = NULL; - struct scsidevs *thisentry; - - type |= qualifier; /* why? */ - - for ( thisentry = knowndevs; thisentry->manufacturer; thisentry++ ) - { - if (type != thisentry->type) { - continue; - } - if (remov != thisentry->removable) { - continue; - } - - if (thisentry->flags & SC_SHOWME) - printf("\n%s-\n%s-", thisentry->manufacturer, manu); - if (match(thisentry->manufacturer, manu)) { - continue; - } - if (thisentry->flags & SC_SHOWME) - printf("\n%s-\n%s-", thisentry->model, model); - if (match(thisentry->model, model)) { - continue; - } - if (thisentry->flags & SC_SHOWME) - printf("\n%s-\n%s-", thisentry->version, rev); - if (match(thisentry->version, rev)) { - continue; - } - bestmatch = thisentry; - break; - } - if (bestmatch == (struct scsidevs *) 0) { - bestmatch = &unknowndev; - } - return (bestmatch); -} diff --git a/sys/scsi/scsiconf.h b/sys/scsi/scsiconf.h deleted file mode 100644 index 6961077..0000000 --- a/sys/scsi/scsiconf.h +++ /dev/null @@ -1,618 +0,0 @@ -/* - * 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. - * - * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 - * - * $Id: scsiconf.h,v 1.60 1998/05/24 04:52:31 julian Exp $ - */ -#ifndef SCSI_SCSICONF_H -#define SCSI_SCSICONF_H 1 -typedef int boolean; -typedef int errval; - -#include <scsi/scsi_all.h> -#include <sys/callout.h> /* XXX For ioconf.c */ - -/* - * The following documentation tries to describe the relationship between the - * various structures defined in this file: - * - * each adapter type has a scsi_adapter struct. This describes the adapter and - * identifies routines that can be called to use the adapter. - * each device type has a scsi_device struct. This describes the device and - * identifies routines that can be called to use the device. - * each existing device position (scsibus + target + lun) - * can be described by a scsi_link struct. - * Only scsi positions that actually have devices, have a scsi_link - * structure assigned. so in effect each device has scsi_link struct. - * The scsi_link structure contains information identifying both the - * device driver and the adapter driver for that position on that scsi bus, - * and can be said to 'link' the two. - * each individual scsi bus has an array that points to all the scsi_link - * structs associated with that scsi bus. Slots with no device have - * a NULL pointer. - * each individual device also knows the address of its own scsi_link - * structure. - * - * ------------- - * - * The key to all this is the scsi_link structure which associates all the - * other structures with each other in the correct configuration. The - * scsi_link is the connecting information that allows each part of the - * scsi system to find the associated other parts. - */ - -struct buf; -struct scsi_xfer; -#ifdef PC98 -struct cfdata; -#endif - -/* Don't poke around inside of "scsi_data". Each low level - * driver has its own definition for it. - */ -struct scsi_data; -struct scsi_link; /* scsi_link refers to scsi_device and vice-versa */ - -struct proc; - -/* - * These entrypoints are called by the high-end drivers to get services from - * whatever low-end drivers they are attached to each adapter type has one of - * these statically allocated. - */ -struct scsi_adapter -{ -/* 04*/ int32_t (*scsi_cmd) __P((struct scsi_xfer *xs)); -/* 08*/ void (*scsi_minphys) __P((struct buf *bp)); -#ifdef PC98 -/* 12*/ int32_t (*open_target_lu) __P((struct scsi_link *sc_link, - struct cfdata *cf)); -#else -/* 12*/ int32_t (*open_target_lu) __P((void)); -#endif -/* 16*/ int32_t (*close_target_lu) __P((void)); -/* 20*/ u_int32_t (*adapter_info) __P((int unit)); /* see definitions below */ -/* 24*/ char *name; /* name of scsi bus controller */ -/* 32*/ u_long spare[2]; -}; - -/* - * return values for scsi_cmd() - */ -#define SUCCESSFULLY_QUEUED 0 -#define TRY_AGAIN_LATER 1 -#define COMPLETE 2 -#define HAD_ERROR 3 /* do not use this, use COMPLETE */ -#define ESCAPE_NOT_SUPPORTED 4 - -/* - * Return value from sense handler. IMHO, These ought to be merged - * in with the return codes above, all made negative to distinguish - * from valid errno values, and replace "try again later" with "do retry" - */ -#define SCSIRET_CONTINUE -1 /* Continue with standard sense processing */ -#define SCSIRET_DO_RETRY -2 /* Retry the command that got this sense */ - -/* - * Format of adapter_info() response data - * e.g. maximum number of entries queuable to a device by the adapter - */ - -/* - * These entry points are called by the low-end drivers to get services from - * whatever high-end drivers they are attached to. Each device type has one - * of these statically allocated. - * - * XXX dufault@hda.com: Each adapter driver has a scsi_device structure - * that I don't think should be there. - * This structure should be rearranged and cleaned up once the - * instance down in the adapter drivers is removed. - */ - -/* - * XXX this is so that everything that includes this bloated header doesn't - * also need to include <sys/conf.h>. - */ -typedef int yet_another_d_open_t __P((dev_t, int, int, struct proc *)); - -struct scsi_device -{ -/* 4*/ errval (*err_handler)(struct scsi_xfer *xs); -/* 8*/ void (*start)(u_int32_t unit, u_int32_t flags); -/* 12*/ int32_t (*async) __P((void)); -/* 16*/ int32_t (*done) __P((struct scsi_xfer *xs)); -/* 20*/ char *name; /* name of device type */ -/* 24*/ u_int32_t flags; /* device type dependent flags */ -/* 32*/ int32_t spare[2]; -/* 36*/ int32_t link_flags; /* set -> sc_link at attach time */ -/* 40*/ errval (*attach)(struct scsi_link *sc_link); -/* 44*/ char *desc; /* Description of device */ -/* 48*/ yet_another_d_open_t *open; -/* 52*/ int sizeof_scsi_data; -/* 56*/ int type; /* Type of device this supports */ -/* 60*/ int (*getunit)(dev_t dev); -/* 64*/ dev_t (*setunit)(dev_t dev, int unit); -/* 68*/ int (*dev_open)(dev_t dev, int flags, int fmt, struct proc *p, - struct scsi_link *sc_link); -/* 72*/ int (*dev_ioctl)(dev_t dev, u_long cmd, caddr_t arg, int mode, - struct proc *p, struct scsi_link *sc_link); -/* 76*/ int (*dev_close)(dev_t dev, int flag, int fmt, struct proc *p, - struct scsi_link *sc_link); -/* 80*/ void (*dev_strategy)(struct buf *bp, struct scsi_link *sc_link); - /* Not initialized after this */ -/* 84*/ struct extend_array *links; -/* 88*/ int free_unit; -/* 92*/ struct scsi_device *next; /* Next in list in the registry. */ -}; -/* - * Macros to access soem fields above. - */ -#define SCSI_LINK(DEV, UNIT) \ - ((struct scsi_link *)(extend_get((DEV)->links, (UNIT)))) - -#define SCSI_DATA(DEV, UNIT) \ - ((SCSI_LINK((DEV), (UNIT)) ? (SCSI_LINK((DEV), (UNIT))->sd) : NULL)) - -/* - * SCSI_DEVICE_ENTRIES: A macro to generate all the entry points from the - * name. - */ -#define SCSI_DEVICE_ENTRIES(NAME) \ -static errval NAME##attach(struct scsi_link *sc_link); \ -extern struct scsi_device NAME##_switch; /* XXX actually static */ \ -void NAME##init(void) { \ - scsi_device_register(&NAME##_switch); \ -} \ -static int NAME##open(dev_t dev, int flags, int fmt, struct proc *p) { \ - return scsi_open(dev, flags, fmt, p, &NAME##_switch); \ -} \ -static int NAME##ioctl(dev_t dev, u_long cmd, caddr_t addr, \ - int flag, struct proc *p) { \ - return scsi_ioctl(dev, cmd, addr, flag, p, &NAME##_switch); \ -} \ -static int NAME##close(dev_t dev, int flag, int fmt, struct proc *p) { \ - return scsi_close(dev, flag, fmt, p, &NAME##_switch); \ -} \ -static void NAME##minphys(struct buf *bp) { \ - scsi_minphys(bp, &NAME##_switch); \ -} \ -static void NAME##strategy(struct buf *bp) { \ - scsi_strategy(bp, &NAME##_switch); \ -} - -#ifdef KERNEL -/* Configuration tables for config. - */ -/* A unit, type, etc can be SCCONF_ANY to indicate it is a '?' - * in the config. - */ -#define SCCONF_UNSPEC 255 -#define SCCONF_ANY 254 - -struct isa_driver; -struct scsi_ctlr_config -{ - int scbus; - char *driver; - int unit; - int bus; -}; - -struct scsi_device_config -{ - char *name; /* SCSI device name (sd, st, etc) */ - int unit; /* desired device unit */ - int cunit; /* Controller unit */ - int target; /* SCSI ID (target) */ - int lun; /* SCSI lun */ - int flags; /* Flags from config */ -}; - -extern void (*scsi_tinit[])(void); -extern struct scsi_ctlr_config scsi_cinit[]; -extern struct scsi_device_config scsi_dinit[]; - -#endif - -/* - * Define various devices that we know mis-behave in some way, - * and note how they are bad, so we can correct for them - */ -struct st_mode { -/* 4*/ u_int32_t blksiz; -/* 6*/ u_int16_t quirks; /* same definitions as in XXX */ -/* 7*/ u_int8_t density; -/* 8*/ u_int8_t spare[1]; -}; - -typedef struct st_mode st_modes[4]; - -/* define behaviour codes (quirks) */ -/* common to all SCSI devices */ -#define SCSI_Q_NO_SYNC 0x8000 -#define SCSI_Q_NO_FAST 0x4000 -#define SCSI_Q_NO_WIDE 0x2000 - -/* tape specific ST_Q_* */ -#define ST_Q_NEEDS_PAGE_0 0x0001 -#define ST_Q_FORCE_FIXED_MODE 0x0002 -#define ST_Q_FORCE_VAR_MODE 0x0004 -#define ST_Q_SNS_HLP 0x0008 /* must do READ for good MODE SENSE */ -#define ST_Q_IGNORE_LOADS 0x0010 -#define ST_Q_BLKSIZ 0x0020 /* variable-block media_blksiz > 0 */ -#define ST_Q_CC_NOMSG 0x0040 /* no messages accepted in CC state */ -#define ST_Q_NO_1024 0x0080 /* never ever use 1024-byte fix blk */ - -#define ST_Q_NO_SYNC SCSI_Q_NO_SYNC -#define ST_Q_NO_FAST SCSI_Q_NO_FAST -#define ST_Q_NO_WIDE SCSI_Q_NO_WIDE - -/* disk specific SD_Q_* */ -#define SD_Q_NO_TAGS 0x0001 - -#define SD_Q_NO_SYNC SCSI_Q_NO_SYNC -#define SD_Q_NO_FAST SCSI_Q_NO_FAST -#define SD_Q_NO_WIDE SCSI_Q_NO_WIDE - -/* cd specific CD_Q_* */ -#define CD_Q_NO_TOUCH 0x0001 -#define CD_Q_BCD_TRACKS 0x0002 -#define CD_Q_NO_START 0x0004 - - -/* worm specific WORM_Q_* */ -#define WORM_Q_PLASMON 0x0001 -#define WORM_Q_PHILIPS 0x0002 -/* - * This structure describes the connection between an adapter driver and - * a device driver, and is used by each to call services provided by - * the other, and to allow generic scsi glue code to call these services - * as well. - */ -struct scsi_link -{ - u_int8_t target; /* targ of this dev */ - u_int8_t lun; /* lun of this dev */ - u_int8_t adapter_targ; /* what are we on the scsi bus*/ - u_int8_t adapter_unit; /* e.g. the 0 in aha0 */ - u_int8_t adapter_bus; /* e.g. the 0 in bus0 */ - u_int8_t scsibus; /* the Nth scsibus */ - u_int8_t dev_unit; /* e.g. the 0 in sd0 */ - u_int8_t opennings; /* available operations */ - u_int8_t active; /* operations in progress */ - u_int16_t flags; /* flags all devices have */ - u_int16_t quirks; /* device specific quirks */ - struct scsi_adapter *adapter; /* adapter entry points etc. */ - struct scsi_device *device; /* device entry points etc. */ - struct scsi_xfer *active_xs; /* operations under way */ - void *fordriver; /* for driver's private user */ - void *devmodes; /* dev specific mode tables */ - dev_t dev; /* Device major # (character) */ - struct scsi_data *sd; /* Device data structure */ - struct scsi_inquiry_data inqbuf; /* Inquiry data */ - void *adapter_softc; /* to call foo_scsi_cmd */ -}; - -/* XXX-HA: dufault@hda.com: SDEV_BOUNCE is set down in the adapter drivers - * in an sc_link structure to indicate that this host adapter requires - * ISA DMA bounce buffers. I think the link structure should - * be associated only with the type drive and not the adapter driver, - * and the bounce flag should be in something associated with the - * adapter driver. - * XXX-HA And I added the "supports residuals properly" flag that ALSO goes - * in an adapter structure. I figure I'll fix both at once. - * - * XXX SDEV_OPEN is used for two things: To prevent more than one - * open and to make unit attentions errors be logged on the console. - * These should be split up; I'm adding SDEV_IS_OPEN to enforce one - * open only. - * - * XXX SDEV_UK is used to mark the "uk" device. - */ - -#define SDEV_MEDIA_LOADED 0x0001 /* device figures are still valid */ -#define SDEV_WAITING 0x0002 /* a process is waiting for this */ -#define SDEV_OPEN 0x0004 /* at least 1 open session */ -#define SDEV_BOUNCE 0x0008 /* XXX-HA: unit needs DMA bounce buffer */ -#define SDEV_DBX 0x00F0 /* debugging flags (scsi_debug.h) */ -#define SDEV_ONCE_ONLY 0x0100 /* unit can only be opened once */ -#define SDEV_BOOTVERBOSE 0x0200 /* be noisy during boot */ -#define SDEV_RESIDS_WORK 0x0400 /* XXX-HA: Residuals work */ -#define SDEV_TARGET_OPS 0x0800 /* XXX-HA: Supports target ops */ -#define SDEV_IS_OPEN 0x1000 /* at least 1 open session */ -#define SDEV_UK 0x2000 /* this is the "uk" device */ -#define SDEV_XLOCK 0x4000 /* Device is locked */ -#define SDEV_WANT 0x8000 /* A process is waiting for lock */ - -/* - * One of these is allocated and filled in for each scsi bus. - * it holds pointers to allow the scsi bus to get to the driver - * That is running each LUN on the bus - * it also has a template entry which is the prototype struct - * supplied by the adapter driver, this is used to initialise - * the others, before they have the rest of the fields filled in - */ -struct scsibus_data { - u_char maxtarg; - u_char maxlun; - struct scsi_link *adapter_link; /* prototype supplied by adapter */ - struct scsi_link *(*sc_link)[][8]; /* dynamically allocated */ -}; - -/* - * Each scsi transaction is fully described by one of these structures - * It includes information about the source of the command and also the - * device and adapter for which the command is destined. - * (via the scsi_link structure) * - */ -struct scsi_xfer -{ -/*04*/ struct scsi_xfer *next; /* when free */ -/*08*/ u_int32_t flags; -/*12*/ struct scsi_link *sc_link; /* all about our device and adapter */ -/*13*/ u_int8_t retries; /* the number of times to retry */ -/*16*/ u_int8_t spare[3]; -/*20*/ int32_t timeout; /* in milliseconds */ -/*24*/ struct scsi_generic *cmd; /* The scsi command to execute */ -/*28*/ int32_t cmdlen; /* how long it is */ -/*32*/ u_char *data; /* dma address OR a uio address */ -/*36*/ int32_t datalen; /* data len (blank if uio) */ -/*40*/ int32_t resid; /* how much buffer was not touched */ -/*44*/ int32_t error; /* an error value */ -/*48*/ struct buf *bp; /* If we need to associate with a buf */ -/*80*/ struct scsi_sense_data sense; /* 32 bytes*/ - /* - * Believe it or not, Some targets fall on the ground with - * anything but a certain sense length. - */ -/*84*/ int32_t req_sense_length; /* Explicit request sense length */ -/*88*/ int32_t status; /* SCSI status */ -/*100*/ struct scsi_generic cmdstore; /* stash the command in here */ - /* - * Handle for scheduling - * command timeouts. - */ - struct callout_handle timeout_ch; -}; - -/* - * Per-request Flag values - */ -#define SCSI_NOSLEEP 0x01 /* Not a user... don't sleep */ -#define SCSI_NOMASK 0x02 /* dont allow interrupts.. booting */ -#define SCSI_NOSTART 0x04 /* left over from ancient history */ -#define SCSI_USER 0x08 /* Is a user cmd, call scsi_user_done */ -#define SCSI_ITSDONE 0x10 /* the transfer is as done as it gets */ -#define ITSDONE 0x10 /* the transfer is as done as it gets */ -#define SCSI_INUSE 0x20 /* The scsi_xfer block is in use */ -#define INUSE 0x20 /* The scsi_xfer block is in use */ -#define SCSI_SILENT 0x40 /* Don't report errors to console */ -#define SCSI_ERR_OK 0x80 /* An error on this operation is OK. */ -#define SCSI_RESET 0x100 /* Reset the device in question */ -#define SCSI_DATA_UIO 0x200 /* The data address refers to a UIO */ -#define SCSI_DATA_IN 0x400 /* expect data to come INTO memory */ -#define SCSI_DATA_OUT 0x800 /* expect data to flow OUT of memory */ -#define SCSI_TARGET 0x1000 /* This defines a TARGET mode op. */ -#define SCSI_ESCAPE 0x2000 /* Escape operation */ -#define SCSI_EOF 0x4000 /* The operation should return EOF */ -#define SCSI_RESID_VALID 0x8000 /* The resid field contains valid data */ - -/* - * Escape op codes. This provides an extensible setup for operations - * that are not scsi commands. They are intended for modal operations. - */ - -#define SCSI_OP_TARGET 0x0001 -#define SCSI_OP_RESET 0x0002 -#define SCSI_OP_BDINFO 0x0003 - -/* - * Error values an adapter driver may return - */ -#define XS_NOERROR 0x0 /* there is no error, (sense is invalid) */ -#define XS_SENSE 0x1 /* Check the returned sense for the error */ -#define XS_DRIVER_STUFFUP 0x2 /* Driver failed to perform operation */ -#define XS_TIMEOUT 0x03 /* The device timed out.. turned off? */ -#define XS_SWTIMEOUT 0x04 /* The Timeout reported was caught by SW */ -#define XS_BUSY 0x08 /* The device busy, try again later? */ -#define XS_LENGTH 0x09 /* Illegal length (over/under run) */ -#define XS_SELTIMEOUT 0x10 /* Device failed to respond to selection */ - -#ifdef KERNEL -void *extend_get(struct extend_array *ea, int index); -void scsi_attachdevs __P((struct scsibus_data *scbus)); -u_int32_t scsi_read_capacity __P(( struct scsi_link *sc_link, - u_int32_t *blk_size, u_int32_t flags)); -errval scsi_test_unit_ready __P(( struct scsi_link *sc_link, u_int32_t flags)); -errval scsi_reset_target __P((struct scsi_link *)); -errval scsi_target_mode __P((struct scsi_link *, int)); -errval scsi_inquire( struct scsi_link *sc_link, - struct scsi_inquiry_data *inqbuf, u_int32_t flags); -errval scsi_prevent( struct scsi_link *sc_link, u_int32_t type,u_int32_t flags); -struct scsibus_data *scsi_alloc_bus __P((void)); -errval scsi_probe_bus __P((int, int, int)); -errval scsi_probe_busses __P(( int, int, int)); -errval scsi_start_unit( struct scsi_link *sc_link, u_int32_t flags); -errval scsi_stop_unit(struct scsi_link *sc_link, u_int32_t eject, u_int32_t flags); -void scsi_done(struct scsi_xfer *xs); -void scsi_user_done(struct scsi_xfer *xs); -errval scsi_scsi_cmd __P(( struct scsi_link *, struct scsi_generic *, - u_int32_t, u_char *, - u_int32_t, u_int32_t, - u_int32_t, struct buf *, - u_int32_t)); -int scsi_do_ioctl __P((dev_t dev, u_long cmd, caddr_t addr, int mode, - struct proc *p, struct scsi_link *sc_link)); - -struct scsi_link *scsi_link_get __P((int bus, int targ, int lun)); -dev_t scsi_dev_lookup __P((int (*opener)(dev_t dev, int flags, int fmt, -struct proc *p))); - -int scsi_opened_ok __P((dev_t dev, int flag, int type, struct scsi_link *sc_link)); -errval scsi_set_bus __P((int, struct scsi_link *)); - -char *scsi_sense_desc __P((int, int)); -void scsi_sense_print __P((struct scsi_xfer *)); -void show_scsi_cmd __P((struct scsi_xfer *)); - -void scsi_uto3b __P((u_int32_t , u_char *)); -u_int32_t scsi_3btou __P((u_char *)); -int32_t scsi_3btoi __P((u_char *)); -void scsi_uto4b __P((u_int32_t, u_char *)); -u_int32_t scsi_4btou __P((u_char *)); -void scsi_uto2b __P((u_int32_t, u_char *)); -u_int32_t scsi_2btou __P((u_char *)); - -void sc_print_addr __P((struct scsi_link *)); -void sc_print_start __P((struct scsi_link *)); -void sc_print_init __P((void)); -void sc_print_finish __P((void)); - -#ifndef SCSIDEBUG -void scsi_print_info __P((struct scsi_link *)); -#endif - -void scsi_device_register __P((struct scsi_device *sd)); - -void scsi_configure_start __P((void)); -void scsi_configure_finish __P((void)); - -void ukinit __P((void)); - -#ifdef SCSI_2_DEF -errval scsi_change_def( struct scsi_link *sc_link, u_int32_t flags); -#endif -#endif /* KERNEL */ - -#define SCSI_EXTERNALLEN (sizeof(struct scsi_link)) - - -/* XXX This belongs in a tape file. - */ - -/********************************************************************** - from the scsi2 spec - Value Tracks Density(bpi) Code Type Reference Note - 0x1 9 800 NRZI R X3.22-1983 2 - 0x2 9 1600 PE R X3.39-1986 2 - 0x3 9 6250 GCR R X3.54-1986 2 - 0x5 4/9 8000 GCR C X3.136-1986 1 - 0x6 9 3200 PE R X3.157-1987 2 - 0x7 4 6400 IMFM C X3.116-1986 1 - 0x8 4 8000 GCR CS X3.158-1986 1 - 0x9 18 37871 GCR C X3B5/87-099 2 - 0xA 22 6667 MFM C X3B5/86-199 1 - 0xB 4 1600 PE C X3.56-1986 1 - 0xC 24 12690 GCR C HI-TC1 1,5 - 0xD 24 25380 GCR C HI-TC2 1,5 - 0xF 15 10000 GCR C QIC-120 1,5 - 0x10 18 10000 GCR C QIC-150 1,5 - 0x11 26 16000 GCR C QIC-320(525?) 1,5 - 0x12 30 51667 RLL C QIC-1350 1,5 - 0x13 1 61000 DDS CS X3B5/88-185A 4 - 0x14 1 43245 RLL CS X3.202-1991 4 - 0x15 1 45434 RLL CS ECMA TC17 4 - 0x16 48 10000 MFM C X3.193-1990 1 - 0x17 48 42500 MFM C X3B5/91-174 1 - - where Code means: - NRZI Non Return to Zero, change on ones - GCR Group Code Recording - PE Phase Encoded - IMFM Inverted Modified Frequency Modulation - MFM Modified Frequency Modulation - DDS Dat Data Storage - RLL Run Length Encoding - - where Type means: - R Real-to-Real - C Cartridge - CS cassette - - where Notes means: - 1 Serial Recorded - 2 Parallel Recorded - 3 Old format know as QIC-11 - 4 Helical Scan - 5 Not ANSI standard, rather industry standard. - -********************************************************************/ - -#define HALFINCH_800 0x01 -#define HALFINCH_1600 0x02 -#define HALFINCH_6250 0x03 -#define QIC_11 0x04 /* from Archive 150S Theory of Op. XXX */ -#define QIC_24 0x05 /* may be bad, works for CIPHER ST150S XXX */ -#define QIC_120 0x0f -#define QIC_150 0x10 -#define QIC_320 0x11 -#define QIC_525 0x11 -#define QIC_1320 0x12 -#define DDS 0x13 -#define DAT_1 0x13 -#define QIC_3080 0x29 - - -/* XXX (dufault@hda.com) This is used only by "su" and "sctarg". - * The minor number field conflicts with the disk slice code, - * and so it is tough to access the disks through the "su" device. - */ - -/* Device number fields: - * - * NON-FIXED SCSI devices: - * - * ?FC? ???? ???? ???? MMMMMMMM mmmmmmmm - * - * F: Fixed device (nexus in number): must be 0. - * C: Control device; only user mode ioctl is supported. - * ?: Don't know; those bits didn't use to exist, currently always 0. - * M: Major device number. - * m: Old style minor device number. - * - * FIXED SCSI devices: - * - * XXX Conflicts with the slice code. Maybe the slice code can be - * changed to respect the F bit? - * - * ?FC? ?BBB TTTT ?LLL MMMMMMMM mmmmmmmm - * - * F: Fixed device (nexus in number); must be 1. - * C: Control device; only user mode ioctl is supported. - * B: SCSI bus - * T: SCSI target ID - * L: Logical unit - * M: Major device number - * m: Old style minor device number. - */ - -#define SCSI_FIXED_MASK 0x40000000 -#define SCSI_FIXED(DEV) (((DEV) & SCSI_FIXED_MASK)) -#define SCSI_CONTROL_MASK 0x20000000 -#define SCSI_CONTROL(DEV) (((DEV) & SCSI_CONTROL_MASK)) - -#define SCSI_BUS(DEV) (((DEV) & 0x07000000) >> 24) -#define SCSI_ID(DEV) (((DEV) & 0x00F00000) >> 20) -#define SCSI_LUN(DEV) (((DEV) & 0x00070000) >> 16) - -#define SCSI_MKFIXED(B, T, L, P) ( \ - ((B) << 24) | \ - ((T) << 20) | \ - ((L) << 16) | \ - (P) | \ - SCSI_FIXED_MASK ) - -#endif /*SCSI_SCSICONF_H*/ -/* END OF FILE */ diff --git a/sys/scsi/sctarg.c b/sys/scsi/sctarg.c deleted file mode 100644 index d2f8f6f..0000000 --- a/sys/scsi/sctarg.c +++ /dev/null @@ -1,319 +0,0 @@ -/* - * sctarg: Target mode user interface - * - * Copyright (C) 1995, HD Associates, Inc. - * PO Box 276 - * Pepperell, MA 01463 - * 508 433 5266 - * dufault@hda.com - * - * This code is contributed to the University of California at Berkeley: - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id: sctarg.c,v 1.27 1998/07/04 22:30:24 julian Exp $ - */ - -#include "opt_bounce.h" -#include "opt_devfs.h" -#include "opt_scsi.h" - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/buf.h> -#include <sys/conf.h> -#include <sys/kernel.h> -#ifdef DEVFS -#include <sys/devfsext.h> -#endif /*DEVFS*/ -#include <scsi/scsiconf.h> -#include <scsi/scsi_debug.h> -#include <scsi/scsi_driver.h> - -#include "ioconf.h" - -#define OPEN 0x01 - -struct scsi_data { - struct buf_queue_head buf_queue; - int flags; /* Already open */ -}; - -static d_open_t sctargopen; -static d_read_t sctargread; -static d_write_t sctargwrite; -static d_close_t sctargclose; -static d_ioctl_t sctargioctl; -static d_strategy_t sctargstrategy; - -#define CDEV_MAJOR 65 -static struct cdevsw sctarg_cdevsw = - { sctargopen, sctargclose, sctargread, sctargwrite, /*65*/ - sctargioctl, nostop, nullreset, nodevtotty,/* sctarg */ - seltrue, nommap, sctargstrategy, "sctarg", NULL, -1 }; - -SCSI_DEVICE_ENTRIES(sctarg) - -static errval sctarg_open(dev_t dev, int flags, int fmt, struct proc *p, - struct scsi_link *sc_link); -static void sctargstart(u_int32_t unit, u_int32_t unused_flags); -static void sctarg_strategy(struct buf *bp, struct scsi_link *sc_link); - -static struct scsi_device sctarg_switch = -{ - NULL, - sctargstart, /* we have a queue, and this is how we service it */ - NULL, - NULL, - "sctarg", - 0, - {0, 0}, - SDEV_ONCE_ONLY, - sctargattach, - "Processor Target", - sctargopen, - sizeof(struct scsi_data), - T_TARGET, - 0, - 0, - sctarg_open, - 0, - 0, - sctarg_strategy, -}; - -static errval -sctargattach(struct scsi_link *sc_link) -{ - struct scsi_data *sctarg; - - sctarg = sc_link->sd; - bufq_init(&sctarg->buf_queue); - sctarg->flags = 0; - - return 0; -} - -static errval -sctarg_open(dev_t dev, int flags, int fmt, struct proc *p, - struct scsi_link *sc_link) -{ - int ret = 0; - - /* Does this host adapter support target mode operation? - */ - if ((sc_link->flags & SDEV_TARGET_OPS) == 0) - return ENODEV; /* Operation not supported */ - - if (SCSI_FIXED(dev)) { - sc_link->scsibus = SCSI_BUS(dev); - scsi_set_bus(sc_link->scsibus, sc_link); - - sc_link->target = SCSI_ID(dev); - sc_link->lun = SCSI_LUN(dev); - } - - if (sc_link->scsibus == SCCONF_UNSPEC || - sc_link->target == SCCONF_UNSPEC || - sc_link->lun == SCCONF_UNSPEC) - return ENXIO; - - /* XXX: You can have more than one target device on a single - * host adapter. We need a reference count. - */ - if ((sc_link->sd->flags & OPEN) == 0) /* Enable target mode */ - { - ret = scsi_target_mode(sc_link, 1); - sc_link->sd->flags |= OPEN; - } - - return ret; -} - -static int -sctargread( dev_t dev, struct uio *uio, int ioflag) -{ - return (physio(sctargstrategy, NULL, dev, 1, minphys, uio)); -} - -static int -sctargwrite ( dev_t dev, struct uio *uio, int ioflag) -{ - return (physio(sctargstrategy, NULL, dev, 0, minphys, uio)); -} - -/* - * sctargstart looks to see if there is a buf waiting for the device - * and that the device is not already busy. If both are true, - * It dequeues the buf and creates a scsi command to perform the - * transfer required. The transfer request will call scsi_done - * on completion, which will in turn call this routine again - * so that the next queued transfer is performed. - * The bufs are queued by the strategy routine (sctargstrategy) - * - * This routine is also called after other non-queued requests - * have been made of the scsi driver, to ensure that the queue - * continues to be drained. - * sctargstart() is called at splbio - */ -static void -sctargstart(unit, unused_flags) - u_int32_t unit; - u_int32_t unused_flags; -{ - struct scsi_link *sc_link = SCSI_LINK(&sctarg_switch, unit); - struct scsi_data *sctarg = sc_link->sd; - register struct buf *bp = 0; - struct - { -#define PROCESSOR_SEND 0x0A -#define PROCESSOR_RECEIVE 0x08 - u_char op_code; - u_char byte2; - u_char len[3]; - u_char control; - } cmd; - - u_int32_t flags; - - SC_DEBUG(sc_link, SDEV_DB2, ("sctargstart ")); - /* - * See if there is a buf to do and we are not already - * doing one - */ - while (sc_link->opennings != 0) { - - /* if a special awaits, let it proceed first */ - if (sc_link->flags & SDEV_WAITING) { - sc_link->flags &= ~SDEV_WAITING; - wakeup((caddr_t)sc_link); - return; - } - - bp = bufq_first(&sctarg->buf_queue); - if (bp == NULL) - return; - bufq_remove(&sctarg->buf_queue, bp); - - /* - * Fill out the scsi command - */ - bzero(&cmd, sizeof(cmd)); - flags = SCSI_TARGET; - if ((bp->b_flags & B_READ) == B_WRITE) { - cmd.op_code = PROCESSOR_SEND; - flags |= SCSI_DATA_OUT; - } else { - cmd.op_code = PROCESSOR_RECEIVE; - flags |= SCSI_DATA_IN; - } - - scsi_uto3b(bp->b_bcount, cmd.len); - /* - * go ask the adapter to do all this for us - */ - if (scsi_scsi_cmd(sc_link, - (struct scsi_generic *) &cmd, - sizeof(cmd), - (u_char *) bp->b_data, - bp->b_bcount, - 0, - 100000, - bp, - flags | SCSI_NOSLEEP) == SUCCESSFULLY_QUEUED) { - } else { - printf("sctarg%lu: oops not queued\n", (u_long)unit); - bp->b_flags |= B_ERROR; - bp->b_error = EIO; - biodone(bp); - } - } /* go back and see if we can cram more work in.. */ -} - -static void -sctarg_strategy(struct buf *bp, struct scsi_link *sc_link) -{ - unsigned char unit; - u_int32_t opri; - struct scsi_data *sctarg; - - unit = minor((bp->b_dev)); - sctarg = sc_link->sd; - - opri = splbio(); - - /* - * Use a bounce buffer if necessary - */ -#ifdef BOUNCE_BUFFERS - if (sc_link->flags & SDEV_BOUNCE) - vm_bounce_alloc(bp); -#endif - - /* - * Place it at the end of the queue of activities for this device. - */ - bufq_insert_tail(&sctarg->buf_queue, bp); - - /* - * Tell the device to get going on the transfer if it's - * not doing anything, otherwise just wait for completion - * (All a bit silly if we're only allowing 1 open but..) - */ - sctargstart(unit, 0); - - splx(opri); - return; -} - -static sctarg_devsw_installed = 0; -#ifdef DEVFS -static void *sctarg_devfs_token; -#endif - -static void sctarg_drvinit(void *unused) -{ - dev_t dev; - - if( ! sctarg_devsw_installed ) { - dev = makedev(CDEV_MAJOR, 0); - cdevsw_add(&dev,&sctarg_cdevsw, NULL); - sctarg_devsw_installed = 1; -#ifdef DEVFS - /* XXX should be in ADAPTER code */ - sctarg_devfs_token = - devfs_add_devswf(&sctarg_cdevsw, 0, DV_CHR, 0, 0, - 0600, "sctarg"); -#endif - } -} - -SYSINIT(sctargdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,sctarg_drvinit,NULL) - - diff --git a/sys/scsi/sd.c b/sys/scsi/sd.c deleted file mode 100644 index 56aa859..0000000 --- a/sys/scsi/sd.c +++ /dev/null @@ -1,1065 +0,0 @@ -/* - * Written by Julian Elischer (julian@dialix.oz.au) - * 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. - * - * Ported to run under 386BSD by Julian Elischer (julian@dialix.oz.au) Sept 1992 - * - * $Id: sd.c,v 1.139 1998/08/23 20:16:35 phk Exp $ - */ - -#include "opt_bounce.h" -#include "opt_devfs.h" -#include "opt_hw_wdog.h" -#include "opt_scsi.h" - -#define SPLSD splbio -#include <sys/param.h> -#include <sys/kernel.h> -#include <sys/dkbad.h> -#include <sys/systm.h> -#include <sys/buf.h> -#include <sys/disklabel.h> -#include <sys/diskslice.h> -#include <sys/dkstat.h> -#include <sys/conf.h> -#ifdef DEVFS -#include <sys/devfsext.h> -#endif /* DEVFS */ - -#include <scsi/scsi_disk.h> -#include <scsi/scsiconf.h> -#include <scsi/scsi_debug.h> -#include <scsi/scsi_driver.h> - -#include <vm/vm.h> -#include <vm/vm_prot.h> -#include <vm/pmap.h> -#include <machine/md_var.h> -#include <i386/i386/cons.h> /* XXX *//* for aborting dump */ -#ifdef PC98 -#include <pc98/pc98/pc98_machdep.h> -#endif - -#include "ioconf.h" - -static u_int32_t sdstrats, sdqueues; - -#define SECSIZE 512 -#ifdef PC98 -#define SDOUTSTANDING 2 -#else -#define SDOUTSTANDING 4 -#endif -#define SD_RETRIES 4 -#define MAXTRANSFER 8 /* 1 page at a time */ - -#define PARTITION(dev) dkpart(dev) -#define SDUNIT(dev) dkunit(dev) - -/* XXX introduce a dkmodunit() macro for this. */ -#define SDSETUNIT(DEV, U) \ - makedev(major(DEV), dkmakeminor((U), dkslice(DEV), dkpart(DEV))) - -static errval sd_get_parms __P((int unit, int flags)); -#if 0 -static errval sd_reassign_blocks __P((int unit, int block)); -#endif -static int sd_size(int unit, u_int32_t *sizep, u_int16_t *secsizep, int flags); -static void sdstrategy1 __P((struct buf *)); - -static int sd_sense_handler __P((struct scsi_xfer *)); -static void sdstart __P((u_int32_t, u_int32_t)); - -struct scsi_data { - u_int32_t flags; -#define SDINIT 0x04 /* device has been init'd */ - struct disk_parms { - u_char heads; /* Number of heads */ - u_int16_t cyls; /* Number of cylinders */ - u_char sectors;/*XXX*/ /* Number of sectors/track */ - u_int16_t secsiz; /* Number of bytes/sector */ - u_int32_t disksize; /* total number sectors */ - } params; - struct diskslices *dk_slices; /* virtual drives */ - struct buf_queue_head buf_queue; - int dkunit; /* disk stats unit number */ -#ifdef DEVFS - void *b_devfs_token; - void *c_devfs_token; - void *ctl_devfs_token; -#endif -}; - - -static int sdunit(dev_t dev) { return SDUNIT(dev); } -static dev_t sdsetunit(dev_t dev, int unit) { return SDSETUNIT(dev, unit); } -static errval sd_open __P((dev_t dev, int mode, int fmt, struct proc *p, - struct scsi_link *sc_link)); -static errval sd_ioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, - struct proc *p, struct scsi_link *sc_link); -static errval sd_close __P((dev_t dev, int flag, int fmt, struct proc *p, - struct scsi_link *sc_link)); -static void sd_strategy(struct buf *bp, struct scsi_link *sc_link); - -static d_open_t sdopen; -static d_read_t sdread; -static d_write_t sdwrite; -static d_close_t sdclose; -static d_ioctl_t sdioctl; -static d_dump_t sddump; -static d_psize_t sdsize; -static d_strategy_t sdstrategy; - -#define CDEV_MAJOR 13 -#define BDEV_MAJOR 4 - -static struct cdevsw sd_cdevsw = { - sdopen, sdclose, sdread, sdwrite, - sdioctl, nostop, nullreset, nodevtotty, - seltrue, nommap, sdstrategy, "sd", - NULL, -1, sddump, sdsize, - D_DISK, 0, -1 }; - - - - -SCSI_DEVICE_ENTRIES(sd) - -static struct scsi_device sd_switch = -{ - sd_sense_handler, - sdstart, /* have a queue, served by this */ - NULL, /* have no async handler */ - NULL, /* Use default 'done' routine */ - "sd", - 0, - {0, 0}, - 0, /* Link flags */ - sdattach, - "Direct-Access", - sdopen, - sizeof(struct scsi_data), - T_DIRECT, - sdunit, - sdsetunit, - sd_open, - sd_ioctl, - sd_close, - sd_strategy, -}; -static struct scsi_xfer sx; - - -static __inline void -sd_registerdev(int unit) -{ - if(dk_ndrive < DK_NDRIVE) { - sprintf(dk_names[dk_ndrive], "sd%d", unit); - dk_wpms[dk_ndrive] = (8*1024*1024/2); - SCSI_DATA(&sd_switch, unit)->dkunit = dk_ndrive++; - } else { - SCSI_DATA(&sd_switch, unit)->dkunit = -1; - } -} - - -/* - * The routine called by the low level scsi routine when it discovers - * a device suitable for this driver. - */ -static errval -sdattach(struct scsi_link *sc_link) -{ - u_int32_t unit; - struct disk_parms *dp; -#ifdef DEVFS - int mynor; -#endif - - struct scsi_data *sd = sc_link->sd; - - unit = sc_link->dev_unit; - - dp = &(sd->params); - - if (sc_link->opennings > SDOUTSTANDING) - sc_link->opennings = SDOUTSTANDING; - - bufq_init(&sd->buf_queue); - /* - * In case it is a funny one, tell it to start - * not needed for most hard drives (ignore failure) - */ - scsi_start_unit(sc_link, - SCSI_ERR_OK | SCSI_SILENT | SCSI_NOSLEEP | SCSI_NOMASK); - /* - * Use the subdriver to request information regarding - * the drive. We cannot use interrupts yet, so the - * request must specify this. This may fail with removable media. - */ - if (sd_get_parms(unit, SCSI_NOSLEEP | SCSI_NOMASK) == 0) { - /* - * if we don't have actual parameters, assume 512 bytes/sec - * (could happen on removable media - MOD) - * -- this avoids the division below from falling over - */ - printf("%luMB (%lu %u byte sectors)", - (u_long)(dp->disksize / ((1024L * 1024L) / dp->secsiz)), - (u_long)dp->disksize, dp->secsiz); - -#ifndef SCSI_REPORT_GEOMETRY - if ( (sc_link->flags & SDEV_BOOTVERBOSE) ) -#endif - { - sc_print_addr(sc_link); - printf("with %d cyls, %d heads, and an average %d sectors/track", - dp->cyls, dp->heads, dp->sectors); - } - } else { - printf("Media parameters not available"); - } - sd->flags |= SDINIT; - sd_registerdev(unit); - -#ifdef DEVFS - mynor = dkmakeminor(unit, WHOLE_DISK_SLICE, RAW_PART); - sd->b_devfs_token = devfs_add_devswf(&sd_cdevsw, mynor, DV_BLK, - UID_ROOT, GID_OPERATOR, 0640, - "sd%d", unit); - sd->c_devfs_token = devfs_add_devswf(&sd_cdevsw, mynor, DV_CHR, - UID_ROOT, GID_OPERATOR, 0640, - "rsd%d", unit); - mynor = dkmakeminor(unit, 0, 0); /* XXX */ - sd->ctl_devfs_token = devfs_add_devswf(&sd_cdevsw, - mynor | SCSI_CONTROL_MASK, - DV_CHR, - UID_ROOT, GID_WHEEL, 0600, - "rsd%d.ctl", unit); -#endif - return 0; -} - - -/* - * open the device. Make sure the partition info is a up-to-date as can be. - */ -static errval -sd_open(dev_t dev, int mode, int fmt, struct proc *p, struct scsi_link *sc_link) -{ - errval errcode = 0; - u_int32_t unit; - struct disklabel label; - struct scsi_data *sd; - - unit = SDUNIT(dev); - sd = sc_link->sd; - - /* - * Make sure the disk has been initialised - * At some point in the future, get the scsi driver - * to look for a new device if we are not initted - */ - if ((!sd) || (!(sd->flags & SDINIT))) { - return (ENXIO); - } - - SC_DEBUG(sc_link, SDEV_DB1, - ("sd_open: dev=0x%lx (unit %lu, partition %d)\n", - (u_long)dev, (u_long)unit, PARTITION(dev))); - - /* - * "unit attention" errors should occur here if the - * drive has been restarted or the pack changed. - * just ingnore the result, it's a decoy instruction - * The error handlers will act on the error though - * and invalidate any media information we had. - */ - scsi_test_unit_ready(sc_link, 0); - - errcode = scsi_device_lock(sc_link); - if (errcode) - return errcode; - - /* - * If it's been invalidated, then forget the label - */ - sc_link->flags |= SDEV_OPEN; /* unit attn becomes an err now */ - if (!(sc_link->flags & SDEV_MEDIA_LOADED) && sd->dk_slices != NULL) { - /* - * If somebody still has it open, then forbid re-entry. - */ - if (dsisopen(sd->dk_slices)) { - errcode = ENXIO; - goto close; - } - - dsgone(&sd->dk_slices); - } - - /* - * Check that it is still responding and ok. - */ - if (scsi_test_unit_ready(sc_link, 0)) { - SC_DEBUG(sc_link, SDEV_DB3, ("device not reponding\n")); - errcode = ENXIO; - goto close; - } - SC_DEBUG(sc_link, SDEV_DB3, ("device ok\n")); - - /* - * Load the physical device parameters - */ - if(errcode = sd_get_parms(unit, 0)) /* sets SDEV_MEDIA_LOADED */ - goto close; - - SC_DEBUG(sc_link, SDEV_DB3, ("Params loaded ")); - - /* Lock the pack in. */ - scsi_prevent(sc_link, PR_PREVENT, SCSI_ERR_OK | SCSI_SILENT); - - /* Build label for whole disk. */ - bzero(&label, sizeof label); - label.d_type = DTYPE_SCSI; - label.d_secsize = sd->params.secsiz; - label.d_nsectors = sd->params.sectors; - label.d_ntracks = sd->params.heads; - label.d_ncylinders = sd->params.cyls; - label.d_secpercyl = sd->params.heads * sd->params.sectors; - if (label.d_secpercyl == 0) - label.d_secpercyl = 100; - /* XXX as long as it's not 0 - readdisklabel divides by it (?) */ - label.d_secperunit = sd->params.disksize; - - /* Initialize slice tables. */ - errcode = dsopen("sd", dev, fmt, 0, &sd->dk_slices, &label, sdstrategy1, - (ds_setgeom_t *)NULL, &sd_cdevsw); - if (errcode != 0) - goto close; - SC_DEBUG(sc_link, SDEV_DB3, ("Slice tables initialized ")); - - SC_DEBUG(sc_link, SDEV_DB3, ("open %lu %lu\n", - (u_long)sdstrats, (u_long)sdqueues)); - - scsi_device_unlock(sc_link); - return 0; - -close: - if (!dsisopen(sd->dk_slices)) - { - scsi_prevent(sc_link, PR_ALLOW, SCSI_ERR_OK | SCSI_SILENT); - sc_link->flags &= ~SDEV_OPEN; - } - scsi_device_unlock(sc_link); - return errcode; -} - -/* - * close the device.. only called if we are the LAST occurence of an open - * device. Convenient now but usually a pain. - */ -static errval -sd_close(dev_t dev,int mode, int fmt, struct proc *p, struct scsi_link *sc_link) -{ - struct scsi_data *sd; - errval errcode; - - sd = sc_link->sd; - errcode = scsi_device_lock(sc_link); - if (errcode) - return errcode; - dsclose(dev, fmt, sd->dk_slices); - if (!dsisopen(sd->dk_slices)) { - scsi_prevent(sc_link, PR_ALLOW, SCSI_SILENT | SCSI_ERR_OK); - sc_link->flags &= ~SDEV_OPEN; - } - scsi_device_unlock(sc_link); - return (0); -} - -static int -sdread(dev_t dev, struct uio *uio, int ioflag) -{ - return (physio(sdstrategy, NULL, dev, 1, minphys, uio)); -} - -static int -sdwrite(dev_t dev, struct uio *uio, int ioflag) -{ - return (physio(sdstrategy, NULL, dev, 0, minphys, uio)); -} - -/* - * Actually translate the requested transfer into one the physical driver - * can understand. The transfer is described by a buf and will include - * only one physical transfer. - */ -static void -sd_strategy(struct buf *bp, struct scsi_link *sc_link) -{ - u_int32_t opri; - struct scsi_data *sd; - u_int32_t unit; - - sdstrats++; - unit = SDUNIT((bp->b_dev)); - sd = sc_link->sd; - /* - * If the device has been made invalid, error out - */ - if (!(sc_link->flags & SDEV_MEDIA_LOADED)) { - bp->b_error = EIO; - goto bad; - } - - /* - * check it's not too big a transfer for our adapter - */ - scsi_minphys(bp,&sd_switch); - - /* - * Do bounds checking, adjust transfer, and set b_pbklno. - */ - if (dscheck(bp, sd->dk_slices) <= 0) - goto done; /* XXX check b_resid */ - - opri = SPLSD(); - /* - * Use a bounce buffer if necessary - */ -#ifdef BOUNCE_BUFFERS - if (sc_link->flags & SDEV_BOUNCE) - vm_bounce_alloc(bp); -#endif - - /* - * Place it in the queue of disk activities for this disk - */ -#ifdef SDDISKSORT - bufq_disksort(&sd->buf_queue, bp); -#else - bufq_insert_tail(&sd->buf_queue, bp); -#endif - - /* - * Tell the device to get going on the transfer if it's - * not doing anything, otherwise just wait for completion - */ - sdstart(unit, 0); - - splx(opri); - return /*0*/; -bad: - bp->b_flags |= B_ERROR; -done: - - /* - * Correctly set the buf to indicate a completed xfer - */ - bp->b_resid = bp->b_bcount; - biodone(bp); - return /*0*/; -} - -static void -sdstrategy1(struct buf *bp) -{ - /* - * XXX - do something to make sdstrategy() but not this block while - * we're doing dsinit() and dsioctl(). - */ - sdstrategy(bp); -} - -/* - * sdstart looks to see if there is a buf waiting for the device - * and that the device is not already busy. If both are true, - * It dequeues the buf and creates a scsi command to perform the - * transfer in the buf. The transfer request will call scsi_done - * on completion, which will in turn call this routine again - * so that the next queued transfer is performed. - * The bufs are queued by the strategy routine (sdstrategy) - * - * This routine is also called after other non-queued requests - * have been made of the scsi driver, to ensure that the queue - * continues to be drained. - * - * must be called at the correct (highish) spl level - * sdstart() is called at SPLSD from sdstrategy and scsi_done - */ -static void -sdstart(u_int32_t unit, u_int32_t flags) -{ - register struct scsi_link *sc_link = SCSI_LINK(&sd_switch, unit); - register struct scsi_data *sd = sc_link->sd; - struct buf *bp = NULL; - struct scsi_rw_big cmd; - u_int32_t blkno, nblk, secsize; - - SC_DEBUG(sc_link, SDEV_DB2, ("sdstart ")); - /* - * Check if the device has room for another command - */ - while (sc_link->opennings) { - - /* - * there is excess capacity, but a special waits - * It'll need the adapter as soon as we clear out of the - * way and let it run (user level wait). - */ - if (sc_link->flags & SDEV_WAITING) { - return; - } - /* - * See if there is a buf with work for us to do.. - */ - bp = bufq_first(&sd->buf_queue); - if (bp == NULL) { /* yes, an assign */ - return; - } - bufq_remove(&sd->buf_queue, bp); - - /* - * If the device has become invalid, abort all the - * reads and writes until all files have been closed and - * re-openned - */ - if (!(sc_link->flags & SDEV_MEDIA_LOADED)) { - goto bad; - } - /* - * We have a buf, now we know we are going to go through - * With this thing.. - */ - secsize = sd->params.secsiz; - blkno = bp->b_pblkno; - if (bp->b_bcount & (secsize - 1)) - { - goto bad; - } - nblk = bp->b_bcount / secsize; - - /* - * Fill out the scsi command - */ - cmd.op_code = (bp->b_flags & B_READ) - ? READ_BIG : WRITE_BIG; - cmd.addr_3 = (blkno & 0xff000000UL) >> 24; - cmd.addr_2 = (blkno & 0xff0000) >> 16; - cmd.addr_1 = (blkno & 0xff00) >> 8; - cmd.addr_0 = blkno & 0xff; - cmd.length2 = (nblk & 0xff00) >> 8; - cmd.length1 = (nblk & 0xff); - cmd.byte2 = cmd.reserved = cmd.control = 0; - /* - * Call the routine that chats with the adapter. - * Note: we cannot sleep as we may be an interrupt - */ - if (scsi_scsi_cmd(sc_link, - (struct scsi_generic *) &cmd, - sizeof(cmd), - (u_char *) bp->b_data, - bp->b_bcount, - SD_RETRIES, - 10000, - bp, - flags | ((bp->b_flags & B_READ) ? - SCSI_DATA_IN : SCSI_DATA_OUT)) - == SUCCESSFULLY_QUEUED) { - sdqueues++; - if(sd->dkunit >= 0) { - dk_xfer[sd->dkunit]++; - dk_seek[sd->dkunit]++; /* don't know */ - dk_wds[sd->dkunit] += bp->b_bcount >> 6; - } - } else { -bad: - printf("sd%lu: oops not queued\n", (u_long)unit); - bp->b_error = EIO; - bp->b_flags |= B_ERROR; - biodone(bp); - } - } -} - -/* - * Perform special action on behalf of the user - * Knows about the internals of this device - */ -static errval -sd_ioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p, - struct scsi_link *sc_link) -{ - errval error; - struct scsi_data *sd = sc_link->sd; - SC_DEBUG(sc_link, SDEV_DB1, ("sdioctl (0x%lx)", cmd)); - -#if 0 - /* Wait until we have exclusive access to the device. */ - /* XXX this is how wd does it. How did we work without this? */ - sdsleep(du->dk_ctrlr, "wdioct"); -#endif - - /* - * If the device is not valid.. abandon ship - */ - if (!(sc_link->flags & SDEV_MEDIA_LOADED)) - return (EIO); - - if (cmd == DIOCSBAD) - return (EINVAL); /* XXX */ - - error = scsi_device_lock(sc_link); - if (error) - return error; - error = dsioctl("sd", dev, cmd, addr, flag, &sd->dk_slices, - sdstrategy1, (ds_setgeom_t *)NULL); - scsi_device_unlock(sc_link); - if (error != ENOIOCTL) - return (error); - if (PARTITION(dev) != RAW_PART) - return (ENOTTY); - return (scsi_do_ioctl(dev, cmd, addr, flag, p, sc_link)); -} - -/* - * Find out from the device what its capacity is. It turns - * out this is also the best way to find out the sector size. - */ -static int -sd_size(int unit, u_int32_t *sizep, u_int16_t *secsizep, int flags) -{ - struct scsi_read_cap_data rdcap; - struct scsi_read_capacity scsi_cmd; - u_int32_t size; - u_int32_t secsize; - struct scsi_link *sc_link = SCSI_LINK(&sd_switch, unit); - - /* - * make up a scsi command and ask the scsi driver to do - * it for you. - */ - bzero(&scsi_cmd, sizeof(scsi_cmd)); - scsi_cmd.op_code = READ_CAPACITY; - - /* - * If the command works, interpret the result as a 4 byte - * number of blocks - */ - if (scsi_scsi_cmd(sc_link, - (struct scsi_generic *) &scsi_cmd, - sizeof(scsi_cmd), - (u_char *) & rdcap, - sizeof(rdcap), - SD_RETRIES, - 2000, - NULL, - flags | SCSI_DATA_IN) != 0) { - printf("sd%d: could not get size\n", unit); - return (ENXIO); - } - size = rdcap.addr_0 + 1; - size += rdcap.addr_1 << 8; - size += rdcap.addr_2 << 16; - size += rdcap.addr_3 << 24; - secsize = rdcap.length_0; - secsize += rdcap.length_1 << 8; - secsize += rdcap.length_2 << 16; - secsize += rdcap.length_3 << 24; - *secsizep = secsize; - *sizep = size; - return (0); -} - -#if 0 -/* - * Tell the device to map out a defective block - */ -static errval -sd_reassign_blocks(unit, block) - int unit, block; -{ - struct scsi_reassign_blocks scsi_cmd; - struct scsi_reassign_blocks_data rbdata; - struct scsi_link *sc_link = SCSI_LINK(&sd_switch, unit); - - bzero(&scsi_cmd, sizeof(scsi_cmd)); - bzero(&rbdata, sizeof(rbdata)); - scsi_cmd.op_code = REASSIGN_BLOCKS; - - rbdata.length_msb = 0; - rbdata.length_lsb = sizeof(rbdata.defect_descriptor[0]); - rbdata.defect_descriptor[0].dlbaddr_3 = ((block >> 24) & 0xff); - rbdata.defect_descriptor[0].dlbaddr_2 = ((block >> 16) & 0xff); - rbdata.defect_descriptor[0].dlbaddr_1 = ((block >> 8) & 0xff); - rbdata.defect_descriptor[0].dlbaddr_0 = ((block) & 0xff); - - return (scsi_scsi_cmd(sc_link, - (struct scsi_generic *) &scsi_cmd, - sizeof(scsi_cmd), - (u_char *) & rbdata, - sizeof(rbdata), - SD_RETRIES, - 5000, - NULL, - SCSI_DATA_OUT)); -} -#endif - -#define b2tol(a) (((unsigned)(a##_1) << 8) + (unsigned)a##_0 ) - -/* - * Get the scsi driver to send a full inquiry to the - * device and use the results to fill out the disk - * parameter structure. - * Even if we get an error, complete with some dummy information. - * XXX this is backwards. The read_cap (sd_size()) should be done first. - */ -static errval -sd_get_parms(int unit, int flags) -{ - struct scsi_link *sc_link = SCSI_LINK(&sd_switch, unit); - struct scsi_data *sd = sc_link->sd; - struct disk_parms *disk_parms = &sd->params; - struct scsi_mode_sense scsi_cmd; - struct scsi_mode_sense_data { - struct scsi_mode_header header; - struct blk_desc blk_desc; - union disk_pages pages; - } scsi_sense; - u_int32_t sectors; - int error = 0; - - /* - * First check if we have it all loaded - */ - if (sc_link->flags & SDEV_MEDIA_LOADED) - return 0; - - /* - * do a "mode sense page 4" - */ - bzero(&scsi_cmd, sizeof(scsi_cmd)); - scsi_cmd.op_code = MODE_SENSE; - scsi_cmd.page = 4; - scsi_cmd.length = 0x20; -#ifdef PC98 - if (sd_bios_parms(disk_parms, sc_link)) { - } else -#endif - /* - * If the command worked, use the results to fill out - * the parameter structure - */ - if (scsi_scsi_cmd(sc_link, - (struct scsi_generic *) &scsi_cmd, - sizeof(scsi_cmd), - (u_char *) & scsi_sense, - sizeof(scsi_sense), - SD_RETRIES, - 4000, - NULL, - flags | SCSI_DATA_IN) != 0) { - - printf("sd%d could not mode sense (4).", unit); - printf(" Using fictitious geometry\n"); - /* - * use adaptec standard fictitious geometry - * this depends on which controller (e.g. 1542C is - * different. but we have to put SOMETHING here..) - */ - if (error = sd_size(unit, §ors, &disk_parms->secsiz, flags)) { - /* we couldn't get anyhthing. removable? */ - sectors = 32 * 64; - disk_parms->secsiz= DEV_BSIZE;; - } - disk_parms->heads = 64; - disk_parms->sectors = 32; - disk_parms->cyls = sectors / (64 * 32); - disk_parms->disksize = sectors; - } else { - - SC_DEBUG(sc_link, SDEV_DB3, - ("%lu cyls, %d heads, %u precomp, %u red_write, %u land_zone\n", - (u_long)scsi_3btou(&scsi_sense.pages.rigid_geometry.ncyl_2), - scsi_sense.pages.rigid_geometry.nheads, - b2tol(scsi_sense.pages.rigid_geometry.st_cyl_wp), - b2tol(scsi_sense.pages.rigid_geometry.st_cyl_rwc), - b2tol(scsi_sense.pages.rigid_geometry.land_zone))); - - /* - * KLUDGE!!(for zone recorded disks) - * give a number of sectors so that sec * trks * cyls - * is <= disk_size - * can lead to wasted space! THINK ABOUT THIS ! - */ - disk_parms->heads = scsi_sense.pages.rigid_geometry.nheads; - disk_parms->cyls = scsi_3btou( - &scsi_sense.pages.rigid_geometry.ncyl_2); - /* set in a default value */ - disk_parms->secsiz = scsi_3btou(scsi_sense.blk_desc.blklen); - - if (error = sd_size(unit, §ors, - &disk_parms->secsiz, flags)) { - /* we couldn't get anyhthing. removable? */ - sectors = 64 * 32; /* just so non 0 */ - } - disk_parms->disksize = sectors; - /* Check if none of these values are zero */ - if(disk_parms->heads && disk_parms->cyls) { - sectors /= (disk_parms->heads * disk_parms->cyls); - } else { - /* set it to something reasonable */ - disk_parms->heads = 64; - disk_parms->cyls = sectors / (64 * 32); - sectors = 32; - } - /* keep secsiz sane too - we may divide by it later */ - if(disk_parms->secsiz == 0) - disk_parms->secsiz = SECSIZE; - disk_parms->sectors = sectors; /* dubious on SCSI *//*XXX */ - } - switch (sd->params.secsiz) { - case 512: - case 1024: - case 2048: - break; - default: - printf("sd%lu: Can't deal with %u bytes logical blocks\n", - (u_long)unit, sd->params.secsiz); - error = ENXIO; - } - if (error == 0) - sc_link->flags |= SDEV_MEDIA_LOADED; - return (error); -} - -static int -sdsize(dev_t dev) -{ - struct scsi_data *sd; - - sd = SCSI_DATA(&sd_switch, (u_int32_t) SDUNIT(dev)); - if (sd == NULL) - return (-1); - return (dssize(dev, &sd->dk_slices, sdopen, sdclose)); -} - -/* - * sense handler: Called to determine what to do when the - * device returns a CHECK CONDITION. - * - * This will issue a retry when the device returns a - * non-media hardware failure. The CDC-WREN IV does this - * when you access it during thermal calibrarion, so the drive - * is pretty useless without this. - * - * In general, you probably almost always would like to issue a retry - * for your disk I/O. It can't hurt too much (the caller only retries - * so many times) and it may save your butt. - */ - -static int -sd_sense_handler(struct scsi_xfer *xs) -{ - struct scsi_sense_data *sense; - struct scsi_inquiry_data *inqbuf; - - sense = &(xs->sense); - - /* I don't know what the heck to do with a deferred error, - * so I'll just kick it back to the caller. - */ - if ((sense->error_code & SSD_ERRCODE) == 0x71) - return SCSIRET_CONTINUE; - - if (((sense->error_code & SSD_ERRCODE) == 0x70) && - ((sense->ext.extended.flags & SSD_KEY) == 0x05)) - /* No point in retrying Illegal Requests */ - return SCSIRET_CONTINUE; - - inqbuf = &(xs->sc_link->inqbuf); - - /* It is dangerous to retry on removable drives without - * looking carefully at the additional sense code - * and sense code qualifier and ensuring the disk hasn't changed: - */ - if (inqbuf->dev_qual2 & SID_REMOVABLE) - return SCSIRET_CONTINUE; - - /* Retry all disk errors. - */ - scsi_sense_print(xs); - if (xs->retries) - printf(", retries:%d\n", xs->retries); - else - printf(", FAILURE\n"); - - return SCSIRET_DO_RETRY; -} - -/* - * dump all of physical memory into the partition specified, starting - * at offset 'dumplo' into the partition. - * XXX for SLICE starts at argument 'start'. - */ -static errval -sddump(dev_t dev) -{ /* dump core after a system crash */ - struct disklabel *lp; - int32_t num; /* number of sectors to write */ - u_int32_t unit, part; - int32_t nblocks; - int32_t blkoff; - static int sddoingadump = 0; - register struct scsi_data *sd; /* disk unit to do the IO */ - struct scsi_link *sc_link; - int32_t blknum, blkcnt = MAXTRANSFER; - char *addr; - struct scsi_rw_big cmd; - struct scsi_xfer *xs = &sx; - errval retval; - - addr = (char *) 0; /* starting address */ - - /* toss any characters present prior to dump */ - while (cncheckc() != -1) ; - - /* size of memory to dump */ - num = Maxmem; - unit = SDUNIT(dev); /* eventually support floppies? */ - part = PARTITION(dev); /* file system */ - - sc_link = SCSI_LINK(&sd_switch, unit); - - if (!sc_link) - return ENXIO; - - sd = sc_link->sd; - - /* was it ever initialized etc. ? */ - if (!(sd->flags & SDINIT)) - return (ENXIO); - if ((sc_link->flags & SDEV_MEDIA_LOADED) != SDEV_MEDIA_LOADED) - return (ENXIO); - if (sd->dk_slices == NULL) - Debugger("sddump: no slices"); - if ((lp = dsgetlabel(dev, sd->dk_slices)) == NULL) - return (ENXIO); - - /* Convert to disk sectors */ - /* XXX it must be 512 */ - num = (u_int32_t) num * PAGE_SIZE / sd->params.secsiz; - - /* check if controller active */ - if (sddoingadump) - return (EFAULT); - - nblocks = lp->d_partitions[part].p_size; - blkoff = lp->d_partitions[part].p_offset; - /* XXX */ - blkoff += sd->dk_slices->dss_slices[dkslice(dev)].ds_offset; - - /* check transfer bounds against partition size */ - if ((dumplo < 0) || ((dumplo + num) > nblocks)) - return (EINVAL); - - sddoingadump = 1; - - blknum = dumplo + blkoff; - while (num > 0) { - if (is_physical_memory((vm_offset_t)addr)) - pmap_enter(kernel_pmap, (vm_offset_t)CADDR1, - trunc_page(addr), VM_PROT_READ, TRUE); - else - pmap_enter(kernel_pmap, (vm_offset_t)CADDR1, - trunc_page(0), VM_PROT_READ, TRUE); - /* - * Fill out the scsi command - */ - bzero(&cmd, sizeof(cmd)); - cmd.op_code = WRITE_BIG; - cmd.addr_3 = (blknum & 0xff000000) >> 24; - cmd.addr_2 = (blknum & 0xff0000) >> 16; - cmd.addr_1 = (blknum & 0xff00) >> 8; - cmd.addr_0 = blknum & 0xff; - cmd.length2 = (blkcnt & 0xff00) >> 8; - cmd.length1 = (blkcnt & 0xff); - /* - * Fill out the scsi_xfer structure - * Note: we cannot sleep as we may be an interrupt - * don't use scsi_scsi_cmd() as it may want - * to wait for an xs. - */ - bzero(xs, sizeof(sx)); - xs->flags |= SCSI_NOMASK | SCSI_NOSLEEP | INUSE | SCSI_DATA_OUT; - xs->sc_link = sc_link; - xs->retries = SD_RETRIES; - xs->timeout = 10000; /* 10000 millisecs for a disk ! */ - xs->cmd = (struct scsi_generic *) &cmd; - xs->cmdlen = sizeof(cmd); - xs->resid = 0; - xs->error = XS_NOERROR; - xs->bp = 0; - xs->data = (u_char *) CADDR1; /* XXX use pmap_enter() */ - xs->datalen = blkcnt * sd->params.secsiz; - - /* - * Pass all this info to the scsi driver. - */ - retval = (*(sc_link->adapter->scsi_cmd)) (xs); - switch (retval) { - case SUCCESSFULLY_QUEUED: - case HAD_ERROR: - return (ENXIO); /* we said not to sleep! */ - case COMPLETE: - break; - default: - return (ENXIO); /* we said not to sleep! */ - } - - /* - * If we are dumping core, it may take a while. - * So reassure the user and hold off any watchdogs. - */ - if ((uintptr_t)addr % (1024 * 1024) == 0) { -#ifdef HW_WDOG - if (wdog_tickler) - (*wdog_tickler)(); -#endif /* HW_WDOG */ - printf("%ld ", (u_long)(num / 2048)); - } - /* update block count */ - num -= blkcnt; - blknum += blkcnt; - addr += blkcnt * sd->params.secsiz; - - /* operator aborting dump? */ - if (cncheckc() != -1) - return (EINTR); - } - return (0); -} - -static sd_devsw_installed = 0; - -static void sd_drvinit(void *unused) -{ - - if( ! sd_devsw_installed ) { - cdevsw_add_generic(BDEV_MAJOR, CDEV_MAJOR, &sd_cdevsw); - sd_devsw_installed = 1; - } -} - -SYSINIT(sddev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,sd_drvinit,NULL) - diff --git a/sys/scsi/ssc.c b/sys/scsi/ssc.c deleted file mode 100644 index 1014daa..0000000 --- a/sys/scsi/ssc.c +++ /dev/null @@ -1,162 +0,0 @@ -/* "superscsi" pseudo device. - * "superscsi" supports general SCSI utilities that can iterate - * over all SCSI targets, including those without device entry - * points. - * - * "superscsi" supports the SCIOCADDR ioctl to change the BUS, ID, LUN - * of the target so that you can get to all devices. The only thing - * you can do to "superscsi" is open it, set the target, perform ioctl - * calls, and close it. - * - * Keep "superscsi" protected: you can drive a truck through the - * security hole if you don't. - * - *Begin copyright - * - * Copyright (C) 1993, 1994, 1995, HD Associates, Inc. - * PO Box 276 - * Pepperell, MA 01463 - * 508 433 5266 - * dufault@hda.com - * - * This code is contributed to the University of California at Berkeley: - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - *End copyright - * $Id: ssc.c,v 1.18 1998/01/24 02:54:52 eivind Exp $ - */ - -#include "opt_devfs.h" - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/conf.h> -#include <sys/disklabel.h> -#include <sys/scsiio.h> -#include <sys/kernel.h> -#include <sys/stat.h> -#ifdef DEVFS -#include <sys/devfsext.h> -#endif /*DEVFS*/ -#include <scsi/scsiconf.h> - -static d_open_t sscopen; -static d_close_t sscclose; -static d_ioctl_t sscioctl; - -extern d_open_t suopen; -extern d_close_t suclose; -extern d_ioctl_t suioctl; - -#define CDEV_MAJOR 49 -static struct cdevsw ssc_cdevsw = - { sscopen, sscclose, noread, nowrite, /*49*/ - sscioctl, nostop, nullreset, nodevtotty, - seltrue, nommap, nostrategy, "ssc", NULL, -1 }; - -static dev_t sscdev = NODEV; - -static int -sscopen(dev_t dev, int flag, int type, struct proc *p) -{ - if (sscdev != NODEV) - return suopen(sscdev, flag, type, p); - return 0; -} - -static int -sscclose(dev_t dev, int fflag, int type, struct proc *p) -{ - - if (sscdev != NODEV) - return suclose(sscdev, fflag, type, p); - return 0; -} - -static int -sscioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *p) -{ - if (cmd == SCIOCADDR) - { - struct scsi_addr *sca; - dev_t newdev; - int ret; - - sca = (struct scsi_addr *) data; - newdev = SCSI_MKFIXED(sca->scbus,sca->target,sca->lun,RAW_PART); - - if (sscdev != NODEV) - { - suclose(sscdev, fflag, S_IFCHR, p); - sscdev = NODEV; - } - - if ( (ret = suopen(newdev, fflag, S_IFCHR, p)) ) - return ret; - - sscdev = newdev; - - return 0; - } - - if (sscdev != NODEV) - return suioctl(sscdev, cmd, data, fflag, p); - - return ENXIO; -} - -/* - * I've elected not to support any other entries. There really is no - * good reason other than I'm not sure how you would use them. - */ - -static ssc_devsw_installed = 0; -#ifdef DEVFS -static void *ssc_devfs_token; -#endif - -static void -ssc_drvinit(void *unused) -{ - dev_t dev; - - if( ! ssc_devsw_installed ) { - dev = makedev(CDEV_MAJOR, 0); - cdevsw_add(&dev,&ssc_cdevsw, NULL); - ssc_devsw_installed = 1; -#ifdef DEVFS - ssc_devfs_token = - devfs_add_devswf(&ssc_cdevsw, 0, DV_CHR, 0, 0, - 0600, "ssc"); -#endif - } -} - -SYSINIT(sscdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,ssc_drvinit,NULL) - diff --git a/sys/scsi/st.c b/sys/scsi/st.c deleted file mode 100644 index b4feb02..0000000 --- a/sys/scsi/st.c +++ /dev/null @@ -1,2005 +0,0 @@ -/* - * Written by Julian Elischer (julian@tfs.com)(now julian@DIALix.oz.au) - * 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. - * - * $Id: st.c,v 1.93 1998/08/18 00:32:49 bde Exp $ - */ - -/* - * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 - * major changes by Julian Elischer (julian@jules.dialix.oz.au) May 1993 - */ - -/* - * To do: - * work out some better way of guessing what a good timeout is going - * to be depending on whether we expect to retension or not. - * - */ - -#include "opt_bounce.h" -#include "opt_devfs.h" -#include "opt_scsi.h" - -#include <sys/param.h> -#include <sys/systm.h> - -#include <sys/fcntl.h> -#include <sys/malloc.h> -#include <sys/buf.h> -#include <sys/mtio.h> -#include <sys/conf.h> -#include <sys/kernel.h> -#ifdef DEVFS -#include <sys/devfsext.h> -#endif /*DEVFS*/ - -#include <scsi/scsi_tape.h> -#include <scsi/scsiconf.h> -#include <scsi/scsi_debug.h> -#include <scsi/scsi_driver.h> - -#include "ioconf.h" - -/* Defines for device specific stuff */ -#define PAGE_0_SENSE_DATA_SIZE 12 -#define DEF_FIXED_BSIZE 512 -#define ST_RETRIES 4 /* only on non IO commands */ - -#define STUNIT(DEV) ((minor(DEV)&0xF0) >> 4) /* 4 bit unit. */ -#define STSETUNIT(DEV, U) makedev(major(DEV), ((U) << 4)) - -#define MODE(z) ( (minor(z) & 0x03) ) -#define DSTY(z) ( ((minor(z) >> 2) & 0x03) ) -#define CTLMODE 3 - -#define IS_CTLMODE(DEV) (MODE(DEV) == CTLMODE) - -static errval st_space __P((u_int32_t unit, int32_t number, u_int32_t what, u_int32_t flags)); -static errval st_rewind __P((u_int32_t unit, boolean immed, u_int32_t flags)); -static errval st_erase __P((u_int32_t unit, boolean immed, u_int32_t flags)); -static errval st_mode_sense __P((u_int32_t unit, u_int32_t flags, \ - struct tape_pages *page, u_int32_t pagelen, u_int32_t pagecode)); -static errval st_decide_mode __P((u_int32_t unit, boolean first_read)); -static errval st_read __P((u_int32_t unit, char *buf, u_int32_t size, - u_int32_t flags)); -static errval st_rd_blk_lim __P((u_int32_t unit, u_int32_t flags)); -static errval st_touch_tape __P((u_int32_t unit)); -static errval st_write_filemarks __P((u_int32_t unit, int32_t number, u_int32_t flags)); -static errval st_load __P((u_int32_t unit, u_int32_t type, u_int32_t flags)); -static errval st_mode_select __P((u_int32_t unit, u_int32_t flags, \ - struct tape_pages *page, u_int32_t pagelen, u_int32_t byte2)); -static errval st_comp __P((u_int32_t unit, u_int32_t mode)); -static int32_t st_chkeod __P((u_int32_t unit, boolean position, int32_t *nmarks, - u_int32_t flags)); -static void ststart(u_int32_t unit, u_int32_t flags); -static void st_unmount __P((int unit, boolean eject)); -static errval st_mount_tape __P((dev_t dev, u_int32_t flags)); -static void st_loadquirks __P((struct scsi_link *sc_link)); -static errval st_interpret_sense __P((struct scsi_xfer *xs)); - -#define ESUCCESS 0 -#define NOEJECT 0 -#define EJECT 1 - -struct scsi_data { -/*--------------------present operating parameters, flags etc.----------------*/ - u_int32_t flags; /* see below */ - u_int32_t blksiz; /* blksiz we are using */ - u_int32_t density; /* present density */ - u_int32_t comp; /* present compression mode */ - u_int32_t quirks; /* quirks for the open mode */ - u_int32_t last_dsty; /* last density openned */ -/*--------------------parameters reported by the device ----------------------*/ - u_int32_t blkmin; /* min blk size */ - u_int32_t blkmax; /* max blk size */ -/*--------------------parameters reported by the device for this media--------*/ - u_int32_t numblks; /* nominal blocks capacity */ - u_int32_t media_blksiz; /* 0 if not ST_FIXEDBLOCKS */ - u_int32_t media_density; /* this is what it said when asked */ -/*--------------------quirks for the whole drive------------------------------*/ - u_int32_t drive_quirks; /* quirks of this drive */ -/*--------------------How we should set up when openning each minor device----*/ - st_modes modes; /* plus more for each mode */ - u_int8_t modeflags[4]; /* flags for the modes */ -#define DENSITY_SET_BY_USER 0x01 -#define DENSITY_SET_BY_QUIRK 0x02 -#define BLKSIZE_SET_BY_USER 0x04 -#define BLKSIZE_SET_BY_QUIRK 0x08 -#define COMPRES_SET_BY_USER 0x10 -#define COMPRES_SET_BY_QUIRK 0x20 -/*--------------------storage for sense data returned by the drive------------*/ - unsigned char saved_page0[PAGE_0_SENSE_DATA_SIZE]; /* - * additional sense data needed - * for mode sense/select. - */ - struct buf_queue_head buf_queue; - struct scsi_xfer scsi_xfer; /* scsi xfer struct for this drive */ - u_int32_t xfer_block_wait; /* is a process waiting? */ -#ifdef DEVFS - struct { - void *rst; - void *nrst; - void *erst; - /* end of aliases */ - void *rst_[4]; - void *nrst_[4]; - void *erst_[4]; - void *ctl_[4]; - void *ctl; - } devfs_token; -#endif -}; - -static int stunit(dev_t dev) { return STUNIT(dev); } -static dev_t stsetunit(dev_t dev, int unit) { return STSETUNIT(dev, unit); } - -static errval st_open(dev_t dev, int flags, int fmt, struct proc *p, - struct scsi_link *sc_link); -static errval st_ioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, - struct proc *p, struct scsi_link *sc_link); -static errval st_close(dev_t dev, int flag, int fmt, struct proc *p, - struct scsi_link *sc_link); -static void st_strategy(struct buf *bp, struct scsi_link *sc_link); - -static d_open_t stopen; -static d_read_t stread; -static d_write_t stwrite; -static d_close_t stclose; -static d_ioctl_t stioctl; -static d_strategy_t ststrategy; - -#define CDEV_MAJOR 14 -#define BDEV_MAJOR 5 -static struct cdevsw st_cdevsw = { - stopen, stclose, stread, stwrite, - stioctl, nostop, nullreset, nodevtotty, - seltrue, nommap, ststrategy, "st", - NULL, -1 }; - -SCSI_DEVICE_ENTRIES(st) - -static struct scsi_device st_switch = -{ - st_interpret_sense, /* check errors with us first */ - ststart, /* we have a queue, and this is how we service it */ - NULL, - NULL, /* use the default 'done' routine */ - "st", - 0, - {0, 0}, - 0, /* Link flags */ - stattach, - "Sequential-Access", - stopen, - sizeof(struct scsi_data), - T_SEQUENTIAL, - stunit, - stsetunit, - st_open, - st_ioctl, - st_close, - st_strategy, -}; - -#define ST_INITIALIZED 0x01 -#define ST_INFO_VALID 0x02 -#define ST_OPEN 0x04 -#define ST_BLOCK_SET 0x08 /* block size, mode set by ioctl */ -#define ST_WRITTEN 0x10 /* data have been written, EOD needed */ -#define ST_FIXEDBLOCKS 0x20 -#define ST_AT_FILEMARK 0x40 -#define ST_EIO_PENDING 0x80 /* we couldn't report it then (had data) */ -#define ST_NEW_MOUNT 0x100 /* still need to decide mode */ -#define ST_READONLY 0x200 /* st_mode_sense says write protected */ -#define ST_FM_WRITTEN 0x400 /* - * EOF file mark written -- used with - * ~ST_WRITTEN to indicate that multiple file - * marks have been written - */ -#define ST_BLANK_READ 0x800 /* BLANK CHECK encountered already */ -#define ST_2FM_AT_EOD 0x1000 /* write 2 file marks at EOD */ -#define ST_MOUNTED 0x2000 /* Device is presently mounted */ -#define ST_SENSE_READ 0x4000 /* mode sense read from drive */ - -#define ST_PER_ACTION (ST_AT_FILEMARK | ST_EIO_PENDING | ST_BLANK_READ) -#define ST_PER_MOUNT (ST_INFO_VALID | ST_BLOCK_SET | ST_WRITTEN | \ - ST_FIXEDBLOCKS | ST_READONLY | \ - ST_FM_WRITTEN | ST_2FM_AT_EOD | ST_PER_ACTION) - -/* - * The routine called by the low level scsi routine when it discovers - * a device suitable for this driver - */ - -static errval -stattach(struct scsi_link *sc_link) -{ - u_int32_t unit; -#ifdef DEVFS - int ii; -#endif /*DEVFS*/ - - struct scsi_data *st = sc_link->sd; - - unit = sc_link->dev_unit; - - bufq_init(&st->buf_queue); - /* - * Check if the drive is a known criminal and take - * Any steps needed to bring it into line - */ - st_loadquirks(sc_link); - /* - * Use the subdriver to request information regarding - * the drive. We cannot use interrupts yet, so the - * request must specify this. - */ - if (st_mode_sense(unit, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT, - NULL, 0, 0)) { - printf("drive offline"); - } else { - printf("density code 0x%lx, ", (u_long)st->media_density); - if (!scsi_test_unit_ready(sc_link, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT)) { - if (st->media_blksiz) { - printf("%lu-byte", (u_long)st->media_blksiz); - } else { - printf("variable"); - } - printf(" blocks, write-%s", - (st->flags & ST_READONLY) ? "protected" : "enabled"); - } else { - printf(" drive empty"); - } - } - /* - * Set up the buf queue for this device - */ - st->flags |= ST_INITIALIZED; -#ifdef DEVFS - for(ii=0; ii<4; ii++) { - st->devfs_token.rst_[ii] = - devfs_add_devswf(&st_cdevsw, - (unit << 4 ) + (ii * 4), DV_CHR, - UID_ROOT, GID_OPERATOR, 0660, - "rst%lu.%d", (u_long)unit, ii); - st->devfs_token.nrst_[ii] = - devfs_add_devswf(&st_cdevsw, - (unit << 4 ) + ((ii * 4) + 1), DV_CHR, - UID_ROOT, GID_OPERATOR, 0660, - "nrst%lu.%d", (u_long)unit, ii); - st->devfs_token.erst_[ii] = - devfs_add_devswf(&st_cdevsw, - (unit << 4 ) + ((ii * 4) + 2), DV_CHR, - UID_ROOT, GID_OPERATOR, 0660, - "erst%lu.%d", (u_long)unit, ii); - st->devfs_token.ctl_[ii] = - devfs_add_devswf(&st_cdevsw, - (unit << 4 ) + ((ii * 4) + 3), DV_CHR, - UID_ROOT, GID_OPERATOR, 0600, - "st%luctl.%d", (u_long)unit, ii); - } - - st->devfs_token.ctl = - devfs_add_devswf(&st_cdevsw, (unit << 4 ) | SCSI_CONTROL_MASK, - DV_CHR, UID_ROOT, GID_WHEEL, 0600, - "rst%d.ctl", unit); - /** add links **/ - st->devfs_token.rst = - devfs_link(st->devfs_token.rst_[0], "rst%lu", (u_long)unit); - st->devfs_token.nrst = - devfs_link(st->devfs_token.nrst_[0], "nrst%lu", (u_long)unit); - st->devfs_token.erst = - devfs_link(st->devfs_token.erst_[0], "erst%lu", (u_long)unit); -#endif - return 0; -} - - -/* - * initialise the subdevices to the default (QUIRK) state. - * this will remove any setting made by the system operator or previous - * operations. - */ -static void -st_loadquirks(sc_link) - struct scsi_link *sc_link; -{ - struct scsi_data *st = sc_link->sd; - int i; - struct st_mode *mode; - struct st_mode *mode2; - - mode = (struct st_mode*) sc_link->devmodes; - if (!mode) - return; - - st->quirks = st->drive_quirks = sc_link->quirks; - - mode2 = st->modes; - - for (i = 0; i < 4; i++) { - bzero(mode2, sizeof(*mode2)); - st->modeflags[i] &= ~(BLKSIZE_SET_BY_QUIRK - | DENSITY_SET_BY_QUIRK - | BLKSIZE_SET_BY_USER - | DENSITY_SET_BY_USER); - if (mode->blksiz && ((mode->quirks | st->drive_quirks) - & (ST_Q_FORCE_FIXED_MODE))) { - mode2->blksiz = mode->blksiz; - st->modeflags[i] |= BLKSIZE_SET_BY_QUIRK; - } else { - if ((mode->quirks | st->drive_quirks) - & ST_Q_FORCE_VAR_MODE) { - mode2->blksiz = 0; - st->modeflags[i] |= BLKSIZE_SET_BY_QUIRK; - } - } - if (mode->density) { - mode2->density = mode->density; - st->modeflags[i] |= DENSITY_SET_BY_QUIRK; - } - mode++; - mode2++; - } -} - -/* - * open the device. - */ -static errval -st_open(dev_t dev, int flags, int fmt, struct proc *p, -struct scsi_link *sc_link) -{ - u_int32_t unit, mode, dsty; - errval errno = 0; - struct scsi_data *st; - - unit = STUNIT(dev); - mode = MODE(dev); - dsty = DSTY(dev); - - st = sc_link->sd; - /* - * Make sure the device has been initialised - */ - if ((st == NULL) || (!(st->flags & ST_INITIALIZED))) - return (ENXIO); - - /* - * Only allow one at a time - */ - if (st->flags & ST_OPEN) { - return (EBUSY); - } - /* - * Throw out a dummy instruction to catch 'Unit attention - * errors (the error handling will invalidate all our - * device info if we get one, but otherwise, ignore it) - */ - scsi_test_unit_ready(sc_link, SCSI_SILENT); - - sc_link->flags |= SDEV_OPEN; /* unit attn are now errors */ - /* - * If the mode is 3 (e.g. minor = 3,7,11,15) - * then the device has been openned to set defaults - * This mode does NOT ALLOW I/O, only ioctls. - * XXX: Where do we lock out I/O? - */ - if (IS_CTLMODE(dev)) - return 0; - - /* - * Check that the device is ready to use (media loaded?) - * This time take notice of the return result - */ - if ( (errno = scsi_test_unit_ready(sc_link, 0)) ) { - uprintf("st%d: not ready\n", unit); - st_unmount(unit, NOEJECT); - return (errno); - } - /* - * if it's a different mode, or if the media has been - * invalidated, unmount the tape from the previous - * session but continue with open processing - */ - if ((st->last_dsty != dsty) - || (!(sc_link->flags & SDEV_MEDIA_LOADED))) { - st_unmount(unit, NOEJECT); - } - /* - * If we are not mounted, then we should start a new - * mount session. - */ - if (!(st->flags & ST_MOUNTED)) { - st_mount_tape(dev, flags); - st->last_dsty = dsty; - } - /* - * Make sure that a tape opened in write-only mode will have - * file marks written on it when closed, even if not written to. - * This is for SUN compatibility - */ - if (flags & FWRITE) - st->flags |= ST_WRITTEN; - - /* PREVENT ALLOW MEDIUM REMOVAL is optional per the SCSI-2 specs */ - scsi_prevent(sc_link, PR_PREVENT, SCSI_SILENT | SCSI_ERR_OK); - - SC_DEBUG(sc_link, SDEV_DB2, ("Open complete\n")); - - st->flags |= ST_OPEN; - return 0; -} - -/* - * close the device.. only called if we are the LAST - * occurence of an open device - */ -static errval -st_close(dev_t dev, int flag, int fmt, struct proc *p, - struct scsi_link *sc_link) -{ - u_int32_t unit, mode; - struct scsi_data *st; - errval errcode = 0; - - unit = STUNIT(dev); - mode = MODE(dev); - st = sc_link->sd; - - if ((st->flags & (ST_WRITTEN | ST_FM_WRITTEN)) == ST_WRITTEN) - errcode = st_write_filemarks(unit, 1, 0); - - /* - * Since the device has seen its last close, allow media removal. - * Do this before we attempt an eject. - */ - scsi_prevent(sc_link, PR_ALLOW, SCSI_SILENT); - - switch (mode & 0x3) { - case 0: - case 3: /* for now */ - st_unmount(unit, NOEJECT); - break; - case 1: /*leave mounted unless media seems to have been removed */ - if (!(sc_link->flags & SDEV_MEDIA_LOADED)) { - st_unmount(unit, NOEJECT); - } - break; - case 2: - st_unmount(unit, EJECT); - break; - } - - sc_link->flags &= ~SDEV_OPEN; - st->flags &= ~ST_OPEN; - - return (errcode); -} - -/* - * Start a new mount session. - * Copy in all the default parameters from the selected device mode. - * and try guess any that seem to be defaulted. - */ -static errval -st_mount_tape(dev, flags) - dev_t dev; - u_int32_t flags; -{ - u_int32_t unit, mode, dsty; - struct scsi_data *st; - struct scsi_link *sc_link; - errval errno = 0; - - unit = STUNIT(dev); - mode = MODE(dev); - dsty = DSTY(dev); - sc_link = SCSI_LINK(&st_switch, unit); - st = sc_link->sd; - - if (st->flags & ST_MOUNTED) - return 0; - - SC_DEBUG(sc_link, SDEV_DB1, ("mounting\n ")); - st->flags |= ST_NEW_MOUNT; - st->quirks = st->drive_quirks | st->modes[dsty].quirks; - /* - * If the media is new, then make sure we give it a chance to - * to do a 'load' instruction. ( We assume it is new) - */ - if ( (errno = st_load(unit, LD_LOAD, 0)) ) { - return (errno); - } - /* - * Throw another dummy instruction to catch - * 'Unit attention' errors. Some drives appear to give - * these after doing a Load instruction. - * (noteably some DAT drives) - */ - scsi_test_unit_ready(sc_link, SCSI_SILENT); - - /* - * Some devices can't tell you much until they have been - * asked to look at the media. This quirk does this. - */ - if (st->quirks & ST_Q_SNS_HLP) { - if ( (errno = st_touch_tape(unit)) ) - return errno; - } - /* - * Load the physical device parameters - * loads: blkmin, blkmax - */ - if ( (errno = st_rd_blk_lim(unit, 0)) ) { - return errno; - } - /* - * Load the media dependent parameters - * includes: media_blksiz,media_density,numblks - * As we have a tape in, it should be reflected here. - * If not you may need the "quirk" above. - */ - if ( (errno = st_mode_sense(unit, 0, NULL, 0, 0)) ) { - return errno; - } - /* - * If we have gained a permanent density from somewhere, - * then use it in preference to the one supplied by - * default by the driver. - */ - if (st->modeflags[dsty] & (DENSITY_SET_BY_QUIRK | DENSITY_SET_BY_USER)) { - st->density = st->modes[dsty].density; - } else { - st->density = st->media_density; - } - /* - * If we have gained a permanent blocksize - * then use it in preference to the one supplied by - * default by the driver. - */ - st->flags &= ~ST_FIXEDBLOCKS; - if (st->modeflags[dsty] & (BLKSIZE_SET_BY_QUIRK | BLKSIZE_SET_BY_USER)) { - st->blksiz = st->modes[dsty].blksiz; - if (st->blksiz) { - st->flags |= ST_FIXEDBLOCKS; - } - } else { - if ( (errno = st_decide_mode(unit, FALSE)) ) { - return errno; - } - } - if ( (errno = st_mode_select(unit, 0, NULL, 0, 0)) ) { - printf("st%lu: Cannot set selected mode", (u_long)unit); - return errno; - } - st->flags &= ~ST_NEW_MOUNT; - st->flags |= ST_MOUNTED; - sc_link->flags |= SDEV_MEDIA_LOADED; - - return 0; -} - -/* - * End the present mount session. - * Rewind, and optionally eject the tape. - * Reset various flags to indicate that all new - * operations require another mount operation - */ -void -st_unmount(int unit, boolean eject) -{ - struct scsi_link *sc_link = SCSI_LINK(&st_switch, unit); - struct scsi_data *st = sc_link->sd; - int32_t nmarks; - - if (!(st->flags & ST_MOUNTED)) - return; - SC_DEBUG(sc_link, SDEV_DB1, ("unmounting\n")); - st_chkeod(unit, FALSE, &nmarks, SCSI_SILENT); - st_rewind(unit, FALSE, SCSI_SILENT); - if (eject) { - st_load(unit, LD_UNLOAD, SCSI_SILENT); - } - st->flags &= ~(ST_MOUNTED | ST_NEW_MOUNT); - sc_link->flags &= ~SDEV_MEDIA_LOADED; -} - -/* - * Given all we know about the device, media, mode, 'quirks' and - * initial operation, make a decision as to how we should be set - * to run (regarding blocking and EOD marks) - */ -static errval -st_decide_mode(unit, first_read) - u_int32_t unit; - boolean first_read; -{ - struct scsi_link *sc_link = SCSI_LINK(&st_switch, unit); - struct scsi_data *st = sc_link->sd; - - SC_DEBUG(sc_link, SDEV_DB2, ("starting block mode decision\n")); - - /* - * If the user hasn't already specified fixed or variable-length - * blocks and the block size (zero if variable-length), we'll - * have to try to figure them out ourselves. - * - * Our first shot at a method is, "The quirks made me do it!" - */ - switch ((int)(st->quirks & (ST_Q_FORCE_FIXED_MODE | ST_Q_FORCE_VAR_MODE))) { - case (ST_Q_FORCE_FIXED_MODE | ST_Q_FORCE_VAR_MODE): - printf("st%lu: bad quirks\n", (u_long)unit); - return (EINVAL); - case ST_Q_FORCE_FIXED_MODE: /*specified fixed, but not what size */ - st->flags |= ST_FIXEDBLOCKS; - if (st->blkmin && (st->blkmin == st->blkmax)) - st->blksiz = st->blkmin; - else if (st->media_blksiz > 0) - st->blksiz = st->media_blksiz; - else - st->blksiz = DEF_FIXED_BSIZE; - SC_DEBUG(sc_link, SDEV_DB3, ("Quirks force fixed mode(%lu)\n", - (u_long)st->blksiz)); - goto done; - case ST_Q_FORCE_VAR_MODE: - st->flags &= ~ST_FIXEDBLOCKS; - st->blksiz = 0; - SC_DEBUG(sc_link, SDEV_DB3, ("Quirks force variable mode\n")); - goto done; - } - /* - * If the drive can only handle fixed-length blocks and only at - * one size, perhaps we should just do that. - */ - if (st->blkmin && (st->blkmin == st->blkmax)) { - st->flags |= ST_FIXEDBLOCKS; - st->blksiz = st->blkmin; - SC_DEBUG(sc_link, SDEV_DB3, - ("blkmin == blkmax of %lu\n", (u_long)st->blkmin)); - goto done; - } - /* - * If the tape density mandates (or even suggests) use of fixed - * or variable-length blocks, comply. - */ - switch ((int)st->density) { - case HALFINCH_800: - case HALFINCH_1600: - case HALFINCH_6250: - case DDS: - case QIC_525: - case QIC_1320: - case QIC_3080: - st->flags &= ~ST_FIXEDBLOCKS; - st->blksiz = 0; - SC_DEBUG(sc_link, SDEV_DB3, ("density specified variable\n")); - goto done; - case QIC_11: - case QIC_24: - case QIC_120: - case QIC_150: - st->flags |= ST_FIXEDBLOCKS; - if (st->media_blksiz > 0) { - st->blksiz = st->media_blksiz; - } else { - st->blksiz = DEF_FIXED_BSIZE; - } - SC_DEBUG(sc_link, SDEV_DB3, ("density specified fixed\n")); - goto done; - } - /* - * If we're about to read the tape, perhaps we should choose - * fixed or variable-length blocks and block size according to - * what the drive found on the tape. - */ - if (first_read - && (!(st->quirks & ST_Q_BLKSIZ) - || (st->media_blksiz == 0) - || (st->media_blksiz == DEF_FIXED_BSIZE) - || (st->media_blksiz == 1024))) { - if (st->media_blksiz == 0) { - st->flags &= ~ST_FIXEDBLOCKS; - } else { - st->flags |= ST_FIXEDBLOCKS; - } - st->blksiz = st->media_blksiz; - SC_DEBUG(sc_link, SDEV_DB3, - ("Used media_blksiz of %lu\n", (u_long)st->media_blksiz)); - goto done; - } - /* - * We're getting no hints from any direction. Choose variable- - * length blocks arbitrarily. - */ - st->flags &= ~ST_FIXEDBLOCKS; - st->blksiz = 0; - SC_DEBUG(sc_link, SDEV_DB3, ("Give up and default to variable mode\n")); -done: - - /* - * Decide whether or not to write two file marks to signify end- - * of-data. Make the decision as a function of density. If - * the decision is not to use a second file mark, the SCSI BLANK - * CHECK condition code will be recognized as end-of-data when - * first read. - * (I think this should be a by-product of fixed/variable..julian) - */ - switch ((int)st->density) { -/* case 8 mm: What is the SCSI density code for 8 mm, anyway? */ - case QIC_11: - case QIC_24: - case QIC_120: - case QIC_150: - case QIC_525: - case QIC_1320: - case QIC_3080: - st->flags &= ~ST_2FM_AT_EOD; - break; - default: - st->flags |= ST_2FM_AT_EOD; - } - return 0; -} - -static int -stread(dev_t dev, struct uio *uio, int ioflag) -{ - return (physio(ststrategy, NULL, dev, 1, minphys, uio)); -} - -static int -stwrite(dev_t dev, struct uio *uio, int ioflag) -{ - return (physio(ststrategy, NULL, dev, 0, minphys, uio)); -} - -/* - * Actually translate the requested transfer into - * one the physical driver can understand - * The transfer is described by a buf and will include - * only one physical transfer. - */ -static void -st_strategy(struct buf *bp, struct scsi_link *sc_link) -{ - u_int32_t unit; - u_int32_t opri; - struct scsi_data *st; - int len; - - unit = STUNIT((bp->b_dev)); - st = sc_link->sd; - /* - * If it's a null transfer, return immediatly - */ - if ((len = bp->b_bcount) == 0) { - goto done; - } - /* - * Check the adapter can do it - */ - scsi_minphys(bp,&st_switch); - /* - * Odd sized request on fixed drives are verboten - */ - if (st->flags & ST_FIXEDBLOCKS) { - if (bp->b_bcount % st->blksiz) { - printf("st%lu: bad request, must be multiple of %lu\n", - (u_long)unit, (u_long)st->blksiz); - bp->b_error = EIO; - goto bad; - } - } - /* - * as are out-of-range requests on variable drives. - * (or if we got chopped by minphys) - */ - else { - if ((bp->b_bcount < st->blkmin || bp->b_bcount > st->blkmax)) { - printf( - "st%lu: bad request, must be between %lu and %lu\n", - (u_long)unit, (u_long)st->blkmin, - (u_long)st->blkmax); - bp->b_error = EIO; - goto bad; - } - if (len != bp->b_bcount) { - printf( - "st%lu: bad request, must be less than %ld bytes\n", - (u_long)unit, bp->b_bcount + 1); - bp->b_error = EIO; - goto bad; - } - } - opri = splbio(); - - /* - * Use a bounce buffer if necessary - */ -#ifdef BOUNCE_BUFFERS - if (sc_link->flags & SDEV_BOUNCE) - vm_bounce_alloc(bp); -#endif - - /* - * Place it in the queue of activities for this tape - * at the end (a bit silly because we only have on user.. - * (but it could fork() )) - */ - bufq_insert_tail(&st->buf_queue, bp); - - /* - * Tell the device to get going on the transfer if it's - * not doing anything, otherwise just wait for completion - * (All a bit silly if we're only allowing 1 open but..) - */ - ststart(unit, 0); - - splx(opri); - return; -bad: - bp->b_flags |= B_ERROR; -done: - /* - * Correctly set the buf to indicate a completed xfer - */ - biodone(bp); - return; -} - -/* - * ststart looks to see if there is a buf waiting for the device - * and that the device is not already busy. If both are true, - * It dequeues the buf and creates a scsi command to perform the - * transfer required. The transfer request will call scsi_done - * on completion, which will in turn call this routine again - * so that the next queued transfer is performed. - * The bufs are queued by the strategy routine (ststrategy) - * - * This routine is also called after other non-queued requests - * have been made of the scsi driver, to ensure that the queue - * continues to be drained. - * ststart() is called at splbio - */ -static void -ststart(unit, flags) - u_int32_t unit; - u_int32_t flags; -{ - struct scsi_link *sc_link = SCSI_LINK(&st_switch, unit); - struct scsi_data *st = sc_link->sd; - register struct buf *bp = 0; - struct scsi_rw_tape cmd; - - SC_DEBUG(sc_link, SDEV_DB2, ("ststart ")); - /* - * See if there is a buf to do and we are not already - * doing one - */ - while (sc_link->opennings != 0) { - - /* if a special awaits, let it proceed first */ - if (sc_link->flags & SDEV_WAITING) { - sc_link->flags &= ~SDEV_WAITING; - wakeup((caddr_t)sc_link); - return; - } - - bp = bufq_first(&st->buf_queue); - if (bp == NULL) { /* yes, an assign */ - return; - } - bufq_remove(&st->buf_queue, bp); - - /* - * if the device has been unmounted by the user - * then throw away all requests until done - */ - if ((!(st->flags & ST_MOUNTED)) - || (!(sc_link->flags & SDEV_MEDIA_LOADED))) { - /* make sure that one implies the other.. */ - sc_link->flags &= ~SDEV_MEDIA_LOADED; - goto badnews; - } - /* - * only FIXEDBLOCK devices have pending operations - */ - if (st->flags & ST_FIXEDBLOCKS) { - /* - * If we are at a filemark but have not reported it yet - * then we should report it now - */ - if (st->flags & ST_AT_FILEMARK) { - if ((bp->b_flags & B_READ) == B_WRITE) { - /* - * Handling of ST_AT_FILEMARK in - * st_space will fill in the right file - * mark count. - * Back up over filemark - */ - if (st_space(unit, 0, SP_FILEMARKS, 0) != - ESUCCESS) - goto badnews; - } else { - bp->b_resid = bp->b_bcount; - bp->b_error = 0; - bp->b_flags &= ~B_ERROR; - st->flags &= ~ST_AT_FILEMARK; - biodone(bp); - continue; /* seek more work */ - } - } - /* - * If we are at EIO (e.g. EOM) but have not reported it - * yet then we should report it now - */ - if (st->flags & ST_EIO_PENDING) { - bp->b_resid = bp->b_bcount; - bp->b_error = EIO; - bp->b_flags |= B_ERROR; - st->flags &= ~ST_EIO_PENDING; - biodone(bp); - continue; /* seek more work */ - } - } - /* - * Fill out the scsi command - */ - bzero(&cmd, sizeof(cmd)); - if ((bp->b_flags & B_READ) == B_WRITE) { - cmd.op_code = WRITE_COMMAND_TAPE; - st->flags &= ~ST_FM_WRITTEN; - st->flags |= ST_WRITTEN; - flags |= SCSI_DATA_OUT; - } else { - cmd.op_code = READ_COMMAND_TAPE; - flags |= SCSI_DATA_IN; - } - /* - * Handle "fixed-block-mode" tape drives by using the - * block count instead of the length. - */ - if (st->flags & ST_FIXEDBLOCKS) { - cmd.byte2 |= SRWT_FIXED; - scsi_uto3b(bp->b_bcount / st->blksiz, cmd.len); - } else { - scsi_uto3b(bp->b_bcount, cmd.len); - } - /* - * go ask the adapter to do all this for us - */ - if (scsi_scsi_cmd(sc_link, - (struct scsi_generic *) &cmd, - sizeof(cmd), - (u_char *) bp->b_data, - bp->b_bcount, - 0, /* can't retry a read on a tape really */ - 1000000, - bp, - flags) == SUCCESSFULLY_QUEUED) { - } else { -badnews: - printf("st%lu: oops not queued\n", (u_long)unit); - bp->b_flags |= B_ERROR; - bp->b_error = EIO; - biodone(bp); - } - } /* go back and see if we can cram more work in.. */ -} - -/* - * Perform special action on behalf of the user; - * knows about the internals of this device - */ -static errval -st_ioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, -struct proc *p, struct scsi_link *sc_link) -{ - errval errcode = 0; - u_int32_t unit; - u_int32_t number, flags, dsty; - struct scsi_data *st; - u_int32_t hold_blksiz; - u_int32_t hold_density; - int32_t nmarks; - struct mtop *mt = (struct mtop *) arg; - - /* - * Find the device that the user is talking about - */ - flags = 0; /* give error messages, act on errors etc. */ - unit = STUNIT(dev); - dsty = DSTY(dev); - st = sc_link->sd; - hold_blksiz = st->blksiz; - hold_density = st->density; - - switch (cmd) { - - case MTIOCGET: - { - struct mtget *g = (struct mtget *) arg; - - SC_DEBUG(sc_link, SDEV_DB1, ("[ioctl: get status]\n")); - bzero(g, sizeof(struct mtget)); - g->mt_type = 0x7; /* Ultrix compat *//*? */ - g->mt_density = st->density; - g->mt_blksiz = st->blksiz; - g->mt_comp = st->comp; - g->mt_density0 = st->modes[0].density; - g->mt_density1 = st->modes[1].density; - g->mt_density2 = st->modes[2].density; - g->mt_density3 = st->modes[3].density; - g->mt_blksiz0 = st->modes[0].blksiz; - g->mt_blksiz1 = st->modes[1].blksiz; - g->mt_blksiz2 = st->modes[2].blksiz; - g->mt_blksiz3 = st->modes[3].blksiz; - g->mt_comp0 = 0; - g->mt_comp1 = 0; - g->mt_comp2 = 0; - g->mt_comp3 = 0; - break; - } - case MTIOCTOP: - { - - SC_DEBUG(sc_link, SDEV_DB1, - ("[ioctl: op=0x%x count=0x%lx]\n", - mt->mt_op, (long)mt->mt_count)); - - /* compat: in U*x it is a short */ - number = mt->mt_count; - switch ((short) (mt->mt_op)) { - case MTWEOF: /* write an end-of-file record */ - errcode = st_write_filemarks(unit, number, flags); - break; - case MTBSF: /* backward space file */ - number = -number; - case MTFSF: /* forward space file */ - errcode = st_chkeod(unit, FALSE, &nmarks, flags); - if (errcode == ESUCCESS) - errcode = st_space(unit, number - nmarks, - SP_FILEMARKS, flags); - break; - case MTBSR: /* backward space record */ - number = -number; - case MTFSR: /* forward space record */ - errcode = st_chkeod(unit, TRUE, &nmarks, flags); - if (errcode == ESUCCESS) - errcode = st_space(unit, number, SP_BLKS, flags); - break; - case MTEOD: /* space to end of recorded medium */ - errcode = st_chkeod(unit, FALSE, &nmarks, flags); - if (errcode == ESUCCESS) - errcode = st_space(unit, 0, SP_EOM, - flags); - break; - case MTREW: /* rewind */ - errcode = st_rewind(unit, FALSE, flags); - break; - case MTERASE: /* erase */ - errcode = st_erase(unit, FALSE, flags); - break; - case MTRETENS: /* re-tension tape */ - errcode = st_load(unit, LD_LOAD|LD_RETEN, - flags); - break; - case MTOFFL: /* rewind and put the drive offline */ - /* - * Be sure to allow media removal before - * attempting the eject. - */ - scsi_prevent(sc_link, PR_ALLOW, SCSI_SILENT); - st_unmount(unit, EJECT); - break; - case MTNOP: /* no operation, sets status only */ - case MTCACHE: /* enable controller cache */ - case MTNOCACHE: /* disable controller cache */ - break; - case MTSETBSIZ: /* Set block size for device */ -#ifdef NOTYET - if (!(st->flags & ST_NEW_MOUNT)) { - uprintf("re-mount tape before changing blocksize"); - errcode = EINVAL; - break; - } -#endif - if (number == 0) { - st->flags &= ~ST_FIXEDBLOCKS; - } else { - if ((st->blkmin || st->blkmax) /* they exist */ - &&((number < st->blkmin - || number > st->blkmax))) { - errcode = EINVAL; - break; - } - st->flags |= ST_FIXEDBLOCKS; - } - st->blksiz = number; - st->flags |= ST_BLOCK_SET; /*XXX */ - goto try_new_value; - - case MTSETDNSTY: /* Set density for device and mode */ - if (number > (u_int8_t)0xff) { - /* Guard against overflows */ - errcode = EINVAL; - } else { - st->density = number; - goto try_new_value; - } - break; - case MTCOMP: /* enable default compression */ - errcode = st_comp(unit,number); - break; - default: - errcode = EINVAL; - } - break; - } - case MTIOCIEOT: - case MTIOCEEOT: - break; - default: - if(IS_CTLMODE(dev)) - errcode = scsi_do_ioctl(dev, cmd, arg, flag, p, sc_link); - else - errcode = ENOTTY; - break; - } - return errcode; -/*-----------------------------*/ -try_new_value: - /* - * Check that the mode being asked for is aggreeable to the - * drive. If not, put it back the way it was. - */ - if ( (errcode = st_mode_select(unit, 0, NULL, 0, 0)) ) { - /* - * put back as it was - */ - printf("st%lu: Cannot set selected mode", (u_long)unit); - st->density = hold_density; - st->blksiz = hold_blksiz; - if (st->blksiz) { - st->flags |= ST_FIXEDBLOCKS; - } else { - st->flags &= ~ST_FIXEDBLOCKS; - } - return (errcode); - } - /* - * As the drive liked it, if we are setting a new default, - * set it into the structures as such. - * - * The means for deciding this are not finalised yet - */ - if (IS_CTLMODE(dev)) { - /* special mode */ - /* XXX */ - switch ((short) (mt->mt_op)) { - case MTSETBSIZ: - st->modes[dsty].blksiz = st->blksiz; - st->modeflags[dsty] |= BLKSIZE_SET_BY_USER; - break; - case MTSETDNSTY: - st->modes[dsty].density = st->density; - st->modeflags[dsty] |= DENSITY_SET_BY_USER; - break; - } - } - return 0; -} - -/* - * Do a synchronous read. - */ -static errval -st_read(unit, buf, size, flags) - u_int32_t unit, size, flags; - char *buf; -{ - struct scsi_link *sc_link = SCSI_LINK(&st_switch, unit); - struct scsi_data *st = sc_link->sd; - struct scsi_rw_tape scsi_cmd; - - /* - * If it's a null transfer, return immediatly - */ - if (size == 0) { - return (ESUCCESS); - } - bzero(&scsi_cmd, sizeof(scsi_cmd)); - scsi_cmd.op_code = READ_COMMAND_TAPE; - if (st->flags & ST_FIXEDBLOCKS) { - scsi_cmd.byte2 |= SRWT_FIXED; - scsi_uto3b(size / (st->blksiz ? st->blksiz : DEF_FIXED_BSIZE), - scsi_cmd.len); - } else { - scsi_uto3b(size, scsi_cmd.len); - } - return (scsi_scsi_cmd(sc_link, - (struct scsi_generic *) &scsi_cmd, - sizeof(scsi_cmd), - (u_char *) buf, - size, - 0, /* not on io commands */ - 1000000, - NULL, - flags | SCSI_DATA_IN)); -} -#ifdef __STDC__ -#define b2tol(a) (((unsigned)(a##_1) << 8) + (unsigned)a##_0 ) -#else -#define b2tol(a) (((unsigned)(a/**/_1) << 8) + (unsigned)a/**/_0 ) -#endif - -/* - * Ask the drive what its min and max blk sizes are. - */ -static errval -st_rd_blk_lim(unit, flags) - u_int32_t unit, flags; -{ - struct scsi_link *sc_link = SCSI_LINK(&st_switch, unit); - struct scsi_data *st = sc_link->sd; - struct scsi_blk_limits scsi_cmd; - struct scsi_blk_limits_data scsi_blkl; - errval errno; - - /* - * First check if we have it all loaded - */ - if ((sc_link->flags & SDEV_MEDIA_LOADED)) - return 0; - - /* - * do a 'Read Block Limits' - */ - bzero(&scsi_cmd, sizeof(scsi_cmd)); - scsi_cmd.op_code = READ_BLK_LIMITS; - - /* - * do the command, update the global values - */ - if ( (errno = scsi_scsi_cmd(sc_link, - (struct scsi_generic *) &scsi_cmd, - sizeof(scsi_cmd), - (u_char *) & scsi_blkl, - sizeof(scsi_blkl), - ST_RETRIES, - 5000, - NULL, - flags | SCSI_DATA_IN)) ) { - return errno; - } - st->blkmin = b2tol(scsi_blkl.min_length); - st->blkmax = scsi_3btou(&scsi_blkl.max_length_2); - - SC_DEBUG(sc_link, SDEV_DB3, - ("(%lu <= blksiz <= %lu)\n", - (u_long)st->blkmin, (u_long)st->blkmax)); - return 0; -} - -/* - * Get the scsi driver to send a full inquiry to the - * device and use the results to fill out the global - * parameter structure. - * - * called from: - * attach - * open - * ioctl (to reset original blksize) - */ -static errval -st_mode_sense(unit, flags, page, pagelen, pagecode) - u_int32_t unit, flags; - struct tape_pages *page; - u_int32_t pagelen,pagecode; -{ - u_int32_t dat_len; - errval errno; - struct scsi_mode_sense scsi_cmd; - struct { - struct scsi_mode_header header; - struct blk_desc blk_desc; - struct tape_pages page; - } dat; - - /* Tandberg tape drives returns page 00 - * with the sense data, whether or not - * you want it( ie the don't like you - * saying you want anything less!!!!! - * They also expect page 00 - * back when you issue a mode select - */ - struct scsi_link *sc_link = SCSI_LINK(&st_switch, unit); - struct scsi_data *st = sc_link->sd; - - st->flags &= ~ST_SENSE_READ; - /* - * Check if we need to use a default page.. - */ - if ((st->quirks & ST_Q_NEEDS_PAGE_0) && (!page)) { - pagelen = PAGE_0_SENSE_DATA_SIZE; - page = (struct tape_pages *) st->saved_page0; - pagecode = 0; - } - /* - * Now work out the total dat size etc. - */ - dat_len = sizeof(struct scsi_mode_header) - + sizeof(struct blk_desc) - + (page ? pagelen : 0); - /* - * Set up a mode sense - */ - bzero(&scsi_cmd, sizeof(scsi_cmd)); - scsi_cmd.op_code = MODE_SENSE; - scsi_cmd.page = (u_char) pagecode; - scsi_cmd.length = dat_len; - - /* - * do the command, - * use the results to set blksiz, numblks and density - * or if we need it as a template for the mode select - * store it away. - */ - if ( (errno = scsi_scsi_cmd(sc_link, - (struct scsi_generic *) &scsi_cmd, - sizeof(scsi_cmd), - (u_char *) &dat, - dat_len, - ST_RETRIES, - 5000, - NULL, - flags | SCSI_DATA_IN)) ) { - return errno; - } - st->numblks = scsi_3btou(dat.blk_desc.nblocks); - st->media_blksiz = scsi_3btou(dat.blk_desc.blklen); - st->media_density = dat.blk_desc.density; - if (dat.header.dev_spec & SMH_DSP_WRITE_PROT) { - st->flags |= ST_READONLY; - } - SC_DEBUG(sc_link, SDEV_DB3, - ("density code 0x%lx, %lu-byte blocks, write-%s, ", - (u_long)st->media_density, (u_long)st->media_blksiz, - st->flags & ST_READONLY ? "protected" : "enabled")); - SC_DEBUG(sc_link, SDEV_DB3, ("%sbuffered\n", - ((dat.header.dev_spec & SMH_DSP_BUFF_MODE) ? "" : "un"))); - if (page) { - bcopy(&dat.page, page, pagelen); - } - st->flags |= ST_SENSE_READ; - return 0; -} - -/* - * Send a filled out parameter structure to the drive to - * set it into the desire modes etc. - */ -static errval -st_mode_select(unit, flags, page, pagelen, byte2) - u_int32_t unit, flags; - struct tape_pages *page; - u_int32_t pagelen; - u_int32_t byte2; -{ - u_int32_t dat_len; - struct scsi_mode_select scsi_cmd; - struct { - struct scsi_mode_header header; - struct blk_desc blk_desc; - struct tape_pages page; - } dat; - struct scsi_link *sc_link = SCSI_LINK(&st_switch, unit); - struct scsi_data *st = sc_link->sd; - - /* - * Check if we need to use a default page.. - * Gee, hope we saved one before now........ - */ - if ((st->quirks & ST_Q_NEEDS_PAGE_0) && (!page)) { - pagelen = PAGE_0_SENSE_DATA_SIZE; - page = (struct tape_pages *) st->saved_page0; - } - /* - * Now work out the total dat size etc. - */ - dat_len = sizeof(struct scsi_mode_header) - + sizeof(struct blk_desc) - + (page ? pagelen : 0); - /* - * Set up for a mode select - */ - bzero(&dat, dat_len); - bzero(&scsi_cmd, sizeof(scsi_cmd)); - scsi_cmd.op_code = MODE_SELECT; - scsi_cmd.length = dat_len; - scsi_cmd.byte2 = (u_char)byte2; - dat.header.blk_desc_len = sizeof(struct blk_desc); - dat.header.dev_spec |= SMH_DSP_BUFF_MODE_ON; - dat.blk_desc.density = st->density; - if (st->flags & ST_FIXEDBLOCKS) { - scsi_uto3b(st->blksiz, dat.blk_desc.blklen); - } - if (page) { - bcopy(page, &dat.page, pagelen); - /* the Tandberg tapes need the block size to */ - /* be set on each mode sense/select. */ - } - /* - * do the command - */ - return (scsi_scsi_cmd(sc_link, - (struct scsi_generic *) &scsi_cmd, - sizeof(scsi_cmd), - (u_char *) &dat, - dat_len, - ST_RETRIES, - 5000, - NULL, - flags | SCSI_DATA_OUT)); -} - -static int noisy_st = 0; -/***************************************************************\ -* Set the compression mode of the drive to on (1) or off (0) * - still doesn't work! grrr! -\***************************************************************/ -static errval -st_comp(unit,mode) -u_int32_t unit,mode; -{ - struct tape_pages page; - int pagesize; - int retval; - struct scsi_link *sc_link = SCSI_LINK(&st_switch, unit); - struct scsi_data *st = sc_link->sd; - - bzero(&page, sizeof(page)); - pagesize = sizeof(page.pages.configuration) + PAGE_HEADERLEN; - - if ( (retval = st_mode_sense(unit, 0, - &page, pagesize, ST_PAGE_CONFIGURATION)) ) - { - printf("sense returned an error of %d\n",retval); - return retval; - } - if ( noisy_st) - printf("drive reports value of %d, setting %lu\n", - page.pages.configuration.data_compress_alg, - (u_long)mode); - - page.pg_code &= ST_P_CODE; - page.pg_length = sizeof(page.pages.configuration); - - switch(mode) - { - case 0: - page.pages.configuration.data_compress_alg = 0; - break; - case 1: - page.pages.configuration.data_compress_alg = 1; - break; - default: - printf("st%lu: bad value for compression mode\n", (u_long)unit); - return EINVAL; - } - /* - * send ST_PAGE_CONFIGURATION page as SCSI-II command because it - * is a SCSI-II structure. This requires the PF bit (0x10) to be - * set for byte2. - */ - if ( (retval = st_mode_select(unit, 0, &page, pagesize, 0x10)) ) - { - printf("select returned an error of %d\n",retval); - return retval; - } - st->comp = mode; - return 0; -} -/* - * skip N blocks/filemarks/seq filemarks/eom - */ -static errval -st_space(unit, number, what, flags) - u_int32_t unit, what, flags; - int32_t number; -{ - errval error; - struct scsi_space scsi_cmd; - struct scsi_link *sc_link = SCSI_LINK(&st_switch, unit); - struct scsi_data *st = sc_link->sd; - - switch ((int)what) { - case SP_BLKS: - if (st->flags & ST_PER_ACTION) { - if (number > 0) { - st->flags &= ~ST_PER_ACTION; - return (EIO); - } else if (number < 0) { - if (st->flags & ST_AT_FILEMARK) { - /* - * Handling of ST_AT_FILEMARK - * in st_space will fill in the - * right file mark count. - */ - error = st_space(unit, 0, SP_FILEMARKS, - flags); - if (error) - return (error); - } - if (st->flags & ST_BLANK_READ) { - st->flags &= ~ST_BLANK_READ; - return (EIO); - } - st->flags &= ~ST_EIO_PENDING; - } - } - break; - case SP_FILEMARKS: - if (st->flags & ST_EIO_PENDING) { - if (number > 0) { /* pretend we just discover the error */ - st->flags &= ~ST_EIO_PENDING; - return (EIO); - } else if (number < 0) { /* back away from the error */ - st->flags &= ~ST_EIO_PENDING; - } - } - if (st->flags & ST_AT_FILEMARK) { - st->flags &= ~ST_AT_FILEMARK; - number--; - } - if ((st->flags & ST_BLANK_READ) && (number < 0)) { /* back away from unwritten tape */ - st->flags &= ~ST_BLANK_READ; - number++; /* dubious */ - } - break; - case SP_EOM: - if (st->flags & ST_EIO_PENDING) - { - /* we are already at EOM */ - st->flags &= ~ST_EIO_PENDING; - return(ESUCCESS); - } - number = 1; /* we have only one end-of-medium */ - break; - } - if (number == 0) { - return (ESUCCESS); - } - bzero(&scsi_cmd, sizeof(scsi_cmd)); - scsi_cmd.op_code = SPACE; - scsi_cmd.byte2 = what & SS_CODE; - scsi_uto3b(number, scsi_cmd.number); - return (scsi_scsi_cmd(sc_link, - (struct scsi_generic *) &scsi_cmd, - sizeof(scsi_cmd), - 0, - 0, - 0, /* no retries please , just fail */ - 3600000, /* wait up to an hour for completion */ - NULL, - flags)); -} - -/* - * write N filemarks - */ -static errval -st_write_filemarks(unit, number, flags) - u_int32_t unit, flags; - int32_t number; -{ - struct scsi_write_filemarks scsi_cmd; - struct scsi_link *sc_link = SCSI_LINK(&st_switch, unit); - struct scsi_data *st = sc_link->sd; - - /* - * It's hard to write a negative number of file marks. - * Don't try. - */ - if (number < 0) { - return EINVAL; - } - switch ((int)number) { - case 0: /* really a command to sync the drive's buffers */ - break; - case 1: - if (st->flags & ST_FM_WRITTEN) { /* already have one down */ - st->flags &= ~ST_WRITTEN; - } else { - st->flags |= ST_FM_WRITTEN; - } - st->flags &= ~ST_PER_ACTION; - break; - default: - st->flags &= ~(ST_PER_ACTION | ST_WRITTEN); - } - bzero(&scsi_cmd, sizeof(scsi_cmd)); - scsi_cmd.op_code = WRITE_FILEMARKS; - scsi_uto3b(number, scsi_cmd.number); - return scsi_scsi_cmd(sc_link, - (struct scsi_generic *) &scsi_cmd, - sizeof(scsi_cmd), - 0, - 0, - 0, /* no retries, just fail */ - 1000000, /* 100 secs.. (may need to repos head ) */ - NULL, - flags); -} - -/* - * Make sure the right number of file marks is on tape if the - * tape has been written. If the position argument is true, - * leave the tape positioned where it was originally. - * - * nmarks returns the number of marks to skip (or, if position - * true, which were skipped) to get back original position. - */ -static int32_t -st_chkeod(unit, position, nmarks, flags) - u_int32_t unit; - boolean position; - int32_t *nmarks; - u_int32_t flags; -{ - errval error; - struct scsi_data *st = SCSI_DATA(&st_switch, unit); - - switch ((int)(st->flags & (ST_WRITTEN | ST_FM_WRITTEN | ST_2FM_AT_EOD))) { - default: - *nmarks = 0; - return (ESUCCESS); - case ST_WRITTEN: - case ST_WRITTEN | ST_FM_WRITTEN | ST_2FM_AT_EOD: - *nmarks = 1; - break; - case ST_WRITTEN | ST_2FM_AT_EOD: - *nmarks = 2; - } - error = st_write_filemarks(unit, *nmarks, flags); - if (position && (error == ESUCCESS)) - error = st_space(unit, -*nmarks, SP_FILEMARKS, flags); - return (error); -} - -/* - * load/unload (with retension if true) - */ -static errval -st_load(unit, type, flags) - u_int32_t unit, type, flags; -{ - struct scsi_load scsi_cmd; - struct scsi_link *sc_link = SCSI_LINK(&st_switch, unit); - struct scsi_data *st = sc_link->sd; - - bzero(&scsi_cmd, sizeof(scsi_cmd)); - if (type != LD_LOAD) { - errval error; - int32_t nmarks; - - error = st_chkeod(unit, FALSE, &nmarks, flags); - if (error != ESUCCESS) - return (error); - sc_link->flags &= ~SDEV_MEDIA_LOADED; - } - if (st->quirks & ST_Q_IGNORE_LOADS) - return (0); - scsi_cmd.op_code = LOAD_UNLOAD; - scsi_cmd.how |= type; - return (scsi_scsi_cmd(sc_link, - (struct scsi_generic *) &scsi_cmd, - sizeof(scsi_cmd), - 0, - 0, - ST_RETRIES, - 900000, /* 15 min */ - NULL, - flags)); -} - -/* - * Rewind the device - */ -static errval -st_rewind(unit, immed, flags) - u_int32_t unit, flags; - boolean immed; -{ - struct scsi_rewind scsi_cmd; - struct scsi_link *sc_link = SCSI_LINK(&st_switch, unit); - struct scsi_data *st = sc_link->sd; - errval error; - int32_t nmarks; - - error = st_chkeod(unit, FALSE, &nmarks, flags); - if (error != ESUCCESS) - return (error); - st->flags &= ~ST_PER_ACTION; - bzero(&scsi_cmd, sizeof(scsi_cmd)); - scsi_cmd.op_code = REWIND; - scsi_cmd.byte2 = immed ? SR_IMMED : 0; - return (scsi_scsi_cmd(sc_link, - (struct scsi_generic *) &scsi_cmd, - sizeof(scsi_cmd), - 0, - 0, - ST_RETRIES, - immed ? 5000 : 300000, /* 5 sec or 5 min */ - NULL, - flags)); -} - -/* -** Erase the device -*/ -static errval -st_erase(unit, immed, flags) - u_int32_t unit, flags; - boolean immed; -{ - struct scsi_erase scsi_cmd; - struct scsi_link *sc_link = SCSI_LINK(&st_switch, unit); - struct scsi_data *st = sc_link->sd; - errval error; - int32_t nmarks; - - error = st_chkeod(unit, FALSE, &nmarks, flags); - if (error != ESUCCESS) - return (error); - /* - ** Archive Viper 2525 technical manual 5.7 (ERASE 19h): - ** tape has to be positioned to BOT first before erase command - ** is issued or command is rejected. So we rewind the tape first - ** and exit with an error, if the tape can't be rewinded. - */ - error = st_rewind(unit, FALSE, SCSI_SILENT); - if (error != ESUCCESS) - return (error); - st->flags &= ~ST_PER_ACTION; - bzero(&scsi_cmd, sizeof(scsi_cmd)); - scsi_cmd.op_code = ERASE; - scsi_cmd.byte2 = SE_LONG; /* LONG_ERASE */ - scsi_cmd.byte2 += immed ? SE_IMMED : 0; /* immed bit is here the 2nd! */ - return (scsi_scsi_cmd(sc_link, - (struct scsi_generic *) &scsi_cmd, - sizeof(scsi_cmd), - 0, - 0, - ST_RETRIES, - immed ? 5000 : (200 * 60 * 1000), /* 5 sec or 200 min */ - NULL, - flags)); -} - -/* - * Look at the returned sense and act on the error and detirmine - * The unix error number to pass back... (0 = report no error) - * (SCSIRET_CONTINUE = continue processing) - */ -static errval -st_interpret_sense(xs) - struct scsi_xfer *xs; -{ - struct scsi_link *sc_link = xs->sc_link; - struct scsi_sense_data *sense = &(xs->sense); - boolean silent = xs->flags & SCSI_SILENT; - u_int32_t unit = sc_link->dev_unit; - struct scsi_data *st = SCSI_DATA(&st_switch, unit); - u_int32_t key; - int32_t info; - - /* - * Get the sense fields and work out what code - */ - if (sense->error_code & SSD_ERRCODE_VALID) { - info = ntohl(*((int32_t *) sense->ext.extended.info)); - } else { - if (st->flags & ST_FIXEDBLOCKS) { - info = xs->datalen / st->blksiz; - } else { - info = xs->datalen; - } - } - - key = sense->ext.extended.flags & SSD_KEY; - - if (((sense->error_code & SSD_ERRCODE) != 0x70) - || (key == 0x7)) /* Media Write Protected */ { - return SCSIRET_CONTINUE;/* let the generic code handle it */ - } - if(sense->ext.extended.flags & (SSD_EOM|SSD_FILEMARK|SSD_ILI)) { - if (st->flags & ST_FIXEDBLOCKS) { - xs->resid = info * st->blksiz; - xs->flags |= SCSI_RESID_VALID; - if (sense->ext.extended.flags & SSD_EOM) { - st->flags |= ST_EIO_PENDING; - } - if (sense->ext.extended.flags & SSD_FILEMARK) { - st->flags |= ST_AT_FILEMARK; - } - if (sense->ext.extended.flags & SSD_ILI) { - st->flags |= ST_EIO_PENDING; - if (sense->error_code & SSD_ERRCODE_VALID && - !silent) - printf( - "st%lu: block wrong size, %ld blocks residual\n", - (u_long)unit, (long)info); - /*XXX*/ /* is this how it works ? */ - /* check def of ILI for fixed blk tapes */ - - /* - * This quirk code helps the drive read - * the first tape block, regardless of - * format. That is required for these - * drives to return proper MODE SENSE - * information. - */ - if ((st->quirks & ST_Q_SNS_HLP) && - !(st->flags & ST_SENSE_READ)) { - st->blksiz -= 512; - } - } - /* - * If no data was tranfered, do it immediatly - */ - if (xs->resid >= xs->datalen) { - xs->flags &= ~SCSI_RESID_VALID; - if (st->flags & ST_AT_FILEMARK) { - xs->flags |= SCSI_EOF; - st->flags &= ~ST_AT_FILEMARK; - return 0; - } - if (st->flags & ST_EIO_PENDING) { - st->flags &= ~ST_EIO_PENDING; - return EIO; - } - } - return 0; - } else { /* must be variable mode */ - xs->resid = xs->datalen; /* to be sure */ - if (sense->ext.extended.flags & SSD_EOM) { - return (EIO); - } - if (sense->ext.extended.flags & SSD_FILEMARK) { - xs->flags |= SCSI_EOF; - } - if (sense->ext.extended.flags & SSD_ILI) { - if (info < 0) { - /* - * the record was bigger than the read - */ - if (!silent) - printf( - "st%lu: %ld-byte record too big\n", - (u_long)unit, - (long)(xs->datalen - info)); - return (EIO); - } - xs->resid = info; - xs->flags |= SCSI_RESID_VALID; - } - } - return 0; - } - - if (key == 0x8) { - xs->flags |= SCSI_EOF; /* some drives need this */ - /* - * This quirk code helps the drive read the - * first tape block, regardless of format. That - * is required for these drives to return proper - * MODE SENSE information. - */ - if ((st->quirks & ST_Q_SNS_HLP) && - !(st->flags & ST_SENSE_READ)) { - /* still starting */ - st->blksiz -= 512; - } else if (!(st->flags & (ST_2FM_AT_EOD | ST_BLANK_READ))) { - st->flags |= ST_BLANK_READ; - xs->flags |= SCSI_EOF; - return (ESUCCESS); - } - } - return SCSIRET_CONTINUE; /* Use the the generic handler */ -} - -/* - * The quirk here is that the drive returns some value to st_mode_sense - * incorrectly until the tape has actually passed by the head. - * - * The method is to set the drive to large fixed-block state (user-specified - * density and 1024-byte blocks), then read and rewind to get it to sense the - * tape. If that doesn't work, try 512-byte fixed blocks. If that doesn't - * work, as a last resort, try variable- length blocks. The result will be - * the ability to do an accurate st_mode_sense. - * - * We know we can do a rewind because we just did a load, which implies rewind. - * Rewind seems preferable to space backward if we have a virgin tape. - * - * The rest of the code for this quirk is in ILI processing and BLANK CHECK - * error processing, both part of st_interpret_sense. - */ -static errval -st_touch_tape(unit) - u_int32_t unit; -{ - struct scsi_data *st = SCSI_DATA(&st_switch, unit); - char *buf; - u_int32_t readsiz; - errval errno; - -#ifdef BOUNCE_BUFFERS - buf = (caddr_t) vm_bounce_kva_alloc(btoc(1024)); -#else - buf = malloc(1024, M_TEMP, M_NOWAIT); -#endif - if (!buf) - return (ENOMEM); - - if (( errno = st_mode_sense(unit, 0, NULL, 0, 0)) ) { - goto bad; - } - st->blksiz = (st->quirks & ST_Q_NO_1024)? 512: 1024; - do { - switch ((int)st->blksiz) { - case 512: - case 1024: - readsiz = st->blksiz; - st->flags |= ST_FIXEDBLOCKS; - break; - default: - readsiz = 1; - st->flags &= ~ST_FIXEDBLOCKS; - } if ( (errno = st_mode_select(unit, 0, NULL, 0, 0)) ) { - goto bad; - } - st_read(unit, buf, readsiz, SCSI_SILENT); - if ( (errno = st_rewind(unit, FALSE, 0)) ) { -bad: free(buf, M_TEMP); - return (errno); - } - } while (readsiz != 1 && readsiz > st->blksiz); -#ifdef BOUNCE_BUFFERS - vm_bounce_kva_alloc_free((vm_offset_t) buf, btoc(1024)); -#else - free(buf, M_TEMP); -#endif - return 0; -} - -static st_devsw_installed = 0; - -static void -st_drvinit(void *unused) -{ - - if( ! st_devsw_installed ) { - dev_t dev; - - dev = makedev(CDEV_MAJOR, 0); - cdevsw_add(&dev, &st_cdevsw, NULL); - st_devsw_installed = 1; - } -} - -SYSINIT(stdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,st_drvinit,NULL) - - diff --git a/sys/scsi/su.c b/sys/scsi/su.c deleted file mode 100644 index 785e831..0000000 --- a/sys/scsi/su.c +++ /dev/null @@ -1,361 +0,0 @@ -/* su: SCSI Universal. This is a universal SCSI device that - * has a fixed minor number format. This allows you to refer - * to your devices by BUS, ID, LUN instead of st0, st1, ... - * - * This code looks up the underlying device for a given SCSI - * target and uses that driver. - * - *Begin copyright - * - * Copyright (C) 1993, 1994, 1995, HD Associates, Inc. - * PO Box 276 - * Pepperell, MA 01463 - * 508 433 5266 - * dufault@hda.com - * - * This code is contributed to the University of California at Berkeley: - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - *End copyright - * - * $Id: su.c,v 1.20 1998/07/04 22:30:25 julian Exp $ - * - * Tabstops 4 - * XXX devfs entries for this device should be handled by generic scsiconfig - * Add a bdevsw interface.. ? - */ - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/conf.h> -#include <sys/stat.h> -#include <sys/buf.h> -#include <sys/kernel.h> -#include <scsi/scsiconf.h> -#define CDEV_MAJOR 18 - -/* These three used by ssc. */ -extern d_open_t suopen; -extern d_close_t suclose; -extern d_ioctl_t suioctl; - -static d_read_t suread; -static d_write_t suwrite; -static d_poll_t supoll; -static d_strategy_t sustrategy; - -static struct cdevsw su_cdevsw = - { suopen, suclose, suread, suwrite, /*18*/ - suioctl, nostop, nullreset, nodevtotty,/* scsi */ - supoll, nommap, sustrategy, "su", NULL, -1 }; - - -/* Build an old style device number (unit encoded in the minor number) - * from a base old one (no flag bits) and a full new one - * (BUS, LUN, TARG in the minor number, and flag bits). - * - * OLDDEV has the major number and device unit only. It was constructed - * at attach time and is stored in the scsi_link structure. - * - * NEWDEV can have whatever in it, but only the old control flags and the - * super bit are present. IT CAN'T HAVE ANY UNIT INFORMATION or you'll - * wind up with the wrong unit. - */ -#define OLD_DEV(NEWDEV, OLDDEV) ((OLDDEV) | ((NEWDEV) & 0x080000FF)) - -/* cnxio: non existent device entries. */ - -static d_open_t nxopen; -static d_close_t nxclose; -static d_read_t nxread; -static d_write_t nxwrite; -static d_ioctl_t nxioctl; -#define nxstop nostop /* one void return is as good as another */ -#define nxreset noreset /* one unused function is as good as another */ -#define nxdevtotty nodevtotty /* one NULL return is as good as another */ -#define nxmmap nommap /* one -1 return is as good as another */ -#define nxstrategy nostrategy /* one NULL value is as good as another */ -static d_dump_t nxdump; -#define nxpsize nopsize /* one NULL value is as good as another */ - -static struct cdevsw cnxio = { - nxopen, - nxclose, - nxread, - nxwrite, - nxioctl, - nxstop, - nxreset, - nxdevtotty, - seltrue, - nxmmap, - nxstrategy, - "NON", - NULL, - -1, - nxdump, - nxpsize, - 0, - 0, - -1 -}; - -/* getsws: Look up the base dev switch for a given "by minor number" style - * device. - */ -static int -getsws(dev_t dev, int type, struct cdevsw **devswpp, dev_t *base) -{ - int ret = 0; - struct scsi_link *scsi_link; - int chr_dev, blk_dev; - - struct cdevsw *devswp; - - int bus = SCSI_BUS(dev), - lun = SCSI_LUN(dev), - id = SCSI_ID(dev); - - /* Try to look up the base device by finding the major number in - * the scsi_link structure: - */ - if ((scsi_link = scsi_link_get(bus, id, lun)) == 0 || - scsi_link->dev == NODEV) - { - ret = ENXIO; - devswp = &cnxio; - chr_dev = NODEV; - blk_dev = NODEV; - } - else - { - int bmaj, cmaj; - - cmaj = major(scsi_link->dev); - devswp = cdevsw[cmaj]; - chr_dev = OLD_DEV(dev, scsi_link->dev); - bmaj = devswp->d_bmaj; - blk_dev = OLD_DEV(dev, makedev(bmaj, minor(scsi_link->dev))); - } - - if (devswp) - *devswpp = devswp; - - if (type == S_IFCHR) - *base = chr_dev; - else - *base = blk_dev; - - return ret; -} - -int -suopen(dev_t dev, int flag, int type, struct proc *p) -{ - struct cdevsw *devswp; - dev_t base; - - if (getsws(dev, type, &devswp, &base)) - { - /* Device not configured? Reprobe then try again. - */ - int bus = SCSI_BUS(dev), lun = SCSI_LUN(dev), id = SCSI_ID(dev); - - if (scsi_probe_bus(bus, id, lun) || getsws(dev, type, &devswp, - &base)) - return ENXIO; - } - - /* There is a properly configured underlying device. - * Synthesize an appropriate device number: - */ - return (*devswp->d_open)(base, flag, type, p); -} - -int -suclose(dev_t dev, int fflag, int type, struct proc *p) -{ - struct cdevsw *devswp; - dev_t base; - - (void)getsws(dev, type, &devswp, &base); - - return (*devswp->d_close)(base, fflag, type, p); -} - -static void -sustrategy(struct buf *bp) -{ - dev_t base; - struct cdevsw *devswp; - dev_t dev = bp->b_dev; - - /* XXX: I have no way of knowing if this was through the - * block or the character entry point. - */ - (void)getsws(dev, S_IFBLK, &devswp, &base); - - bp->b_dev = base; - - (*devswp->d_strategy)(bp); - - bp->b_dev = dev; /* strat needs a dev_t */ -} - -int -suioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *p) -{ - struct cdevsw *devswp; - dev_t base; - - /* XXX: I have no way of knowing if this was through the - * block or the character entry point. - */ - (void)getsws(dev, S_IFCHR, &devswp, &base); - - return (*devswp->d_ioctl)(base, cmd, data, fflag, p); -} - -static int -suread(dev_t dev, struct uio *uio, int ioflag) -{ - dev_t base; - struct cdevsw *devswp; - - (void)getsws(dev, S_IFCHR, &devswp, &base); - - return (*devswp->d_read)(base, uio, ioflag); -} - -static int -suwrite(dev_t dev, struct uio *uio, int ioflag) -{ - dev_t base; - struct cdevsw *devswp; - - (void)getsws(dev, S_IFCHR, &devswp, &base); - - return (*devswp->d_write)(base, uio, ioflag); -} - -static int -supoll(dev_t dev, int events, struct proc *p) -{ - dev_t base; - struct cdevsw *devswp; - - (void)getsws(dev, S_IFCHR, &devswp, &base); - - return (*devswp->d_poll)(base, events, p); -} - -static int -nxopen(dev, flags, fmt, p) - dev_t dev; - int flags; - int fmt; - struct proc *p; -{ - - return (ENXIO); -} - -static int -nxclose(dev, flags, fmt, p) - dev_t dev; - int flags; - int fmt; - struct proc *p; -{ - - printf("nxclose(0x%x) called\n", dev); - return (ENXIO); -} - -static int -nxread(dev, uio, ioflag) - dev_t dev; - struct uio *uio; - int ioflag; -{ - - printf("nxread(0x%x) called\n", dev); - return (ENXIO); -} - -static int -nxwrite(dev, uio, ioflag) - dev_t dev; - struct uio *uio; - int ioflag; -{ - - printf("nxwrite(0x%x) called\n", dev); - return (ENXIO); -} - -static int -nxioctl(dev, cmd, data, flags, p) - dev_t dev; - u_long cmd; - caddr_t data; - int flags; - struct proc *p; -{ - - printf("nxioctl(0x%x) called\n", dev); - return (ENXIO); -} - -static int -nxdump(dev) - dev_t dev; -{ - - printf("nxdump(0x%x) called\n", dev); - return (ENXIO); -} - -static su_devsw_installed = 0; - -static void -su_drvinit(void *unused) -{ - dev_t dev; - - if( ! su_devsw_installed ) { - dev = makedev(CDEV_MAJOR, 0); - cdevsw_add(&dev,&su_cdevsw, NULL); - su_devsw_installed = 1; - } -} - -SYSINIT(sudev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,su_drvinit,NULL) - - diff --git a/sys/scsi/uk.c b/sys/scsi/uk.c deleted file mode 100644 index a9b8edf..0000000 --- a/sys/scsi/uk.c +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Driver for a device we can't identify. - * by Julian Elischer (julian@tfs.com) - * - * $Id: uk.c,v 1.18 1997/08/02 14:33:16 bde Exp $ - * - * If you find that you are adding any code to this file look closely - * at putting it in "scsi_driver.c" instead. - */ - -#include <opt_devfs.h> - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/conf.h> -#include <sys/kernel.h> -#ifdef DEVFS -#include <sys/devfsext.h> -#endif /*DEVFS*/ -#include <scsi/scsiconf.h> -#include <scsi/scsi_driver.h> - -struct scsi_data { -#ifdef DEVFS - void *devfs_data_tok; -#endif -}; - -static d_open_t ukopen; -static d_close_t ukclose; -static d_ioctl_t ukioctl; - -#define CDEV_MAJOR 31 -static struct cdevsw uk_cdevsw = - { ukopen, ukclose, noread, nowrite, /*31*/ - ukioctl, nostop, nullreset, nodevtotty,/* unknown */ - seltrue, nommap, NULL, "uk" ,NULL, -1 }; - -SCSI_DEVICE_ENTRIES(uk) - -struct scsi_device uk_switch = -{ - NULL, - NULL, - NULL, - NULL, - "uk", - 0, - {0, 0}, - SDEV_ONCE_ONLY|SDEV_UK, /* Only one open allowed */ - ukattach, - "Unknown", - ukopen, - sizeof(struct scsi_data), - T_UNKNOWN, - 0, - 0, - 0, - 0, - 0, - 0, -}; - - -static uk_devsw_installed = 0; - -static errval -ukattach(struct scsi_link *sc_link) -{ -#ifdef DEVFS - struct scsi_data *uk = sc_link->sd; - - uk->devfs_data_tok = devfs_add_devswf(&uk_cdevsw, - sc_link->dev_unit, - DV_CHR, - UID_ROOT, GID_WHEEL, 0600, - "uk%d", sc_link->dev_unit); -#endif - return 0; -} - - -static void uk_drvinit(void *unused) -{ - dev_t dev; - - if( ! uk_devsw_installed ) { - dev = makedev(CDEV_MAJOR, 0); - cdevsw_add(&dev,&uk_cdevsw, NULL); - uk_devsw_installed = 1; - } -} - -SYSINIT(ukdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,uk_drvinit,NULL) - - diff --git a/sys/scsi/worm.c b/sys/scsi/worm.c deleted file mode 100644 index 1601d8e..0000000 --- a/sys/scsi/worm.c +++ /dev/null @@ -1,1811 +0,0 @@ -/* - * worm: Write Once device driver - * - * Copyright (C) 1995, HD Associates, Inc. - * PO Box 276 - * Pepperell, MA 01463 - * 508 433 5266 - * dufault@hda.com - * - * Copyright (C) 1996-97 interface business GmbH - * Naumannstr. 1 - * D-01309 Dresden - * F.R. Germany - * <joerg_wunsch@interface-business.de> - * - * This code is contributed to the University of California at Berkeley: - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id: worm.c,v 1.58 1998/07/04 22:30:25 julian Exp $ - */ - -#include "opt_bounce.h" -#include "opt_devfs.h" -#include "opt_scsi.h" - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/buf.h> -#include <sys/cdio.h> -#include <sys/wormio.h> -#include <sys/fcntl.h> -#include <sys/conf.h> -#include <sys/kernel.h> -#ifdef DEVFS -#include <sys/devfsext.h> -#endif /*DEVFS*/ -#include <scsi/scsiconf.h> -#include <scsi/scsi_debug.h> -#include <scsi/scsi_disk.h> -#include <scsi/scsi_driver.h> -#include <scsi/scsi_worm.h> -#include <scsi/scsi_cd.h> -#include <sys/dkstat.h> -#include <sys/malloc.h> - -#include "ioconf.h" - -struct worm_quirks -{ - /* - * The device-specific functions that need to be called during - * the several steps. - */ - errval (*prepare_disk)(struct scsi_link *, int dummy, int speed); - errval (*prepare_track)(struct scsi_link *, struct wormio_prepare_track *t); - errval (*finalize_track)(struct scsi_link *); - errval (*finalize_disk)(struct scsi_link *, int toc_type, int onp); - errval (*write_session)(struct scsi_link *, struct wormio_write_session *); - errval (*read_first_writable_address)(struct scsi_link *sc_link, - int track, int mode, int raw, int audio, int *addr); -}; - - -struct scsi_data -{ - struct buf_queue_head buf_queue; - int dkunit; /* disk stats unit number */ - u_int32_t blk_size; /* Size of each blocks */ -#ifdef DEVFS - void *b_devfs_token; - void *c_devfs_token; - void *ctl_devfs_token; -#endif - - struct worm_quirks *quirks; /* model-specific functions */ - struct wormio_prepare_track preptrack; /* scratch region */ - struct wormio_write_session *write_session; /* scratch region */ - - u_int8_t dummy; /* use dummy writes */ - u_int8_t speed; /* select drive speed */ - - u_int32_t worm_flags; /* driver-internal flags */ -#define WORMFL_DISK_PREPED 0x01 /* disk parameters have been spec'ed */ -#define WORMFL_TRACK_PREPED 0x02 /* track parameters have been sent */ -#define WORMFL_WRITTEN 0x04 /* track has been written */ -#define WORMFL_IOCTL_ONLY 0x08 /* O_NDELAY, only ioctls allowed */ -#define WORMFL_TRACK_PREP 0x10 /* track parameters have been spec'ed */ - - int error; /* last error */ -}; - -static struct { - int asc; - int devmode; - int error; - int ret; -} worm_error[] = { - {0x24, WORM_Q_PLASMON|WORM_Q_PHILIPS, WORM_ABSORPTION_CONTROL_ERROR, 0}, - {0xb0, WORM_Q_PLASMON|WORM_Q_PHILIPS, WORM_CALIBRATION_AREA_ALMOST_FULL, 0}, - {0xb4, WORM_Q_PLASMON|WORM_Q_PHILIPS, WORM_CALIBRATION_AREA_FULL, SCSIRET_CONTINUE}, - {0xb5, WORM_Q_PLASMON|WORM_Q_PHILIPS, WORM_DUMMY_BLOCKS_ADDED, 0}, - {0xaa, WORM_Q_PLASMON|WORM_Q_PHILIPS, WORM_END_OF_MEDIUM, SCSIRET_CONTINUE}, - {0xad, WORM_Q_PLASMON|WORM_Q_PHILIPS, WORM_BUFFER_UNDERRUN, SCSIRET_CONTINUE}, - {0xaf, WORM_Q_PLASMON|WORM_Q_PHILIPS, WORM_OPTIMUM_POWER_CALIBRATION_ERROR, SCSIRET_CONTINUE}, - {0, 0, 0, 0} -}; - -static void wormstart(u_int32_t unit, u_int32_t flags); - -static errval worm_open(dev_t dev, int flags, int fmt, struct proc *p, - struct scsi_link *sc_link); -static errval worm_ioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, - struct proc *p, struct scsi_link *sc_link); -static errval worm_close(dev_t dev, int flag, int fmt, struct proc *p, - struct scsi_link *sc_link); -static void worm_strategy(struct buf *bp, struct scsi_link *sc_link); -static errval worm_read_toc(struct scsi_link *sc_link, - u_int32_t mode, u_int32_t start, - struct cd_toc_entry *data, u_int32_t len); -static errval worm_rezero_unit(struct scsi_link *sc_link); -static errval worm_read_session_info(struct scsi_link *, struct wormio_session_info *); -static int worm_sense_handler(struct scsi_xfer *); -static errval worm_set_blksize(struct scsi_link *sc_link, int size); - -/* XXX should be moved out to an LKM */ -static errval rf4100_prepare_disk(struct scsi_link *, int dummy, int speed); -static errval rf4100_prepare_track(struct scsi_link *, struct wormio_prepare_track *); -static errval rf4100_finalize_track(struct scsi_link *); -static errval rf4100_finalize_disk(struct scsi_link *, int toc_type, int onp); - -static errval hp4020i_prepare_disk(struct scsi_link *, int dummy, int speed); -static errval hp4020i_prepare_track(struct scsi_link *, struct wormio_prepare_track *); -static errval hp4020i_finalize_track(struct scsi_link *); -static errval hp4020i_finalize_disk(struct scsi_link *, int toc_type, int onp); -static errval hp4020i_write_session(struct scsi_link *, struct wormio_write_session *); -static errval hp4020i_read_first_writable_address (struct scsi_link *sc_link, - int track, int mode, int raw, int audio, int *addr); - -static worm_devsw_installed = 0; - -static d_open_t wormopen; -static d_read_t wormread; -static d_write_t wormwrite; -static d_close_t wormclose; -static d_ioctl_t wormioctl; -static d_strategy_t wormstrategy; - -#define CDEV_MAJOR 62 -#define BDEV_MAJOR 23 - -static struct cdevsw worm_cdevsw = { - wormopen, wormclose, wormread, wormwrite, - wormioctl, nostop, nullreset, nodevtotty, - seltrue, nommap, wormstrategy, "worm", - NULL, -1, nodump, nopsize, - D_DISK, 0, -1 }; - -static int -wormunit(dev_t dev) -{ - return (minor(dev) & ~(SCSI_FIXED_MASK|SCSI_CONTROL_MASK)); -} - -SCSI_DEVICE_ENTRIES(worm) - -static struct scsi_device worm_switch = -{ - worm_sense_handler, - wormstart, /* we have a queue, and this is how we service it */ - NULL, - NULL, - "worm", - 0, - {0, 0}, - SDEV_ONCE_ONLY, /* Only one open allowed */ - wormattach, - "Write-Once", - wormopen, - sizeof(struct scsi_data), - T_WORM, - wormunit, - 0, - worm_open, - worm_ioctl, - worm_close, - worm_strategy, -}; - -static struct worm_quirks worm_quirks_plasmon = { - rf4100_prepare_disk, rf4100_prepare_track, - rf4100_finalize_track, rf4100_finalize_disk, - 0, hp4020i_read_first_writable_address -}; -static struct worm_quirks worm_quirks_philips = { - hp4020i_prepare_disk, hp4020i_prepare_track, - hp4020i_finalize_track, hp4020i_finalize_disk, - hp4020i_write_session, hp4020i_read_first_writable_address -}; - -static __inline void -worm_registerdev(int unit) -{ - if (dk_ndrive < DK_NDRIVE) { - sprintf(dk_names[dk_ndrive], "worm%d", unit); - dk_wpms[dk_ndrive] = (1*1024*1024/2); /* 1MB/sec XXX - fake! */ - SCSI_DATA(&worm_switch, unit)->dkunit = dk_ndrive++; - } else { - SCSI_DATA(&worm_switch, unit)->dkunit = -1; - } -} - -static errval -worm_size(struct scsi_link *sc_link, int flags) -{ - errval ret; - struct scsi_data *worm = sc_link->sd; - int blk_size; - u_int32_t n_blks; - - SC_DEBUG(sc_link, SDEV_DB2, ("worm_size")); - - n_blks = scsi_read_capacity(sc_link, &blk_size, flags); - - /* - * CD-R devices can assume various sizes, depending on the - * intended purpose of the track. Hence, READ CAPACITY - * doesn't give us any good results. We make a more educated - * guess when it comes to prepare a track. - */ - - if (n_blks > 0) { - sc_link->flags |= SDEV_MEDIA_LOADED; - ret = 0; - } else { - sc_link->flags &= ~SDEV_MEDIA_LOADED; - ret = ENXIO; - } - - return ret; -} - -static errval -wormattach(struct scsi_link *sc_link) -{ - u_int32_t unit = sc_link->dev_unit; -#ifdef DEVFS - int mynor; -#endif - struct scsi_data *worm = sc_link->sd; - - if (sc_link->devmodes == 0) - printf(", warning: unknown drive type"); - - bufq_init(&worm->buf_queue); - -#ifdef DEVFS - mynor = wormunit(sc_link->dev); - worm->b_devfs_token = - devfs_add_devswf(&worm_cdevsw, mynor, - DV_BLK, 0, 0, 0444, "worm%d", mynor); - worm->c_devfs_token = - devfs_add_devswf(&worm_cdevsw, mynor, - DV_CHR, 0, 0, 0644, "rworm%d", mynor); - worm->ctl_devfs_token = - devfs_add_devswf(&worm_cdevsw, mynor | SCSI_CONTROL_MASK, - DV_CHR, 0, 0, 0600, "rworm%d.ctl", mynor); -#endif - worm_registerdev(unit); - return 0; -} - -static int -wormread(dev_t dev, struct uio *uio, int ioflag) -{ - return (physio(wormstrategy, NULL, dev, 1, minphys, uio)); -} - -static int -wormwrite(dev_t dev, struct uio *uio, int ioflag) -{ - return (physio(wormstrategy, NULL, dev, 0, minphys, uio)); -} - -/* - * wormstart looks to see if there is a buf waiting for the device - * and that the device is not already busy. If both are true, - * It dequeues the buf and creates a scsi command to perform the - * transfer required. The transfer request will call scsi_done - * on completion, which will in turn call this routine again - * so that the next queued transfer is performed. - * The bufs are queued by the strategy routine (wormstrategy) - * - * This routine is also called after other non-queued requests - * have been made of the scsi driver, to ensure that the queue - * continues to be drained. - * wormstart() is called at splbio - * - * XXX It looks like we need a "scsistart" to hoist common code up - * into. In particular, the removable media checking should be - * handled in one place. - * - * Writes will fail if the disk and track not been prepared via the control - * device. - */ -static void -wormstart(unit, flags) - u_int32_t unit; - u_int32_t flags; -{ - struct scsi_link *sc_link = SCSI_LINK(&worm_switch, unit); - struct scsi_data *worm = sc_link->sd; - register struct buf *bp = 0; - struct scsi_rw_big cmd; - - u_int32_t lba; /* Logical block address */ - u_int32_t tl; /* Transfer length */ - - SC_DEBUG(sc_link, SDEV_DB2, ("wormstart ")); - - /* - * We should reject all queued entries if SDEV_MEDIA_LOADED is not true. - */ - if (!(sc_link->flags & SDEV_MEDIA_LOADED)) { - goto badnews; /* no I/O.. media changed or something */ - } - - /* - * See if there is a buf to do and we are not already - * doing one - */ - while (sc_link->opennings != 0) { - - /* if a special awaits, let it proceed first */ - if (sc_link->flags & SDEV_WAITING) { - sc_link->flags &= ~SDEV_WAITING; - wakeup(sc_link); - return; - } - - bp = bufq_first(&worm->buf_queue); - if (bp == NULL) - return; - - bufq_remove(&worm->buf_queue, bp); - - if ((bp->b_flags & B_READ) == B_WRITE) { - if ((worm->worm_flags & WORMFL_TRACK_PREPED) == 0) { - if ((worm->worm_flags & WORMFL_TRACK_PREP) == 0 && - !worm->write_session) { - SC_DEBUG(sc_link, SDEV_DB3, ("sequence error\n")); - bp->b_error = EIO; - bp->b_flags |= B_ERROR; - worm->error = WORM_SEQUENCE_ERROR; - biodone(bp); - goto badnews; - } else { - if (worm->write_session) { - if ((worm->quirks->write_session) - (sc_link, worm->write_session)) { - biodone(bp); - goto badnews; - } - } else - if (worm->quirks->prepare_track(sc_link, &worm->preptrack) - != 0) { - biodone(bp); - goto badnews; - } - worm->worm_flags |= WORMFL_TRACK_PREPED; - } - } - } - /* - * Fill out the scsi command - */ - bzero(&cmd, sizeof(cmd)); - if ((bp->b_flags & B_READ) == B_WRITE) { - cmd.op_code = WRITE_BIG; - flags |= SCSI_DATA_OUT; - } else { - cmd.op_code = READ_BIG; - flags |= SCSI_DATA_IN; - } - - worm->error = 0; - - lba = bp->b_blkno / (worm->blk_size / DEV_BSIZE); - tl = bp->b_bcount / worm->blk_size; - - if (bp->b_flags & B_READ) - /* - * Leave the LBA as 0 for write operations, it - * is reserved in this case (and wouldn't make - * any sense to set it at all, since CD-R write - * operations are in `streaming' mode anyway. - */ - scsi_uto4b(lba, &cmd.addr_3); - scsi_uto2b(tl, &cmd.length2); - - /* - * go ask the adapter to do all this for us - */ - if (scsi_scsi_cmd(sc_link, - (struct scsi_generic *) &cmd, - sizeof(cmd), - (u_char *) bp->b_data, - bp->b_bcount, - 0, - 100000, - bp, - flags | SCSI_NOSLEEP) == SUCCESSFULLY_QUEUED) { - if (worm->dkunit >= 0) { /* Cloned from od.c, possibly with same mistakes. :) */ - dk_xfer[worm->dkunit]++; - dk_seek[worm->dkunit] = 1; /* single track */ - dk_wds[worm->dkunit] += bp->b_bcount >> 6; - } - if ((bp->b_flags & B_READ) == B_WRITE) - worm->worm_flags |= WORMFL_WRITTEN; - } else { - printf("worm%lu: oops not queued\n", (u_long)unit); - if (bp) { - bp->b_flags |= B_ERROR; - bp->b_error = EIO; - biodone(bp); - } - } - } /* go back and see if we can cram more work in.. */ -badnews: ; -} - -static void -worm_strategy(struct buf *bp, struct scsi_link *sc_link) -{ - unsigned char unit; - u_int32_t opri; - struct scsi_data *worm; - - unit = wormunit(bp->b_dev); - worm = sc_link->sd; - - if ((worm->worm_flags & WORMFL_IOCTL_ONLY) != 0) { - SC_DEBUG(sc_link, SDEV_DB3, - ("attempted IO on ioctl-only descriptor\n")); - bp->b_error = EBADF; - bp->b_flags |= B_ERROR; - biodone(bp); - return; - } - - /* - * check it's not too big a transfer for our adapter - */ - wormminphys(bp); - - opri = splbio(); - - /* - * Use a bounce buffer if necessary - * XXX: How can we move this up? - */ -#ifdef BOUNCE_BUFFERS - if (sc_link->flags & SDEV_BOUNCE) - vm_bounce_alloc(bp); -#endif - - /* - * Place it in the queue of activities for this device - * at the end. - */ - bufq_insert_tail(&worm->buf_queue, bp); - - wormstart(unit, 0); - - splx(opri); - return; -} - -/* - * Open the device. - * Only called for the "real" device, not for the control device. - */ -static int -worm_open(dev_t dev, int flags, int fmt, struct proc *p, - struct scsi_link *sc_link) -{ - struct scsi_data *worm; - errval error; - - error = 0; - worm = sc_link->sd; - - if (sc_link->flags & SDEV_OPEN) - return EBUSY; - - /* - * Unknown drive type: only the control device can be opened - * in this case, so scsi(8) and things like cdrecord will - * work. - */ - if (sc_link->devmodes == 0) - return ENXIO; - - /* - * Check that it is still responding and ok. - * if the media has been changed this will result in a - * "unit attention" error which the error code will - * disregard because the SDEV_OPEN flag is not yet set - * - * XXX This should REALLY be hoisted up. As soon as Bruce - * finishes that slice stuff. (Add a different flag, - * and then do a "scsi_test_unit_ready" with the "ignore - * unit attention" thing set. Then all this replicated - * test unit ready code can be pulled up. - */ - scsi_test_unit_ready(sc_link, SCSI_SILENT); - - /* - * The semantics of the "flags" is as follows: - * - * If the device has been opened with O_NONBLOCK set, no - * actual IO will be allowed, and the command sequence is only - * subject to the restrictions as in worm_ioctl() below. - */ - /* - * Next time actually take notice of error returns, - * unit attn errors are now errors. - */ - sc_link->flags |= SDEV_OPEN; - - if (scsi_test_unit_ready(sc_link, SCSI_SILENT) != 0) { - SC_DEBUG(sc_link, SDEV_DB3, ("not ready\n")); - error = ENXIO; - goto out; - } - - if ((flags & O_NONBLOCK) == 0) { - scsi_start_unit(sc_link, SCSI_SILENT); - scsi_prevent(sc_link, PR_PREVENT, SCSI_SILENT); - - if((flags & FWRITE) != 0) { - if ((error = worm_rezero_unit(sc_link)) != 0 || - (error = worm_size(sc_link, 0)) != 0) { - SC_DEBUG(sc_link, SDEV_DB3, - ("rezero, or get size failed\n")); - error = EIO; - goto out; - } - } else { - /* read/only */ - if ((error = worm_size(sc_link, 0)) != 0) { - SC_DEBUG(sc_link, SDEV_DB3, - ("get size failed\n")); - error = EIO; - goto out; - } - worm->blk_size = 2048; - } - } else - worm->worm_flags |= WORMFL_IOCTL_ONLY; - - switch (*(int *) sc_link->devmodes) { - case WORM_Q_PLASMON: - worm->quirks = &worm_quirks_plasmon; - break; - case WORM_Q_PHILIPS: - worm->quirks = &worm_quirks_philips; - break; - default: - error = ENXIO; - } - worm->error = 0; - - out: - if (error) { - scsi_prevent(sc_link, PR_ALLOW, SCSI_SILENT); - worm->worm_flags &= ~(WORMFL_TRACK_PREPED| WORMFL_TRACK_PREP); - sc_link->flags &= ~SDEV_OPEN; - } - - return error; -} - -static int -worm_close(dev_t dev, int flags, int fmt, struct proc *p, - struct scsi_link *sc_link) -{ - struct scsi_data *worm = sc_link->sd; - errval error; - - error = 0; - - if ((worm->worm_flags & WORMFL_IOCTL_ONLY) == 0) { - if ((flags & FWRITE) != 0) { - worm->error = 0; - if ((worm->worm_flags & WORMFL_TRACK_PREPED) != 0) { - error = (worm->quirks->finalize_track)(sc_link); - worm->worm_flags &= - ~(WORMFL_TRACK_PREPED | WORMFL_TRACK_PREP); - } - } - scsi_prevent(sc_link, PR_ALLOW, SCSI_SILENT); - } else { - worm->worm_flags &= ~WORMFL_IOCTL_ONLY; - if (worm->write_session) { -#ifdef BOUNCE_BUFFERS - vm_bounce_kva_alloc_free((vm_offset_t)worm->write_session, - btoc(sizeof(struct wormio_write_session) + - worm->write_session->length)); -#else - free(worm->write_session, M_DEVBUF); -#endif - worm->write_session = 0; - } - } - sc_link->flags &= ~SDEV_OPEN; - - return error; -} - -/* - * Perform special action on behalf of the user. - * Knows about the internals of this device - */ -errval -worm_ioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p, - struct scsi_link *sc_link) -{ - errval error = 0; - u_int8_t unit; - register struct scsi_data *worm; - - /* - * Find the device that the user is talking about - */ - unit = wormunit(dev); - worm = sc_link->sd; - SC_DEBUG(sc_link, SDEV_DB2, ("wormioctl 0x%lx ", cmd)); - - switch (cmd) { - case WORMIOCPREPDISK: - { - struct wormio_prepare_disk *w = - (struct wormio_prepare_disk *)addr; - if (w->dummy != 0 && w->dummy != 1) - error = EINVAL; - else { - error = (worm->quirks->prepare_disk) - (sc_link, w->dummy, w->speed); - if (error == 0) { - worm->worm_flags |= WORMFL_DISK_PREPED; - worm->dummy = w->dummy; - worm->speed = w->speed; - } - } - } - break; - - case WORMIOCPREPTRACK: - { - struct wormio_prepare_track *w = - (struct wormio_prepare_track *)addr; - if (w->audio != 0 && w->audio != 1) - error = EINVAL; - else if (w->audio == 0 && w->preemp) - error = EINVAL; - else if ((worm->worm_flags & WORMFL_DISK_PREPED)==0) { - error = EINVAL; - worm->error = WORM_SEQUENCE_ERROR; - } else { - /* - * This sets a flag only. Actual preparation of a - * track will be deferred up to the first write. - */ - worm->worm_flags |= WORMFL_TRACK_PREP; - worm->preptrack = *w; - if (worm->write_session) { -#ifdef BOUNCE_BUFFERS - vm_bounce_kva_alloc_free((vm_offset_t)worm->write_session, - btoc(sizeof(struct wormio_write_session) + - worm->write_session->length)); -#else - free(worm->write_session, M_DEVBUF); -#endif - worm->write_session = 0; - } - } - } - break; - - case WORMIOCFINISHTRACK: - if ((worm->worm_flags & WORMFL_TRACK_PREPED) != 0) - error = (worm->quirks->finalize_track)(sc_link); - worm->worm_flags &= ~(WORMFL_TRACK_PREPED | WORMFL_TRACK_PREP); - break; - - case WORMIOCFIXATION: - { - struct wormio_fixation *w = - (struct wormio_fixation *)addr; - - if ((worm->worm_flags & WORMFL_WRITTEN) == 0) - error = EINVAL; - else if (w->toc_type < WORM_TOC_TYPE_AUDIO || - w->toc_type > WORM_TOC_TYPE_CDI) - error = EINVAL; - else if (w->onp != 0 && w->onp != 1) - error = EINVAL; - else { - worm->worm_flags = 0; - /* no fixation needed if dummy write */ - if (worm->dummy == 0) { - worm->error = 0; - error = (worm->quirks->finalize_disk) - (sc_link, w->toc_type, w->onp); - } - } - } - break; - - case WORMIOCREADSESSIONINFO: - { - struct wormio_session_info si; - error = worm_read_session_info(sc_link, &si); - if (error) - break; - NTOHS(si.lead_in); - NTOHS(si.lead_out); - bcopy(&si, addr, sizeof si); - } - break; - - case WORMIOCWRITESESSION: - if (worm->quirks->write_session) { - if ((worm->worm_flags & WORMFL_DISK_PREPED)==0) { - error = EINVAL; - worm->error = WORM_SEQUENCE_ERROR; - } else { -#ifdef BOUNCE_BUFFERS - worm->write_session = (struct wormio_write_session *) - vm_bounce_kva_alloc( - btoc(sizeof(struct wormio_write_session) + - ((struct wormio_write_session *) addr)->length)); - if (!worm->write_session) { - error = ENOMEM; - break; - } -#else - worm->write_session = malloc(sizeof(struct wormio_write_session) + - ((struct wormio_write_session *) addr)->length, - M_DEVBUF, M_WAITOK); -#endif - bcopy(addr, worm->write_session, sizeof(struct wormio_write_session)); - worm->write_session->track_desc = sizeof(struct wormio_write_session) + - (u_char *) worm->write_session; - bcopy(((struct wormio_write_session *) addr)->track_desc, - worm->write_session->track_desc, ((struct wormio_write_session *) addr)->length); - } - } else - error = ENXIO; - break; - - case WORMIOCFIRSTWRITABLEADDR: - if (worm->quirks->read_first_writable_address) { - int address; - struct wormio_first_writable_addr *a = - (struct wormio_first_writable_addr *) addr; - if ((a->audio & ~1) || (a->raw & ~1) || (a->mode & ~3) - || (a->track & ~0x7f)) { - error = EINVAL; - break; - } - error = worm->quirks->read_first_writable_address(sc_link, a->track, - a->mode, a->raw, - a->audio, &address); - if (error) - break; - error = copyout(&address, a->addr, sizeof(int)); - } else - error = ENXIO; - break; - - case WORMIOERROR: - bcopy(&(worm->error), addr, sizeof (int)); - break; - - case CDIOREADTOCHEADER: - { - struct ioc_toc_header th; - error = worm_read_toc(sc_link, 0, 0, - (struct cd_toc_entry *)&th, - sizeof th); - if (error) - break; - NTOHS(th.len); - bcopy(&th, addr, sizeof th); - } - break; - - case CDIOREADTOCENTRYS: - { - struct { - struct ioc_toc_header header; - struct cd_toc_entry entries[100]; - } data; - struct { - struct ioc_toc_header header; - struct cd_toc_entry entry; - } lead; - struct ioc_read_toc_entry *te = - (struct ioc_read_toc_entry *) addr; - struct ioc_toc_header *th; - u_int32_t len, readlen, idx, num; - u_int32_t starting_track = te->starting_track; - - if (te->data_len < sizeof(struct cd_toc_entry) - || (te->data_len % sizeof(struct cd_toc_entry)) != 0 - || te->address_format != CD_MSF_FORMAT - && te->address_format != CD_LBA_FORMAT) { - error = EINVAL; - break; - } - - th = &data.header; - error = worm_read_toc(sc_link, 0, 0, - (struct cd_toc_entry *)th, - sizeof (*th)); - if (error) - break; - - if (starting_track == 0) - starting_track = th->starting_track; - else if (starting_track == 0xaa) - starting_track = th->ending_track + 1; - else if (starting_track < th->starting_track || - starting_track > th->ending_track + 1) { - error = EINVAL; - break; - } - - /* calculate reading length without leadout entry */ - readlen = (th->ending_track - starting_track + 1) * - sizeof(struct cd_toc_entry); - - /* and with leadout entry */ - len = readlen + sizeof(struct cd_toc_entry); - if (te->data_len < len) { - len = te->data_len; - if (readlen > len) - readlen = len; - } - if (len > sizeof(data.entries)) { - error = EINVAL; - break; - } - num = len / sizeof(struct cd_toc_entry); - - if (readlen > 0) { - error = worm_read_toc(sc_link, - te->address_format, - starting_track, - (struct cd_toc_entry *)&data, - readlen + sizeof (*th)); - if (error) - break; - } - - /* make leadout entry if needed */ - idx = starting_track + num - 1; - if (idx == th->ending_track + 1) { - error = worm_read_toc(sc_link, - te->address_format, 0xaa, - (struct cd_toc_entry *)&lead, - sizeof(lead)); - if (error) - break; - data.entries[idx - starting_track] = lead.entry; - } - - error = copyout(data.entries, te->data, len); - } - break; - - case CDIOREADTOCENTRY: - { - struct { - struct ioc_toc_header header; - struct cd_toc_entry entry; - } data; - struct ioc_read_toc_single_entry *te = - (struct ioc_read_toc_single_entry *) addr; - struct ioc_toc_header *th; - u_int32_t track; - - if (te->address_format != CD_MSF_FORMAT - && te->address_format != CD_LBA_FORMAT) { - error = EINVAL; - break; - } - - th = &data.header; - error = worm_read_toc(sc_link, 0, 0, - (struct cd_toc_entry *)th, - sizeof (*th)); - if (error) - break; - - track = te->track; - if (track == 0) - track = th->starting_track; - else if (track == 0xaa) - /* OK */; - else if (track < th->starting_track || - track > th->ending_track + 1) { - error = EINVAL; - break; - } - - error = worm_read_toc(sc_link, te->address_format, - track, - (struct cd_toc_entry *)&data, - sizeof data); - if (error) - break; - - bcopy(&data.entry, &te->entry, - sizeof(struct cd_toc_entry)); - } - break; - - default: - error = ENOTTY; - break; - } - return (error); -} - - -static errval -worm_rezero_unit(struct scsi_link *sc_link) -{ - struct scsi_rezero_unit cmd; - - SC_DEBUG(sc_link, SDEV_DB2, ("worm_rezero_unit")); - - /* - * Re-initialize the unit, just to be sure. - */ - bzero(&cmd, sizeof(cmd)); - cmd.op_code = REZERO_UNIT; - return scsi_scsi_cmd(sc_link, - (struct scsi_generic *) &cmd, - sizeof(cmd), - 0, /* no data transfer */ - 0, - /*WORMRETRY*/ 4, - 5000, - NULL, - 0); -} - -static errval -worm_read_session_info(struct scsi_link *sc_link, struct wormio_session_info *data) -{ - struct scsi_read_session_info cmd; - - SC_DEBUG(sc_link, SDEV_DB2, ("worm_read_session_info")); - - bzero(&cmd, sizeof(cmd)); - cmd.op_code = READ_SESSION_INFO; - cmd.transfer_length = sizeof(struct wormio_session_info); - return scsi_scsi_cmd(sc_link, - (struct scsi_generic *) &cmd, - sizeof(cmd), - (u_char *) data, - sizeof(struct wormio_session_info), - /*WORMRETRY*/ 4, - 5000, - NULL, - SCSI_DATA_IN); -} - -/* - * Read table of contents - * - * Stolen from cd.c - */ -static errval -worm_read_toc(struct scsi_link *sc_link, u_int32_t mode, u_int32_t start, - struct cd_toc_entry *data, u_int32_t len) -{ - struct scsi_read_toc scsi_cmd; - u_int32_t ntoc; - - bzero(&scsi_cmd, sizeof(scsi_cmd)); - ntoc = len; - - scsi_cmd.op_code = READ_TOC; - if (mode == CD_MSF_FORMAT) - scsi_cmd.byte2 |= CD_MSF; - scsi_cmd.from_track = start; - scsi_cmd.data_len[0] = (ntoc) >> 8; - scsi_cmd.data_len[1] = (ntoc) & 0xff; - return (scsi_scsi_cmd(sc_link, - (struct scsi_generic *) &scsi_cmd, - sizeof(struct scsi_read_toc), - (u_char *) data, - len, - /*WORMRETRY*/ 4, - 5000, - NULL, - SCSI_DATA_IN)); -} - -static int -worm_sense_handler(struct scsi_xfer *xs) -{ - struct scsi_data *worm; - struct scsi_sense_data *sense; - struct scsi_sense_extended *ext; - int asc, devmode, i; - - worm = xs->sc_link->sd; - sense = &(xs->sense); - ext = (struct scsi_sense_extended *) &(sense->ext.extended); - asc = ext->add_sense_code; - devmode = *(int *) xs->sc_link->devmodes; - - for (i = 0; worm_error[i].asc; i++) - if ((asc == worm_error[i].asc) && (devmode & worm_error[i].devmode)) { - worm->error = worm_error[i].error; - return worm_error[i].ret; - } - worm->error = -1; - return SCSIRET_CONTINUE; -} - -static errval -worm_set_blksize(struct scsi_link *sc_link, int size) -{ - struct scsi_mode_select scsi_cmd; - struct { - struct scsi_mode_header header; - struct blk_desc desc; - } dat; - bzero(&scsi_cmd, sizeof(scsi_cmd)); - bzero(&dat, sizeof(dat)); - scsi_cmd.op_code = MODE_SELECT; - scsi_cmd.length = sizeof(dat); - dat.header.blk_desc_len = sizeof(struct blk_desc); - scsi_uto3b(size, dat.desc.blklen); - return scsi_scsi_cmd(sc_link, - (struct scsi_generic *) &scsi_cmd, - sizeof(scsi_cmd), - (u_char *) &dat, - sizeof(dat), - /*WORM_RETRIES*/ 4, - 5000, - NULL, - SCSI_DATA_OUT); -} - -static void -worm_drvinit(void *unused) -{ - - if (!worm_devsw_installed) { - cdevsw_add_generic(BDEV_MAJOR, CDEV_MAJOR, &worm_cdevsw); - worm_devsw_installed = 1; - } -} - -SYSINIT(wormdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,worm_drvinit,NULL) - -/* - * Begin device-specific stuff. Subject to being moved out to LKMs. - */ - -static u_char -ascii_to_6bit (char c) -{ - if (c < '0' || c > 'Z' || (c > '9' && c < 'A')) - return 0; - if (c <= '9') - return c - '0'; - else - return c - 'A' + 11; -} -/* - * PLASMON RF4100/4102 - * Perhaps other Plasmon's, too. - * - * NB: By now, you'll certainly have to compare the SCSI reference - * manual in order to understand the following. - */ - -/* The following mode pages might apply to other drives as well. */ - -struct plasmon_rf4100_pages -{ - u_char page_code; -#define RF4100_PAGE_CODE_20 0x20 -#define RF4100_PAGE_CODE_21 0x21 -#define RF4100_PAGE_CODE_22 0x22 -#define RF4100_PAGE_CODE_23 0x23 -#define RF4100_PAGE_CODE_24 0x24 -#define RF4100_PAGE_CODE_25 0x25 - u_char param_len; - union - { - /* page 0x20 omitted by now */ - struct - { - u_char reserved1; - u_char mode; -#define RF4100_RAW_MODE 0x10 /* raw mode enabled */ -#define RF4100_MIXED_MODE 0x08 /* mixed mode data enabled */ -#define RF4100_AUDIO_MODE 0x04 /* audio mode data enabled */ -#define RF4100_MODE_1 0x01 /* mode 1 blocks are enabled */ -#define RF4100_MODE_2 0x02 /* mode 2 blocks are enabled */ - u_char track_number; - u_char isrc_i1; /* country code, ASCII */ - u_char isrc_i2; - u_char isrc_i3; /* owner code, ASCII */ - u_char isrc_i4; - u_char isrc_i5; - u_char isrc_i6_7; /* country code, BCD */ - u_char isrc_i8_9; /* serial number, BCD */ - u_char isrc_i10_11; - u_char isrc_i12_0; - u_char reserved2[2]; - } - page_0x21; - /* mode page 0x22 omitted by now */ - struct - { - u_char speed_select; -#define RF4100_SPEED_AUDIO 0x01 -#define RF4100_SPEED_DOUBLE 0x02 - u_char dummy_write; -#define RF4100_DUMMY_WRITE 0x01 - u_char reserved[4]; - } - page_0x23; - /* pages 0x24 and 0x25 omitted by now */ - } - pages; -}; - - -static errval -rf4100_prepare_disk(struct scsi_link *sc_link, int dummy, int speed) -{ - struct scsi_mode_select scsi_cmd; - struct { - struct scsi_mode_header header; - struct plasmon_rf4100_pages page; - } dat; - u_int32_t pagelen, dat_len; - - pagelen = sizeof(dat.page.pages.page_0x23) + PAGE_HEADERLEN; - dat_len = sizeof(struct scsi_mode_header) + pagelen; - - SC_DEBUG(sc_link, SDEV_DB2, ("rf4100_prepare_disk")); - - if (speed != RF4100_SPEED_AUDIO && speed != RF4100_SPEED_DOUBLE) - return EINVAL; - - /* - * Set up a mode page 0x23 - */ - bzero(&dat, sizeof(dat)); - bzero(&scsi_cmd, sizeof(scsi_cmd)); - scsi_cmd.op_code = MODE_SELECT; - scsi_cmd.length = dat_len; - /* dat.header.dev_spec = host application code; (see spec) */ - dat.page.page_code = RF4100_PAGE_CODE_23; - dat.page.param_len = sizeof(dat.page.pages.page_0x23); - dat.page.pages.page_0x23.speed_select = speed; - dat.page.pages.page_0x23.dummy_write = dummy? RF4100_DUMMY_WRITE: 0; - /* - * Fire it off. - */ - return scsi_scsi_cmd(sc_link, - (struct scsi_generic *) &scsi_cmd, - sizeof(scsi_cmd), - (u_char *) &dat, - dat_len, - /*WORM_RETRIES*/ 4, - 5000, - NULL, - SCSI_DATA_OUT); -} - - -static errval -rf4100_prepare_track(struct scsi_link *sc_link, struct wormio_prepare_track *t) -{ - struct scsi_mode_select scsi_cmd; - struct scsi_data *worm; - struct { - struct scsi_mode_header header; - struct blk_desc blk_desc; - struct plasmon_rf4100_pages page; - } dat; - u_int32_t pagelen, dat_len, blk_len; - int year; - - worm = sc_link->sd; - - pagelen = sizeof(dat.page.pages.page_0x21) + PAGE_HEADERLEN; - dat_len = sizeof(struct scsi_mode_header) - + sizeof(struct blk_desc) - + pagelen; - - SC_DEBUG(sc_link, SDEV_DB2, ("rf4100_prepare_track")); - - /* - * Set up a mode page 0x21. Note that the block descriptor is - * mandatory in at least one of the MODE SELECT commands, in - * order to select the block length in question. We do this - * here, just prior to opening the write channel. (Spec: - * ``All information for the write is included in the MODE - * SELECT, MODE PAGE 21h, and the write channel can be - * considered open on receipt of the first WRITE command.'' I - * didn't have luck with an explicit WRITE TRACK command - * anyway, this might be different for other CD-R drives. - - * Jörg) - */ - bzero(&dat, sizeof(dat)); - bzero(&scsi_cmd, sizeof(scsi_cmd)); - scsi_cmd.op_code = MODE_SELECT; - scsi_cmd.length = dat_len; - dat.header.blk_desc_len = sizeof(struct blk_desc); - dat.page.page_code = RF4100_PAGE_CODE_21; - dat.page.param_len = sizeof(dat.page.pages.page_0x21); - /* dat.header.dev_spec = host application code; (see spec) */ - if (t->audio) { - blk_len = 2352; - dat.page.pages.page_0x21.mode = RF4100_AUDIO_MODE + - (t->preemp? RF4100_MODE_1 : 0); - } else - switch (t->track_type) { - case BLOCK_RAW: - blk_len = 2352; - dat.page.pages.page_0x21.mode = RF4100_RAW_MODE; - break; - case BLOCK_MODE_1: - blk_len = 2048; - dat.page.pages.page_0x21.mode = RF4100_MODE_1; - break; - case BLOCK_MODE_2: - blk_len = 2336; - dat.page.pages.page_0x21.mode = RF4100_MODE_2; - break; - case BLOCK_MODE_2_FORM_1: - blk_len = 2048; - dat.page.pages.page_0x21.mode = RF4100_MODE_2; - break; - case BLOCK_MODE_2_FORM_1b: - blk_len = 2056; - dat.page.pages.page_0x21.mode = RF4100_MODE_2; - break; - case BLOCK_MODE_2_FORM_2: - blk_len = 2324; - dat.page.pages.page_0x21.mode = RF4100_MODE_2; - break; - case BLOCK_MODE_2_FORM_2b: - blk_len = 2332; - dat.page.pages.page_0x21.mode = RF4100_MODE_2; - break; - default: - return EINVAL; - } - dat.page.pages.page_0x21.mode |= t->copy_bits << 5; - - worm->blk_size = blk_len; - - dat.page.pages.page_0x21.track_number = t->track_number; - - dat.page.pages.page_0x21.isrc_i1 = ascii_to_6bit(t->ISRC_country[0]); - dat.page.pages.page_0x21.isrc_i2 = ascii_to_6bit(t->ISRC_country[1]); - dat.page.pages.page_0x21.isrc_i3 = ascii_to_6bit(t->ISRC_owner[0]); - dat.page.pages.page_0x21.isrc_i4 = ascii_to_6bit(t->ISRC_owner[1]); - dat.page.pages.page_0x21.isrc_i5 = ascii_to_6bit(t->ISRC_owner[2]); - year = t->ISRC_year % 100; - if (year < 0) - return EINVAL; - dat.page.pages.page_0x21.isrc_i6_7 = bin2bcd(year); - if (t->ISRC_serial[0]) { - dat.page.pages.page_0x21.isrc_i8_9 = ((t->ISRC_serial[0]-'0') << 4) | - (t->ISRC_serial[1] - '0'); - dat.page.pages.page_0x21.isrc_i10_11 = ((t->ISRC_serial[2]-'0') << 4) | - (t->ISRC_serial[3] - '0'); - dat.page.pages.page_0x21.isrc_i12_0 = (t->ISRC_serial[4] - '0' << 4); - } - scsi_uto3b(blk_len, dat.blk_desc.blklen); - - /* - * Fire it off. - */ - return scsi_scsi_cmd(sc_link, - (struct scsi_generic *) &scsi_cmd, - sizeof(scsi_cmd), - (u_char *) &dat, - dat_len, - /*WORM_RETRIES*/ 4, - 5000, - NULL, - SCSI_DATA_OUT); -} - - -static errval -rf4100_finalize_track(struct scsi_link *sc_link) -{ - struct scsi_synchronize_cache cmd; - int error; - - SC_DEBUG(sc_link, SDEV_DB2, ("rf4100_finalize_track")); - - /* - * Only a "synchronize cache" is needed. - */ - bzero(&cmd, sizeof(cmd)); - cmd.op_code = SYNCHRONIZE_CACHE; - error = scsi_scsi_cmd(sc_link, - (struct scsi_generic *) &cmd, - sizeof(cmd), - 0, /* no data transfer */ - 0, - 1, - 60000, /* this may take a while */ - NULL, - 0); - if (!error) - error = worm_set_blksize(sc_link, 2048); - - return error; -} - - -static errval -rf4100_finalize_disk(struct scsi_link *sc_link, int toc_type, int onp) -{ - struct scsi_fixation cmd; - - SC_DEBUG(sc_link, SDEV_DB2, ("rf4100_finalize_disk")); - - if (toc_type < 0 || toc_type > WORM_TOC_TYPE_CDI) - return EINVAL; - - /* - * Fixate this session. Mark the next one as opened if onp - * is true. Otherwise, the disk will be finalized once and - * for all. ONP stands for "open next program area". - */ - - bzero(&cmd, sizeof(cmd)); - cmd.op_code = FIXATION; - cmd.action = (onp? WORM_FIXATION_ONP: 0) + toc_type; - return scsi_scsi_cmd(sc_link, - (struct scsi_generic *) &cmd, - sizeof(cmd), - 0, /* no data transfer */ - 0, - 1, - 20*60*1000, /* takes a huge amount of time */ - NULL, - 0); -} - -/* - * End Plasmon RF4100/4102 section. - */ - -/* - * HP C4324/C4325 (This is what the scsi spec. and firmware says) - * Drive model 4020i - * This is very similar to the Plasmon above. - */ - -/* The following mode pages might apply to other drives as well. */ - -struct hp_4020i_pages -{ - u_char page_code; -#define HP4020I_PAGE_CODE_20 0x20 -#define HP4020I_PAGE_CODE_21 0x21 -#define HP4020I_PAGE_CODE_22 0x22 -#define HP4020I_PAGE_CODE_23 0x23 -#define HP4020I_PAGE_CODE_24 0x24 -#define HP4020I_PAGE_CODE_25 0x25 - u_char param_len; - union - { - /* page 0x20 omitted by now */ - struct - { - u_char reserved1; - u_char mode; -#define HP4020I_RAW_MODE 0x10 /* raw mode enabled */ -#define HP4020I_MIXED_MODE 0x08 /* mixed mode data enabled */ -#define HP4020I_AUDIO_MODE 0x04 /* audio mode data enabled */ -#define HP4020I_MODE_1 0x01 /* mode 1 blocks are enabled */ -#define HP4020I_MODE_2 0x02 /* mode 2 blocks are enabled */ - u_char track_number; - u_char isrc_i1; /* country code, ASCII */ - u_char isrc_i2; - u_char isrc_i3; /* owner code, ASCII */ - u_char isrc_i4; - u_char isrc_i5; - u_char isrc_i6_7; /* year code, BCD */ - u_char isrc_i8_9; /* serial number, BCD */ - u_char isrc_i10_11; - u_char isrc_i12_0; - u_char reserved2[2]; - } - page_0x21; - struct - { - u_char catalog_valid; - u_char catalog_c1_c2; /* catalog number, BCD */ - u_char catalog_c3_c4; - u_char catalog_c5_c6; - u_char catalog_c7_c8; - u_char catalog_c9_c10; - u_char catalog_c11_c12; - u_char catalog_c13_0; - } page_0x22; - struct - { - u_char speed_select; -#define HP4020I_SPEED_AUDIO 0x01 -#define HP4020I_SPEED_DOUBLE 0x02 - u_char dummy_write; -#define HP4020I_DUMMY_WRITE 0x01 - u_char reserved[4]; - } - page_0x23; - /* pages 0x24 and 0x25 omitted by now */ - } - pages; -}; - -static errval -hp4020i_prepare_disk(struct scsi_link *sc_link, int dummy, int speed) -{ - struct scsi_mode_select scsi_cmd; - struct { - struct scsi_mode_header header; - struct hp_4020i_pages page; - } dat; - u_int32_t pagelen, dat_len; - - pagelen = sizeof(dat.page.pages.page_0x23) + PAGE_HEADERLEN; - dat_len = sizeof(struct scsi_mode_header) + pagelen; - - SC_DEBUG(sc_link, SDEV_DB2, ("hp4020i_prepare_disk")); - - if (speed != HP4020I_SPEED_AUDIO && speed != HP4020I_SPEED_DOUBLE) - return EINVAL; - - /* - * Set up a mode page 0x23 - */ - bzero(&dat, sizeof(dat)); - bzero(&scsi_cmd, sizeof(scsi_cmd)); - scsi_cmd.op_code = MODE_SELECT; - scsi_cmd.byte2 |= SMS_PF; - scsi_cmd.length = dat_len; - /* dat.header.dev_spec = host application code; (see spec) */ - dat.page.page_code = HP4020I_PAGE_CODE_23; - dat.page.param_len = sizeof(dat.page.pages.page_0x23); - dat.page.pages.page_0x23.speed_select = speed; - dat.page.pages.page_0x23.dummy_write = dummy? HP4020I_DUMMY_WRITE: 0; - /* - * Fire it off. - */ - return scsi_scsi_cmd(sc_link, - (struct scsi_generic *) &scsi_cmd, - sizeof(scsi_cmd), - (u_char *) &dat, - dat_len, - /*WORM_RETRIES*/ 4, - 5000, - NULL, - SCSI_DATA_OUT); -} - - -static errval -hp4020i_prepare_track(struct scsi_link *sc_link, struct wormio_prepare_track *t) -{ - struct scsi_mode_select scsi_cmd; - struct scsi_data *worm; - struct { - struct scsi_mode_header header; - struct blk_desc blk_desc; - struct hp_4020i_pages page; - } dat; - u_int32_t pagelen, dat_len, blk_len; - int year; - - worm = sc_link->sd; - - pagelen = sizeof(dat.page.pages.page_0x21) + PAGE_HEADERLEN; - dat_len = sizeof(struct scsi_mode_header) - + sizeof(struct blk_desc) - + pagelen; - - SC_DEBUG(sc_link, SDEV_DB2, ("hp4020i_prepare_track")); - - - /* - * Set up a mode page 0x21. Note that the block descriptor is - * mandatory in at least one of the MODE SELECT commands, in - * order to select the block length in question. We do this - * here, just prior to opening the write channel. (Spec: - * ``All information for the write is included in the MODE - * SELECT, MODE PAGE 21h, and the write channel can be - * considered open on receipt of the first WRITE command.'' I - * didn't have luck with an explicit WRITE TRACK command - * anyway, this might be different for other CD-R drives. - - * Jörg) - */ - bzero(&dat, sizeof(dat)); - bzero(&scsi_cmd, sizeof(scsi_cmd)); - scsi_cmd.op_code = MODE_SELECT; - scsi_cmd.byte2 |= SMS_PF; - scsi_cmd.length = dat_len; - dat.header.blk_desc_len = sizeof(struct blk_desc); - dat.page.page_code = HP4020I_PAGE_CODE_21; - dat.page.param_len = sizeof(dat.page.pages.page_0x21); - /* dat.header.dev_spec = host application code; (see spec) */ - if (t->audio) { - blk_len = 2352; - dat.page.pages.page_0x21.mode = HP4020I_AUDIO_MODE + - (t->preemp? HP4020I_MODE_1 : 0); - } else - switch (t->track_type) { - case BLOCK_RAW: - blk_len = 2352; - dat.page.pages.page_0x21.mode = HP4020I_RAW_MODE; - break; - case BLOCK_MODE_1: - blk_len = 2048; - dat.page.pages.page_0x21.mode = HP4020I_MODE_1; - break; - case BLOCK_MODE_2: - blk_len = 2336; - dat.page.pages.page_0x21.mode = HP4020I_MODE_2; - break; - case BLOCK_MODE_2_FORM_1: - blk_len = 2048; - dat.page.pages.page_0x21.mode = HP4020I_MODE_2; - break; - case BLOCK_MODE_2_FORM_1b: - blk_len = 2056; - dat.page.pages.page_0x21.mode = HP4020I_MODE_2; - break; - case BLOCK_MODE_2_FORM_2: - blk_len = 2324; - dat.page.pages.page_0x21.mode = HP4020I_MODE_2; - break; - case BLOCK_MODE_2_FORM_2b: - blk_len = 2332; - dat.page.pages.page_0x21.mode = HP4020I_MODE_2; - break; - default: - return EINVAL; - } - dat.page.pages.page_0x21.mode |= t->copy_bits << 5; - - worm->blk_size = blk_len; - - dat.page.pages.page_0x21.track_number = t->track_number; - - dat.page.pages.page_0x21.isrc_i1 = ascii_to_6bit(t->ISRC_country[0]); - dat.page.pages.page_0x21.isrc_i2 = ascii_to_6bit(t->ISRC_country[1]); - dat.page.pages.page_0x21.isrc_i3 = ascii_to_6bit(t->ISRC_owner[0]); - dat.page.pages.page_0x21.isrc_i4 = ascii_to_6bit(t->ISRC_owner[1]); - dat.page.pages.page_0x21.isrc_i5 = ascii_to_6bit(t->ISRC_owner[2]); - year = t->ISRC_year % 100; - if (year < 0) - return EINVAL; - dat.page.pages.page_0x21.isrc_i6_7 = bin2bcd(year); - if (t->ISRC_serial[0]) { - dat.page.pages.page_0x21.isrc_i8_9 = ((t->ISRC_serial[0]-'0') << 4) | - (t->ISRC_serial[1] - '0'); - dat.page.pages.page_0x21.isrc_i10_11 = ((t->ISRC_serial[2]-'0') << 4) | - (t->ISRC_serial[3] - '0'); - dat.page.pages.page_0x21.isrc_i12_0 = (t->ISRC_serial[4] - '0' << 4); - } - - scsi_uto3b(blk_len, dat.blk_desc.blklen); - - /* - * Fire it off. - */ - return scsi_scsi_cmd(sc_link, - (struct scsi_generic *) &scsi_cmd, - sizeof(scsi_cmd), - (u_char *) &dat, - dat_len, - /*WORM_RETRIES*/ 4, - 5000, - NULL, - SCSI_DATA_OUT); -} - - -static errval -hp4020i_finalize_track(struct scsi_link *sc_link) -{ - struct scsi_synchronize_cache cmd; - int error; - - SC_DEBUG(sc_link, SDEV_DB2, ("hp4020i_finalize_track")); - - /* - * Only a "synchronize cache" is needed. - */ - bzero(&cmd, sizeof(cmd)); - cmd.op_code = SYNCHRONIZE_CACHE; - error = scsi_scsi_cmd(sc_link, - (struct scsi_generic *) &cmd, - sizeof(cmd), - 0, /* no data transfer */ - 0, - 1, - 60000, /* this may take a while */ - NULL, - 0); - if (!error) - error = worm_set_blksize(sc_link, 2048); - - return error; -} - - -static errval -hp4020i_finalize_disk(struct scsi_link *sc_link, int toc_type, int onp) -{ - struct scsi_fixation cmd; - - SC_DEBUG(sc_link, SDEV_DB2, ("hp4020i_finalize_disk")); - - if (toc_type < 0 || toc_type > WORM_TOC_TYPE_CDI) - return EINVAL; - - /* - * Fixate this session. Mark the next one as opened if onp - * is true. Otherwise, the disk will be finalized once and - * for all. ONP stands for "open next program area". - */ - - bzero(&cmd, sizeof(cmd)); - cmd.op_code = FIXATION; - cmd.action = (onp? WORM_FIXATION_ONP: 0) + toc_type; - return scsi_scsi_cmd(sc_link, - (struct scsi_generic *) &cmd, - sizeof(cmd), - 0, /* no data transfer */ - 0, - 1, - 20*60*1000, /* takes a huge amount of time */ - NULL, - 0); -} -static errval -hp4020i_write_session(struct scsi_link *sc_link, struct wormio_write_session *ws) -{ - struct { - struct scsi_mode_header header; - struct blk_desc blk_desc; - struct hp_4020i_pages page; - } dat; - struct scsi_mode_select cmd1; - struct scsi_write_session cmd2; - struct scsi_data *worm; - u_int32_t pagelen, dat_len, blk_len; - errval error; - - SC_DEBUG(sc_link, SDEV_DB2, ("hp4020i_write_session")); - - if (ws->toc_type < 0 || ws->toc_type > WORM_TOC_TYPE_CDI || ws->lofp & ~3) - return EINVAL; - - pagelen = sizeof(dat.page.pages.page_0x22) + PAGE_HEADERLEN; - dat_len = sizeof(struct scsi_mode_header) - + sizeof(struct blk_desc) - + pagelen; - - worm = sc_link->sd; - - /* set the block size to 2352 and the catalog */ - bzero(&dat, sizeof(dat)); - bzero(&cmd1, sizeof(cmd1)); - cmd1.op_code = MODE_SELECT; - cmd1.byte2 |= SMS_PF; - cmd1.length = dat_len; - dat.header.blk_desc_len = sizeof(struct blk_desc); - dat.page.page_code = HP4020I_PAGE_CODE_22; - dat.page.param_len = sizeof(dat.page.pages.page_0x22); - blk_len = 2352; - if (ws->catalog[0] >= '0' && ws->catalog[0] <= '9') { - dat.page.pages.page_0x22.catalog_valid = 1; - dat.page.pages.page_0x22.catalog_c1_c2 = ((ws->catalog[0]-'0') << 4) - | ((ws->catalog[1]-'0') << 4); - dat.page.pages.page_0x22.catalog_c3_c4 = ((ws->catalog[2]-'0') << 4) - | ((ws->catalog[3]-'0') << 4); - dat.page.pages.page_0x22.catalog_c5_c6 = ((ws->catalog[4]-'0') << 4) - | ((ws->catalog[5]-'0') << 4); - dat.page.pages.page_0x22.catalog_c7_c8 = ((ws->catalog[6]-'0') << 4) - | ((ws->catalog[7]-'0') << 4); - dat.page.pages.page_0x22.catalog_c9_c10 = ((ws->catalog[8]-'0') << 4) - | ((ws->catalog[9]-'0') << 4); - dat.page.pages.page_0x22.catalog_c11_c12 = ((ws->catalog[10]-'0') << 4) - | ((ws->catalog[11]-'0') << 4); - dat.page.pages.page_0x22.catalog_c13_0 = ((ws->catalog[12]-'0') << 4); - } - scsi_uto3b(blk_len, dat.blk_desc.blklen); - - error = scsi_scsi_cmd(sc_link, - (struct scsi_generic *) &cmd1, - sizeof(cmd1), - (u_char *) &dat, - dat_len, - /*WORM_RETRIES*/ 4, - 5000, - NULL, - SCSI_DATA_OUT); - - if (!error) { - worm->blk_size = blk_len; - bzero(&cmd2, sizeof(cmd2)); - cmd2.op_code = WRITE_SESSION; - cmd2.action = (ws->lofp << 4) | (ws->onp? WORM_FIXATION_ONP: 0) + ws->toc_type; - scsi_uto2b(ws->length, &cmd2.transfer_length_2); - - error = scsi_scsi_cmd(sc_link, - (struct scsi_generic *) &cmd2, - sizeof(cmd2), - ws->track_desc, - ws->length, - 1, - 5000, - NULL, - SCSI_DATA_OUT); - } - return error; -} - -static errval -hp4020i_read_first_writable_address (struct scsi_link *sc_link, - int track, int mode, int raw, int audio, int *addr) -{ - struct scsi_first_writable_address cmd; - char data[6]; - errval error; - - SC_DEBUG(sc_link, SDEV_DB2, ("worm_read_first_writable_address")); - - bzero(&cmd, sizeof(cmd)); - cmd.op_code = FIRST_WRITEABLE_ADDR; - cmd.track_number = track; - cmd.mode = (raw << 3) | (audio << 2) | mode; - cmd.transfer_length = sizeof(data); - error = scsi_scsi_cmd(sc_link, - (struct scsi_generic *) &cmd, - sizeof(cmd), - (u_char *) data, - sizeof(data), - /*WORMRETRY*/ 4, - 5000, - NULL, - SCSI_DATA_IN); - *addr = scsi_4btou (data+1); - return error; -} - -/* - * End HP C4324/C4325 (4020i) section. - */ |