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

📄 ultrastor.c

📁 LINUX 1.0 内核c源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	in_byte = inb(U14F_PRODUCT_ID(config.port_address));
	if (in_byte != US14F_PRODUCT_ID_0) {
#if (ULTRASTOR_DEBUG & UD_DETECT)
# ifdef PORT_OVERRIDE
	    printk("US14F: detect: wrong product ID 0 - %02X\n", in_byte);
# else
	    printk("US14F: detect: no adapter at port %03X\n", config.port_address);
# endif
#endif
#ifdef PORT_OVERRIDE
	    return FALSE;
#else
	    continue;
#endif
	}
	in_byte = inb(U14F_PRODUCT_ID(config.port_address) + 1);
	/* Only upper nibble is significant for Product ID 1 */
	if ((in_byte & 0xF0) != US14F_PRODUCT_ID_1) {
#if (ULTRASTOR_DEBUG & UD_DETECT)
# ifdef PORT_OVERRIDE
	    printk("US14F: detect: wrong product ID 1 - %02X\n", in_byte);
# else
	    printk("US14F: detect: no adapter at port %03X\n", config.port_address);
# endif
#endif
#ifdef PORT_OVERRIDE
	    return FALSE;
#else
	    continue;
#endif
	}
	version_byte = in_byte;
#ifndef PORT_OVERRIDE
	break;
    }
    if (i == ARRAY_SIZE(ultrastor_ports_14f)) {
# if (ULTRASTOR_DEBUG & UD_DETECT)
	printk("US14F: detect: no port address found!\n");
# endif
	return FALSE;
    }
#endif

#if (ULTRASTOR_DEBUG & UD_DETECT)
    printk("US14F: detect: adapter found at port address %03X\n",
	   config.port_address);
#endif

    /* Set local doorbell mask to disallow bus reset unless
       ultrastor_bus_reset is true.  */
    outb(ultrastor_bus_reset ? 0xc2 : 0x82, LCL_DOORBELL_MASK(config.port_address));

    /* All above tests passed, must be the right thing.  Get some useful
       info. */

    snarf_region(config.port_address, 0x0c); /* Register the I/O space that we use */

    *(char *)&config_1 = inb(CONFIG(config.port_address + 0));
    *(char *)&config_2 = inb(CONFIG(config.port_address + 1));
    config.bios_segment = bios_segment_table[config_1.bios_segment];
    config.doorbell_address = config.port_address;
    config.ogm_address = config.port_address + 0x8;
    config.icm_address = config.port_address + 0xC;
    config.interrupt = interrupt_table_14f[config_1.interrupt];
    config.ha_scsi_id = config_2.ha_scsi_id;
    config.heads = mapping_table[config_2.mapping_mode].heads;
    config.sectors = mapping_table[config_2.mapping_mode].sectors;
    config.bios_drive_number = config_2.bios_drive_number;
    config.subversion = (version_byte & 0x0F);
    if (config.subversion == U34F)
	config.dma_channel = 0;
    else
	config.dma_channel = dma_channel_table_14f[config_1.dma_channel];

    if (!config.bios_segment) {
#if (ULTRASTOR_DEBUG & UD_DETECT)
	printk("US14F: detect: not detected.\n");
#endif
	return FALSE;
    }

    /* Final consistancy check, verify previous info. */
    if (config.subversion != U34F)
	if (!config.dma_channel || !(config_2.tfr_port & 0x2)) {
#if (ULTRASTOR_DEBUG & UD_DETECT)
	    printk("US14F: detect: consistancy check failed\n");
#endif
	    return FALSE;
	}

    /* If we were TRULY paranoid, we could issue a host adapter inquiry
       command here and verify the data returned.  But frankly, I'm
       exhausted! */

    /* Finally!  Now I'm satisfied... */
#if (ULTRASTOR_DEBUG & UD_DETECT)
    printk("US14F: detect: detect succeeded\n"
	   "  Port address: %03X\n"
	   "  BIOS segment: %05X\n"
	   "  Interrupt: %u\n"
	   "  DMA channel: %u\n"
	   "  H/A SCSI ID: %u\n"
	   "  Subversion: %u\n",
	   config.port_address, config.bios_segment, config.interrupt,
	   config.dma_channel, config.ha_scsi_id, config.subversion);
#endif
    config.host_number = hostnum;
    scsi_hosts[hostnum].this_id = config.ha_scsi_id;
    scsi_hosts[hostnum].unchecked_isa_dma = (config.subversion != U34F);

#if ULTRASTOR_MAX_CMDS > 1
    config.mscp_free = ~0;
#endif

    if (request_irq(config.interrupt, ultrastor_interrupt)) {
	printk("Unable to allocate IRQ%u for UltraStor controller.\n",
	       config.interrupt);
	return FALSE;
    }
    if (config.dma_channel && request_dma(config.dma_channel)) {
	printk("Unable to allocate DMA channel %u for UltraStor controller.\n",
	       config.dma_channel);
	free_irq(config.interrupt);
	return FALSE;
    }
    scsi_hosts[hostnum].sg_tablesize = ULTRASTOR_14F_MAX_SG;
    printk("UltraStor driver version" VERSION ".  Using %d SG lists.\n",
	   ULTRASTOR_14F_MAX_SG);

    return TRUE;
}

static int ultrastor_24f_detect(int hostnum)
{
  register int i;

#if (ULTRASTOR_DEBUG & UD_DETECT)
  printk("US24F: detect");
#endif

  /* probe each EISA slot at slot address C80 */
  for (i = 1; i < 15; i++)
    {
      unsigned char config_1, config_2;
      unsigned short addr = (i << 12) | ULTRASTOR_24F_PORT;

      if (inb(addr) != US24F_PRODUCT_ID_0 &&
	  inb(addr+1) != US24F_PRODUCT_ID_1 &&
	  inb(addr+2) != US24F_PRODUCT_ID_2)
	continue;

      config.revision = inb(addr+3);
      config.slot = i;
      if (! (inb(addr+4) & 1))
	{
#if (ULTRASTOR_DEBUG & UD_DETECT)
	  printk("U24F: found disabled card in slot %u\n", i);
#endif
	  continue;
	}
#if (ULTRASTOR_DEBUG & UD_DETECT)
      printk("U24F: found card in slot %u\n", i);
#endif
      config_1 = inb(addr + 5);
      config.bios_segment = bios_segment_table[config_1 & 7];
      switch(config_1 >> 4)
	{
	case 1:
	  config.interrupt = 15;
	  break;
	case 2:
	  config.interrupt = 14;
	  break;
	case 4:
	  config.interrupt = 11;
	  break;
	case 8:
	  config.interrupt = 10;
	  break;
	default:
	  printk("U24F: invalid IRQ\n");
	  return FALSE;
	}
      if (request_irq(config.interrupt, ultrastor_interrupt))
	{
	  printk("Unable to allocate IRQ%u for UltraStor controller.\n",
		 config.interrupt);
	  return FALSE;
	}
      /* BIOS addr set */
      /* base port set */
      config.port_address = addr;
      config.doorbell_address = addr + 12;
      config.ogm_address = addr + 0x17;
      config.icm_address = addr + 0x1C;
      config_2 = inb(addr + 7);
      config.ha_scsi_id = config_2 & 7;
      config.heads = mapping_table[(config_2 >> 3) & 3].heads;
      config.sectors = mapping_table[(config_2 >> 3) & 3].sectors;
#if (ULTRASTOR_DEBUG & UD_DETECT)
      printk("US24F: detect: detect succeeded\n"
	     "  Port address: %03X\n"
	     "  BIOS segment: %05X\n"
	     "  Interrupt: %u\n"
	     "  H/A SCSI ID: %u\n",
	     config.port_address, config.bios_segment,
	     config.interrupt, config.ha_scsi_id);
#endif
      config.host_number = hostnum;
      scsi_hosts[hostnum].this_id = config.ha_scsi_id;
      scsi_hosts[hostnum].unchecked_isa_dma = 0;
      scsi_hosts[hostnum].sg_tablesize = ULTRASTOR_14F_MAX_SG;

#if ULTRASTOR_MAX_CMDS > 1
      config.mscp_free = ~0;
#endif
      /* Mark ICM and OGM free */
      outb(0, addr + 0x16);
      outb(0, addr + 0x1B);

      /* Set local doorbell mask to disallow bus reset unless
	 ultrastor_bus_reset is true.  */
      outb(ultrastor_bus_reset ? 0xc2 : 0x82, LCL_DOORBELL_MASK(addr+12));
      outb(0x02, SYS_DOORBELL_MASK(addr+12));
      printk("UltraStor driver version " VERSION ".  Using %d SG lists.\n",
	     ULTRASTOR_14F_MAX_SG);
      return TRUE;
    }
  return FALSE;
}

int ultrastor_detect(int hostnum)
{
  return ultrastor_14f_detect(hostnum) || ultrastor_24f_detect(hostnum);
}

const char *ultrastor_info(void)
{
    static char buf[64];

    if (config.slot)
      sprintf(buf, "UltraStor 24F SCSI @ Slot %u IRQ%u\n",
	      config.slot, config.interrupt);
    else if (config.subversion)
      sprintf(buf, "UltraStor 34F SCSI @ Port %03X BIOS %05X IRQ%u\n",
	      config.port_address, (int)config.bios_segment,
	      config.interrupt);
    else
      sprintf(buf, "UltraStor 14F SCSI @ Port %03X BIOS %05X IRQ%u DMA%u\n",
	      config.port_address, (int)config.bios_segment,
	      config.interrupt, config.dma_channel);
    return buf;
}

static inline void build_sg_list(register struct mscp *mscp, Scsi_Cmnd *SCpnt)
{
	struct scatterlist *sl;
	long transfer_length = 0;
	int i, max;

	sl = (struct scatterlist *) SCpnt->request_buffer;
	max = SCpnt->use_sg;
	for (i = 0; i < max; i++) {
		mscp->sglist[i].address = (unsigned int)sl[i].address;
		mscp->sglist[i].num_bytes = sl[i].length;
		transfer_length += sl[i].length;
	}
	mscp->number_of_sg_list = max;
	mscp->transfer_data = (unsigned int)mscp->sglist;
	/* ??? May not be necessary.  Docs are unclear as to whether transfer
	   length field is ignored or whether it should be set to the total
	   number of bytes of the transfer.  */
	mscp->transfer_data_length = transfer_length;
}

int ultrastor_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
{
    register struct mscp *my_mscp;
#if ULTRASTOR_MAX_CMDS > 1
    int mscp_index;
#endif
    unsigned int status;
    int flags;

    /* Next test is for debugging; "can't happen" */
    if ((config.mscp_free & ((1U << ULTRASTOR_MAX_CMDS) - 1)) == 0)
	panic("ultrastor_queuecommand: no free MSCP\n");
    mscp_index = find_and_clear_bit_16(&config.mscp_free);

    /* Has the command been aborted?  */
    if (xchgb(0xff, &config.aborted[mscp_index]) != 0)
      {
	status = DID_ABORT << 16;
	goto aborted;
      }

    my_mscp = &config.mscp[mscp_index];

#if 1
    /* This way is faster.  */
    *(unsigned char *)my_mscp = OP_SCSI | (DTD_SCSI << 3);
#else
    my_mscp->opcode = OP_SCSI;
    my_mscp->xdir = DTD_SCSI;
    my_mscp->dcn = FALSE;
#endif
    /* Tape drives don't work properly if the cache is used.  The SCSI
       READ command for a tape doesn't have a block offset, and the adapter
       incorrectly assumes that all reads from the tape read the same
       blocks.  Results will depend on read buffer size and other disk
       activity. 

       ???  Which other device types should never use the cache?   */
    my_mscp->ca = scsi_devices[SCpnt->index].type != TYPE_TAPE;
    my_mscp->target_id = SCpnt->target;
    my_mscp->ch_no = 0;
    my_mscp->lun = SCpnt->lun;
    if (SCpnt->use_sg) {
	/* Set scatter/gather flag in SCSI command packet */
	my_mscp->sg = TRUE;
	build_sg_list(my_mscp, SCpnt);
    } else {
	/* Unset scatter/gather flag in SCSI command packet */
	my_mscp->sg = FALSE;
	my_mscp->transfer_data = (unsigned int)SCpnt->request_buffer;
	my_mscp->transfer_data_length = SCpnt->request_bufflen;
    }
    my_mscp->command_link = 0;		/*???*/
    my_mscp->scsi_command_link_id = 0;	/*???*/
    my_mscp->length_of_sense_byte = sizeof SCpnt->sense_buffer;
    my_mscp->length_of_scsi_cdbs = COMMAND_SIZE(*(unsigned char *)SCpnt->cmnd);
    memcpy(my_mscp->scsi_cdbs, SCpnt->cmnd, my_mscp->length_of_scsi_cdbs);
    my_mscp->adapter_status = 0;
    my_mscp->target_status = 0;
    my_mscp->sense_data = (unsigned int)&SCpnt->sense_buffer;
    my_mscp->done = done;
    my_mscp->SCint = SCpnt;
    SCpnt->host_scribble = (unsigned char *)my_mscp;

    /* Find free OGM slot.  On 24F, look for OGM status byte == 0.
       On 14F and 34F, wait for local interrupt pending flag to clear.  */

  retry:
    if (config.slot)
	while (inb(config.ogm_address - 1) != 0 &&
	       config.aborted[mscp_index] == 0xff);

    /* else??? */

    while ((inb(LCL_DOORBELL_INTR(config.doorbell_address)) & 
	    (config.slot ? 2 : 1)) 
	   && config.aborted[mscp_index] == 0xff);

    /* To avoid race conditions, make the code to write to the adapter
       atomic.  This simplifies the abort code.  */

    save_flags(flags);
    cli();

    if (inb(LCL_DOORBELL_INTR(config.doorbell_address)) &
	(config.slot ? 2 : 1))
      {
      restore_flags(flags);
      goto retry;
      }

    status = xchgb(0, &config.aborted[mscp_index]);
    if (status != 0xff) {
	restore_flags(flags);

#if ULTRASTOR_DEBUG & (UD_COMMAND | UD_ABORT)

⌨️ 快捷键说明

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