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

📄 fdomain.c

📁 LINUX 1.0 内核c源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
      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;
      chip = tmc1800;
   } else {			            /* test for 0xe960 id */
      if (inb( port + MSB_ID_Code ) != 0x60) return 0;
      chip = tmc18c50;
   }

   /* 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 + Configuration1 );

#if DEBUG_DETECT
   printk( " Options = %x\n", options );
#endif

				/* Check for board with lowest bios_base. */
   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 = 0;
   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( "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_major = signatures[j].major_bios_version;
	    bios_minor = signatures[j].minor_bios_version;
	    bios_base = addresses[i];
	 }
      }
   }

   if (!bios_base) {
#if DEBUG_DETECT
      printk( " FAILED: NO BIOS\n" );
#endif
      return 0;
   }

   if (bios_major == 2) {
      /* 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.  It
	 also means that we don't have a Version 2.0 BIOS :-)
       */
      
#if DEBUG_DETECT
      if (bios_major != 2) 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.

	 Do not, however, check ports which the kernel knows are being used
         by another driver.
       */

      for (i = 0; !flag && i < PORT_COUNT; i++) {
	 port_base = ports[i];
	 if (check_region( port_base, 0x10 )) {
#if DEBUG_DETECT
	    printf( " (%x inuse),", port_base );
#endif
	    continue;
	 }
#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 */
   }

   print_banner();

   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 );

   if (fdomain_test_loopback()) {
#if DEBUG_DETECT
      printk( "Future Domain: LOOPBACK TEST FAILED, FAILING DETECT!\n" );
#endif
      return 0;
   }

   this_host = hostnum;

				/* Log IRQ with kernel */
   
   if (!interrupt_level) {
      panic( "Future Domain: *NO* interrupt level selected!\n" );
   } else {
      /* Register the IRQ with the kernel */

      sa.sa_handler  = fdomain_16x0_intr;
      sa.sa_flags    = SA_INTERRUPT;
      sa.sa_mask     = 0;
      sa.sa_restorer = NULL;
      
      retcode = irqaction( interrupt_level, &sa );

      if (retcode < 0) {
	 if (retcode == -EINVAL) {
	    printk( "Future Domain: 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( "Future Domain: IRQ %d is already in use!\n",
		    interrupt_level );
	    printk( "               Please use another IRQ!\n" );
	 } else {
	    printk( "Future Domain: Error getting IRQ %d\n", interrupt_level );
	    printk( "               This shouldn't happen!\n" );
	    printk( "               Send mail to faith@cs.unc.edu\n" );
	 }
	 panic( "Future Domain: Driver requires interruptions\n" );
      } else {
	 printk( "Future Domain: IRQ %d requested from kernel\n",
		 interrupt_level );
      }
   }

				/* Log I/O ports with kernel */

   snarf_region( port_base, 0x10 );

   if ((bios_major == 3 && bios_minor >= 2) || bios_major < 0) {
      adapter_mask = 0x80;
      scsi_hosts[this_host].this_id = 7;
   }
   
#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( "Future Domain detection routine scanning for devices:\n" );
   for (i = 0; i < 8; i++) {
      SCinit.target = i;
      if (i == scsi_hosts[this_host].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;
}

const char *fdomain_16x0_info(void)
{
   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++ = '\n';
      *pt = '\0';
   } else {			/* Assume VERSION is a number */
      strcat( buffer, " " VERSION "\n" );
   }
      
   return buffer;
}

#if 0
static 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 */
   outb( 0x04 | PARITY_MASK, TMC_Cntl_port ); /* Start arbitration */

   timeout = jiffies + 50;	              /* 500 mS */
   while (jiffies < timeout) {
      status = inb( TMC_Status_port );        /* Read adapter status */
      if (status & 0x02)		      /* Arbitration complete */
	    return 0;	
   }

   /* Make bus idle */
   fdomain_make_bus_idle();

#if EVERY_ACCESS
   printk( "Arbitration failed, status = %x\n", status );
#endif
#if ERRORS_ONLY
   printk( "Future Domain: Arbitration failed, status = %x", status );
#endif
   return 1;
}
#endif

static int fdomain_select( int target )
{
   int           status;
   unsigned long timeout;


   outb( 0x82, SCSI_Cntl_port ); /* Bus Enable + Select */
   outb( adapter_mask | (1 << target), SCSI_Data_NoACK_port );

   /* Stop arbitration and enable parity */
   outb( PARITY_MASK, TMC_Cntl_port ); 

   timeout = jiffies + 25;	        /* 250mS */
   while (jiffies < timeout) {
      status = inb( SCSI_Status_port ); /* Read adapter status */
      if (status & 1) {		        /* Busy asserted */
	 /* Enable SCSI Bus (on error, should make bus idle with 0) */
	 outb( 0x80, SCSI_Cntl_port );
	 return 0;
      }
   }
   /* Make bus idle */
   fdomain_make_bus_idle();
#if EVERY_ACCESS
   if (!target) printk( "Selection failed\n" );
#endif
#if ERRORS_ONLY
   if (!target) printk( "Future Domain: Selection failed" );
#endif

⌨️ 快捷键说明

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