atp870u.c
来自「linux 内核源代码」· C语言 代码 · 共 2,946 行 · 第 1/5 页
C
2,946 行
outb(0x00, tmport++); tmport += 0x03; outb(0x08, tmport); dev->in_int[c] = 0; goto handled; } else {// tmport = workport + 0x17;// inb(tmport);// dev->working[c] = 0; dev->in_int[c] = 0; goto handled; } handled:#ifdef ED_DBGP printk("atp870u_intr_handle exit\n");#endif return IRQ_HANDLED;}/** * atp870u_queuecommand - Queue SCSI command * @req_p: request block * @done: completion function * * Queue a command to the ATP queue. Called with the host lock held. */static int atp870u_queuecommand(struct scsi_cmnd * req_p, void (*done) (struct scsi_cmnd *)){ unsigned char c; unsigned int tmport,m; struct atp_unit *dev; struct Scsi_Host *host; c = scmd_channel(req_p); req_p->sense_buffer[0]=0; req_p->resid = 0; if (scmd_channel(req_p) > 1) { req_p->result = 0x00040000; done(req_p);#ifdef ED_DBGP printk("atp870u_queuecommand : req_p->device->channel > 1\n"); #endif return 0; } host = req_p->device->host; dev = (struct atp_unit *)&host->hostdata; m = 1; m = m << scmd_id(req_p); /* * Fake a timeout for missing targets */ if ((m & dev->active_id[c]) == 0) { req_p->result = 0x00040000; done(req_p); return 0; } if (done) { req_p->scsi_done = done; } else {#ifdef ED_DBGP printk( "atp870u_queuecommand: done can't be NULL\n");#endif req_p->result = 0; done(req_p); return 0; } /* * Count new command */ dev->quend[c]++; if (dev->quend[c] >= qcnt) { dev->quend[c] = 0; } /* * Check queue state */ if (dev->quhd[c] == dev->quend[c]) { if (dev->quend[c] == 0) { dev->quend[c] = qcnt; }#ifdef ED_DBGP printk("atp870u_queuecommand : dev->quhd[c] == dev->quend[c]\n");#endif dev->quend[c]--; req_p->result = 0x00020000; done(req_p); return 0; } dev->quereq[c][dev->quend[c]] = req_p; tmport = dev->ioport[c] + 0x1c;#ifdef ED_DBGP printk("dev->ioport[c] = %x inb(tmport) = %x dev->in_int[%d] = %d dev->in_snd[%d] = %d\n",dev->ioport[c],inb(tmport),c,dev->in_int[c],c,dev->in_snd[c]);#endif if ((inb(tmport) == 0) && (dev->in_int[c] == 0) && (dev->in_snd[c] == 0)) {#ifdef ED_DBGP printk("Call sent_s870(atp870u_queuecommand)\n");#endif send_s870(dev,c); }#ifdef ED_DBGP printk("atp870u_queuecommand : exit\n");#endif return 0;}/** * send_s870 - send a command to the controller * @host: host * * On entry there is work queued to be done. We move some of that work to the * controller itself. * * Caller holds the host lock. */static void send_s870(struct atp_unit *dev,unsigned char c){ unsigned int tmport; struct scsi_cmnd *workreq; unsigned int i;//,k; unsigned char j, target_id; unsigned char *prd; unsigned short int tmpcip, w; unsigned long l, bttl = 0; unsigned int workport; struct scatterlist *sgpnt; unsigned long sg_count; if (dev->in_snd[c] != 0) {#ifdef ED_DBGP printk("cmnd in_snd\n");#endif return; }#ifdef ED_DBGP printk("Sent_s870 enter\n");#endif dev->in_snd[c] = 1; if ((dev->last_cmd[c] != 0xff) && ((dev->last_cmd[c] & 0x40) != 0)) { dev->last_cmd[c] &= 0x0f; workreq = dev->id[c][dev->last_cmd[c]].curr_req; if (workreq != NULL) { /* check NULL pointer */ goto cmd_subp; } dev->last_cmd[c] = 0xff; if (dev->quhd[c] == dev->quend[c]) { dev->in_snd[c] = 0; return ; } } if ((dev->last_cmd[c] != 0xff) && (dev->working[c] != 0)) { dev->in_snd[c] = 0; return ; } dev->working[c]++; j = dev->quhd[c]; dev->quhd[c]++; if (dev->quhd[c] >= qcnt) { dev->quhd[c] = 0; } workreq = dev->quereq[c][dev->quhd[c]]; if (dev->id[c][scmd_id(workreq)].curr_req == 0) { dev->id[c][scmd_id(workreq)].curr_req = workreq; dev->last_cmd[c] = scmd_id(workreq); goto cmd_subp; } dev->quhd[c] = j; dev->working[c]--; dev->in_snd[c] = 0; return;cmd_subp: workport = dev->ioport[c]; tmport = workport + 0x1f; if ((inb(tmport) & 0xb0) != 0) { goto abortsnd; } tmport = workport + 0x1c; if (inb(tmport) == 0) { goto oktosend; }abortsnd:#ifdef ED_DBGP printk("Abort to Send\n");#endif dev->last_cmd[c] |= 0x40; dev->in_snd[c] = 0; return;oktosend:#ifdef ED_DBGP printk("OK to Send\n"); scmd_printk(KERN_DEBUG, workreq, "CDB"); for(i=0;i<workreq->cmd_len;i++) { printk(" %x",workreq->cmnd[i]); } printk("\n");#endif if (dev->dev_id == ATP885_DEVID) { j = inb(dev->baseport + 0x29) & 0xfe; outb(j, dev->baseport + 0x29); dev->r1f[c][scmd_id(workreq)] = 0; } if (workreq->cmnd[0] == READ_CAPACITY) { if (workreq->request_bufflen > 8) { workreq->request_bufflen = 0x08; } } if (workreq->cmnd[0] == 0x00) { workreq->request_bufflen = 0; } tmport = workport + 0x1b; j = 0; target_id = scmd_id(workreq); /* * Wide ? */ w = 1; w = w << target_id; if ((w & dev->wide_id[c]) != 0) { j |= 0x01; } outb(j, tmport); while ((inb(tmport) & 0x01) != j) { outb(j,tmport);#ifdef ED_DBGP printk("send_s870 while loop 1\n");#endif } /* * Write the command */ tmport = workport; outb(workreq->cmd_len, tmport++); outb(0x2c, tmport++); if (dev->dev_id == ATP885_DEVID) { outb(0x7f, tmport++); } else { outb(0xcf, tmport++); } for (i = 0; i < workreq->cmd_len; i++) { outb(workreq->cmnd[i], tmport++); } tmport = workport + 0x0f; outb(workreq->device->lun, tmport); tmport += 0x02; /* * Write the target */ outb(dev->id[c][target_id].devsp, tmport++); #ifdef ED_DBGP printk("dev->id[%d][%d].devsp = %2x\n",c,target_id,dev->id[c][target_id].devsp);#endif /* * Figure out the transfer size */ if (workreq->use_sg) {#ifdef ED_DBGP printk("Using SGL\n");#endif l = 0; sgpnt = (struct scatterlist *) workreq->request_buffer; sg_count = pci_map_sg(dev->pdev, sgpnt, workreq->use_sg, workreq->sc_data_direction); for (i = 0; i < workreq->use_sg; i++) { if (sgpnt[i].length == 0 || workreq->use_sg > ATP870U_SCATTER) { panic("Foooooooood fight!"); } l += sgpnt[i].length; }#ifdef ED_DBGP printk( "send_s870: workreq->use_sg %d, sg_count %d l %8ld\n", workreq->use_sg, sg_count, l);#endif } else if(workreq->request_bufflen && workreq->sc_data_direction != PCI_DMA_NONE) {#ifdef ED_DBGP printk("Not using SGL\n");#endif workreq->SCp.dma_handle = pci_map_single(dev->pdev, workreq->request_buffer, workreq->request_bufflen, workreq->sc_data_direction); l = workreq->request_bufflen;#ifdef ED_DBGP printk( "send_s870: workreq->use_sg %d, l %8ld\n", workreq->use_sg, l);#endif } else l = 0; /* * Write transfer size */ outb((unsigned char) (((unsigned char *) (&l))[2]), tmport++); outb((unsigned char) (((unsigned char *) (&l))[1]), tmport++); outb((unsigned char) (((unsigned char *) (&l))[0]), tmport++); j = target_id; dev->id[c][j].last_len = l; dev->id[c][j].tran_len = 0;#ifdef ED_DBGP printk("dev->id[%2d][%2d].last_len = %d\n",c,j,dev->id[c][j].last_len);#endif /* * Flip the wide bits */ if ((j & 0x08) != 0) { j = (j & 0x07) | 0x40; } /* * Check transfer direction */ if (workreq->sc_data_direction == DMA_TO_DEVICE) { outb((unsigned char) (j | 0x20), tmport++); } else { outb(j, tmport++); } outb((unsigned char) (inb(tmport) | 0x80), tmport); outb(0x80, tmport); tmport = workport + 0x1c; dev->id[c][target_id].dirct = 0; if (l == 0) { if (inb(tmport) == 0) { tmport = workport + 0x18;#ifdef ED_DBGP printk("change SCSI_CMD_REG 0x08\n"); #endif outb(0x08, tmport); } else { dev->last_cmd[c] |= 0x40; } dev->in_snd[c] = 0; return; } tmpcip = dev->pciport[c]; prd = dev->id[c][target_id].prd_table; dev->id[c][target_id].prd_pos = prd; /* * Now write the request list. Either as scatter/gather or as * a linear chain. */ if (workreq->use_sg) { sgpnt = (struct scatterlist *) workreq->request_buffer; i = 0; for (j = 0; j < workreq->use_sg; j++) { bttl = sg_dma_address(&sgpnt[j]); l=sg_dma_len(&sgpnt[j]);#ifdef ED_DBGP printk("1. bttl %x, l %x\n",bttl, l);#endif while (l > 0x10000) { (((u16 *) (prd))[i + 3]) = 0x0000; (((u16 *) (prd))[i + 2]) = 0x0000; (((u32 *) (prd))[i >> 1]) = cpu_to_le32(bttl); l -= 0x10000; bttl += 0x10000; i += 0x04; } (((u32 *) (prd))[i >> 1]) = cpu_to_le32(bttl); (((u16 *) (prd))[i + 2]) = cpu_to_le16(l); (((u16 *) (prd))[i + 3]) = 0; i += 0x04; } (((u16 *) (prd))[i - 1]) = cpu_to_le16(0x8000); #ifdef ED_DBGP printk("prd %4x %4x %4x %4x\n",(((unsigned short int *)prd)[0]),(((unsigned short int *)prd)[1]),(((unsigned short int *)prd)[2]),(((unsigned short int *)prd)[3])); printk("2. bttl %x, l %x\n",bttl, l);#endif } else { /* * For a linear request write a chain of blocks */ bttl = workreq->SCp.dma_handle; l = workreq->request_bufflen; i = 0;#ifdef ED_DBGP printk("3. bttl %x, l %x\n",bttl, l);#endif while (l > 0x10000) { (((u16 *) (prd))[i + 3]) = 0x0000; (((u16 *) (prd))[i + 2]) = 0x0000; (((u32 *) (prd))[i >> 1]) = cpu_to_le32(bttl); l -= 0x10000; bttl += 0x10000; i += 0x04; } (((u16 *) (prd))[i + 3]) = cpu_to_le16(0x8000); (((u16 *) (prd))[i + 2]) = cpu_to_le16(l); (((u32 *) (prd))[i >> 1]) = cpu_to_le32(bttl); #ifdef ED_DBGP printk("prd %4x %4x %4x %4x\n",(((unsigned short int *)prd)[0]),(((unsigned short int *)prd)[1]),(((unsigned short int *)prd)[2]),(((unsigned short int *)prd)[3])); printk("4. bttl %x, l %x\n",bttl, l);#endif } tmpcip += 4;#ifdef ED_DBGP printk("send_s870: prdaddr_2 0x%8x tmpcip %x target_id %d\n", dev->id[c][target_id].prdaddr,tmpcip,target_id);#endif dev->id[c][target_id].prdaddr = dev->id[c][target_id].prd_bus; outl(dev->id[c][target_id].prdaddr, tmpcip); tmpcip = tmpcip - 2; outb(0x06, tmpcip); outb(0x00, tmpcip); if (dev->dev_id == ATP885_DEVID) { tmpcip--; j=inb(tmpcip) & 0xf3; if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) { j |= 0x0c; } outb(j,tmpcip); tmpcip--; } else if ((dev->dev_id == ATP880_DEVID1) || (dev->dev_id == ATP880_DEVID2)) { tmpcip =tmpcip -2; 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 { tmpcip =tmpcip -2; tmport = workport + 0x3a; if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) { outb((inb(tmport) & 0xf3) | 0x08, tmport); } else { outb(inb(tmport) & 0xf3, tmport); } } tmport = workport + 0x1c; if(workreq->sc_data_direction == DMA_TO_DEVICE) { dev->id[c][target_id].dirct = 0x20; if (inb(tmport) == 0) { tmport = workport + 0x18; outb(0x08, tmport); outb(0x01, tmpcip);#ifdef ED_DBGP printk( "start DMA(to target)\n");#endif } else { dev->last_cmd[c] |= 0x40; } dev->in_snd[c] = 0; return; } if (inb(tmport) == 0) { tmport = workport + 0x18; outb(0x08, tmport); outb(0x09, tmpcip);#ifdef ED_DBGP printk( "start DMA(to host)\n");#endif } else { dev->last_cmd[c] |= 0x40; } dev->in_snd[c] = 0; return;}static unsigned char fun_scam(struct atp_unit *dev, unsigned short int *val){ unsigned int tmport; unsigned short int i, k; unsigned char j; tmport = dev->ioport[0] + 0x1c; outw(*val, tmport);FUN_D7: for (i = 0; i < 10; i++) { /* stable >= bus settle delay(400 ns) */ k = inw(tmport); j = (unsigned char) (k >> 8); if ((k & 0x8000) != 0) { /* DB7 all release? */ goto FUN_D7; } } *val |= 0x4000; /* assert DB6 */ outw(*val, tmport); *val &= 0xdfff; /* assert DB5 */ outw(*val, tmport);FUN_D5: for (i = 0; i < 10; i++) { /* stable >= bus settle delay(400 ns) */ if ((inw(tmport) & 0x2000) != 0) { /* DB5 all release? */ goto FUN_D5; } } *val |= 0x8000; /* no DB4-0, assert DB7 */ *val &= 0xe0ff; outw(*val, tmport); *val &= 0xbfff; /* release DB6 */ outw(*val, tmport);FUN_D6: for (i = 0; i < 10; i++) { /* stable >= bus settle delay(400 ns) */ if ((inw(tmport) & 0x4000) != 0) { /* DB6 all release? */ goto FUN_D6; } } return j;}static void tscam(struct Scsi_Host *host){ unsigned int tmport; unsigned char i, j, k; unsigned long n; unsigned short int m, assignid_map, val; unsigned char mbuf[33], quintet[2]; struct atp_unit *dev = (struct atp_unit *)&host->hostdata; static unsigned char g2q_tab[8] = { 0x38, 0x31, 0x32, 0x2b, 0x34, 0x2d, 0x2e, 0x27 };/* I can't believe we need this before we've even done anything. Remove it * and see if anyone bitches. for (i = 0; i < 0x10; i++) { udelay(0xffff); } */ tmport = dev->ioport[0] + 1; outb(0x08, tmport++); outb(0x7f, tmport); tmport = dev->ioport[0] + 0x11; outb(0x20, tmport); if ((dev->scam_on & 0x40) == 0) { return; } m = 1; m <<= dev->host_id[0]; j = 16; if (dev->chip_ver < 4) { m |= 0xff00; j = 8; } assignid_map = m; tmport = dev->ioport[0] + 0x02; outb(0x02, tmport++); /* 2*2=4ms,3EH 2/32*3E=3.9ms */ outb(0, tmport++); outb(0, tmport++); outb(0, tmport++); outb(0, tmport++); outb(0, tmport++); outb(0, tmport++); for (i = 0; i < j; i++) { m = 1; m = m << i; if ((m & assignid_map) != 0) { continue; } tmport = dev->ioport[0] + 0x0f; outb(0, tmport++); tmport += 0x02; outb(0, tmport++); outb(0, tmport++); outb(0, tmport++); if (i > 7) { k = (i & 0x07) | 0x40; } else { k = i; } outb(k, tmport++); tmport = dev->ioport[0] + 0x1b; if (dev->chip_ver == 4) { outb(0x01, tmport); } else { outb(0x00, tmport); }wait_rdyok: tmport = dev->ioport[0] + 0x18; outb(0x09, tmport); tmport += 0x07; while ((inb(tmport) & 0x80) == 0x00) cpu_relax();
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?