static DEF_SCSI_QCMD()

in atp870u.c [700:979]


static DEF_SCSI_QCMD(atp870u_queuecommand)

/*
 *	send_s870	-	send a command to the controller
 *
 *	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)
{
	struct scsi_cmnd *workreq = NULL;
	unsigned int i;//,k;
	unsigned char  j, target_id;
	unsigned char *prd;
	unsigned short int w;
	unsigned long l, bttl = 0;
	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) {
			dev->last_cmd[c] = 0xff;
			if (dev->quhd[c] == dev->quend[c]) {
				dev->in_snd[c] = 0;
				return;
			}
		}
	}
	if (!workreq) {
		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 != NULL) {
			dev->quhd[c] = j;
			dev->working[c]--;
			dev->in_snd[c] = 0;
			return;
		}
		dev->id[c][scmd_id(workreq)].curr_req = workreq;
		dev->last_cmd[c] = scmd_id(workreq);
	}
	if ((atp_readb_io(dev, c, 0x1f) & 0xb0) != 0 ||
	    atp_readb_io(dev, c, 0x1c) != 0) {
#ifdef ED_DBGP
		printk("Abort to Send\n");
#endif
		dev->last_cmd[c] |= 0x40;
		dev->in_snd[c] = 0;
		return;
	}
#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
	l = scsi_bufflen(workreq);

	if (is885(dev)) {
		j = atp_readb_base(dev, 0x29) & 0xfe;
		atp_writeb_base(dev, 0x29, j);
		dev->r1f[c][scmd_id(workreq)] = 0;
	}

	if (workreq->cmnd[0] == READ_CAPACITY) {
		if (l > 8)
			l = 8;
	}
	if (workreq->cmnd[0] == TEST_UNIT_READY) {
		l = 0;
	}

	j = 0;
	target_id = scmd_id(workreq);

	/*
	 *	Wide ?
	 */
	w = 1;
	w = w << target_id;
	if ((w & dev->wide_id[c]) != 0) {
		j |= 0x01;
	}
	atp_writeb_io(dev, c, 0x1b, j);
	while ((atp_readb_io(dev, c, 0x1b) & 0x01) != j) {
		atp_writeb_pci(dev, c, 0x1b, j);
#ifdef ED_DBGP
		printk("send_s870 while loop 1\n");
#endif
	}
	/*
	 *	Write the command
	 */

	atp_writeb_io(dev, c, 0x00, workreq->cmd_len);
	atp_writeb_io(dev, c, 0x01, 0x2c);
	if (is885(dev))
		atp_writeb_io(dev, c, 0x02, 0x7f);
	else
		atp_writeb_io(dev, c, 0x02, 0xcf);
	for (i = 0; i < workreq->cmd_len; i++)
		atp_writeb_io(dev, c, 0x03 + i, workreq->cmnd[i]);
	atp_writeb_io(dev, c, 0x0f, workreq->device->lun);
	/*
	 *	Write the target
	 */
	atp_writeb_io(dev, c, 0x11, dev->id[c][target_id].devsp);
#ifdef ED_DBGP
	printk("dev->id[%d][%d].devsp = %2x\n",c,target_id,
	       dev->id[c][target_id].devsp);
#endif

	sg_count = scsi_dma_map(workreq);
	/*
	 *	Write transfer size
	 */
	atp_writeb_io(dev, c, 0x12, ((unsigned char *) (&l))[2]);
	atp_writeb_io(dev, c, 0x13, ((unsigned char *) (&l))[1]);
	atp_writeb_io(dev, c, 0x14, ((unsigned char *) (&l))[0]);
	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)
		atp_writeb_io(dev, c, 0x15, j | 0x20);
	else
		atp_writeb_io(dev, c, 0x15, j);
	atp_writeb_io(dev, c, 0x16, atp_readb_io(dev, c, 0x16) | 0x80);
	atp_writeb_io(dev, c, 0x16, 0x80);
	dev->id[c][target_id].dirct = 0;
	if (l == 0) {
		if (atp_readb_io(dev, c, 0x1c) == 0) {
#ifdef ED_DBGP
			printk("change SCSI_CMD_REG 0x08\n");
#endif
			atp_writeb_io(dev, c, 0x18, 0x08);
		} else
			dev->last_cmd[c] |= 0x40;
		dev->in_snd[c] = 0;
		return;
	}
	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 (l) {
		struct scatterlist *sgpnt;
		i = 0;
		scsi_for_each_sg(workreq, sgpnt, sg_count, j) {
			bttl = sg_dma_address(sgpnt);
			l=sg_dma_len(sgpnt);
#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
	}
#ifdef ED_DBGP
	printk("send_s870: prdaddr_2 0x%8x target_id %d\n",
	       dev->id[c][target_id].prdaddr,target_id);
#endif
	dev->id[c][target_id].prdaddr = dev->id[c][target_id].prd_bus;
	atp_writel_pci(dev, c, 4, dev->id[c][target_id].prdaddr);
	atp_writeb_pci(dev, c, 2, 0x06);
	atp_writeb_pci(dev, c, 2, 0x00);
	if (is885(dev)) {
		j = atp_readb_pci(dev, c, 1) & 0xf3;
		if ((workreq->cmnd[0] == READ_6) ||
		    (workreq->cmnd[0] == READ_10) ||
		    (workreq->cmnd[0] == WRITE_6) ||
		    (workreq->cmnd[0] == WRITE_10)) {
			j |= 0x0c;
		}
		atp_writeb_pci(dev, c, 1, j);
	} else if (is880(dev)) {
		if ((workreq->cmnd[0] == READ_6) ||
		    (workreq->cmnd[0] == READ_10) ||
		    (workreq->cmnd[0] == WRITE_6) ||
		    (workreq->cmnd[0] == WRITE_10))
			atp_writeb_base(dev, 0x3b,
					(atp_readb_base(dev, 0x3b) & 0x3f) | 0xc0);
		else
			atp_writeb_base(dev, 0x3b,
					atp_readb_base(dev, 0x3b) & 0x3f);
	} else {
		if ((workreq->cmnd[0] == READ_6) ||
		    (workreq->cmnd[0] == READ_10) ||
		    (workreq->cmnd[0] == WRITE_6) ||
		    (workreq->cmnd[0] == WRITE_10))
			atp_writeb_base(dev, 0x3a,
					(atp_readb_base(dev, 0x3a) & 0xf3) | 0x08);
		else
			atp_writeb_base(dev, 0x3a,
					atp_readb_base(dev, 0x3a) & 0xf3);
	}

	if(workreq->sc_data_direction == DMA_TO_DEVICE) {
		dev->id[c][target_id].dirct = 0x20;
		if (atp_readb_io(dev, c, 0x1c) == 0) {
			atp_writeb_io(dev, c, 0x18, 0x08);
			atp_writeb_pci(dev, c, 0, 0x01);
#ifdef ED_DBGP
		printk( "start DMA(to target)\n");
#endif
		} else {
			dev->last_cmd[c] |= 0x40;
		}
		dev->in_snd[c] = 0;
		return;
	}
	if (atp_readb_io(dev, c, 0x1c) == 0) {
		atp_writeb_io(dev, c, 0x18, 0x08);
		atp_writeb_pci(dev, c, 0, 0x09);
#ifdef ED_DBGP
		printk( "start DMA(to host)\n");
#endif
	} else {
		dev->last_cmd[c] |= 0x40;
	}
	dev->in_snd[c] = 0;
	return;

}