Commit b056db71 authored by Jamie Lenehan's avatar Jamie Lenehan Committed by James Bottomley

[PATCH] dc395x [2/5] - sg list handling cleanups

Cleanup a lot of the sg list handling to make it easier to follow in
preparation for making this work on sparc64 (big-endian & 64bit).
parent ba44f971
......@@ -210,11 +210,6 @@ static char tracebuf[64];
#define DC395x_write16(acb,address,value) outw((value), acb->io_port_base + (address))
#define DC395x_write32(acb,address,value) outl((value), acb->io_port_base + (address))
#define BUS_ADDR(sg) sg_dma_address(&(sg))
#define CPU_ADDR(sg) (page_address((sg).page)+(sg).offset)
#define PAGE_ADDRESS(sg) page_address((sg)->page)
/* cmd->result */
#define RES_TARGET 0x000000FF /* Target State */
#define RES_TARGET_LNX STATUS_MASK /* Only official ... */
......@@ -233,6 +228,13 @@ static char tracebuf[64];
#define TAG_NONE 255
/*
* srb->segement_x is the hw sg list. It is always allocated as a
* DC395x_MAX_SG_LISTENTRY entries in a linear block which does not
* cross a page boundy.
*/
#define SEGMENTX_LEN (sizeof(struct SGentry)*DC395x_MAX_SG_LISTENTRY)
struct SGentry {
u32 address; /* bus! address */
......@@ -276,21 +278,28 @@ struct NvRamType {
struct ScsiReqBlk {
struct list_head list; /* next/prev ptrs for srb lists */
struct DeviceCtlBlk *dcb;
/* HW scatter list (up to 64 entries) */
struct SGentry *segment_x;
Scsi_Cmnd *cmd;
unsigned char *virt_addr; /* set by update_sg_list */
struct SGentry *segment_x; /* Linear array of hw sg entries (up to 64 entries) */
u32 sg_bus_addr; /* Bus address of sg list (ie, of segment_x) */
u32 total_xfer_length;
u32 xferred; /* Backup for the already xferred len */
u8 sg_count; /* No of HW sg entries for this request */
u8 sg_index; /* Index of HW sg entry for this request */
u32 total_xfer_length; /* Total number of bytes remaining to be transfered */
unsigned char *virt_addr; /* Virtual address of current transfer position */
u32 sg_bus_addr; /* bus address of DC395x scatterlist */
/*
* The sense buffer handling function, request_sense, uses
* the first hw sg entry (segment_x[0]) and the transfer
* length (total_xfer_length). While doing this it stores the
* original values into the last sg hw list
* (srb->segment_x[DC395x_MAX_SG_LISTENTRY - 1] and the
* total_xfer_length in xferred. These values are restored in
* pci_unmap_srb_sense. This is the only place xferred is used.
*/
u32 xferred; /* Saved copy of total_xfer_length */
u16 state;
u8 sg_count;
u8 sg_index;
u8 msgin_buf[6];
u8 msgout_buf[6];
......@@ -835,7 +844,8 @@ static void srb_waiting_insert(struct DeviceCtlBlk *dcb,
static void srb_waiting_append(struct DeviceCtlBlk *dcb,
struct ScsiReqBlk *srb)
{
dprintkdbg(DBG_0, "srb_waiting_append: srb %p cmd %li\n", srb, srb->cmd->pid);
dprintkdbg(DBG_0, "srb_waiting_append: srb %p cmd %li\n",
srb, srb->cmd->pid);
list_add_tail(&srb->list, &dcb->srb_waiting_list);
}
......@@ -879,7 +889,8 @@ static void srb_waiting_remove(struct DeviceCtlBlk *dcb,
static void srb_going_to_waiting_move(struct DeviceCtlBlk *dcb,
struct ScsiReqBlk *srb)
{
dprintkdbg(DBG_0, "srb_going_to_waiting_move: srb %p, pid = %li\n", srb, srb->cmd->pid);
dprintkdbg(DBG_0, "srb_going_to_waiting_move: srb %p, pid = %li\n",
srb, srb->cmd->pid);
list_move(&srb->list, &dcb->srb_waiting_list);
}
......@@ -1021,134 +1032,97 @@ static void send_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
static void build_srb(Scsi_Cmnd *cmd, struct DeviceCtlBlk *dcb,
struct ScsiReqBlk *srb)
{
int i, max;
struct SGentry *sgp;
struct scatterlist *sl;
u32 request_size;
int dir;
int dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
dprintkdbg(DBG_0, "build_srb...\n");
srb->dcb = dcb;
srb->cmd = cmd;
dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
srb->sg_count = 0;
srb->total_xfer_length = 0;
srb->sg_bus_addr = 0;
srb->virt_addr = 0;
srb->sg_index = 0;
srb->adapter_status = 0;
srb->target_status = 0;
srb->msg_count = 0;
srb->status = 0;
srb->flag = 0;
srb->state = 0;
srb->retry_count = 0;
srb->tag_number = TAG_NONE;
srb->scsi_phase = PH_BUS_FREE; /* initial phase */
srb->end_message = 0;
if (cmd->use_sg && dir != PCI_DMA_NONE) {
unsigned int len = 0;
/* TODO: In case usg_sg and the no of segments differ, things
* will probably go wrong. */
max = srb->sg_count =
pci_map_sg(dcb->acb->dev,
(struct scatterlist *)cmd->request_buffer,
cmd->use_sg, dir);
sgp = srb->segment_x;
request_size = cmd->request_bufflen;
dprintkdbg(DBG_SGPARANOIA,
"BuildSRB: Bufflen = %d, buffer = %p, use_sg = %d\n",
cmd->request_bufflen, cmd->request_buffer,
cmd->use_sg);
dprintkdbg(DBG_SGPARANOIA,
"Mapped %i Segments to %i\n", cmd->use_sg,
if (dir == PCI_DMA_NONE || !cmd->request_buffer) {
dprintkdbg(DBG_0, "srb[A] len=%d buf=%p use_sg=%d !MAP=%08x\n",
cmd->bufflen, cmd->request_buffer,
cmd->use_sg, srb->segment_x[0].address);
} else if (cmd->use_sg) {
int i;
u32 reqlen = cmd->request_bufflen;
struct scatterlist *sl = (struct scatterlist *)
cmd->request_buffer;
struct SGentry *sgp = srb->segment_x;
srb->sg_count = pci_map_sg(dcb->acb->dev, sl, cmd->use_sg,
dir);
dprintkdbg(DBG_0, "srb[B] len=%d buf=%p use_sg=%d segs=%d\n",
reqlen, cmd->request_buffer, cmd->use_sg,
srb->sg_count);
sl = (struct scatterlist *)cmd->request_buffer;
srb->virt_addr = page_address(sl->page);
for (i = 0; i < max; i++) {
u32 busaddr = (u32) sg_dma_address(&sl[i]);
u32 seglen = (u32) sl[i].length;
for (i = 0; i < srb->sg_count; i++) {
u32 busaddr = (u32)sg_dma_address(&sl[i]);
u32 seglen = (u32)sl[i].length;
sgp[i].address = busaddr;
sgp[i].length = seglen;
len += seglen;
dprintkdbg(DBG_SGPARANOIA,
"Setting up sgp %d, address = 0x%08x, length = %d, tot len = %d\n",
i, busaddr, seglen, len);
}
sgp += max - 1;
/* Fixup for last buffer too big as it is allocated on even page boundaries */
if (len > request_size) {
#if debug_enabled(DBG_KG) || debug_enabled(DBG_SGPARANOIA)
dprintkdbg(DBG_KG|DBG_SGPARANOIA,
"Fixup SG total length: %d->%d, last seg %d->%d\n",
len, request_size, sgp->length,
sgp->length - (len - request_size));
#endif
sgp->length -= (len - request_size);
len = request_size;
srb->total_xfer_length += seglen;
}
/* WIDE padding */
if (dcb->sync_period & WIDE_SYNC && len % 2) {
len++;
sgp += srb->sg_count - 1;
/*
* adjust last page if too big as it is allocated
* on even page boundaries
*/
if (srb->total_xfer_length > reqlen) {
sgp->length -= (srb->total_xfer_length - reqlen);
srb->total_xfer_length = reqlen;
}
/* Fixup for WIDE padding - make sure length is even */
if (dcb->sync_period & WIDE_SYNC &&
srb->total_xfer_length % 2) {
srb->total_xfer_length++;
sgp->length++;
}
srb->total_xfer_length = len; /*? */
/* Hopefully this does not cross a page boundary ... */
srb->sg_bus_addr =
pci_map_single(dcb->acb->dev, srb->segment_x,
sizeof(struct SGentry) *
DC395x_MAX_SG_LISTENTRY,
PCI_DMA_TODEVICE);
dprintkdbg(DBG_SGPARANOIA,
"Map SG descriptor list %p (%05x) to %08x\n",
srb->sg_bus_addr = pci_map_single(dcb->acb->dev,
srb->segment_x,
sizeof(struct SGentry) * DC395x_MAX_SG_LISTENTRY,
srb->sg_bus_addr);
SEGMENTX_LEN,
PCI_DMA_TODEVICE);
dprintkdbg(DBG_SGPARANOIA, "srb[B] map sg %p->%08x(%05x)\n",
srb->segment_x, srb->sg_bus_addr, SEGMENTX_LEN);
} else {
if (cmd->request_buffer && dir != PCI_DMA_NONE) {
u32 len = cmd->request_bufflen; /* Actual request size */
srb->total_xfer_length = cmd->request_bufflen;
srb->sg_count = 1;
srb->segment_x[0].address =
pci_map_single(dcb->acb->dev,
cmd->request_buffer, len, dir);
/* WIDE padding */
if (dcb->sync_period & WIDE_SYNC && len % 2)
len++;
srb->segment_x[0].length = len;
srb->total_xfer_length = len;
srb->virt_addr = cmd->request_buffer;
srb->sg_bus_addr = 0;
dprintkdbg(DBG_SGPARANOIA,
"BuildSRB: len = %d, buffer = %p, use_sg = %d, map %08x\n",
len, cmd->request_buffer, cmd->use_sg,
srb->segment_x[0].address);
} else {
srb->sg_count = 0;
srb->total_xfer_length = 0;
srb->sg_bus_addr = 0;
srb->virt_addr = 0;
dprintkdbg(DBG_SGPARANOIA,
"BuildSRB: buflen = %d, buffer = %p, use_sg = %d, NOMAP %08x\n",
cmd->bufflen, cmd->request_buffer,
cmd->use_sg, srb->segment_x[0].address);
}
}
pci_map_single(dcb->acb->dev, cmd->request_buffer,
srb->total_xfer_length, dir);
srb->sg_index = 0;
srb->adapter_status = 0;
srb->target_status = 0;
srb->msg_count = 0;
srb->status = 0;
srb->flag = 0;
srb->state = 0;
srb->retry_count = 0;
/* Fixup for WIDE padding - make sure length is even */
if (dcb->sync_period & WIDE_SYNC && srb->total_xfer_length % 2)
srb->total_xfer_length++;
#if debug_enabled(DBG_TRACE|DBG_TRACEALL) && debug_enabled(DBG_SGPARANOIA)
if ((unsigned long)srb->debugtrace & (DEBUGTRACEBUFSZ - 1)) {
dprintkdbg(DBG_SGPARANOIA,
"SRB %i (%p): debugtrace %p corrupt!\n",
(srb - dcb->acb->srb_array) /
sizeof(struct ScsiReqBlk), srb, srb->debugtrace);
srb->segment_x[0].length = srb->total_xfer_length;
srb->virt_addr = cmd->request_buffer;
dprintkdbg(DBG_0, "srb[C] len=%d buf=%p use_sg=%d map=%08x\n",
srb->total_xfer_length, cmd->request_buffer,
cmd->use_sg, srb->segment_x[0].address);
}
#endif
#if debug_enabled(DBG_TRACE|DBG_TRACEALL)
srb->debugpos = 0;
srb->debugtrace = 0;
#endif
TRACEPRINTF("pid %li(%li):%02x %02x..(%i-%i) *", cmd->pid,
jiffies, cmd->cmnd[0], cmd->cmnd[1],
cmd->device->id, cmd->device->lun);
srb->tag_number = TAG_NONE;
srb->scsi_phase = PH_BUS_FREE; /* initial phase */
srb->end_message = 0;
}
......@@ -1598,7 +1572,7 @@ static u8 start_scsi(struct AdapterCtlBlk * acb, struct DeviceCtlBlk * dcb,
u8 s_stat, scsicommand, i, identify_message;
u8 *ptr;
dprintkdbg(DBG_0, "start_scsi..............\n");
dprintkdbg(DBG_0, "start_scsi (#%li)\n", srb->cmd->pid);
srb->tag_number = TAG_NONE; /* acb->tag_max_num: had error read in eeprom */
s_stat = DC395x_read8(acb, TRM_S1040_SCSI_SIGNAL);
......@@ -1958,7 +1932,7 @@ static irqreturn_t dc395x_interrupt(int irq, void *dev_id,
static void msgout_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
u16 *pscsi_status)
{
dprintkdbg(DBG_0, "msgout_phase0...\n");
dprintkdbg(DBG_0, "msgout_phase0 (#%li)\n", srb->cmd->pid);
if (srb->state & (SRB_UNEXPECT_RESEL + SRB_ABORT_SENT))
*pscsi_status = PH_BUS_FREE; /*.. initial phase */
......@@ -1974,7 +1948,7 @@ static void msgout_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
u16 i;
u8 *ptr;
dprintkdbg(DBG_0, "msgout_phase1...\n");
dprintkdbg(DBG_0, "msgout_phase1 (#%li)\n", srb->cmd->pid);
TRACEPRINTF("MOP1*");
clear_fifo(acb, "MOP1");
if (!(srb->state & SRB_MSGOUT)) {
......@@ -2014,6 +1988,7 @@ static void msgout_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
static void command_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
u16 *pscsi_status)
{
dprintkdbg(DBG_0, "command_phase0 (#%li)\n", srb->cmd->pid);
TRACEPRINTF("COP0 *");
/*1.25 */
/*clear_fifo(acb, COP0); */
......@@ -2028,7 +2003,7 @@ static void command_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
u8 *ptr;
u16 i;
dprintkdbg(DBG_0, "command_phase1...\n");
dprintkdbg(DBG_0, "command_phase1 (#%li)\n", srb->cmd->pid);
TRACEPRINTF("COP1*");
clear_fifo(acb, "COP1");
DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_CLRATN);
......@@ -2058,8 +2033,11 @@ static void command_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
}
/* Do sanity checks for S/G list */
static inline void check_sg_list(struct ScsiReqBlk *srb)
/*
* Verify that the remaining space in the hw sg lists is the same as
* the count of remaining bytes in srb->total_xfer_length
*/
static void sg_verify_length(struct ScsiReqBlk *srb)
{
if (debug_enabled(DBG_SGPARANOIA)) {
unsigned len = 0;
......@@ -2079,75 +2057,90 @@ static inline void check_sg_list(struct ScsiReqBlk *srb)
* Compute the next Scatter Gather list index and adjust its length
* and address if necessary; also compute virt_addr
*/
static void update_sg_list(struct ScsiReqBlk *srb, u32 left)
static void sg_update_list(struct ScsiReqBlk *srb, u32 left)
{
struct SGentry *psge;
u32 xferred = 0;
u8 idx;
Scsi_Cmnd *cmd = srb->cmd;
struct scatterlist *sg;
Scsi_Cmnd *cmd = srb->cmd;
int segment = cmd->use_sg;
u32 xferred = srb->total_xfer_length - left; /* bytes transfered */
struct SGentry *psge = srb->segment_x + srb->sg_index;
dprintkdbg(DBG_0, "sg_update_list: Transfered %i of %i bytes, "
"%i remain\n",
xferred, srb->total_xfer_length, left);
if (xferred == 0) {
/* nothing to update since we did not transfer any data */
return;
}
dprintkdbg(DBG_KG, "Update SG: Total %i, Left %i\n",
srb->total_xfer_length, left);
check_sg_list(srb);
psge = srb->segment_x + srb->sg_index;
/* data that has already been transferred */
xferred = srb->total_xfer_length - left;
if (srb->total_xfer_length != left) {
/*check_sg_list_TX (srb, xferred); */
/* Remaining */
srb->total_xfer_length = left;
/* parsing from last time disconnect SGIndex */
sg_verify_length(srb);
srb->total_xfer_length = left; /* update remaining count */
for (idx = srb->sg_index; idx < srb->sg_count; idx++) {
if (xferred >= psge->length) {
/* Complete SG entries done */
if (xferred >= psge->length)
xferred -= psge->length;
/* Partial SG entries done */
else {
psge->length -= xferred; /* residue data length */
psge->address += xferred; /* residue data pointer */
} else {
/* Partial SG entry done */
psge->length -= xferred;
psge->address += xferred;
srb->sg_index = idx;
pci_dma_sync_single(srb->dcb->
acb->dev,
srb->sg_bus_addr,
sizeof(struct SGentry)
*
DC395x_MAX_SG_LISTENTRY,
SEGMENTX_LEN,
PCI_DMA_TODEVICE);
break;
}
psge++;
}
check_sg_list(srb);
}
/* We need the corresponding virtual address sg_to_virt */
/*dprintkl(KERN_DEBUG, "sg_to_virt: bus %08x -> virt ", psge->address); */
sg_verify_length(srb);
/* we need the corresponding virtual address */
if (!segment) {
srb->virt_addr += xferred;
/*printk("%p\n", srb->virt_addr); */
return;
}
/* We have to walk the scatterlist to find it */
sg = (struct scatterlist *)cmd->request_buffer;
while (segment--) {
/*printk("(%08x)%p ", BUS_ADDR(*sg), PAGE_ADDRESS(sg)); */
unsigned long mask =
~((unsigned long)sg->length - 1) & PAGE_MASK;
if ((BUS_ADDR(*sg) & mask) == (psge->address & mask)) {
srb->virt_addr = (PAGE_ADDRESS(sg)
if ((sg_dma_address(sg) & mask) == (psge->address & mask)) {
srb->virt_addr = (page_address(sg->page)
+ psge->address -
(psge->address & PAGE_MASK));
/*printk("%p\n", srb->virt_addr); */
return;
}
++sg;
}
dprintkl(KERN_ERR, "sg_to_virt failed!\n");
srb->virt_addr = 0;
}
/*
* We have transfered a single byte (PIO mode?) and need to update
* the count of bytes remaining (total_xfer_length) and update the sg
* entry to either point to next byte in the current sg entry, or of
* already at the end to point to the start of the next sg entry
*/
static void sg_subtract_one(struct ScsiReqBlk *srb)
{
srb->total_xfer_length--;
srb->segment_x[srb->sg_index].length--;
if (srb->total_xfer_length &&
!srb->segment_x[srb->sg_index].length) {
if (debug_enabled(DBG_PIO))
printk(" (next segment)");
srb->sg_index++;
sg_update_list(srb, srb->total_xfer_length);
}
}
/*
* cleanup_after_transfer
*
......@@ -2190,7 +2183,7 @@ static void data_out_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
u16 scsi_status = *pscsi_status;
u32 d_left_counter = 0;
dprintkdbg(DBG_0, "data_out_phase0...\n");
dprintkdbg(DBG_0, "data_out_phase0 (#%li)\n", srb->cmd->pid);
TRACEPRINTF("DOP0*");
/*
......@@ -2310,7 +2303,7 @@ static void data_out_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
srb->total_xfer_length - d_left_counter;
const int diff =
(dcb->sync_period & WIDE_SYNC) ? 2 : 1;
update_sg_list(srb, d_left_counter);
sg_update_list(srb, d_left_counter);
/* KG: Most ugly hack! Apparently, this works around a chip bug */
if ((srb->segment_x[srb->sg_index].length ==
diff && srb->cmd->use_sg)
......@@ -2321,7 +2314,7 @@ static void data_out_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
"Work around chip bug (%i)?\n", diff);
d_left_counter =
srb->total_xfer_length - diff;
update_sg_list(srb, d_left_counter);
sg_update_list(srb, d_left_counter);
/*srb->total_xfer_length -= diff; */
/*srb->virt_addr += diff; */
/*if (srb->cmd->use_sg) */
......@@ -2351,7 +2344,7 @@ static void data_out_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
static void data_out_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
u16 *pscsi_status)
{
dprintkdbg(DBG_0, "data_out_phase1...\n");
dprintkdbg(DBG_0, "data_out_phase1 (#%li)\n", srb->cmd->pid);
/*1.25 */
TRACEPRINTF("DOP1*");
clear_fifo(acb, "DOP1");
......@@ -2368,7 +2361,7 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
u16 scsi_status = *pscsi_status;
u32 d_left_counter = 0;
dprintkdbg(DBG_0, "data_in_phase0...\n");
dprintkdbg(DBG_0, "data_in_phase0 (#%li)\n", srb->cmd->pid);
TRACEPRINTF("DIP0*");
/*
......@@ -2445,7 +2438,7 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
if (d_left_counter
&& srb->total_xfer_length <= DC395x_LASTPIO) {
/*u32 addr = (srb->segment_x[srb->sg_index].address); */
/*update_sg_list (srb, d_left_counter); */
/*sg_update_list (srb, d_left_counter); */
dprintkdbg(DBG_PIO, "DIP0: PIO (%i %s) to %p for remaining %i bytes:",
DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) &
0x1f,
......@@ -2458,32 +2451,19 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2,
CFG2_WIDEFIFO);
while (DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) !=
0x40) {
u8 byte =
DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
while (DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) != 0x40) {
u8 byte = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
*(srb->virt_addr)++ = byte;
if (debug_enabled(DBG_PIO))
printk(" %02x", byte);
srb->total_xfer_length--;
d_left_counter--;
srb->segment_x[srb->sg_index].length--;
if (srb->total_xfer_length
&& !srb->segment_x[srb->sg_index].
length) {
if (debug_enabled(DBG_PIO))
printk(" (next segment)");
srb->sg_index++;
update_sg_list(srb,
d_left_counter);
}
sg_subtract_one(srb);
}
if (srb->dcb->sync_period & WIDE_SYNC) {
#if 1 /* Read the last byte ... */
#if 1
/* Read the last byte ... */
if (srb->total_xfer_length > 0) {
u8 byte =
DC395x_read8
(acb, TRM_S1040_SCSI_FIFO);
u8 byte = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
*(srb->virt_addr)++ = byte;
srb->total_xfer_length--;
if (debug_enabled(DBG_PIO))
......@@ -2563,7 +2543,7 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
* there were some data residue in SCSI FIFO or
* SCSI transfer counter not empty
*/
update_sg_list(srb, d_left_counter);
sg_update_list(srb, d_left_counter);
}
}
/* KG: The target may decide to disconnect: Empty FIFO before! */
......@@ -2597,7 +2577,7 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
static void data_in_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
u16 *pscsi_status)
{
dprintkdbg(DBG_0, "data_in_phase1...\n");
dprintkdbg(DBG_0, "data_in_phase1 (#%li)\n", srb->cmd->pid);
/* FIFO should be cleared, if previous phase was not DataPhase */
/*clear_fifo(acb, "DIP1"); */
/* Allow data in! */
......@@ -2615,7 +2595,7 @@ static void data_io_transfer(struct AdapterCtlBlk *acb,
struct DeviceCtlBlk *dcb = srb->dcb;
u8 bval;
dprintkdbg(DBG_0, "DataIO_transfer %c (pid %li): len = %i, SG: %i/%i\n",
dprintkdbg(DBG_0, "data_io_transfer %c (#%li): len=%i, sg=(%i/%i)\n",
((io_dir & DMACMD_DIR) ? 'r' : 'w'), srb->cmd->pid,
srb->total_xfer_length, srb->sg_index,
srb->sg_count);
......@@ -2623,7 +2603,12 @@ static void data_io_transfer(struct AdapterCtlBlk *acb,
srb->sg_index, srb->sg_count);
if (srb == acb->tmp_srb)
dprintkl(KERN_ERR, "Using tmp_srb in DataPhase!\n");
if (srb->sg_index < srb->sg_count) {
if (srb->sg_index >= srb->sg_count) {
/* can't happen? out of bounds error */
return;
}
if (srb->total_xfer_length > DC395x_LASTPIO) {
u8 dma_status = DC395x_read8(acb, TRM_S1040_DMA_STATUS);
/*
......@@ -2633,13 +2618,12 @@ static void data_io_transfer(struct AdapterCtlBlk *acb,
if (dma_status & XFERPENDING) {
dprintkl(KERN_DEBUG, "Xfer pending! Expect trouble!!\n");
dump_register_info(acb, dcb, srb);
DC395x_write8(acb, TRM_S1040_DMA_CONTROL,
CLRXFIFO);
DC395x_write8(acb, TRM_S1040_DMA_CONTROL, CLRXFIFO);
}
/* clear_fifo(acb, "IO"); */
/*
* load what physical address of Scatter/Gather list table want to be
* transfer
* load what physical address of Scatter/Gather list table
* want to be transfer
*/
srb->state |= SRB_DATA_XFER;
DC395x_write32(acb, TRM_S1040_DMA_XHIGHADDR, 0);
......@@ -2649,10 +2633,9 @@ static void data_io_transfer(struct AdapterCtlBlk *acb,
srb->sg_bus_addr +
sizeof(struct SGentry) *
srb->sg_index);
/* load how many bytes in the Scatter/Gather list table */
/* load how many bytes in the sg list table */
DC395x_write32(acb, TRM_S1040_DMA_XCNT,
((u32)
(srb->sg_count -
((u32)(srb->sg_count -
srb->sg_index) << 3));
} else { /* without S/G */
io_dir &= ~DMACMD_SG;
......@@ -2668,11 +2651,9 @@ static void data_io_transfer(struct AdapterCtlBlk *acb,
if (io_dir & DMACMD_DIR) { /* read */
DC395x_write8(acb, TRM_S1040_SCSI_COMMAND,
SCMD_DMA_IN);
DC395x_write16(acb, TRM_S1040_DMA_COMMAND,
io_dir);
DC395x_write16(acb, TRM_S1040_DMA_COMMAND, io_dir);
} else {
DC395x_write16(acb, TRM_S1040_DMA_COMMAND,
io_dir);
DC395x_write16(acb, TRM_S1040_DMA_COMMAND, io_dir);
DC395x_write8(acb, TRM_S1040_SCSI_COMMAND,
SCMD_DMA_OUT);
}
......@@ -2680,10 +2661,9 @@ static void data_io_transfer(struct AdapterCtlBlk *acb,
}
#if DC395x_LASTPIO
else if (srb->total_xfer_length > 0) { /* The last four bytes: Do PIO */
/* clear_fifo(acb, "IO"); */
/*
* load what physical address of Scatter/Gather list table want to be
* transfer
* load what physical address of Scatter/Gather list table
* want to be transfer
*/
srb->state |= SRB_DATA_XFER;
/* load total transfer length (24bits) max value 16Mbyte */
......@@ -2696,31 +2676,21 @@ static void data_io_transfer(struct AdapterCtlBlk *acb,
} else { /* write */
int ln = srb->total_xfer_length;
if (srb->dcb->sync_period & WIDE_SYNC)
DC395x_write8
(acb, TRM_S1040_SCSI_CONFIG2,
DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2,
CFG2_WIDEFIFO);
dprintkdbg(DBG_PIO, "DOP1: PIO %i bytes from %p:",
srb->total_xfer_length,
srb->virt_addr);
while (srb->total_xfer_length) {
if (debug_enabled(DBG_PIO))
printk(" %02x", (unsigned char) *(srb->virt_addr));
DC395x_write8
(acb, TRM_S1040_SCSI_FIFO,
DC395x_write8(acb, TRM_S1040_SCSI_FIFO,
*(srb->virt_addr)++);
srb->total_xfer_length--;
srb->segment_x[srb->sg_index].
length--;
if (srb->total_xfer_length
&& !srb->segment_x[srb->
sg_index].
length) {
if (debug_enabled(DBG_PIO))
printk(" (next segment)");
srb->sg_index++;
update_sg_list(srb,
srb->total_xfer_length);
}
sg_subtract_one(srb);
}
if (srb->dcb->sync_period & WIDE_SYNC) {
if (ln % 2) {
......@@ -2728,8 +2698,7 @@ static void data_io_transfer(struct AdapterCtlBlk *acb,
if (debug_enabled(DBG_PIO))
printk(" |00");
}
DC395x_write8
(acb, TRM_S1040_SCSI_CONFIG2, 0);
DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, 0);
}
/*DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, ln); */
if (debug_enabled(DBG_PIO))
......@@ -2754,53 +2723,39 @@ static void data_io_transfer(struct AdapterCtlBlk *acb,
DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, 2);
DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2,
CFG2_WIDEFIFO);
if (io_dir & DMACMD_DIR) { /* read */
data =
DC395x_read8
(acb, TRM_S1040_SCSI_FIFO);
data2 =
DC395x_read8
(acb, TRM_S1040_SCSI_FIFO);
/*dprintkl(KERN_DEBUG, "DataIO: Xfer pad: %02x %02x\n", data, data2); */
if (io_dir & DMACMD_DIR) {
data = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
data2 = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
} else {
/* Danger, Robinson: If you find KGs scattered over the wide
* disk, the driver or chip is to blame :-( */
DC395x_write8(acb, TRM_S1040_SCSI_FIFO,
'K');
DC395x_write8(acb, TRM_S1040_SCSI_FIFO,
'G');
/* Danger, Robinson: If you find KGs
* scattered over the wide disk, the driver
* or chip is to blame :-( */
DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 'K');
DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 'G');
}
DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, 0);
} else {
DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, 1);
/* Danger, Robinson: If you find a collection of Ks on your disk
* something broke :-( */
if (io_dir & DMACMD_DIR) { /* read */
data =
DC395x_read8
(acb, TRM_S1040_SCSI_FIFO);
/*dprintkl(KERN_DEBUG, "DataIO: Xfer pad: %02x\n", data); */
} else {
DC395x_write8(acb, TRM_S1040_SCSI_FIFO,
'K');
}
if (io_dir & DMACMD_DIR)
data = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
else
DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 'K');
}
srb->state |= SRB_XFERPAD;
DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */
/* SCSI command */
bval =
(io_dir & DMACMD_DIR) ? SCMD_FIFO_IN :
SCMD_FIFO_OUT;
bval = (io_dir & DMACMD_DIR) ? SCMD_FIFO_IN : SCMD_FIFO_OUT;
DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, bval);
}
}
}
static void status_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
u16 *pscsi_status)
{
dprintkdbg(DBG_0, "StatusPhase0 (pid %li)\n", srb->cmd->pid);
dprintkdbg(DBG_0, "status_phase0 (#%li)\n", srb->cmd->pid);
TRACEPRINTF("STP0 *");
srb->target_status = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
srb->end_message = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); /* get message */
......@@ -2817,10 +2772,8 @@ static void status_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
static void status_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
u16 *pscsi_status)
{
dprintkdbg(DBG_0, "StatusPhase1 (pid=%li)\n", srb->cmd->pid);
dprintkdbg(DBG_0, "status_phase1 (#%li)\n", srb->cmd->pid);
TRACEPRINTF("STP1 *");
/* Cleanup is now done at the end of DataXXPhase0 */
/*cleanup_after_transfer (acb, srb); */
srb->state = SRB_STATUS;
DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */
......@@ -2900,7 +2853,8 @@ static struct ScsiReqBlk *msgin_qtag(struct AdapterCtlBlk *acb,
struct ScsiReqBlk *srb = NULL;
struct ScsiReqBlk *i;
dprintkdbg(DBG_0, "QTag Msg (SRB %p): %i\n", srb, tag);
dprintkdbg(DBG_0, "msgin_qtag (#%li) tag=%i (srb=%p)\n",
srb->cmd->pid, tag, srb);
if (!(dcb->tag_mask & (1 << tag)))
dprintkl(KERN_DEBUG,
"MsgIn_QTag: tag_mask (%08x) does not reserve tag %i!\n",
......@@ -3147,7 +3101,7 @@ static void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
{
struct DeviceCtlBlk *dcb = acb->active_dcb;
dprintkdbg(DBG_0, "msgin_phase0...\n");
dprintkdbg(DBG_0, "msgin_phase0 (#%li)\n", srb->cmd->pid);
TRACEPRINTF("MIP0*");
srb->msgin_buf[acb->msg_len++] = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
......@@ -3275,7 +3229,7 @@ static void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
static void msgin_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
u16 *pscsi_status)
{
dprintkdbg(DBG_0, "msgin_phase1...\n");
dprintkdbg(DBG_0, "msgin_phase1 (#%li)\n", srb->cmd->pid);
TRACEPRINTF("MIP1 *");
clear_fifo(acb, "MIP1");
DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, 1);
......@@ -3344,7 +3298,7 @@ static void disconnect(struct AdapterCtlBlk *acb)
}
srb = dcb->active_srb;
acb->active_dcb = NULL;
dprintkdbg(DBG_0, "Disconnect (pid=%li)\n", srb->cmd->pid);
dprintkdbg(DBG_0, "disconnect (#%li)\n", srb->cmd->pid);
TRACEPRINTF("DISC *");
srb->scsi_phase = PH_BUS_FREE; /* initial phase */
......@@ -3383,7 +3337,7 @@ static void disconnect(struct AdapterCtlBlk *acb)
/* Normal selection timeout */
TRACEPRINTF("SlTO *");
dprintkdbg(DBG_KG,
"Disc: SelTO (pid=%li) for dev %02i-%i\n",
"Disc: SelTO (#%li) for dev %02i-%i\n",
srb->cmd->pid, dcb->target_id,
dcb->target_lun);
if (srb->retry_count++ > DC395x_MAX_RETRIES
......@@ -3403,7 +3357,7 @@ static void disconnect(struct AdapterCtlBlk *acb)
/*
* SRB_DISCONNECT (This is what we expect!)
*/
/* dprintkl(KERN_DEBUG, "DoWaitingSRB (pid=%li)\n", srb->cmd->pid); */
/* dprintkl(KERN_DEBUG, "DoWaitingSRB (#%li)\n", srb->cmd->pid); */
TRACEPRINTF("+*");
if (bval & 0x40) {
dprintkdbg(DBG_0, "Debug: DISC: SCSI bus stat %02x: ACK set! Other controllers?\n",
......@@ -3425,7 +3379,7 @@ static void disconnect(struct AdapterCtlBlk *acb)
free_tag(dcb, srb);
dcb->active_srb = NULL;
srb->state = SRB_FREE;
/*dprintkl(KERN_DEBUG, "done (pid=%li)\n", srb->cmd->pid); */
/*dprintkl(KERN_DEBUG, "done (#%li)\n", srb->cmd->pid); */
srb_done(acb, dcb, srb);
}
}
......@@ -3598,12 +3552,11 @@ static void pci_unmap_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
if (cmd->use_sg && dir != PCI_DMA_NONE) {
/* unmap DC395x SG list */
dprintkdbg(DBG_SGPARANOIA,
"Unmap SG descriptor list %08x (%05x)\n",
"unmap SG list %08x(%05x)\n",
srb->sg_bus_addr,
sizeof(struct SGentry) * DC395x_MAX_SG_LISTENTRY);
SEGMENTX_LEN);
pci_unmap_single(acb->dev, srb->sg_bus_addr,
sizeof(struct SGentry) *
DC395x_MAX_SG_LISTENTRY,
SEGMENTX_LEN,
PCI_DMA_TODEVICE);
dprintkdbg(DBG_SGPARANOIA, "Unmap %i SG segments from %p\n",
cmd->use_sg, cmd->request_buffer);
......@@ -3612,7 +3565,7 @@ static void pci_unmap_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
(struct scatterlist *)cmd->request_buffer,
cmd->use_sg, dir);
} else if (cmd->request_buffer && dir != PCI_DMA_NONE) {
dprintkdbg(DBG_SGPARANOIA, "Unmap buffer at %08x (%05x)\n",
dprintkdbg(DBG_SGPARANOIA, "Unmap buffer %08x(%05x)\n",
srb->segment_x[0].address, cmd->request_bufflen);
pci_unmap_single(acb->dev, srb->segment_x[0].address,
cmd->request_bufflen, dir);
......@@ -3656,17 +3609,19 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
TRACEPRINTF("DONE *");
dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
if (cmd->use_sg) {
struct scatterlist* sg = (struct scatterlist *)cmd->request_buffer;
ptr = (struct ScsiInqData *)(page_address(sg->page) + sg->offset);
} else {
ptr = (struct ScsiInqData *)(cmd->request_buffer);
if (cmd->use_sg)
ptr =
(struct ScsiInqData *)CPU_ADDR(*(struct scatterlist *)
ptr);
}
dprintkdbg(DBG_SGPARANOIA,
"SRBdone SG=%i (%i/%i), req_buf = %p, adr = %p\n",
"srb_done sg=%i(%i/%i), buf=%p, addr=%p\n",
cmd->use_sg, srb->sg_index, srb->sg_count,
cmd->request_buffer, ptr);
dprintkdbg(DBG_KG,
"SRBdone (pid %li, target %02i-%i): ", srb->cmd->pid,
"srb_done (#%li) (target %02i-%i): ", srb->cmd->pid,
srb->cmd->device->id, srb->cmd->device->lun);
status = srb->target_status;
if (srb->flag & AUTO_REQSENSE) {
......@@ -3850,7 +3805,7 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
else
srb_free_insert(acb, srb);
dprintkdbg(DBG_0, "SRBdone: done pid %li\n", cmd->pid);
dprintkdbg(DBG_0, "srb_done: done (#%li)\n", cmd->pid);
if (debug_enabled(DBG_KG)) {
printk(" 0x%08x\n", cmd->result);
}
......@@ -4065,9 +4020,9 @@ static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
srb->segment_x[0].address =
pci_map_single(acb->dev, cmd->sense_buffer,
sizeof(cmd->sense_buffer), PCI_DMA_FROMDEVICE);
dprintkdbg(DBG_SGPARANOIA, "Map sense buffer at %p (%05x) to %08x\n",
cmd->sense_buffer, sizeof(cmd->sense_buffer),
srb->segment_x[0].address);
dprintkdbg(DBG_SGPARANOIA, "Map sense buffer %p->%08x(%05x)\n",
cmd->sense_buffer, srb->segment_x[0].address,
sizeof(cmd->sense_buffer));
srb->sg_count = 1;
srb->sg_index = 0;
......@@ -4673,8 +4628,7 @@ static int alloc_tracebufs(struct AdapterCtlBlk *acb) { return 0; }
static void adapter_sg_tables_free(struct AdapterCtlBlk *acb)
{
int i;
const unsigned srbs_per_page = PAGE_SIZE/(DC395x_MAX_SG_LISTENTRY
*sizeof(struct SGentry));
const unsigned srbs_per_page = PAGE_SIZE/SEGMENTX_LEN;
for (i = 0; i < DC395x_MAX_SRB_CNT; i += srbs_per_page)
if (acb->srb_array[i].segment_x)
......@@ -4688,11 +4642,9 @@ static void adapter_sg_tables_free(struct AdapterCtlBlk *acb)
static int __init adapter_sg_tables_alloc(struct AdapterCtlBlk *acb)
{
const unsigned mem_needed = (DC395x_MAX_SRB_CNT+1)
*DC395x_MAX_SG_LISTENTRY
*sizeof(struct SGentry);
*SEGMENTX_LEN;
int pages = (mem_needed+(PAGE_SIZE-1))/PAGE_SIZE;
const unsigned srbs_per_page = PAGE_SIZE/(DC395x_MAX_SG_LISTENTRY
*sizeof(struct SGentry));
const unsigned srbs_per_page = PAGE_SIZE/SEGMENTX_LEN;
int srb_idx = 0;
unsigned i = 0;
struct SGentry *ptr;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment