atp870u.c
来自「linux 内核源代码」· C语言 代码 · 共 2,946 行 · 第 1/5 页
C
2,946 行
/* * Copyright (C) 1997 Wu Ching Chen * 2.1.x update (C) 1998 Krzysztof G. Baranowski * 2.5.x update (C) 2002 Red Hat <alan@redhat.com> * 2.6.x update (C) 2004 Red Hat <alan@redhat.com> * * Marcelo Tosatti <marcelo@conectiva.com.br> : SMP fixes * * Wu Ching Chen : NULL pointer fixes 2000/06/02 * support atp876 chip * enable 32 bit fifo transfer * support cdrom & remove device run ultra speed * fix disconnect bug 2000/12/21 * support atp880 chip lvd u160 2001/05/15 * fix prd table bug 2001/09/12 (7.1) * * atp885 support add by ACARD Hao Ping Lian 2005/01/05 */#include <linux/module.h>#include <linux/init.h>#include <linux/interrupt.h>#include <linux/kernel.h>#include <linux/types.h>#include <linux/string.h>#include <linux/ioport.h>#include <linux/delay.h>#include <linux/proc_fs.h>#include <linux/spinlock.h>#include <linux/pci.h>#include <linux/blkdev.h>#include <linux/dma-mapping.h>#include <asm/system.h>#include <asm/io.h>#include <scsi/scsi.h>#include <scsi/scsi_cmnd.h>#include <scsi/scsi_device.h>#include <scsi/scsi_host.h>#include "atp870u.h"static struct scsi_host_template atp870u_template;static void send_s870(struct atp_unit *dev,unsigned char c);static void is885(struct atp_unit *dev, unsigned int wkport,unsigned char c);static void tscam_885(void);static irqreturn_t atp870u_intr_handle(int irq, void *dev_id){ unsigned long flags; unsigned short int tmpcip, id; unsigned char i, j, c, target_id, lun,cmdp; unsigned char *prd; struct scsi_cmnd *workreq; unsigned int workport, tmport, tmport1; unsigned long adrcnt, k;#ifdef ED_DBGP unsigned long l;#endif int errstus; struct Scsi_Host *host = dev_id; struct atp_unit *dev = (struct atp_unit *)&host->hostdata; for (c = 0; c < 2; c++) { tmport = dev->ioport[c] + 0x1f; j = inb(tmport); if ((j & 0x80) != 0) { goto ch_sel; } dev->in_int[c] = 0; } return IRQ_NONE;ch_sel:#ifdef ED_DBGP printk("atp870u_intr_handle enter\n");#endif dev->in_int[c] = 1; cmdp = inb(dev->ioport[c] + 0x10); workport = dev->ioport[c]; if (dev->working[c] != 0) { if (dev->dev_id == ATP885_DEVID) { tmport1 = workport + 0x16; if ((inb(tmport1) & 0x80) == 0) outb((inb(tmport1) | 0x80), tmport1); } tmpcip = dev->pciport[c]; if ((inb(tmpcip) & 0x08) != 0) { tmpcip += 0x2; for (k=0; k < 1000; k++) { if ((inb(tmpcip) & 0x08) == 0) { goto stop_dma; } if ((inb(tmpcip) & 0x01) == 0) { goto stop_dma; } } }stop_dma: tmpcip = dev->pciport[c]; outb(0x00, tmpcip); tmport -= 0x08; i = inb(tmport); if (dev->dev_id == ATP885_DEVID) { tmpcip += 2; outb(0x06, tmpcip); tmpcip -= 2; } tmport -= 0x02; target_id = inb(tmport); tmport += 0x02; /* * Remap wide devices onto id numbers */ if ((target_id & 0x40) != 0) { target_id = (target_id & 0x07) | 0x08; } else { target_id &= 0x07; } if ((j & 0x40) != 0) { if (dev->last_cmd[c] == 0xff) { dev->last_cmd[c] = target_id; } dev->last_cmd[c] |= 0x40; } if (dev->dev_id == ATP885_DEVID) dev->r1f[c][target_id] |= j;#ifdef ED_DBGP printk("atp870u_intr_handle status = %x\n",i);#endif if (i == 0x85) { if ((dev->last_cmd[c] & 0xf0) != 0x40) { dev->last_cmd[c] = 0xff; } if (dev->dev_id == ATP885_DEVID) { tmport -= 0x05; adrcnt = 0; ((unsigned char *) &adrcnt)[2] = inb(tmport++); ((unsigned char *) &adrcnt)[1] = inb(tmport++); ((unsigned char *) &adrcnt)[0] = inb(tmport); if (dev->id[c][target_id].last_len != adrcnt) { k = dev->id[c][target_id].last_len; k -= adrcnt; dev->id[c][target_id].tran_len = k; dev->id[c][target_id].last_len = adrcnt; }#ifdef ED_DBGP printk("tmport = %x dev->id[c][target_id].last_len = %d dev->id[c][target_id].tran_len = %d\n",tmport,dev->id[c][target_id].last_len,dev->id[c][target_id].tran_len);#endif } /* * Flip wide */ if (dev->wide_id[c] != 0) { tmport = workport + 0x1b; outb(0x01, tmport); while ((inb(tmport) & 0x01) != 0x01) { outb(0x01, tmport); } } /* * Issue more commands */ spin_lock_irqsave(dev->host->host_lock, flags); if (((dev->quhd[c] != dev->quend[c]) || (dev->last_cmd[c] != 0xff)) && (dev->in_snd[c] == 0)) {#ifdef ED_DBGP printk("Call sent_s870\n");#endif send_s870(dev,c); } spin_unlock_irqrestore(dev->host->host_lock, flags); /* * Done */ dev->in_int[c] = 0;#ifdef ED_DBGP printk("Status 0x85 return\n");#endif goto handled; } if (i == 0x40) { dev->last_cmd[c] |= 0x40; dev->in_int[c] = 0; goto handled; } if (i == 0x21) { if ((dev->last_cmd[c] & 0xf0) != 0x40) { dev->last_cmd[c] = 0xff; } tmport -= 0x05; adrcnt = 0; ((unsigned char *) &adrcnt)[2] = inb(tmport++); ((unsigned char *) &adrcnt)[1] = inb(tmport++); ((unsigned char *) &adrcnt)[0] = inb(tmport); k = dev->id[c][target_id].last_len; k -= adrcnt; dev->id[c][target_id].tran_len = k; dev->id[c][target_id].last_len = adrcnt; tmport -= 0x04; outb(0x41, tmport); tmport += 0x08; outb(0x08, tmport); dev->in_int[c] = 0; goto handled; } if (dev->dev_id == ATP885_DEVID) { if ((i == 0x4c) || (i == 0x4d) || (i == 0x8c) || (i == 0x8d)) { if ((i == 0x4c) || (i == 0x8c)) i=0x48; else i=0x49; } } if ((i == 0x80) || (i == 0x8f)) {#ifdef ED_DBGP printk(KERN_DEBUG "Device reselect\n");#endif lun = 0; tmport -= 0x07; if (cmdp == 0x44 || i==0x80) { tmport += 0x0d; lun = inb(tmport) & 0x07; } else { if ((dev->last_cmd[c] & 0xf0) != 0x40) { dev->last_cmd[c] = 0xff; } if (cmdp == 0x41) {#ifdef ED_DBGP printk("cmdp = 0x41\n");#endif tmport += 0x02; adrcnt = 0; ((unsigned char *) &adrcnt)[2] = inb(tmport++); ((unsigned char *) &adrcnt)[1] = inb(tmport++); ((unsigned char *) &adrcnt)[0] = inb(tmport); k = dev->id[c][target_id].last_len; k -= adrcnt; dev->id[c][target_id].tran_len = k; dev->id[c][target_id].last_len = adrcnt; tmport += 0x04; outb(0x08, tmport); dev->in_int[c] = 0; goto handled; } else {#ifdef ED_DBGP printk("cmdp != 0x41\n");#endif outb(0x46, tmport); dev->id[c][target_id].dirct = 0x00; tmport += 0x02; outb(0x00, tmport++); outb(0x00, tmport++); outb(0x00, tmport++); tmport += 0x03; outb(0x08, tmport); dev->in_int[c] = 0; goto handled; } } if (dev->last_cmd[c] != 0xff) { dev->last_cmd[c] |= 0x40; } if (dev->dev_id == ATP885_DEVID) { j = inb(dev->baseport + 0x29) & 0xfe; outb(j, dev->baseport + 0x29); tmport = workport + 0x16; } else { tmport = workport + 0x10; outb(0x45, tmport); tmport += 0x06; } target_id = inb(tmport); /* * Remap wide identifiers */ if ((target_id & 0x10) != 0) { target_id = (target_id & 0x07) | 0x08; } else { target_id &= 0x07; } if (dev->dev_id == ATP885_DEVID) { tmport = workport + 0x10; outb(0x45, tmport); } workreq = dev->id[c][target_id].curr_req;#ifdef ED_DBGP scmd_printk(KERN_DEBUG, workreq, "CDB"); for (l = 0; l < workreq->cmd_len; l++) printk(KERN_DEBUG " %x",workreq->cmnd[l]); printk("\n");#endif tmport = workport + 0x0f; outb(lun, tmport); tmport += 0x02; outb(dev->id[c][target_id].devsp, tmport++); adrcnt = dev->id[c][target_id].tran_len; k = dev->id[c][target_id].last_len; outb(((unsigned char *) &k)[2], tmport++); outb(((unsigned char *) &k)[1], tmport++); outb(((unsigned char *) &k)[0], tmport++);#ifdef ED_DBGP printk("k %x, k[0] 0x%x k[1] 0x%x k[2] 0x%x\n", k, inb(tmport-1), inb(tmport-2), inb(tmport-3));#endif /* Remap wide */ j = target_id; if (target_id > 7) { j = (j & 0x07) | 0x40; } /* Add direction */ j |= dev->id[c][target_id].dirct; outb(j, tmport++); outb(0x80,tmport); /* enable 32 bit fifo transfer */ if (dev->dev_id == ATP885_DEVID) { tmpcip = dev->pciport[c] + 1; i=inb(tmpcip) & 0xf3; //j=workreq->cmnd[0]; if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) { i |= 0x0c; } outb(i,tmpcip); } else if ((dev->dev_id == ATP880_DEVID1) || (dev->dev_id == ATP880_DEVID2) ) { tmport = workport - 0x05; if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) { outb((unsigned char) ((inb(tmport) & 0x3f) | 0xc0), tmport); } else { outb((unsigned char) (inb(tmport) & 0x3f), tmport); } } else { tmport = workport + 0x3a; if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) { outb((unsigned char) ((inb(tmport) & 0xf3) | 0x08), tmport); } else { outb((unsigned char) (inb(tmport) & 0xf3), tmport); } } tmport = workport + 0x1b; j = 0; id = 1; id = id << target_id; /* * Is this a wide device */ if ((id & dev->wide_id[c]) != 0) { j |= 0x01; } outb(j, tmport); while ((inb(tmport) & 0x01) != j) { outb(j,tmport); } if (dev->id[c][target_id].last_len == 0) { tmport = workport + 0x18; outb(0x08, tmport); dev->in_int[c] = 0;#ifdef ED_DBGP printk("dev->id[c][target_id].last_len = 0\n");#endif goto handled; }#ifdef ED_DBGP printk("target_id = %d adrcnt = %d\n",target_id,adrcnt);#endif prd = dev->id[c][target_id].prd_pos; while (adrcnt != 0) { id = ((unsigned short int *)prd)[2]; if (id == 0) { k = 0x10000; } else { k = id; } if (k > adrcnt) { ((unsigned short int *)prd)[2] = (unsigned short int) (k - adrcnt); ((unsigned long *)prd)[0] += adrcnt; adrcnt = 0; dev->id[c][target_id].prd_pos = prd; } else { adrcnt -= k; dev->id[c][target_id].prdaddr += 0x08; prd += 0x08; if (adrcnt == 0) { dev->id[c][target_id].prd_pos = prd; } } } tmpcip = dev->pciport[c] + 0x04; outl(dev->id[c][target_id].prdaddr, tmpcip);#ifdef ED_DBGP printk("dev->id[%d][%d].prdaddr 0x%8x\n", c, target_id, dev->id[c][target_id].prdaddr);#endif if (dev->dev_id == ATP885_DEVID) { tmpcip -= 0x04; } else { tmpcip -= 0x02; outb(0x06, tmpcip); outb(0x00, tmpcip); tmpcip -= 0x02; } tmport = workport + 0x18; /* * Check transfer direction */ if (dev->id[c][target_id].dirct != 0) { outb(0x08, tmport); outb(0x01, tmpcip); dev->in_int[c] = 0;#ifdef ED_DBGP printk("status 0x80 return dirct != 0\n");#endif goto handled; } outb(0x08, tmport); outb(0x09, tmpcip); dev->in_int[c] = 0;#ifdef ED_DBGP printk("status 0x80 return dirct = 0\n");#endif goto handled; } /* * Current scsi request on this target */ workreq = dev->id[c][target_id].curr_req; if (i == 0x42) { if ((dev->last_cmd[c] & 0xf0) != 0x40) { dev->last_cmd[c] = 0xff; } errstus = 0x02; workreq->result = errstus; goto go_42; } if (i == 0x16) { if ((dev->last_cmd[c] & 0xf0) != 0x40) { dev->last_cmd[c] = 0xff; } errstus = 0; tmport -= 0x08; errstus = inb(tmport); if (((dev->r1f[c][target_id] & 0x10) != 0)&&(dev->dev_id==ATP885_DEVID)) { printk(KERN_WARNING "AEC67162 CRC ERROR !\n"); errstus = 0x02; } workreq->result = errstus;go_42: if (dev->dev_id == ATP885_DEVID) { j = inb(dev->baseport + 0x29) | 0x01; outb(j, dev->baseport + 0x29); } /* * Complete the command */ if (workreq->use_sg) { pci_unmap_sg(dev->pdev, (struct scatterlist *)workreq->request_buffer, workreq->use_sg, workreq->sc_data_direction); } else if (workreq->request_bufflen && workreq->sc_data_direction != DMA_NONE) { pci_unmap_single(dev->pdev, workreq->SCp.dma_handle, workreq->request_bufflen, workreq->sc_data_direction); } spin_lock_irqsave(dev->host->host_lock, flags); (*workreq->scsi_done) (workreq);#ifdef ED_DBGP printk("workreq->scsi_done\n");#endif /* * Clear it off the queue */ dev->id[c][target_id].curr_req = NULL; dev->working[c]--; spin_unlock_irqrestore(dev->host->host_lock, flags); /* * Take it back wide */ if (dev->wide_id[c] != 0) { tmport = workport + 0x1b; outb(0x01, tmport); while ((inb(tmport) & 0x01) != 0x01) { outb(0x01, tmport); } } /* * If there is stuff to send and nothing going then send it */ spin_lock_irqsave(dev->host->host_lock, flags); if (((dev->last_cmd[c] != 0xff) || (dev->quhd[c] != dev->quend[c])) && (dev->in_snd[c] == 0)) {#ifdef ED_DBGP printk("Call sent_s870(scsi_done)\n");#endif send_s870(dev,c); } spin_unlock_irqrestore(dev->host->host_lock, flags); dev->in_int[c] = 0; goto handled; } if ((dev->last_cmd[c] & 0xf0) != 0x40) { dev->last_cmd[c] = 0xff; } if (i == 0x4f) { i = 0x89; } i &= 0x0f; if (i == 0x09) { tmpcip += 4; outl(dev->id[c][target_id].prdaddr, tmpcip); tmpcip = tmpcip - 2; outb(0x06, tmpcip); outb(0x00, tmpcip); tmpcip = tmpcip - 2; tmport = workport + 0x10; outb(0x41, tmport); if (dev->dev_id == ATP885_DEVID) { tmport += 2; k = dev->id[c][target_id].last_len; outb((unsigned char) (((unsigned char *) (&k))[2]), tmport++); outb((unsigned char) (((unsigned char *) (&k))[1]), tmport++); outb((unsigned char) (((unsigned char *) (&k))[0]), tmport); dev->id[c][target_id].dirct = 0x00; tmport += 0x04; } else { dev->id[c][target_id].dirct = 0x00; tmport += 0x08; } outb(0x08, tmport); outb(0x09, tmpcip); dev->in_int[c] = 0; goto handled; } if (i == 0x08) { tmpcip += 4; outl(dev->id[c][target_id].prdaddr, tmpcip); tmpcip = tmpcip - 2; outb(0x06, tmpcip); outb(0x00, tmpcip); tmpcip = tmpcip - 2; tmport = workport + 0x10; outb(0x41, tmport); if (dev->dev_id == ATP885_DEVID) { tmport += 2; k = dev->id[c][target_id].last_len; outb((unsigned char) (((unsigned char *) (&k))[2]), tmport++); outb((unsigned char) (((unsigned char *) (&k))[1]), tmport++); outb((unsigned char) (((unsigned char *) (&k))[0]), tmport++); } else { tmport += 5; } outb((unsigned char) (inb(tmport) | 0x20), tmport); dev->id[c][target_id].dirct = 0x20; tmport += 0x03; outb(0x08, tmport); outb(0x01, tmpcip); dev->in_int[c] = 0; goto handled; } tmport -= 0x07; if (i == 0x0a) { outb(0x30, tmport); } else { outb(0x46, tmport); } dev->id[c][target_id].dirct = 0x00; tmport += 0x02; outb(0x00, tmport++); outb(0x00, tmport++);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?