/* * 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;
list_for_each_entry_safe(srb, tmp, &dcb->srb_going_list, list) {
p = srb->cmd;
printk("G:%p(%02i-%i) ", p,
p->device->id, (u8)p->device->lun);
list_del(&srb->list);
free_tag(dcb, srb);
list_add_tail(&srb->list, &acb->srb_free_list);
set_host_byte(p, did_flag);
set_status_byte(p, SAM_STAT_GOOD);
pci_unmap_srb_sense(acb, srb);
pci_unmap_srb(acb, srb); if (force) { /* For new EH, we normally don't need to give commands back,
* as they all complete or all time out */
scsi_done(p);
}
}
printk("W:%p<%02i-%i>", p, p->device->id,
(u8)p->device->lun);
list_move_tail(&srb->list, &acb->srb_free_list);
set_host_byte(p, did_flag);
set_status_byte(p, SAM_STAT_GOOD);
pci_unmap_srb_sense(acb, srb);
pci_unmap_srb(acb, srb); if (force) { /* For new EH, we normally don't need to give commands back,
* as they all complete or all time out */
scsi_done(cmd);
}
}
dcb->flag &= ~ABORT_DEV_;
}
}
staticvoid scsi_reset_detect(struct AdapterCtlBlk *acb)
{ /* delay half a second */ if (timer_pending(&acb->waiting_timer))
timer_delete(&acb->waiting_timer);
DC395x_write8(acb, TRM_S1040_SCSI_CONTROL, DO_RSTMODULE);
DC395x_write8(acb, TRM_S1040_DMA_CONTROL, DMARESETMODULE); /*DC395x_write8(acb, TRM_S1040_DMA_CONTROL,STOPDMAXFER); */
udelay(500); /* Maybe we locked up the bus? Then lets wait even longer ... */
acb->last_reset =
jiffies + 5 * HZ / 2 +
HZ * acb->eeprom.delay_time;
/* KG: Can this prevent crap sense data ? */
memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
/* Save some data */
srb->segment_x[DC395x_MAX_SG_LISTENTRY - 1].address =
srb->segment_x[0].address;
srb->segment_x[DC395x_MAX_SG_LISTENTRY - 1].length =
srb->segment_x[0].length;
srb->xferred = srb->total_xfer_length; /* srb->segment_x : a one entry of S/G list table */
srb->total_xfer_length = SCSI_SENSE_BUFFERSIZE;
srb->segment_x[0].length = SCSI_SENSE_BUFFERSIZE; /* Map sense buffer */
srb->segment_x[0].address = dma_map_single(&acb->dev->dev,
cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE,
DMA_FROM_DEVICE);
srb->sg_count = 1;
srb->sg_index = 0;
if (start_scsi(acb, dcb, srb)) { /* Should only happen, if sb. else grabs the bus */
list_move(&srb->list, &dcb->srb_waiting_list);
waiting_set_timer(acb, HZ / 100);
}
}
/** * device_alloc - Allocate a new device instance. This create the * devices instance and sets up all the data items. The adapter * instance is required to obtain confiuration information for this * device. This does *not* add this device to the adapters device * list. * * @acb: The adapter to obtain configuration information from. * @target: The target for the new device. * @lun: The lun for the new device. * * Return the new device if successful or NULL on failure.
**/ staticstruct DeviceCtlBlk *device_alloc(struct AdapterCtlBlk *acb,
u8 target, u8 lun)
{ struct NvRamType *eeprom = &acb->eeprom;
u8 period_index = eeprom->target[target].period & 0x07; struct DeviceCtlBlk *dcb;
/** * adapter_add_device - Adds the device instance to the adaptor instance. * * @acb: The adapter device to be updated * @dcb: A newly created and initialised device instance to add.
**/ staticvoid adapter_add_device(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb)
{ /* backpointer to adapter */
dcb->acb = acb;
/* set run_robin to this device if it is currently empty */ if (list_empty(&acb->dcb_list))
acb->dcb_run_robin = dcb;
/* add device to list */
list_add_tail(&dcb->list, &acb->dcb_list);
/** * adapter_remove_device - Removes the device instance from the adaptor * instance. The device instance is not check in any way or freed by this. * The caller is expected to take care of that. This will simply remove the * device from the adapters data strcutures. * * @acb: The adapter device to be updated * @dcb: A device that has previously been added to the adapter.
**/ staticvoid adapter_remove_device(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb)
{ struct DeviceCtlBlk *i; struct DeviceCtlBlk *tmp;
/* fix up any pointers to this device that we have in the adapter */ if (acb->active_dcb == dcb)
acb->active_dcb = NULL; if (acb->dcb_run_robin == dcb)
acb->dcb_run_robin = dcb_get_next(&acb->dcb_list, dcb);
/* unlink from list */
list_for_each_entry_safe(i, tmp, &acb->dcb_list, list) if (dcb == i) {
list_del(&i->list); break;
}
/* clear map and children */
acb->dcb_map[dcb->target_id] &= ~(1 << dcb->target_lun);
acb->children[dcb->target_id][dcb->target_lun] = NULL;
dcb->acb = NULL;
}
/** * adapter_remove_and_free_device - Removes a single device from the adapter * and then frees the device information. * * @acb: The adapter device to be updated * @dcb: A device that has previously been added to the adapter.
*/ staticvoid adapter_remove_and_free_device(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb)
{ if (list_size(&dcb->srb_going_list) > 1) { return;
}
adapter_remove_device(acb, dcb);
kfree(dcb);
}
/** * adapter_remove_and_free_all_devices - Removes and frees all of the * devices associated with the specified adapter. * * @acb: The adapter from which all devices should be removed.
**/ staticvoid adapter_remove_and_free_all_devices(struct AdapterCtlBlk* acb)
{ struct DeviceCtlBlk *dcb; struct DeviceCtlBlk *tmp;
/** * dc395x_sdev_init - Called by the scsi mid layer to tell us about a new * scsi device that we need to deal with. We allocate a new device and then * insert that device into the adapters device list. * * @scsi_device: The new scsi device that we need to handle.
**/ staticint dc395x_sdev_init(struct scsi_device *scsi_device)
{ struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)scsi_device->host->hostdata; struct DeviceCtlBlk *dcb;
/** * dc395x_sdev_destroy - Called by the scsi mid layer to tell us about a * device that is going away. * * @scsi_device: The new scsi device that we need to handle.
**/ staticvoid dc395x_sdev_destroy(struct scsi_device *scsi_device)
{ struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)scsi_device->host->hostdata; struct DeviceCtlBlk *dcb = find_dcb(acb, scsi_device->id, scsi_device->lun); if (dcb)
adapter_remove_and_free_device(acb, dcb);
}
/** * trms1040_wait_30us: wait for 30 us * * Waits for 30us (using the chip by the looks of it..) * * @io_port: base I/O address
**/ staticvoid trms1040_wait_30us(unsignedlong io_port)
{ /* ScsiPortStallExecution(30); wait 30 us */
outb(5, io_port + TRM_S1040_GEN_TIMER); while (!(inb(io_port + TRM_S1040_GEN_STATUS) & GTIMEOUT)) /* nothing */ ;
}
/** * trms1040_write_cmd - write the secified command and address to * chip * * @io_port: base I/O address * @cmd: SB + op code (command) to send * @addr: address to send
**/ staticvoid trms1040_write_cmd(unsignedlong io_port, u8 cmd, u8 addr)
{ int i;
u8 send_data;
/* program SB + OP code */ for (i = 0; i < 3; i++, cmd <<= 1) {
send_data = NVR_SELECT; if (cmd & 0x04) /* Start from bit 2 */
send_data |= NVR_BITOUT;
/** * trms1040_set_data - store a single byte in the eeprom * * Called from write all to write a single byte into the SSEEPROM * Which is done one bit at a time. * * @io_port: base I/O address * @addr: offset into EEPROM * @byte: bytes to write
**/ staticvoid trms1040_set_data(unsignedlong io_port, u8 addr, u8 byte)
{ int i;
u8 send_data;
/** * trms1040_write_all - write 128 bytes to the eeprom * * Write the supplied 128 bytes to the chips SEEPROM * * @eeprom: the data to write * @io_port: the base io port
**/ staticvoid trms1040_write_all(struct NvRamType *eeprom, unsignedlong io_port)
{
u8 *b_eeprom = (u8 *)eeprom;
u8 addr;
/** * trms1040_get_data - get a single byte from the eeprom * * Called from read all to read a single byte into the SSEEPROM * Which is done one bit at a time. * * @io_port: base I/O address * @addr: offset into SEEPROM * * Returns the byte read.
**/ static u8 trms1040_get_data(unsignedlong io_port, u8 addr)
{ int i;
u8 read_byte;
u8 result = 0;
/** * trms1040_read_all - read all bytes from the eeprom * * Read the 128 bytes from the SEEPROM. * * @eeprom: where to store the data * @io_port: the base io port
**/ staticvoid trms1040_read_all(struct NvRamType *eeprom, unsignedlong io_port)
{
u8 *b_eeprom = (u8 *)eeprom;
u8 addr;
/** * check_eeprom - get and check contents of the eeprom * * Read seeprom 128 bytes into the memory provider in eeprom. * Checks the checksum and if it's not correct it uses a set of default * values. * * @eeprom: caller allocated strcuture to read the eeprom data into * @io_port: io port to read from
**/ staticvoid check_eeprom(struct NvRamType *eeprom, unsignedlong io_port)
{
u16 *w_eeprom = (u16 *)eeprom;
u16 w_addr;
u16 cksum;
u32 d_addr;
u32 *d_eeprom;
/** * print_eeprom_settings - output the eeprom settings * to the kernel log so people can see what they were. * * @eeprom: The eeprom data strucutre to show details for.
**/ staticvoid print_eeprom_settings(struct NvRamType *eeprom)
{
}
for (i = 0; i < DC395x_MAX_SRB_CNT; i += srbs_per_page)
kfree(acb->srb_array[i].segment_x);
}
/* * Allocate SG tables; as we have to pci_map them, an SG list (struct SGentry*)
* should never cross a page boundary */ staticint adapter_sg_tables_alloc(struct AdapterCtlBlk *acb)
{ constunsigned mem_needed = (DC395x_MAX_SRB_CNT+1)
*SEGMENTX_LEN; int pages = (mem_needed+(PAGE_SIZE-1))/PAGE_SIZE; constunsigned srbs_per_page = PAGE_SIZE/SEGMENTX_LEN; int srb_idx = 0; unsigned i = 0; struct SGentry *ptr;
for (i = 0; i < DC395x_MAX_SRB_CNT; i++)
acb->srb_array[i].segment_x = NULL;
while (pages--) {
ptr = kmalloc(PAGE_SIZE, GFP_KERNEL); if (!ptr) {
adapter_sg_tables_free(acb); return 1;
}
i = 0; while (i < srbs_per_page && srb_idx < DC395x_MAX_SRB_CNT)
acb->srb_array[srb_idx++].segment_x =
ptr + (i++ * DC395x_MAX_SG_LISTENTRY);
} if (i < srbs_per_page)
acb->srb.segment_x =
ptr + (i * DC395x_MAX_SG_LISTENTRY); return 0;
}
/** * adapter_print_config - print adapter connection and termination * config * * The io port in the adapter needs to have been set before calling * this function. * * @acb: The adapter to print the information for.
**/ staticvoid adapter_print_config(struct AdapterCtlBlk *acb)
{
u8 bval;
/** * adapter_init_params - Initialize the various parameters in the * adapter structure. Note that the pointer to the scsi_host is set * early (when this instance is created) and the io_port and irq * values are set later after they have been reserved. This just gets * everything set to a good starting position. * * The eeprom structure in the adapter needs to have been set before * calling this function. * * @acb: The adapter to initialize.
**/ staticvoid adapter_init_params(struct AdapterCtlBlk *acb)
{ struct NvRamType *eeprom = &acb->eeprom; int i;
/* NOTE: acb->scsi_host is set at scsi_host/acb creation time */ /* NOTE: acb->io_port_base is set at port registration time */ /* NOTE: acb->io_port_len is set at port registration time */
INIT_LIST_HEAD(&acb->srb_free_list); /* temp SRB for Q tag used or abort command used */
acb->tmp_srb = &acb->srb;
timer_setup(&acb->waiting_timer, waiting_timeout, 0);
timer_setup(&acb->selto_timer, NULL, 0);
acb->srb_count = DC395x_MAX_SRB_CNT;
acb->sel_timeout = DC395x_SEL_TIMEOUT; /* timeout=250ms */ /* NOTE: acb->irq_level is set at IRQ registration time */
for (i = 0; i < DC395x_MAX_SCSI_ID; i++)
acb->dcb_map[i] = 0;
acb->msg_len = 0;
/* link static array of srbs into the srb free list */ for (i = 0; i < acb->srb_count - 1; i++)
list_add_tail(&acb->srb_array[i].list, &acb->srb_free_list);
}
/** * adapter_init_scsi_host - Initialize the scsi host instance based on * values that we have already stored in the adapter instance. There's * some mention that a lot of these are deprecated, so we won't use * them (we'll use the ones in the adapter instance) but we'll fill * them in in case something else needs them. * * The eeprom structure, irq and io ports in the adapter need to have * been set before calling this function. * * @host: The scsi host instance to fill in the values for.
**/ staticvoid adapter_init_scsi_host(struct Scsi_Host *host)
{ struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)host->hostdata; struct NvRamType *eeprom = &acb->eeprom;
/** * adapter_init_chip - Get the chip into a know state and figure out * some of the settings that apply to this adapter. * * The io port in the adapter needs to have been set before calling * this function. The config will be configured correctly on return. * * @acb: The adapter which we are to init.
**/ staticvoid adapter_init_chip(struct AdapterCtlBlk *acb)
{ struct NvRamType *eeprom = &acb->eeprom;
/* Mask all the interrupt */
DC395x_write8(acb, TRM_S1040_DMA_INTEN, 0x00);
DC395x_write8(acb, TRM_S1040_SCSI_INTEN, 0x00);
/** * adapter_init - Grab the resource for the card, setup the adapter * information, set the card into a known state, create the various * tables etc etc. This basically gets all adapter information all up * to date, initialised and gets the chip in sync with it. * * @acb: The adapter which we are to init. * @io_port: The base I/O port * @io_port_len: The I/O port size * @irq: IRQ * * Returns 0 if the initialization succeeds, any other value on * failure.
**/ staticint adapter_init(struct AdapterCtlBlk *acb, unsignedlong io_port,
u32 io_port_len, unsignedint irq)
{ if (!request_region(io_port, io_port_len, DC395X_NAME)) { goto failed;
} /* store port base to indicate we have registered it */
acb->io_port_base = io_port;
acb->io_port_len = io_port_len;
if (request_irq(irq, dc395x_interrupt, IRQF_SHARED, DC395X_NAME, acb)) { /* release the region we just claimed */ goto failed;
} /* store irq to indicate we have registered it */
acb->irq_level = irq;
/* get eeprom configuration information and command line settings etc */
check_eeprom(&acb->eeprom, io_port);
print_eeprom_settings(&acb->eeprom);
/* setup adapter control block */
adapter_init_params(acb);
if (adapter_sg_tables_alloc(acb)) { goto failed;
}
adapter_init_scsi_host(acb->scsi_host);
adapter_init_chip(acb);
set_basic_config(acb);
return 0;
failed: if (acb->irq_level)
free_irq(acb->irq_level, acb); if (acb->io_port_base)
release_region(acb->io_port_base, acb->io_port_len);
adapter_sg_tables_free(acb);
return 1;
}
/** * adapter_uninit_chip - cleanly shut down the scsi controller chip, * stopping all operations and disabling interrupt generation on the * card. * * @acb: The adapter which we are to shutdown.
**/ staticvoid adapter_uninit_chip(struct AdapterCtlBlk *acb)
{ /* disable interrupts */
DC395x_write8(acb, TRM_S1040_DMA_INTEN, 0);
DC395x_write8(acb, TRM_S1040_SCSI_INTEN, 0);
/* reset the scsi bus */ if (acb->config & HCC_SCSI_RESET)
reset_scsi_bus(acb);
/* clear any pending interrupt state */
DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS);
}
/** * adapter_uninit - Shut down the chip and release any resources that * we had allocated. Once this returns the adapter should not be used * anymore. * * @acb: The adapter which we are to un-initialize.
**/ staticvoid adapter_uninit(struct AdapterCtlBlk *acb)
{ unsignedlong flags;
DC395x_LOCK_IO(acb->scsi_host, flags);
/* remove timers */ if (timer_pending(&acb->waiting_timer))
timer_delete(&acb->waiting_timer); if (timer_pending(&acb->selto_timer))
timer_delete(&acb->selto_timer);
/** * dc395x_init_one - Initialise a single instance of the adapter. * * The PCI layer will call this once for each instance of the adapter * that it finds in the system. The pci_dev strcuture indicates which * instance we are being called from. * * @dev: The PCI device to initialize. * @id: Looks like a pointer to the entry in our pci device table * that was actually matched by the PCI subsystem. * * Returns 0 on success, or an error code (-ve) on failure.
**/ staticint dc395x_init_one(struct pci_dev *dev, conststruct pci_device_id *id)
{ struct Scsi_Host *scsi_host = NULL; struct AdapterCtlBlk *acb = NULL; unsignedlong io_port_base; unsignedint io_port_len; unsignedint irq;
fail: if (acb != NULL)
adapter_uninit(acb); if (scsi_host != NULL)
scsi_host_put(scsi_host);
pci_disable_device(dev); return -ENODEV;
}
/** * dc395x_remove_one - Called to remove a single instance of the * adapter. * * @dev: The PCI device to initialize.
**/ staticvoid dc395x_remove_one(struct pci_dev *dev)
{ struct Scsi_Host *scsi_host = pci_get_drvdata(dev); struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)(scsi_host->hostdata);
MODULE_AUTHOR("C.L. Huang / Erich Chen / Kurt Garloff");
MODULE_DESCRIPTION("SCSI host adapter driver for Tekram TRM-S1040 based adapters: Tekram DC395 and DC315 series");
MODULE_LICENSE("GPL");
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.54 Sekunden
(vorverarbeitet am 2026-04-26)
¤
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.