wd7000.c

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

C
1,669
字号
		return (0);	}	if (request_dma(host->dma, "wd7000")) {		printk("wd7000_init: can't get DMA channel %d.\n", host->dma);		free_irq(host->irq, host);		return (0);	}	wd7000_enable_dma(host);	wd7000_enable_intr(host);	if (!wd7000_diagnostics(host, ICB_DIAG_FULL)) {		free_dma(host->dma);		free_irq(host->irq, NULL);		return (0);	}	return (1);}static void wd7000_revision(Adapter * host){	static IcbRevLvl icb = { ICB_OP_GET_REVISION };	icb.phase = 1;	/*	 * Like diagnostics, this is only done at init time, in fact, from	 * wd7000_detect, so there should be OGMBs available.  If it fails,	 * the only damage will be that the revision will show up as 0.0,	 * which in turn means that scatter/gather will be disabled.	 */	mail_out(host, (struct scb *) &icb);	while (icb.phase) {		cpu_relax();	/* wait for completion */		barrier();	}	host->rev1 = icb.primary;	host->rev2 = icb.secondary;}#undef SPRINTF#define SPRINTF(args...) { if (pos < (buffer + length)) pos += sprintf (pos, ## args); }static int wd7000_set_info(char *buffer, int length, struct Scsi_Host *host){	dprintk("Buffer = <%.*s>, length = %d\n", length, buffer, length);	/*	 * Currently this is a no-op	 */	dprintk("Sorry, this function is currently out of order...\n");	return (length);}static int wd7000_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length,  int inout){	Adapter *adapter = (Adapter *)host->hostdata;	unsigned long flags;	char *pos = buffer;#ifdef WD7000_DEBUG	Mailbox *ogmbs, *icmbs;	short count;#endif	/*	 * Has data been written to the file ?	 */	if (inout)		return (wd7000_set_info(buffer, length, host));	spin_lock_irqsave(host->host_lock, flags);	SPRINTF("Host scsi%d: Western Digital WD-7000 (rev %d.%d)\n", host->host_no, adapter->rev1, adapter->rev2);	SPRINTF("  IO base:      0x%x\n", adapter->iobase);	SPRINTF("  IRQ:          %d\n", adapter->irq);	SPRINTF("  DMA channel:  %d\n", adapter->dma);	SPRINTF("  Interrupts:   %d\n", adapter->int_counter);	SPRINTF("  BUS_ON time:  %d nanoseconds\n", adapter->bus_on * 125);	SPRINTF("  BUS_OFF time: %d nanoseconds\n", adapter->bus_off * 125);#ifdef WD7000_DEBUG	ogmbs = adapter->mb.ogmb;	icmbs = adapter->mb.icmb;	SPRINTF("\nControl port value: 0x%x\n", adapter->control);	SPRINTF("Incoming mailbox:\n");	SPRINTF("  size: %d\n", ICMB_CNT);	SPRINTF("  queued messages: ");	for (i = count = 0; i < ICMB_CNT; i++)		if (icmbs[i].status) {			count++;			SPRINTF("0x%x ", i);		}	SPRINTF(count ? "\n" : "none\n");	SPRINTF("Outgoing mailbox:\n");	SPRINTF("  size: %d\n", OGMB_CNT);	SPRINTF("  next message: 0x%x\n", adapter->next_ogmb);	SPRINTF("  queued messages: ");	for (i = count = 0; i < OGMB_CNT; i++)		if (ogmbs[i].status) {			count++;			SPRINTF("0x%x ", i);		}	SPRINTF(count ? "\n" : "none\n");#endif	spin_unlock_irqrestore(host->host_lock, flags);	/*	 * Calculate start of next buffer, and return value.	 */	*start = buffer + offset;	if ((pos - buffer) < offset)		return (0);	else if ((pos - buffer - offset) < length)		return (pos - buffer - offset);	else		return (length);}/* *  Returns the number of adapters this driver is supporting. * *  The source for hosts.c says to wait to call scsi_register until 100% *  sure about an adapter.  We need to do it a little sooner here; we *  need the storage set up by scsi_register before wd7000_init, and *  changing the location of an Adapter structure is more trouble than *  calling scsi_unregister. * */static int wd7000_detect(struct scsi_host_template *tpnt){	short present = 0, biosaddr_ptr, sig_ptr, i, pass;	short biosptr[NUM_CONFIGS];	unsigned iobase;	Adapter *host = NULL;	struct Scsi_Host *sh;	int unit = 0;	dprintk("wd7000_detect: started\n");#ifdef MODULE	if (wd7000)		wd7000_setup(wd7000);#endif	for (i = 0; i < UNITS; wd7000_host[i++] = NULL);	for (i = 0; i < NUM_CONFIGS; biosptr[i++] = -1);	tpnt->proc_name = "wd7000";	tpnt->proc_info = &wd7000_proc_info;	/*	 * Set up SCB free list, which is shared by all adapters	 */	init_scbs();	for (pass = 0; pass < NUM_CONFIGS; pass++) {		/*		 * First, search for BIOS SIGNATURE...		 */		for (biosaddr_ptr = 0; biosaddr_ptr < NUM_ADDRS; biosaddr_ptr++)			for (sig_ptr = 0; sig_ptr < NUM_SIGNATURES; sig_ptr++) {				for (i = 0; i < pass; i++)					if (biosptr[i] == biosaddr_ptr)						break;				if (i == pass) {					void *biosaddr = ioremap(wd7000_biosaddr[biosaddr_ptr] + signatures[sig_ptr].ofs,								 signatures[sig_ptr].len);					short bios_match = 0;					if (biosaddr)						bios_match = memcmp((char *) biosaddr, signatures[sig_ptr].sig, signatures[sig_ptr].len);					iounmap(biosaddr);					if (!bios_match)						goto bios_matched;				}			}	      bios_matched:		/*		 * BIOS SIGNATURE has been found.		 */#ifdef WD7000_DEBUG		dprintk("wd7000_detect: pass %d\n", pass + 1);		if (biosaddr_ptr == NUM_ADDRS)			dprintk("WD-7000 SST BIOS not detected...\n");		else			dprintk("WD-7000 SST BIOS detected at 0x%lx: checking...\n", wd7000_biosaddr[biosaddr_ptr]);#endif		if (configs[pass].irq < 0)			continue;		if (unit == UNITS)			continue;		iobase = configs[pass].iobase;		dprintk("wd7000_detect: check IO 0x%x region...\n", iobase);		if (request_region(iobase, 4, "wd7000")) {			dprintk("wd7000_detect: ASC reset (IO 0x%x) ...", iobase);			/*			 * ASC reset...			 */			outb(ASC_RES, iobase + ASC_CONTROL);			set_current_state(TASK_UNINTERRUPTIBLE);			schedule_timeout(HZ / 100);			outb(0, iobase + ASC_CONTROL);			if (WAIT(iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) {				dprintk("failed!\n");				goto err_release;			} else				dprintk("ok!\n");			if (inb(iobase + ASC_INTR_STAT) == 1) {				/*				 *  We register here, to get a pointer to the extra space,				 *  which we'll use as the Adapter structure (host) for				 *  this adapter.  It is located just after the registered				 *  Scsi_Host structure (sh), and is located by the empty				 *  array hostdata.				 */				sh = scsi_register(tpnt, sizeof(Adapter));				if (sh == NULL)					goto err_release;				host = (Adapter *) sh->hostdata;				dprintk("wd7000_detect: adapter allocated at 0x%x\n", (int) host);				memset(host, 0, sizeof(Adapter));				host->irq = configs[pass].irq;				host->dma = configs[pass].dma;				host->iobase = iobase;				host->int_counter = 0;				host->bus_on = configs[pass].bus_on;				host->bus_off = configs[pass].bus_off;				host->sh = wd7000_host[unit] = sh;				unit++;				dprintk("wd7000_detect: Trying init WD-7000 card at IO " "0x%x, IRQ %d, DMA %d...\n", host->iobase, host->irq, host->dma);				if (!wd7000_init(host))	/* Initialization failed */					goto err_unregister;				/*				 *  OK from here - we'll use this adapter/configuration.				 */				wd7000_revision(host);	/* important for scatter/gather */				/*				 *  For boards before rev 6.0, scatter/gather isn't supported.				 */				if (host->rev1 < 6)					sh->sg_tablesize = SG_NONE;				present++;	/* count it */				if (biosaddr_ptr != NUM_ADDRS)					biosptr[pass] = biosaddr_ptr;				printk(KERN_INFO "Western Digital WD-7000 (rev %d.%d) ", host->rev1, host->rev2);				printk("using IO 0x%x, IRQ %d, DMA %d.\n", host->iobase, host->irq, host->dma);				printk("  BUS_ON time: %dns, BUS_OFF time: %dns\n", host->bus_on * 125, host->bus_off * 125);			}		} else			dprintk("wd7000_detect: IO 0x%x region already allocated!\n", iobase);		continue;	      err_unregister:		scsi_unregister(sh);	      err_release:		release_region(iobase, 4);	}	if (!present)		printk("Failed initialization of WD-7000 SCSI card!\n");	return (present);}static int wd7000_release(struct Scsi_Host *shost){	if (shost->irq)		free_irq(shost->irq, NULL);	if (shost->io_port && shost->n_io_port)		release_region(shost->io_port, shost->n_io_port);	scsi_unregister(shost);	return 0;}#if 0/* *  I have absolutely NO idea how to do an abort with the WD7000... */static int wd7000_abort(Scsi_Cmnd * SCpnt){	Adapter *host = (Adapter *) SCpnt->device->host->hostdata;	if (inb(host->iobase + ASC_STAT) & INT_IM) {		printk("wd7000_abort: lost interrupt\n");		wd7000_intr_handle(host->irq, NULL, NULL);		return FAILED;	}	return FAILED;}#endif/* *  Last resort. Reinitialize the board. */static int wd7000_host_reset(struct scsi_cmnd *SCpnt){	Adapter *host = (Adapter *) SCpnt->device->host->hostdata;	if (wd7000_adapter_reset(host) < 0)		return FAILED;	wd7000_enable_intr(host);	return SUCCESS;}/* *  This was borrowed directly from aha1542.c. (Zaga) */static int wd7000_biosparam(struct scsi_device *sdev,		struct block_device *bdev, sector_t capacity, int *ip){	char b[BDEVNAME_SIZE];	dprintk("wd7000_biosparam: dev=%s, size=%d, ",		bdevname(bdev, b), capacity);	(void)b;	/* unused var warning? */	/*	 * try default translation	 */	ip[0] = 64;	ip[1] = 32;	ip[2] = capacity >> 11;	/*	 * for disks >1GB do some guessing	 */	if (ip[2] >= 1024) {		int info[3];		/*		 * try to figure out the geometry from the partition table		 */		if ((scsicam_bios_param(bdev, capacity, info) < 0) || !(((info[0] == 64) && (info[1] == 32)) || ((info[0] == 255) && (info[1] == 63)))) {			printk("wd7000_biosparam: unable to verify geometry for disk with >1GB.\n" "                  using extended translation.\n");			ip[0] = 255;			ip[1] = 63;			ip[2] = (unsigned long) capacity / (255 * 63);		} else {			ip[0] = info[0];			ip[1] = info[1];			ip[2] = info[2];			if (info[0] == 255)				printk(KERN_INFO "%s: current partition table is " "using extended translation.\n", __FUNCTION__);		}	}	dprintk("bios geometry: head=%d, sec=%d, cyl=%d\n", ip[0], ip[1], ip[2]);	dprintk("WARNING: check, if the bios geometry is correct.\n");	return (0);}MODULE_AUTHOR("Thomas Wuensche, John Boyd, Miroslav Zagorac");MODULE_DESCRIPTION("Driver for the WD7000 series ISA controllers");MODULE_LICENSE("GPL");static struct scsi_host_template driver_template = {	.proc_name		= "wd7000",	.proc_info		= wd7000_proc_info,	.name			= "Western Digital WD-7000",	.detect			= wd7000_detect,	.release		= wd7000_release,	.queuecommand		= wd7000_queuecommand,	.eh_host_reset_handler	= wd7000_host_reset,	.bios_param		= wd7000_biosparam,	.can_queue		= WD7000_Q,	.this_id		= 7,	.sg_tablesize		= WD7000_SG,	.cmd_per_lun		= 1,	.unchecked_isa_dma	= 1,	.use_clustering		= ENABLE_CLUSTERING,};#include "scsi_module.c"

⌨️ 快捷键说明

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