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;
}