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

📄 fdomain.c

📁 linux0.99源代码用于研究linux操作系统
💻 C
📖 第 1 页 / 共 3 页
字号:
/* fdomain.c -- Future Domain TMC-1660/TMC-1680 driver * Created: Sun May  3 18:53:19 1992 by faith * Revised: Wed Dec  9 21:34:53 1992 by root * Author: Rickard E. Faith, faith@cs.unc.edu * Copyright 1992 Rickard E. Faith * * $Log$ * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * General Public License for more details. * WARNING: THIS IS A BETA VERSION! *          USE AT YOUR OWN RISK! *          BACKUP YOUR SYSTEM BEFORE USING! * I would like to thank Maxtor, whose *free* 206 page manual on the LXT * drives was very helpful: "LXT SCSI Products: Specifications and OEM * Technical Manual (Revision B/September 1991)" * I wish that I could thank Future Domain for the necessary documentation, * but I can't.  I used the $25 "TMC-1800 SCSI Chip Specification" document * (FDC-1800T), which documents the *chip* and not the board.  Without it, * I would have been totally lost, but it would have been nice to have some * example source.  (The DOS BIOS source cost $250 and the UN*X driver * source was $750 [both required a non-disclosure agreement].  Ever wonder * why there are no freely available Future Domain drivers?) * Thanks to: Todd Carrico (todd@wutc.wustl.edu), Dan Poirier * (poirier@cs.unc.edu ), Ken Corey (kenc@sol.acs.unt.edu), C. de Bruin * (bruin@dutiba.tudelft.nl) and Sakari Aaltonen (sakaria@vipunen.hit.fi) * for alpha testing.  Also thanks to Drew Eckhardt (drew@cs.colorado.edu) * and Eric Youngdale (eric@tantalus.nrl.navy.mil) for answering questions, * and to Doug Hoffman (hoffman@cs.unc.edu) for lending me SCSI devices to * make the driver more robust. */#include <linux/sched.h>#include <asm/io.h>#include "../blk.h"#include "scsi.h"#include "hosts.h"#include "fdomain.h"#include <asm/system.h>#include <linux/errno.h>#define VERSION          "3.2"	/* Change with each revision *//* START OF USER DEFINABLE OPTIONS */#define DEBUG            1	/* Enable debugging output */#define ENABLE_PARITY    1	/* Enable SCSI Parity */#define QUEUE            1	/* Enable command queueing */#define FIFO_COUNT       2      /* Number of 512 byte blocks before INTR */#define DO_DETECT        0	/* Do device detection here (see scsi.c) */#define RESELECTION      0	/* Support RESELECTION PHASE (NOT stable) *//* END OF USER DEFINABLE OPTIONS */#if DEBUG#define EVERY_ACCESS     0	/* Write a line on every scsi access */#define ERRORS_ONLY      1	/* Only write a line if there is an error */#define DEBUG_DETECT     0	/* Debug fdomain_16x0_detect() */#define DEBUG_MESSAGES   0      /* Debug MESSAGE IN PHASE */#define DEBUG_ABORT      1    /* Debug abort() routine */#else#define EVERY_ACCESS     0	/* LEAVE THESE ALONE--CHANGE THE ONES ABOVE */#define ERRORS_ONLY      0#define DEBUG_DETECT     0#define DEBUG_MESSAGES   0#define DEBUG_ABORT      0#endif/* Errors are reported on the line, so we don't need to report them again */#if EVERY_ACCESS#undef ERRORS_ONLY#define ERRORS_ONLY      0#endif#if ENABLE_PARITY#define PARITY_MASK      0x08#else#define PARITY_MASK      0x00#endifstatic int               port_base = 0;static void              *bios_base = NULL;static int               interrupt_level = 0;static int               Data_Mode_Cntl_port;static int               FIFO_Data_Count_port;static int               Interrupt_Cntl_port;static int               Interrupt_Mask_port;static int               Read_FIFO_port;static int               Read_SCSI_Data_port;static int               SCSI_Cntl_port;static int               SCSI_Data_NoACK_port;static int               SCSI_Status_port;static int               TMC_Cntl_port;static int               TMC_Status_port;static int               Write_FIFO_port;static int               Write_SCSI_Data_port;static int               this_host = 0;static int               can_queue = QUEUE;static volatile int      in_command = 0;static volatile int      in_interrupt_code = 0;static Scsi_Cmnd         *current_SC = NULL;enum { non_queueing   = 0x01,       in_arbitration = 0x02,       in_selection   = 0x04,       in_other       = 0x08,       disconnect     = 0x10,       aborted        = 0x20,       sent_ident     = 0x40,     };extern void              fdomain_16x0_intr( int unused );enum in_port_type { Read_SCSI_Data = 0, SCSI_Status = 1, TMC_Status = 2,			  LSB_ID_Code = 5, MSB_ID_Code = 6, Read_Loopback = 7,		          SCSI_Data_NoACK = 8, Interrupt_Mask = 9,		          Option_Select = 10, Read_FIFO = 12,		          FIFO_Data_Count = 14 };enum out_port_type { Write_SCSI_Data = 0, SCSI_Cntl = 1, Interrupt_Cntl = 2,			   Data_Mode_Cntl = 3, TMC_Cntl = 4, Write_Loopback = 7,			   Write_FIFO = 12 };static void *addresses[] = {   (void *)0xc8000,   (void *)0xca000,   (void *)0xce000,   (void *)0xde000 };#define ADDRESS_COUNT (sizeof( addresses ) / sizeof( unsigned ))		       static unsigned short ports[] = { 0x140, 0x150, 0x160, 0x170 };#define PORT_COUNT (sizeof( ports ) / sizeof( unsigned short ))static unsigned short ints[] = { 3, 5, 10, 11, 12, 14, 15, 0 };/*  READ THIS BEFORE YOU ADD A SIGNATURE!  READING THIS SHORT NOTE CAN SAVE YOU LOTS OF TIME!  READ EVERY WORD, ESPECIALLY THE WORD *NOT*  This driver works *ONLY* for Future Domain cards using the  TMC-1800 chip.  This includes models TMC-1660 and TMC-1680  *ONLY*.  The following BIOS signatures have been tried with this driver.  These  signatures are for boards which do *NOT* work with this driver (but the  first one should work with the Seagate driver):  FUTURE DOMAIN COPR. (C) 1986-1989 V6.0A7/28/90  FUTURE DOMAIN CORP. (C) 1986-1990 V6.0209/18/90  FUTURE DOMAIN CORP. (C) 1986-1990 V7.009/18/90  */struct signature {   char *signature;   int  sig_offset;   int  sig_length;} signatures[] = {   { "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.0 7/28/89", 5, 50 },   { "FUTURE DOMAIN CORP. (C) 1986-1990 1800", 5, 37 },   /* READ NOTICE ABOVE *BEFORE* YOU WASTE YOUR TIME ADDING A SIGANTURE */};#define SIGNATURE_COUNT (sizeof( signatures ) / sizeof( struct signature ))/* These functions are based on include/asm/io.h */inline static unsigned short inw( unsigned short port ){   unsigned short _v;      __asm__ volatile ("inw %1,%0"		     :"=a" (_v):"d" ((unsigned short) port));   return _v;}inline static void outw( unsigned short value, unsigned short port ){   __asm__ volatile ("outw %0,%1"		     ::"a" ((unsigned short) value),		     "d" ((unsigned short) port));}/* These defines are copied from kernel/blk_drv/hd.c */#define insw( buf, count, port ) \      __asm__ volatile \      ( "cld;rep;insw"::"d" (port),"D" (buf),"c" (count):"cx","di" )#define outsw( buf, count, port ) \      __asm__ volatile \      ("cld;rep;outsw"::"d" (port),"S" (buf),"c" (count):"cx","si")static void do_pause( unsigned amount )	/* Pause for amount*10 milliseconds */{   unsigned long the_time = jiffies + amount; /* 0.01 seconds per jiffy */   while (jiffies < the_time);}inline static void fdomain_make_bus_idle( void ){   outb( 0, SCSI_Cntl_port );   outb( 0, Data_Mode_Cntl_port );   outb( 1 | PARITY_MASK, TMC_Cntl_port );}static int fdomain_is_valid_port( int port ){   int options;#if DEBUG_DETECT    printk( " (%x%x),",	  inb( port + MSB_ID_Code ), inb( port + LSB_ID_Code ) );#endif   /* The MCA ID is a unique id for each MCA compatible board.  We      are using ISA boards, but Future Domain provides the MCA ID      anyway.  We can use this ID to ensure that this is a Future      Domain TMC-1660/TMC-1680.    */   if (inb( port + LSB_ID_Code ) != 0xe9) { /* test for 0x6127 id */      if (inb( port + LSB_ID_Code ) != 0x27) return 0;      if (inb( port + MSB_ID_Code ) != 0x61) return 0;   } else {			            /* test for 0xe960 id */      if (inb( port + MSB_ID_Code ) != 0x60) return 0;   }   /* We have a valid MCA ID for a TMC-1660/TMC-1680 Future Domain board.      Now, check to be sure the bios_base matches these ports.      If someone was unlucky enough to have purchased more than one      Future Domain board, then they will have to modify this code, as      we only detect one board here.  [The one with the lowest bios_base.]    */   options = inb( port + Option_Select );#if DEBUG_DETECT   printk( " Options = %x,", options );#endif   if (addresses[ (options & 0xc0) >> 6 ] != bios_base) return 0;   interrupt_level = ints[ (options & 0x0e) >> 1 ];   return 1;}static int fdomain_test_loopback( void ){   int i;   int result;   for (i = 0; i < 255; i++) {      outb( i, port_base + Write_Loopback );      result = inb( port_base + Read_Loopback );      if (i != result) return 1;   }   return 0;}int fdomain_16x0_detect( int hostnum ){   int              i, j;   int              flag;   struct sigaction sa;   int              retcode;#if DO_DETECT   const int        buflen = 255;   Scsi_Cmnd        SCinit;   unsigned char    do_inquiry[] =       { INQUIRY, 0, 0, 0, buflen, 0 };   unsigned char    do_request_sense[] = { REQUEST_SENSE, 0, 0, 0, buflen, 0 };   unsigned char    do_read_capacity[] = { READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0 };   unsigned char    buf[buflen];#endif#if DEBUG_DETECT   printk( "SCSI: fdomain_16x0_detect()," );#endif   for (i = 0; !bios_base && i < ADDRESS_COUNT; i++) {#if DEBUG_DETECT      printk( " %x(%x),", (unsigned)addresses[i], (unsigned)bios_base );#endif      for (j = 0; !bios_base && j < SIGNATURE_COUNT; j++) {	 if (!memcmp( ((char *)addresses[i] + signatures[j].sig_offset),		    signatures[j].signature, signatures[j].sig_length )) {	    bios_base = addresses[i];	 }      }   }   if (!bios_base) {#if DEBUG_DETECT      printk( " FAILED: NO BIOS\n" );#endif      return 0;   }   /* The TMC-1660/TMC-1680 has a RAM area just after the BIOS ROM.      Assuming the ROM is enabled (otherwise we wouldn't have been      able to read the ROM signature :-), then the ROM sets up the      RAM area with some magic numbers, such as a list of port      base addresses and a list of the disk "geometry" reported to      DOS (this geometry has nothing to do with physical geometry).    */   port_base = *((char *)bios_base + 0x1fcc)	 + (*((char *)bios_base + 0x1fcd) << 8);   #if DEBUG_DETECT   printk( " %x,", port_base );#endif   for (flag = 0, i = 0; !flag && i < PORT_COUNT; i++) {      if (port_base == ports[i]) ++flag;   }   if (flag) flag = fdomain_is_valid_port( port_base );   if (!flag) {			/* Cannot get port base from BIOS RAM */            /* This is a bad sign.  It usually means that someone patched the	 BIOS signature list (the signatures variable) to contain a BIOS	 signature for a board *OTHER THAN* the TMC-1660/TMC-1680.       */      #if DEBUG_DETECT      printk( " RAM FAILED, " );#endif      /* Anyway, the alternative to finding the address in the RAM is	 to just search through every possible port address for one	 that is attached to the Future Domain card.  Don't panic,	 though, about reading all these random port addresses--there	 are rumors that the Future Domain BIOS does something very	 similar.       */      for (flag = 0, i = 0; !flag && i < PORT_COUNT; i++) {	 port_base = ports[i];#if DEBUG_DETECT	 printk( " %x,", port_base );#endif	 flag = fdomain_is_valid_port( port_base );      }   }   if (!flag) {#if DEBUG_DETECT      printk( " FAILED: NO PORT\n" );#endif      return 0;		/* Cannot find valid set of ports */   }#if DEBUG_DETECT   printk( "\n" );   printk( "SCSI: bios_base = %x, port_base = %x, interrupt_level = %d\n",	  (unsigned)bios_base, port_base, interrupt_level );#endif   if (interrupt_level) {      printk( "Future Domain: BIOS at %x; port base at %x; using IRQ %d\n",	     (unsigned)bios_base, port_base, interrupt_level );   } else {      printk( "Future Domain: BIOS at %x; port base at %x; *NO* IRQ\n",	     (unsigned)bios_base, port_base );   }      Data_Mode_Cntl_port  = port_base + Data_Mode_Cntl;   FIFO_Data_Count_port = port_base + FIFO_Data_Count;   Interrupt_Cntl_port  = port_base + Interrupt_Cntl;   Interrupt_Mask_port  = port_base + Interrupt_Mask;   Read_FIFO_port       = port_base + Read_FIFO;   Read_SCSI_Data_port  = port_base + Read_SCSI_Data;   SCSI_Cntl_port       = port_base + SCSI_Cntl;   SCSI_Data_NoACK_port = port_base + SCSI_Data_NoACK;   SCSI_Status_port     = port_base + SCSI_Status;   TMC_Cntl_port        = port_base + TMC_Cntl;   TMC_Status_port      = port_base + TMC_Status;   Write_FIFO_port      = port_base + Write_FIFO;   Write_SCSI_Data_port = port_base + Write_SCSI_Data;    fdomain_16x0_reset();   if (fdomain_test_loopback()) {#if DEBUG_DETECT      printk( "SCSI: LOOPBACK TEST FAILED, FAILING DETECT!\n" );#endif      return 0;   }#if DO_DETECT   /* These routines are here because of the way the SCSI bus behaves after      a reset.  This appropriate behavior was not handled correctly by the      higher level SCSI routines when I first wrote this driver.  Now,      however, correct scan routines are part of scsi.c and these routines      are no longer needed.  However, this code is still good for      debugging.    */   SCinit.request_buffer = SCinit.buffer = buf;   SCinit.request_bufflen = SCinit.bufflen = sizeof(buf)-1;   SCinit.use_sg = 0;   SCinit.lun = 0;

⌨️ 快捷键说明

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