ultrastor.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,205 行 · 第 1/3 页

C
1,205
字号
	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	    goto out_release_port;#else	    release_region(config.port_address, 0x0c);	    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	/* all ports probed already released - we can just go straight out */	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. */    /* 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	goto out_release_port;    }    /* Final consistency 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: consistency check failed\n");#endif           goto out_release_port;	}    /* 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    tpnt->this_id = config.ha_scsi_id;    tpnt->unchecked_isa_dma = (config.subversion != U34F);#if ULTRASTOR_MAX_CMDS > 1    config.mscp_free = ~0;#endif    /*     * Brrr, &config.mscp[0].SCint->host) it is something magical....     * XXX and FIXME     */    if (request_irq(config.interrupt, do_ultrastor_interrupt, 0, "Ultrastor", &config.mscp[0].SCint->device->host)) {	printk("Unable to allocate IRQ%u for UltraStor controller.\n",	       config.interrupt);	goto out_release_port;    }    if (config.dma_channel && request_dma(config.dma_channel,"Ultrastor")) {	printk("Unable to allocate DMA channel %u for UltraStor controller.\n",	       config.dma_channel);	free_irq(config.interrupt, NULL);	goto out_release_port;    }    tpnt->sg_tablesize = ULTRASTOR_14F_MAX_SG;    printk("UltraStor driver version" VERSION ".  Using %d SG lists.\n",	   ULTRASTOR_14F_MAX_SG);    return TRUE;out_release_port:    release_region(config.port_address, 0x0c);    return FALSE;}static int ultrastor_24f_detect(Scsi_Host_Template * tpnt){  int i;  struct Scsi_Host * shpnt = NULL;#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;	}      /* 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      tpnt->this_id = config.ha_scsi_id;      tpnt->unchecked_isa_dma = 0;      tpnt->sg_tablesize = ULTRASTOR_24F_MAX_SG;      shpnt = scsi_register(tpnt, 0);      if (!shpnt) {             printk(KERN_WARNING "(ultrastor:) Could not register scsi device. Aborting registration.\n");             free_irq(config.interrupt, do_ultrastor_interrupt);             return FALSE;      }            if (request_irq(config.interrupt, do_ultrastor_interrupt, 0, "Ultrastor", shpnt))	{	  printk("Unable to allocate IRQ%u for UltraStor controller.\n",		 config.interrupt);	  return FALSE;	}      shpnt->irq = config.interrupt;      shpnt->dma_channel = config.dma_channel;      shpnt->io_port = config.port_address;#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",	     tpnt->sg_tablesize);      return TRUE;    }  return FALSE;}static int ultrastor_detect(Scsi_Host_Template * tpnt){	tpnt->proc_name = "ultrastor";	return ultrastor_14f_detect(tpnt) || ultrastor_24f_detect(tpnt);}static int ultrastor_release(struct Scsi_Host *shost){	if (shost->irq)		free_irq(shost->irq, NULL);	if (shost->dma_channel != 0xff)		free_dma(shost->dma_channel);	if (shost->io_port && shost->n_io_port)		release_region(shost->io_port, shost->n_io_port);	scsi_unregister(shost);	return 0;}static const char *ultrastor_info(struct Scsi_Host * shpnt){    static char buf[64];    if (config.slot)      sprintf(buf, "UltraStor 24F SCSI @ Slot %u IRQ%u",	      config.slot, config.interrupt);    else if (config.subversion)      sprintf(buf, "UltraStor 34F SCSI @ Port %03X BIOS %05X IRQ%u",	      config.port_address, (int)config.bios_segment,	      config.interrupt);    else      sprintf(buf, "UltraStor 14F SCSI @ Port %03X BIOS %05X IRQ%u DMA%u",	      config.port_address, (int)config.bios_segment,	      config.interrupt, config.dma_channel);    return buf;}static inline void build_sg_list(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 = isa_page_to_bus(sl[i].page) + sl[i].offset;		mscp->sglist[i].num_bytes = sl[i].length;		transfer_length += sl[i].length;	}	mscp->number_of_sg_list = max;	mscp->transfer_data = isa_virt_to_bus(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;}static int ultrastor_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)){    struct mscp *my_mscp;#if ULTRASTOR_MAX_CMDS > 1    int mscp_index;#endif    unsigned int status;    /* 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];    *(unsigned char *)my_mscp = OP_SCSI | (DTD_SCSI << 3);    /* 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 = SCpnt->device->type != TYPE_TAPE;    my_mscp->target_id = SCpnt->device->id;    my_mscp->ch_no = 0;    my_mscp->lun = SCpnt->device->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 = isa_virt_to_bus(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 = SCpnt->cmd_len;    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 = isa_virt_to_bus(&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.               FIXME: now we are using new_eh we should punt here and let the       midlayer sort it out */retry:    if (config.slot)	while (inb(config.ogm_address - 1) != 0 && config.aborted[mscp_index] == 0xff)		barrier();    /* else??? */    while ((inb(LCL_DOORBELL_INTR(config.doorbell_address)) & (config.slot ? 2 : 1))  && config.aborted[mscp_index] == 0xff)    	barrier();    /* To avoid race conditions, keep the code to write to the adapter       atomic.  This simplifies the abort code.  Right now the       scsi mid layer has the host_lock already held     */    if (inb(LCL_DOORBELL_INTR(config.doorbell_address)) & (config.slot ? 2 : 1))      goto retry;    status = xchgb(0, &config.aborted[mscp_index]);    if (status != 0xff) {#if ULTRASTOR_DEBUG & (UD_COMMAND | UD_ABORT)	printk("USx4F: queuecommand: aborted\n");#if ULTRASTOR_MAX_CMDS > 1	log_ultrastor_abort(&config, mscp_index);#endif#endif	status <<= 16;      aborted:	set_bit(mscp_index, &config.mscp_free);	/* If the driver queues commands, call the done proc here.  Otherwise	   return an error.  */#if ULTRASTOR_MAX_CMDS > 1	SCpnt->result = status;	done(SCpnt);	return 0;#else	return status;#endif    }    /* Store pointer in OGM address bytes */    outl(isa_virt_to_bus(my_mscp), config.ogm_address);

⌨️ 快捷键说明

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