/* * dc395x.c * * Device Driver for Tekram DC395(U/UW/F), DC315(U) * PCI SCSI Bus Master Host Adapter * (SCSI chip set used Tekram ASIC TRM-S1040) * * Authors: * C.L. Huang <ching@tekram.com.tw> * Erich Chen <erich@tekram.com.tw> * (C) Copyright 1995-1999 Tekram Technology Co., Ltd. * * Kurt Garloff <garloff@suse.de> * (C) 1999-2000 Kurt Garloff * * Oliver Neukum <oliver@neukum.name> * Ali Akcaagac <aliakc@web.de> * Jamie Lenehan <lenehan@twibble.org> * (C) 2003 * * License: GNU GPL * ************************************************************************* * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ************************************************************************
*/ #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/delay.h> #include <linux/ctype.h> #include <linux/blkdev.h> #include <linux/interrupt.h> #include <linux/init.h> #include <linux/spinlock.h> #include <linux/pci.h> #include <linux/list.h> #include <linux/vmalloc.h> #include <linux/slab.h> #include <asm/io.h>
/*--------------------------------------------------------------------------- Features
---------------------------------------------------------------------------*/ /* * Set to disable parts of the driver
*/ /*#define DC395x_NO_DISCONNECT*/ /*#define DC395x_NO_TAGQ*/ /*#define DC395x_NO_SYNC*/ /*#define DC395x_NO_WIDE*/
#ifndef PCI_VENDOR_ID_TEKRAM #define PCI_VENDOR_ID_TEKRAM 0x1DE1 /* Vendor ID */ #endif #ifndef PCI_DEVICE_ID_TEKRAM_TRMS1040 #define PCI_DEVICE_ID_TEKRAM_TRMS1040 0x0391 /* Device ID */ #endif
/* * 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 *segment_x; /* Linear array of hw sg entries (up to 64 entries) */
dma_addr_t sg_bus_addr; /* Bus address of sg list (ie, of segment_x) */
u8 sg_count; /* No of HW sg entries for this request */
u8 sg_index; /* Index of HW sg entry for this request */
size_t total_xfer_length; /* Total number of bytes remaining to be transferred */
size_t request_length; /* Total number of bytes in this request */ /* * 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.
*/
size_t xferred; /* Saved copy of total_xfer_length */
struct DeviceCtlBlk { struct list_head list; /* next/prev ptrs for the dcb list */ struct AdapterCtlBlk *acb; struct list_head srb_going_list; /* head of going srb list */ struct list_head srb_waiting_list; /* head of waiting srb list */
/*--------------------------------------------------------------------------- Configuration
---------------------------------------------------------------------------*/ /* * Module/boot parameters currently effect *all* instances of the * card in the system.
*/
/* * Command line parameters are stored in a structure below. * These are the index's into the structure for the various * command line options.
*/ #define CFG_ADAPTER_ID 0 #define CFG_MAX_SPEED 1 #define CFG_DEV_MODE 2 #define CFG_ADAPTER_MODE 3 #define CFG_TAGS 4 #define CFG_RESET_DELAY 5
#define CFG_NUM 6 /* number of configuration items */
/* * Value used to indicate that a command line override * hasn't been used to modify the value.
*/ #define CFG_PARAM_UNSET -1
/* * Hold command line parameters.
*/ struct ParameterData { int value; /* value of this setting */ int min; /* minimum value */ int max; /* maximum value */ int def; /* default value */ int safe; /* safe value */
}; staticstruct ParameterData cfg_data[] = {
{ /* adapter id */
CFG_PARAM_UNSET,
0,
15,
7,
7
},
{ /* max speed */
CFG_PARAM_UNSET,
0,
7,
1, /* 13.3Mhz */
4, /* 6.7Hmz */
},
{ /* dev mode */
CFG_PARAM_UNSET,
0,
0x3f,
NTC_DO_PARITY_CHK | NTC_DO_DISCONNECT | NTC_DO_SYNC_NEGO |
NTC_DO_WIDE_NEGO | NTC_DO_TAG_QUEUEING |
NTC_DO_SEND_START,
NTC_DO_PARITY_CHK | NTC_DO_SEND_START
},
{ /* adapter mode */
CFG_PARAM_UNSET,
0,
0x2f,
NAC_SCANLUN |
NAC_GT2DRIVES | NAC_GREATER_1G | NAC_POWERON_SCSI_RESET /*| NAC_ACTIVE_NEG*/,
NAC_GT2DRIVES | NAC_GREATER_1G | NAC_POWERON_SCSI_RESET | 0x08
},
{ /* tags */
CFG_PARAM_UNSET,
0,
5,
3, /* 16 tags (??) */
2,
},
{ /* reset delay */
CFG_PARAM_UNSET,
0,
180,
1, /* 1 second */
10, /* 10 seconds */
}
};
/* * Safe settings. If set to zero the BIOS/default values with * command line overrides will be used. If set to 1 then safe and * slow settings will be used.
*/ staticbool use_safe_settings = 0;
module_param_named(safe, use_safe_settings, bool, 0);
MODULE_PARM_DESC(safe, "Use safe and slow settings only. Default: false");
/** * set_safe_settings - if the use_safe_settings option is set then * set all values to the safe and slow values.
**/ staticvoid set_safe_settings(void)
{ if (use_safe_settings)
{ int i;
for (i = 0; i < CFG_NUM; i++)
{
cfg_data[i].value = cfg_data[i].safe;
}
}
}
/** * fix_settings - reset any boot parameters which are out of range * back to the default values.
**/ staticvoid fix_settings(void)
{ int i;
for (i = 0; i < CFG_NUM; i++)
{ if (cfg_data[i].value < cfg_data[i].min
|| cfg_data[i].value > cfg_data[i].max)
cfg_data[i].value = cfg_data[i].def;
}
}
/* * Mapping from the eeprom delay index value (index into this array) * to the number of actual seconds that the delay should be for.
*/ staticchar eeprom_index_to_delay_map[] =
{ 1, 3, 5, 10, 16, 30, 60, 120 };
/** * eeprom_index_to_delay - Take the eeprom delay setting and convert it * into a number of seconds. * * @eeprom: The eeprom structure in which we find the delay index to map.
**/ staticvoid eeprom_index_to_delay(struct NvRamType *eeprom)
{
eeprom->delay_time = eeprom_index_to_delay_map[eeprom->delay_time];
}
/** * delay_to_eeprom_index - Take a delay in seconds and return the * closest eeprom index which will delay for at least that amount of * seconds. * * @delay: The delay, in seconds, to find the eeprom index for.
**/ staticint delay_to_eeprom_index(int delay)
{
u8 idx = 0; while (idx < 7 && eeprom_index_to_delay_map[idx] < delay)
idx++; return idx;
}
/** * eeprom_override - Override the eeprom settings, in the provided * eeprom structure, with values that have been set on the command * line. * * @eeprom: The eeprom data to override with command line options.
**/ staticvoid eeprom_override(struct NvRamType *eeprom)
{
u8 id;
if (cfg_data[CFG_ADAPTER_MODE].value != CFG_PARAM_UNSET)
eeprom->channel_cfg = (u8)cfg_data[CFG_ADAPTER_MODE].value;
if (cfg_data[CFG_RESET_DELAY].value != CFG_PARAM_UNSET)
eeprom->delay_time = delay_to_eeprom_index(
cfg_data[CFG_RESET_DELAY].value);
if (cfg_data[CFG_TAGS].value != CFG_PARAM_UNSET)
eeprom->max_tag = (u8)cfg_data[CFG_TAGS].value;
/* Device Settings */ for (id = 0; id < DC395x_MAX_SCSI_ID; id++) { if (cfg_data[CFG_DEV_MODE].value != CFG_PARAM_UNSET)
eeprom->target[id].cfg0 =
(u8)cfg_data[CFG_DEV_MODE].value;
if (cfg_data[CFG_MAX_SPEED].value != CFG_PARAM_UNSET)
eeprom->target[id].period =
(u8)cfg_data[CFG_MAX_SPEED].value;
/* find supplied dcb and then select the next one */
list_for_each_entry(i, head, list) if (use_next) {
next = i; break;
} elseif (i == pos) {
use_next = 1;
} /* if no next one take the head one (ie, wraparound) */ if (!next)
list_for_each_entry(i, head, list) {
next = i; break;
}
/* Sets the timer to wake us up */ staticvoid waiting_set_timer(struct AdapterCtlBlk *acb, unsignedlong to)
{ if (timer_pending(&acb->waiting_timer)) return; if (time_before(jiffies + to, acb->last_reset - HZ / 2))
acb->waiting_timer.expires =
acb->last_reset - HZ / 2 + 1; else
acb->waiting_timer.expires = jiffies + to + 1;
add_timer(&acb->waiting_timer);
}
/* Send the next command from the waiting list to the bus */ staticvoid waiting_process_next(struct AdapterCtlBlk *acb)
{ struct DeviceCtlBlk *start = NULL; struct DeviceCtlBlk *pos; struct DeviceCtlBlk *dcb; struct ScsiReqBlk *srb; struct list_head *dcb_list_head = &acb->dcb_list;
if (timer_pending(&acb->waiting_timer))
timer_delete(&acb->waiting_timer);
if (list_empty(dcb_list_head)) return;
/* * Find the starting dcb. Need to find it again in the list * since the list may have changed since we set the ptr to it
*/
list_for_each_entry(dcb, dcb_list_head, list) if (dcb == acb->dcb_run_robin) {
start = dcb; break;
} if (!start) { /* This can happen! */
start = list_entry(dcb_list_head->next, typeof(*start), list);
acb->dcb_run_robin = start;
}
/* * Loop over the dcb, but we start somewhere (potentially) in * the middle of the loop so we need to manully do this.
*/
pos = start; do { struct list_head *waiting_list_head = &pos->srb_waiting_list;
/* Make sure, the next another device gets scheduled ... */
acb->dcb_run_robin = dcb_get_next(dcb_list_head,
acb->dcb_run_robin);
if (list_empty(waiting_list_head) ||
pos->max_command <= list_size(&pos->srb_going_list)) { /* move to next dcb */
pos = dcb_get_next(dcb_list_head, pos);
} else {
srb = list_entry(waiting_list_head->next, struct ScsiReqBlk, list);
/* Try to send to the bus */ if (!start_scsi(acb, pos, srb))
list_move(&srb->list, &pos->srb_going_list); else
waiting_set_timer(acb, HZ/50); break;
}
} while (pos != start);
}
/* Get the DCB for a given ID/LUN combination */ staticstruct DeviceCtlBlk *find_dcb(struct AdapterCtlBlk *acb, u8 id, u8 lun)
{ return acb->children[id][lun];
}
/* * 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++;
}
/** * dc395x_queue_command_lck - queue scsi command passed from the mid * layer, invoke 'done' on completion * * @cmd: pointer to scsi command object * * Returns 1 if the adapter (host) is busy, else returns 0. One * reason for an adapter to be busy is that the number * of outstanding queued commands is already equal to * struct Scsi_Host::can_queue . * * Required: if struct Scsi_Host::can_queue is ever non-zero * then this function is required. * * Locks: struct Scsi_Host::host_lock held on entry (with "irqsave") * and is expected to be held on return. *
*/ staticint dc395x_queue_command_lck(struct scsi_cmnd *cmd)
{ void (*done)(struct scsi_cmnd *) = scsi_done; struct DeviceCtlBlk *dcb; struct ScsiReqBlk *srb; struct AdapterCtlBlk *acb =
(struct AdapterCtlBlk *)cmd->device->host->hostdata;
/* Assume BAD_TARGET; will be cleared later */
set_host_byte(cmd, DID_BAD_TARGET);
if (!srb) { /* should never happen */ return 1;
}
list_del(&srb->list);
build_srb(cmd, dcb, srb);
if (!list_empty(&dcb->srb_waiting_list)) { /* append to waiting queue */
list_add_tail(&srb->list, &dcb->srb_waiting_list);
waiting_process_next(acb);
} else { /* process immediately */
send_srb(acb, srb);
} return 0;
complete: /* * Complete the command immediatey, and then return 0 to * indicate that we have handled the command. This is usually * done when the commad is for things like non existent * devices.
*/
done(cmd); return 0;
}
/* * perform a hard reset on the SCSI bus * @cmd - some command for this host (for fetching hooks) * Returns: SUCCESS (0x2002) on success, else FAILED (0x2003).
*/ staticint __dc395x_eh_bus_reset(struct scsi_cmnd *cmd)
{ struct AdapterCtlBlk *acb =
(struct AdapterCtlBlk *)cmd->device->host->hostdata;
if (timer_pending(&acb->waiting_timer))
timer_delete(&acb->waiting_timer);
/* * abort an errant SCSI command * @cmd - command to be aborted * Returns: SUCCESS (0x2002) on success, else FAILED (0x2003).
*/ staticint dc395x_eh_abort(struct scsi_cmnd *cmd)
{ /* * Look into our command queues: If it has not been sent already, * we remove it and return success. Otherwise fail.
*/ struct AdapterCtlBlk *acb =
(struct AdapterCtlBlk *)cmd->device->host->hostdata; struct DeviceCtlBlk *dcb; struct ScsiReqBlk *srb;
dcb = find_dcb(acb, cmd->device->id, cmd->device->lun); if (!dcb) return FAILED;
srb = find_cmd(cmd, &dcb->srb_waiting_list); if (srb) {
list_del(&srb->list);
pci_unmap_srb_sense(acb, srb);
pci_unmap_srb(acb, srb);
free_tag(dcb, srb);
list_add_tail(&srb->list, &acb->srb_free_list);
set_host_byte(cmd, DID_ABORT); return SUCCESS;
}
srb = find_cmd(cmd, &dcb->srb_going_list); if (srb) { /* XXX: Should abort the command here */
} return FAILED;
}
#if 0 /* Timer to work around chip flaw: When selecting and the bus is
* busy, we sometimes miss a Selection timeout IRQ */ void selection_timeout_missed(unsignedlong ptr); /* Sets the timer to wake us up */ staticvoid selto_timer(struct AdapterCtlBlk *acb)
{ if (timer_pending(&acb->selto_timer)) return;
acb->selto_timer.function = selection_timeout_missed;
acb->selto_timer.data = (unsignedlong) acb; if (time_before
(jiffies + HZ, acb->last_reset + HZ / 2))
acb->selto_timer.expires =
acb->last_reset + HZ / 2 + 1; else
acb->selto_timer.expires = jiffies + HZ + 1;
add_timer(&acb->selto_timer);
}
srb->tag_number = TAG_NONE; /* acb->tag_max_num: had error read in eeprom */
s_stat = DC395x_read8(acb, TRM_S1040_SCSI_SIGNAL);
s_stat2 = 0;
s_stat2 = DC395x_read16(acb, TRM_S1040_SCSI_STATUS); #if 1 if (s_stat & 0x20 /* s_stat2 & 0x02000 */ ) { /* * Try anyway? * * We could, BUT: Sometimes the TRM_S1040 misses to produce a Selection * Timeout, a Disconnect or a Reselection IRQ, so we would be screwed! * (This is likely to be a bug in the hardware. Obviously, most people * only have one initiator per SCSI bus.) * Instead let this fail and have the timer make sure the command is * tried again after a short time
*/ /*selto_timer (acb); */ return 1;
} #endif if (acb->active_dcb) return 1;
if (DC395x_read16(acb, TRM_S1040_SCSI_STATUS) & SCSIINTERRUPT) return 1;
/* Allow starting of SCSI commands half a second before we allow the mid-level
* to queue them again after a reset */ if (time_before(jiffies, acb->last_reset - HZ / 2)) return 1;
/** * dc395x_handle_interrupt - Handle an interrupt that has been confirmed to * have been triggered for this card. * * @acb: a pointer to the adpter control block * @scsi_status: the status return when we checked the card
**/ staticvoid dc395x_handle_interrupt(struct AdapterCtlBlk *acb,
u16 scsi_status)
{ struct DeviceCtlBlk *dcb; struct ScsiReqBlk *srb;
u16 phase;
u8 scsi_intstatus; unsignedlong flags; void (*dc395x_statev)(struct AdapterCtlBlk *, struct ScsiReqBlk *,
u16 *);
DC395x_LOCK_IO(acb->scsi_host, flags);
/* This acknowledges the IRQ */
scsi_intstatus = DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS);
if (timer_pending(&acb->selto_timer))
timer_delete(&acb->selto_timer);
if (scsi_intstatus & (INT_SELTIMEOUT | INT_DISCONNECT)) {
disconnect(acb); /* bus free interrupt */ goto out_unlock;
} if (scsi_intstatus & INT_RESELECTED) {
reselect(acb); goto out_unlock;
} if (scsi_intstatus & INT_SELECT) goto out_unlock;
if (scsi_intstatus & INT_SCSIRESET) {
scsi_reset_detect(acb); goto out_unlock;
} if (scsi_intstatus & (INT_BUSSERVICE | INT_CMDDONE)) {
dcb = acb->active_dcb; if (!dcb) goto out_unlock;
srb = dcb->active_srb; if (dcb->flag & ABORT_DEV_)
enable_msgout_abort(acb, srb);
/* * if there were any exception occurred scsi_status * will be modify to bus free phase new scsi_status * transfer out from ... previous dc395x_statev
*/
srb->scsi_phase = scsi_status & PHASEMASK;
phase = (u16)scsi_status & PHASEMASK;
/* * We have transferred 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
*/ staticvoid sg_subtract_one(struct ScsiReqBlk *srb)
{
sg_update_list(srb, srb->total_xfer_length - 1);
}
/* * cleanup_after_transfer * * Makes sure, DMA and SCSI engine are empty, after the transfer has finished * KG: Currently called from StatusPhase1 () * Should probably also be called from other places * Best might be to call it in DataXXPhase0, if new phase will differ
*/ staticvoid cleanup_after_transfer(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
{ /*DC395x_write8 (TRM_S1040_DMA_STATUS, FORCEDMACOMP); */ if (DC395x_read16(acb, TRM_S1040_DMA_COMMAND) & 0x0001) { /* read */ if (!(DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & 0x40))
clear_fifo(acb, "cleanup/in"); if (!(DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT) & 0x80))
DC395x_write8(acb, TRM_S1040_DMA_CONTROL, CLRXFIFO);
} else { /* write */ if (!(DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT) & 0x80))
DC395x_write8(acb, TRM_S1040_DMA_CONTROL, CLRXFIFO); if (!(DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & 0x40))
clear_fifo(acb, "cleanup/out");
}
DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);
}
/* * Those no of bytes will be transferred w/ PIO through the SCSI FIFO * Seems to be needed for unknown reasons; could be a hardware bug :-(
*/ #define DC395x_LASTPIO 4
/* * KG: We need to drain the buffers before we draw any conclusions! * This means telling the DMA to push the rest into SCSI, telling * SCSI to push the rest to the bus. * However, the device might have been the one to stop us (phase * change), and the data in transit just needs to be accounted so * it can be retransmitted.)
*/ /* * KG: Stop DMA engine pushing more data into the SCSI FIFO * If we need more data, the DMA SG list will be freshly set up, anyway
*/
DC395x_write8(acb, TRM_S1040_DMA_CONTROL, STOPDMAXFER | CLRXFIFO);
if (!(srb->state & SRB_XFERPAD)) { if (scsi_status & PARITYERROR)
srb->status |= PARITY_ERROR;
/* * KG: Right, we can't just rely on the SCSI_COUNTER, because this * is the no of bytes it got from the DMA engine not the no it * transferred successfully to the device. (And the difference could * be as much as the FIFO size, I guess ...)
*/ if (!(scsi_status & SCSIXFERDONE)) { /* * when data transfer from DMA FIFO to SCSI FIFO * if there was some data left in SCSI FIFO
*/
d_left_counter =
(u32)(DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) &
0x1F); if (dcb->sync_period & WIDE_SYNC)
d_left_counter <<= 1;
} /* * calculate all the residue data that not yet tranfered * SCSI transfer counter + left in SCSI FIFO data * * .....TRM_S1040_SCSI_COUNTER (24bits) * The counter always decrement by one for every SCSI byte transfer. * .....TRM_S1040_SCSI_FIFOCNT ( 5bits) * The counter is SCSI FIFO offset counter (in units of bytes or! words)
*/ if (srb->total_xfer_length > DC395x_LASTPIO)
d_left_counter +=
DC395x_read32(acb, TRM_S1040_SCSI_COUNTER);
/* Is this a good idea? */ /*clear_fifo(acb, "DOP1"); */ /* KG: What is this supposed to be useful for? WIDE padding stuff? */ if (d_left_counter == 1 && dcb->sync_period & WIDE_SYNC
&& scsi_bufflen(srb->cmd) % 2) {
d_left_counter = 0;
} /* * KG: Oops again. Same thinko as above: The SCSI might have been * faster than the DMA engine, so that it ran out of data. * In that case, we have to do just nothing! * But: Why the interrupt: No phase change. No XFERCNT_2_ZERO. Or?
*/ /* * KG: This is nonsense: We have been WRITING data to the bus * If the SCSI engine has no bytes left, how should the DMA engine?
*/ if (d_left_counter == 0) {
srb->total_xfer_length = 0;
} else { /* * if transfer not yet complete * there were some data residue in SCSI FIFO or * SCSI transfer counter not empty
*/ long oldxferred =
srb->total_xfer_length - d_left_counter; constint diff =
(dcb->sync_period & WIDE_SYNC) ? 2 : 1;
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 && scsi_sg_count(srb->cmd))
|| ((oldxferred & ~PAGE_MASK) ==
(PAGE_SIZE - diff))
) {
d_left_counter =
srb->total_xfer_length - diff;
sg_update_list(srb, d_left_counter); /*srb->total_xfer_length -= diff; */ /*srb->virt_addr += diff; */ /*if (srb->cmd->use_sg) */ /* srb->sg_index++; */
}
}
} if ((*pscsi_status & PHASEMASK) != PH_DATA_OUT)
cleanup_after_transfer(acb, srb);
}
staticvoid data_out_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
u16 *pscsi_status)
{
clear_fifo(acb, "data_out_phase1"); /* do prepare before transfer when data out phase */
data_io_transfer(acb, srb, XFERDATAOUT);
}
/* * KG: DataIn is much more tricky than DataOut. When the device is finished * and switches to another phase, the SCSI engine should be finished too. * But: There might still be bytes left in its FIFO to be fetched by the DMA * engine and transferred to memory. * We should wait for the FIFOs to be emptied by that (is there any way to * enforce this?) and then stop the DMA engine, because it might think, that * there are more bytes to follow. Yes, the device might disconnect prior to * having all bytes transferred! * Also we should make sure that all data from the DMA engine buffer's really * made its way to the system memory! Some documentation on this would not * seem to be a bad idea, actually.
*/ if (!(srb->state & SRB_XFERPAD)) {
u32 d_left_counter; unsignedint sc, fc;
if (scsi_status & PARITYERROR) {
srb->status |= PARITY_ERROR;
} /* * KG: We should wait for the DMA FIFO to be empty ... * but: it would be better to wait first for the SCSI FIFO and then the * the DMA FIFO to become empty? How do we know, that the device not already * sent data to the FIFO in a MsgIn phase, eg.?
*/ if (!(DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT) & 0x80)) { #if 0 int ctr = 6000000; /*DC395x_write8 (TRM_S1040_DMA_CONTROL, STOPDMAXFER); */ /*DC395x_write32 (TRM_S1040_SCSI_COUNTER, 7); */ /*DC395x_write8 (TRM_S1040_SCSI_COMMAND, SCMD_DMA_IN); */ while (!
(DC395x_read16(acb, TRM_S1040_DMA_FIFOSTAT) &
0x80) && --ctr); /*DC395x_write32 (TRM_S1040_SCSI_COUNTER, 0); */ #endif
} /* Now: Check remainig data: The SCSI counters should tell us ... */
sc = DC395x_read32(acb, TRM_S1040_SCSI_COUNTER);
fc = DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT);
d_left_counter = sc + ((fc & 0x1f)
<< ((srb->dcb->sync_period & WIDE_SYNC) ? 1 :
0)); #if DC395x_LASTPIO /* KG: Less than or equal to 4 bytes can not be transferred via DMA, it seems. */ if (d_left_counter
&& srb->total_xfer_length <= DC395x_LASTPIO) {
size_t left_io = srb->total_xfer_length;
local_irq_save(flags); /* Assumption: it's inside one page as it's at most 4 bytes and
I just assume it's on a 4-byte boundary */
base = scsi_kmap_atomic_sg(scsi_sglist(srb->cmd),
srb->sg_count, &offset, &len);
virt = base + offset;
#if 0 /* * KG: This was in DATAOUT. Does it also belong here? * Nobody seems to know what counter and fifo_cnt count exactly ...
*/ if (!(scsi_status & SCSIXFERDONE)) { /* * when data transfer from DMA FIFO to SCSI FIFO * if there was some data left in SCSI FIFO
*/
d_left_counter =
(u32)(DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) &
0x1F); if (srb->dcb->sync_period & WIDE_SYNC)
d_left_counter <<= 1; /* * if WIDE scsi SCSI FIFOCNT unit is word !!! * so need to *= 2 * KG: Seems to be correct ...
*/
} #endif /* KG: This should not be needed any more! */ if (d_left_counter == 0
|| (scsi_status & SCSIXFERCNT_2_ZERO)) { #if 0 int ctr = 6000000;
u8 TempDMAstatus; do {
TempDMAstatus =
DC395x_read8(acb, TRM_S1040_DMA_STATUS);
} while (!(TempDMAstatus & DMAXFERCOMP) && --ctr);
srb->total_xfer_length = 0; #endif
srb->total_xfer_length = d_left_counter;
} else { /* phase changed */ /* * parsing the case: * when a transfer not yet complete * but be disconnected by target * if transfer not yet complete * there were some data residue in SCSI FIFO or * SCSI transfer counter not empty
*/
sg_update_list(srb, d_left_counter);
}
} /* KG: The target may decide to disconnect: Empty FIFO before! */ if ((*pscsi_status & PHASEMASK) != PH_DATA_IN)
cleanup_after_transfer(acb, srb);
}
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); /* * KG: What should we do: Use SCSI Cmd 0x90/0x92? * Maybe, even ABORTXFER would be appropriate
*/ if (dma_status & XFERPENDING) {
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
*/
srb->state |= SRB_DATA_XFER;
DC395x_write32(acb, TRM_S1040_DMA_XHIGHADDR, 0); if (scsi_sg_count(srb->cmd)) { /* with S/G */
io_dir |= DMACMD_SG;
DC395x_write32(acb, TRM_S1040_DMA_XLOWADDR,
srb->sg_bus_addr + sizeof(struct SGentry) *
srb->sg_index); /* load how many bytes in the sg list table */
DC395x_write32(acb, TRM_S1040_DMA_XCNT,
((u32)(srb->sg_count -
srb->sg_index) << 3));
} else { /* without S/G */
io_dir &= ~DMACMD_SG;
DC395x_write32(acb, TRM_S1040_DMA_XLOWADDR,
srb->segment_x[0].address);
DC395x_write32(acb, TRM_S1040_DMA_XCNT,
srb->segment_x[0].length);
} /* load total transfer length (24bits) max value 16Mbyte */
DC395x_write32(acb, TRM_S1040_SCSI_COUNTER,
srb->total_xfer_length);
DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ 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);
} else {
DC395x_write16(acb, TRM_S1040_DMA_COMMAND, io_dir);
DC395x_write8(acb, TRM_S1040_SCSI_COMMAND,
SCMD_DMA_OUT);
}
} #if DC395x_LASTPIO elseif (srb->total_xfer_length > 0) { /* The last four bytes: Do PIO */ /* * 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 */
DC395x_write32(acb, TRM_S1040_SCSI_COUNTER,
srb->total_xfer_length);
DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ if (io_dir & DMACMD_DIR) { /* read */
DC395x_write8(acb, TRM_S1040_SCSI_COMMAND,
SCMD_FIFO_IN);
} else { /* write */ int ln = srb->total_xfer_length;
size_t left_io = srb->total_xfer_length;
if (srb->dcb->sync_period & WIDE_SYNC)
DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2,
CFG2_WIDEFIFO);
memcpy(srb->msgin_buf, dcb->active_srb->msgin_buf, acb->msg_len);
srb->state |= dcb->active_srb->state;
srb->state |= SRB_DATA_XFER;
dcb->active_srb = srb; /* How can we make the DORS happy? */ return srb;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.