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 + -
显示快捷键?