?? seagate.c
字號(hào):
/* * seagate.c Copyright (C) 1992, 1993 Drew Eckhardt * low level scsi driver for ST01/ST02, Future Domain TMC-885, * TMC-950 by * * Drew Eckhardt * * <drew@colorado.edu> * * Note : TMC-880 boards don't work because they have two bits in * the status register flipped, I'll fix this "RSN" * * This card does all the I/O via memory mapped I/O, so there is no need * to check or snarf a region of the I/O address space. *//* * Configuration : * To use without BIOS -DOVERRIDE=base_address -DCONTROLLER=FD or SEAGATE * -DIRQ will overide the default of 5. * Note: You can now set these options from the kernel's "command line". * The syntax is: * * st0x=ADDRESS,IRQ (for a Seagate controller) * or: * tmc8xx=ADDRESS,IRQ (for a TMC-8xx or TMC-950 controller) * eg: * tmc8xx=0xC8000,15 * * will configure the driver for a TMC-8xx style controller using IRQ 15 * with a base address of 0xC8000. * * -DFAST or -DFAST32 will use blind transfers where possible * * -DARBITRATE will cause the host adapter to arbitrate for the * bus for better SCSI-II compatability, rather than just * waiting for BUS FREE and then doing its thing. Should * let us do one command per Lun when I integrate my * reorganization changes into the distribution sources. * * -DSLOW_HANDSHAKE will allow compatability with broken devices that don't * handshake fast enough (ie, some CD ROM's) for the Seagate * code. * * -DSLOW_RATE=x, x some number will let you specify a default * transfer rate if handshaking isn't working correctly. */#include <linux/config.h>#if defined(CONFIG_SCSI_SEAGATE) || defined(CONFIG_SCSI_FD_8xx) #include <asm/io.h>#include <asm/system.h>#include <linux/signal.h>#include <linux/sched.h>#include <linux/string.h>#include "../block/blk.h"#include "scsi.h"#include "hosts.h"#include "seagate.h"#include "constants.h"#ifndef IRQ#define IRQ 5#endif#if (defined(FAST32) && !defined(FAST))#define FAST#endif#if defined(SLOW_RATE) && !defined(SLOW_HANDSHAKE)#define SLOW_HANDSHAKE#endif#if defined(SLOW_HANDSHAKE) && !defined(SLOW_RATE)#define SLOW_RATE 50#endif#if defined(LINKED)#undef LINKED /* Linked commands are currently broken ! */#endifstatic int internal_command(unsigned char target, unsigned char lun, const void *cmnd, void *buff, int bufflen, int reselect);static int incommand; /* set if arbitration has finished and we are in some command phase. */static void *base_address = NULL; /* Where the card ROM starts, used to calculate memory mapped register location. */static volatile int abort_confirm = 0;static volatile void *st0x_cr_sr; /* control register write, status register read. 256 bytes in length. Read is status of SCSI BUS, as per STAT masks. */static volatile void *st0x_dr; /* data register, read write 256 bytes in length. */static volatile int st0x_aborted=0; /* set when we are aborted, ie by a time out, etc. */static unsigned char controller_type = 0; /* set to SEAGATE for ST0x boards or FD for TMC-8xx boards */static unsigned char irq = IRQ; #define retcode(result) (((result) << 16) | (message << 8) | status) #define STATUS (*(volatile unsigned char *) st0x_cr_sr)#define CONTROL STATUS #define DATA (*(volatile unsigned char *) st0x_dr)void st0x_setup (char *str, int *ints) { controller_type = SEAGATE; base_address = (void *) ints[1]; irq = ints[2];}void tmc8xx_setup (char *str, int *ints) { controller_type = FD; base_address = (void *) ints[1]; irq = ints[2];} #ifndef OVERRIDE static const char * seagate_bases[] = { (char *) 0xc8000, (char *) 0xca000, (char *) 0xcc000, (char *) 0xce000, (char *) 0xdc000, (char *) 0xde000};typedef struct { char *signature ; unsigned offset; unsigned length; unsigned char type;} Signature; static const Signature signatures[] = {#ifdef CONFIG_SCSI_SEAGATE{"ST01 v1.7 (C) Copyright 1987 Seagate", 15, 37, SEAGATE},{"SCSI BIOS 2.00 (C) Copyright 1987 Seagate", 15, 40, SEAGATE},/* * The following two lines are NOT mistakes. One detects ROM revision * 3.0.0, the other 3.2. Since seagate has only one type of SCSI adapter, * and this is not going to change, the "SEAGATE" and "SCSI" together * are probably "good enough" */{"SEAGATE SCSI BIOS ",16, 17, SEAGATE},{"SEAGATE SCSI BIOS ",17, 17, SEAGATE},/* * However, future domain makes several incompatable SCSI boards, so specific * signatures must be used. */{"FUTURE DOMAIN CORP. (C) 1986-1989 V5.0C2/14/89", 5, 46, FD},{"FUTURE DOMAIN CORP. (C) 1986-1989 V6.0A7/28/89", 5, 46, FD},{"FUTURE DOMAIN CORP. (C) 1986-1990 V6.0105/31/90",5, 47, FD},{"FUTURE DOMAIN CORP. (C) 1986-1990 V6.0209/18/90",5, 47, FD},{"FUTURE DOMAIN CORP. (C) 1986-1990 V7.009/18/90", 5, 46, FD},{"FUTURE DOMAIN CORP. (C) 1992 V8.00.004/02/92", 5, 44, FD},{"FUTURE DOMAIN TMC-950", 5, 21, FD},#endif /* CONFIG_SCSI_SEAGATE */};#define NUM_SIGNATURES (sizeof(signatures) / sizeof(Signature))#endif /* n OVERRIDE *//* * hostno stores the hostnumber, as told to us by the init routine. */static int hostno = -1;static void seagate_reconnect_intr(int);#ifdef FASTstatic int fast = 1;#endif #ifdef SLOW_HANDSHAKE/* * Support for broken devices : * The Seagate board has a handshaking problem. Namely, a lack * thereof for slow devices. You can blast 600K/second through * it if you are polling for each byte, more if you do a blind * transfer. In the first case, with a fast device, REQ will * transition high-low or high-low-high before your loop restarts * and you'll have no problems. In the second case, the board * will insert wait states for up to 13.2 usecs for REQ to * transition low->high, and everything will work. * * However, there's nothing in the state machine that says * you *HAVE* to see a high-low-high set of transitions before * sending the next byte, and slow things like the Trantor CD ROMS * will break because of this. * * So, we need to slow things down, which isn't as simple as it * seems. We can't slow things down period, because then people * who don't recompile their kernels will shoot me for ruining * their performance. We need to do it on a case per case basis. * * The best for performance will be to, only for borken devices * (this is stored on a per-target basis in the scsi_devices array) * * Wait for a low->high transition before continuing with that * transfer. If we timeout, continue anyways. We don't need * a long timeout, because REQ should only be asserted until the * corresponding ACK is recieved and processed. * * Note that we can't use the system timer for this, because of * resolution, and we *really* can't use the timer chip since * gettimeofday() and the beeper routines use that. So, * the best thing for us to do will be to calibrate a timing * loop in the initialization code using the timer chip before * gettimeofday() can screw with it. */static int borken_calibration = 0;static void borken_init (void) { register int count = 0, start = jiffies + 1, stop = start + 25; while (jiffies < start); for (;jiffies < stop; ++count);/* * Ok, we now have a count for .25 seconds. Convert to a * count per second and divide by transer rate in K. */ borken_calibration = (count * 4) / (SLOW_RATE*1024); if (borken_calibration < 1) borken_calibration = 1;#if (DEBUG & DEBUG_BORKEN) printk("scsi%d : borken calibrated to %dK/sec, %d cycles per transfer\n", hostno, BORKEN_RATE, borken_calibration);#endif}static inline void borken_wait(void) { register int count; for (count = borken_calibration; count && (STATUS & STAT_REQ); --count); if (count)#if (DEBUG & DEBUG_BORKEN) printk("scsi%d : borken timeout\n", hostno);#else ;#endif }#endif /* def SLOW_HANDSHAKE */int seagate_st0x_detect (int hostnum) {#ifndef OVERRIDE int i,j;#endif static struct sigaction seagate_sigaction = { &seagate_reconnect_intr, 0, SA_INTERRUPT, NULL};/* * First, we try for the manual override. */#ifdef DEBUG printk("Autodetecting seagate ST0x\n");#endif if (hostno != -1) { printk ("ERROR : seagate_st0x_detect() called twice.\n"); return 0; } /* If the user specified the controller type from the command line, controller_type will be non-zero, so don't try and detect one */ if (!controller_type) {#ifdef OVERRIDE base_address = (void *) OVERRIDE;/* CONTROLLER is used to override controller (SEAGATE or FD). PM: 07/01/93 */#ifdef CONTROLLER controller_type = CONTROLLER;#else#error Please use -DCONTROLLER=SEAGATE or -DCONTROLLER=FD to override controller type#endif /* CONTROLLER */#ifdef DEBUG printk("Base address overridden to %x, controller type is %s\n", base_address,controller_type == SEAGATE ? "SEAGATE" : "FD");#endif #else /* OVERIDE */ /* * To detect this card, we simply look for the signature * from the BIOS version notice in all the possible locations * of the ROM's. This has a nice sideeffect of not trashing * any register locations that might be used by something else. * * XXX - note that we probably should be probing the address * space for the on-board RAM instead. */ for (i = 0; i < (sizeof (seagate_bases) / sizeof (char * )); ++i) for (j = 0; !base_address && j < NUM_SIGNATURES; ++j) if (!memcmp ((void *) (seagate_bases[i] + signatures[j].offset), (void *) signatures[j].signature, signatures[j].length)) { base_address = (void *) seagate_bases[i]; controller_type = signatures[j].type; }#endif /* OVERIDE */ } /* (! controller_type) */ scsi_hosts[hostnum].this_id = (controller_type == SEAGATE) ? 7 : 6; if (base_address) { st0x_cr_sr =(void *) (((unsigned char *) base_address) + (controller_type == SEAGATE ? 0x1a00 : 0x1c00)); st0x_dr = (void *) (((unsigned char *) base_address ) + (controller_type == SEAGATE ? 0x1c00 : 0x1e00));#ifdef DEBUG printk("ST0x detected. Base address = %x, cr = %x, dr = %x\n", base_address, st0x_cr_sr, st0x_dr);#endif/* * At all times, we will use IRQ 5. Should also check for IRQ3 if we * loose our first interrupt. */ hostno = hostnum; if (irqaction((int) irq, &seagate_sigaction)) { printk("scsi%d : unable to allocate IRQ%d\n", hostno, (int) irq); return 0; }#ifdef SLOW_HANDSHAKE borken_init();#endif return 1; } else {#ifdef DEBUG printk("ST0x not detected.\n");#endif return 0; } } const char *seagate_st0x_info(void) { static char buffer[256]; sprintf(buffer, "scsi%d : %s at irq %d address %p options :"#ifdef ARBITRATE" ARBITRATE"#endif#ifdef SLOW_HANDSHAKE" SLOW_HANDSHAKE"#endif#ifdef FAST#ifdef FAST32" FAST32"#else" FAST"#endif#endif #ifdef LINKED" LINKED"#endif "\n", hostno, (controller_type == SEAGATE) ? "seagate" : "FD TMC-8xx", irq, base_address); return buffer;}/* * These are our saved pointers for the outstanding command that is * waiting for a reconnect */static unsigned char current_target, current_lun;static unsigned char *current_cmnd, *current_data;static int current_nobuffs;static struct scatterlist *current_buffer;static int current_bufflen;#ifdef LINKED/* * linked_connected indicates weather or not we are currently connected to * linked_target, linked_lun and in an INFORMATION TRANSFER phase, * using linked commands. */static int linked_connected = 0;static unsigned char linked_target, linked_lun;#endifstatic void (*done_fn)(Scsi_Cmnd *) = NULL;static Scsi_Cmnd * SCint = NULL;/* * These control whether or not disconnect / reconnect will be attempted, * or are being attempted. */#define NO_RECONNECT 0#define RECONNECT_NOW 1#define CAN_RECONNECT 2#ifdef LINKED/* * LINKED_RIGHT indicates that we are currently connected to the correct target * for this command, LINKED_WRONG indicates that we are connected to the wrong * target. Note that these imply CAN_RECONNECT. */#define LINKED_RIGHT 3#define LINKED_WRONG 4#endif/* * This determines if we are expecting to reconnect or not. */static int should_reconnect = 0;/* * The seagate_reconnect_intr routine is called when a target reselects the * host adapter. This occurs on the interrupt triggered by the target * asserting SEL. */static void seagate_reconnect_intr (int unused) { int temp; Scsi_Cmnd * SCtmp;/* enable all other interrupts. */ sti();#if (DEBUG & PHASE_RESELECT) printk("scsi%d : seagate_reconnect_intr() called\n", hostno);#endif if (!should_reconnect) printk("scsi%d: unexpected interrupt.\n", hostno); else { should_reconnect = 0;#if (DEBUG & PHASE_RESELECT) printk("scsi%d : internal_command(" "%d, %08x, %08x, %d, RECONNECT_NOW\n", hostno, current_target, current_data, current_bufflen);#endif temp = internal_command (current_target, current_lun, current_cmnd, current_data, current_bufflen, RECONNECT_NOW); if (msg_byte(temp) != DISCONNECT) { if (done_fn) {#if (DEBUG & PHASE_RESELECT) printk("scsi%d : done_fn(%d,%08x)", hostno, hostno, temp);#endif if(!SCint) panic("SCint == NULL in seagate"); SCtmp = SCint; SCint = NULL; SCtmp->result = temp; done_fn (SCtmp); } else printk("done_fn() not defined.\n"); } } } /* * The seagate_st0x_queue_command() function provides a queued interface * to the seagate SCSI driver. Basically, it just passes control onto the * seagate_command() function, after fixing it so that the done_fn() * is set to the one passed to the function. We have to be very careful, * because there are some commands on some devices that do not disconnect, * and if we simply call the done_fn when the command is done then another * command is started and queue_command is called again... We end up * overflowing the kernel stack, and this tends not to be such a good idea. */static int recursion_depth = 0;int seagate_st0x_queue_command (Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *)) { int result, reconnect; Scsi_Cmnd * SCtmp; done_fn = done; current_target = SCpnt->target; current_lun = SCpnt->lun; (const void *) current_cmnd = SCpnt->cmnd; current_data = (unsigned char *) SCpnt->request_buffer; current_bufflen = SCpnt->request_bufflen; SCint = SCpnt; if(recursion_depth) { return 0; }; recursion_depth++; do{#ifdef LINKED/* * Set linked command bit in control field of SCSI command. */ current_cmnd[COMMAND_SIZE(current_cmnd[0])] |= 0x01; if (linked_connected) {#if (DEBUG & DEBUG_LINKED) printk("scsi%d : using linked commands, current I_T_L nexus is ", hostno);#endif if ((linked_target == current_target) && (linked_lun == current_lun)) {#if (DEBUG & DEBUG_LINKED) printk("correct\n");#endif reconnect = LINKED_RIGHT; } else {#if (DEBUG & DEBUG_LINKED) printk("incorrect\n");#endif reconnect = LINKED_WRONG; } } else #endif /* LINKED */ reconnect = CAN_RECONNECT; result = internal_command (SCint->target, SCint->lun, SCint->cmnd, SCint->request_buffer, SCint->request_bufflen, reconnect); if (msg_byte(result) == DISCONNECT) break; SCtmp = SCint; SCint = NULL; SCtmp->result = result; done_fn (SCtmp); } while(SCint); recursion_depth--;
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -