fdomain.c

来自「GNU Mach 微内核源代码, 基于美国卡内基美隆大学的 Mach 研究项目」· C语言 代码 · 共 1,993 行 · 第 1/5 页

C
1,993
字号
{   int              error;   unsigned char    pci_bus, pci_dev_fn;    /* PCI bus & device function */   unsigned char    pci_irq;                /* PCI interrupt line */   unsigned int     pci_base;               /* PCI I/O base address */   unsigned short   pci_vendor, pci_device; /* PCI vendor & device IDs */   /* If the PCI BIOS doesn't exist, use the old-style detection routines.      Otherwise, get the I/O base address and interrupt from the PCI config      registers. */      if (!pcibios_present()) return fdomain_pci_nobios_detect( irq, iobase );#if DEBUG_DETECT   /* Tell how to print a list of the known PCI devices from bios32 and      list vendor and device IDs being used if in debug mode.  */         printk( "\nINFO: cat /proc/pci to see list of PCI devices from bios32\n" );   printk( "\nTMC-3260 detect:"	   " Using PCI Vendor ID: 0x%x, PCI Device ID: 0x%x\n",	   PCI_VENDOR_ID_FD, 	   PCI_DEVICE_ID_FD_36C70 );#endif    /* We will have to change this if more than 1 PCI bus is present and the      FD scsi host is not on the first bus (i.e., a PCI to PCI bridge,      which is not supported by bios32 right now anyway).  This should      probably be done by a call to pcibios_find_device but I can't get it      to work...  Also the device ID reported from the PCI config registers      does not match the device ID quoted in the tech manual or available      from offset 5 from the I/O base address.  It should be 0x60E9, but it      is 0x0 if read from the PCI config registers.  I guess the FD folks      neglected to write it to the PCI registers...  This loop is necessary      to get the device function (at least until someone can get      pcibios_find_device to work, I cannot but 53c7,8xx.c uses it...). */       pci_bus = 0;   for (pci_dev_fn = 0x0; pci_dev_fn < 0xff; pci_dev_fn++) {      pcibios_read_config_word( pci_bus,				pci_dev_fn,				PCI_VENDOR_ID,				&pci_vendor );      if (pci_vendor == PCI_VENDOR_ID_FD) {	 pcibios_read_config_word( pci_bus,				   pci_dev_fn,				   PCI_DEVICE_ID,				   &pci_device );	 if (pci_device == PCI_DEVICE_ID_FD_36C70) {	    /* Break out once we have the correct device.  If other FD	       PCI devices are added to this driver we will need to add	       an or of the other PCI_DEVICE_ID_FD_XXXXX's here. */	    break;	 } else {	    /* If we can't find an FD scsi card we give up. */	    return 0;	 }      }   }       #if DEBUG_DETECT   printk( "Future Domain 36C70 : at PCI bus %u, device %u, function %u\n",	   pci_bus,	   (pci_dev_fn & 0xf8) >> 3, 	   pci_dev_fn & 7 );#endif   /* We now have the appropriate device function for the FD board so we      just read the PCI config info from the registers.  */   if ((error = pcibios_read_config_dword( pci_bus,					   pci_dev_fn, 					   PCI_BASE_ADDRESS_0,					   &pci_base ))       || (error = pcibios_read_config_byte( pci_bus,					     pci_dev_fn, 					     PCI_INTERRUPT_LINE,					     &pci_irq ))) {      printk ( "PCI ERROR: Future Domain 36C70 not initializing"	       " due to error reading configuration space\n" );      return 0;   } else {#if DEBUG_DETECT      printk( "TMC-3260 PCI: IRQ = %u, I/O base = 0x%lx\n", 	      pci_irq, pci_base );#endif      /* Now we have the I/O base address and interrupt from the PCI	 configuration registers.  Unfortunately it seems that the I/O base	 address is off by one on my card so I mask it with 0xfff8.  This	 must be some kind of goof in the FD code that does the autoconfig	 and writes to the PCI registers (or maybe I just don't understand	 something).  If they fix it in later versions of the card or BIOS	 we may have to adjust the address based on the signature or	 something...  */      *irq    = pci_irq;      *iobase = (pci_base & 0xfff8);#if DEBUG_DETECT      printk( "TMC-3260 fix: Masking I/O base address with 0xff00.\n" );       printk( "TMC-3260: IRQ = %d, I/O base = 0x%x\n", *irq, *iobase );#endif      if (!fdomain_is_valid_port( *iobase )) return 0;      return 1;   }   return 0;}#endifint fdomain_16x0_detect( Scsi_Host_Template *tpnt ){   int              i, j;   int              retcode;   struct Scsi_Host *shpnt;#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( "fdomain_16x0_detect()," );#endif   tpnt->proc_dir = &proc_scsi_fdomain;   if (setup_called) {#if DEBUG_DETECT      printk( "no BIOS, using port_base = 0x%x, irq = %d\n",	      port_base, interrupt_level );#endif      if (!fdomain_is_valid_port( port_base )) {	 printk( "fdomain: cannot locate chip at port base 0x%x\n",		 port_base );	 printk( "fdomain: bad LILO parameters?\n" );	 return 0;      }   } else {      int flag = 0;            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_major = signatures[j].major_bios_version;	       bios_minor = signatures[j].minor_bios_version;	       PCI_bus    = (signatures[j].flag == 1);	       Quantum    = (signatures[j].flag > 1) ? signatures[j].flag : 0;	       bios_base  = addresses[i];	    }	 }      }      if (!bios_base) {#if DEBUG_DETECT	 printk( " FAILED: NO BIOS\n" );#endif	 return 0;      }      if (!PCI_bus) {	 flag = fdomain_isa_detect( &interrupt_level, &port_base );      } else {#ifdef CONFIG_PCI	 flag = fdomain_pci_bios_detect( &interrupt_level, &port_base );#else	 flag = fdomain_pci_nobios_detect( &interrupt_level, &port_base );#endif      }	       if (!flag) {#if DEBUG_DETECT	 printk( " FAILED: NO PORT\n" );#endif#ifdef CONFIG_PCI	 printk( "\nTMC-3260 36C70 PCI scsi chip detection failed.\n" );	 printk( "Send mail to mckinley@msupa.pa.msu.edu.\n" );#endif	 return 0;		/* Cannot find valid set of ports */      }   }   SCSI_Mode_Cntl_port   = port_base + SCSI_Mode_Cntl;   FIFO_Data_Count_port  = port_base + FIFO_Data_Count;   Interrupt_Cntl_port   = port_base + Interrupt_Cntl;   Interrupt_Status_port = port_base + Interrupt_Status;   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( NULL, 0 );   if (fdomain_test_loopback()) {#if DEBUG_DETECT      printk( "fdomain: LOOPBACK TEST FAILED, FAILING DETECT!\n" );#endif      if (setup_called) {	 printk( "fdomain: loopback test failed at port base 0x%x\n",		 port_base );	 printk( "fdomain: bad LILO parameters?\n" );      }      return 0;   }   if (this_id) {      tpnt->this_id = (this_id & 0x07);      adapter_mask  = (1 << tpnt->this_id);   } else {      if (PCI_bus || (bios_major == 3 && bios_minor >= 2) || bios_major < 0) {	 tpnt->this_id = 7;	 adapter_mask  = 0x80;      } else {	 tpnt->this_id = 6;	 adapter_mask  = 0x40;      }   }				/* Print out a banner here in case we can't				   get resources.  */   shpnt = scsi_register( tpnt, 0 );   shpnt->irq = interrupt_level;   shpnt->io_port = port_base;   shpnt->n_io_port = 0x10;   print_banner( shpnt );				/* Log IRQ with kernel */      if (!interrupt_level) {      panic( "fdomain: *NO* interrupt level selected!\n" );   } else {      /* Register the IRQ with the kernel */      retcode = request_irq( interrupt_level,			     fdomain_16x0_intr, SA_INTERRUPT, "fdomain", NULL);      if (retcode < 0) {	 if (retcode == -EINVAL) {	    printk( "fdomain: IRQ %d is bad!\n", interrupt_level );	    printk( "         This shouldn't happen!\n" );	    printk( "         Send mail to faith@cs.unc.edu\n" );	 } else if (retcode == -EBUSY) {	    printk( "fdomain: IRQ %d is already in use!\n", interrupt_level );	    printk( "         Please use another IRQ!\n" );	 } else {	    printk( "fdomain: Error getting IRQ %d\n", interrupt_level );	    printk( "         This shouldn't happen!\n" );	    printk( "         Send mail to faith@cs.unc.edu\n" );	 }	 panic( "fdomain: Driver requires interruptions\n" );      }   }				/* Log I/O ports with kernel */   request_region( port_base, 0x10, "fdomain" );#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;   printk( "fdomain: detection routine scanning for devices:\n" );   for (i = 0; i < 8; i++) {      SCinit.target = i;      if (i == tpnt->this_id)	/* Skip host adapter */	    continue;      memcpy(SCinit.cmnd, do_request_sense, sizeof(do_request_sense));      retcode = fdomain_16x0_command(&SCinit);      if (!retcode) {	 memcpy(SCinit.cmnd, do_inquiry, sizeof(do_inquiry));	 retcode = fdomain_16x0_command(&SCinit);	 if (!retcode) {	    printk( "     SCSI ID %d: ", i );	    for (j = 8; j < (buf[4] < 32 ? buf[4] : 32); j++)		  printk( "%c", buf[j] >= 20 ? buf[j] : ' ' );	    memcpy(SCinit.cmnd, do_read_capacity, sizeof(do_read_capacity));	    retcode = fdomain_16x0_command(&SCinit);	    if (!retcode) {	       unsigned long blocks, size, capacity;	       	       blocks = (buf[0] << 24) | (buf[1] << 16)		     | (buf[2] << 8) | buf[3];	       size = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];	       capacity = +( +(blocks / 1024L) * +(size * 10L)) / 1024L;	       	       printk( "%lu MB (%lu byte blocks)",		       ((capacity + 5L) / 10L), size );	    } else {	       memcpy(SCinit.cmnd, do_request_sense, sizeof(do_request_sense));	       retcode = fdomain_16x0_command(&SCinit);	    }	    printk ("\n" );	 } else {	    memcpy(SCinit.cmnd, do_request_sense, sizeof(do_request_sense));	    retcode = fdomain_16x0_command(&SCinit);	 }      }   }#endif   return 1;			/* Maximum of one adapter will be detected. */}const char *fdomain_16x0_info( struct Scsi_Host *ignore ){   static char buffer[80];   char        *pt;      strcpy( buffer, "Future Domain TMC-16x0 SCSI driver, version" );   if (strchr( VERSION, ':')) { /* Assume VERSION is an RCS Revision string */      strcat( buffer, strchr( VERSION, ':' ) + 1 );      pt = strrchr( buffer, '$') - 1;      if (!pt)  		/* Stripped RCS Revision string? */	    pt = buffer + strlen( buffer ) - 1;      if (*pt != ' ')	    ++pt;      *pt = '\0';   } else {			/* Assume VERSION is a number */      strcat( buffer, " " VERSION );   }         return buffer;}				/* First pass at /proc information routine. *//* * inout : decides on the direction of the dataflow and the meaning of the  *         variables * buffer: If inout==FALSE data is being written to it else read from it * *start: If inout==FALSE start of the valid data in the buffer * offset: If inout==FALSE offset from the beginning of the imaginary file  *         from which we start writing into the buffer * length: If inout==FALSE max number of bytes to be written into the buffer  *         else number of bytes in the buffer */int fdomain_16x0_proc_info( char *buffer, char **start, off_t offset,			    int length, int hostno, int inout ){   const char *info = fdomain_16x0_info( NULL );   int        len;   int        pos;   int        begin;   if (inout) return(-ENOSYS);       begin = 0;   strcpy( buffer, info );   strcat( buffer, "\n" );   pos = len = strlen( buffer );   if(pos < offset) {      len = 0;      begin = pos;   }       *start = buffer + (offset - begin);   /* Start of wanted data */   len -= (offset - begin);   if(len > length) len = length;      return(len);}   #if 0static int fdomain_arbitrate( void ){   int           status = 0;   unsigned long timeout;#if EVERY_ACCESS   printk( "fdomain_arbitrate()\n" );#endif      outb( 0x00, SCSI_Cntl_port );              /* Disable data drivers */   outb( adapter_mask, port_base + SCSI_Data_NoACK ); /* Set our id bit */

⌨️ 快捷键说明

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