Commit 7934d2d8 authored by James Bottomley's avatar James Bottomley

Merge dj/hch fixes

parents 6bbb049e 6a50969a
......@@ -1325,9 +1325,9 @@ config SCSI_QLOGIC_FC_FIRMWARE
bool "Include loadable firmware in driver"
depends on SCSI_QLOGIC_FC
help
Say Y to include ISP2100 Fabric Initiator/Target Firmware, with
Say Y to include ISP2X00 Fabric Initiator/Target Firmware, with
expanded LUN addressing and FcTape (FCP-2) support, in the
Qlogic QLA 1280 driver. This is required on some platforms.
qlogicfc driver. This is required on some platforms.
config SCSI_QLOGIC_1280
tristate "Qlogic QLA 1280 SCSI support"
......
......@@ -120,13 +120,11 @@ obj-$(CONFIG_BLK_DEV_SD) += sd_mod.o
obj-$(CONFIG_BLK_DEV_SR) += sr_mod.o
obj-$(CONFIG_CHR_DEV_SG) += sg.o
scsi_mod-objs := scsi.o hosts.o scsi_ioctl.o constants.o scsicam.o \
scsi_error.o scsi_lib.o scsi_scan.o scsi_syms.o \
scsi_sysfs.o
ifdef CONFIG_PROC_FS
scsi_mod-objs += scsi_proc.o
endif
scsi_mod-y += scsi.o hosts.o scsi_ioctl.o constants.o \
scsicam.o scsi_error.o scsi_lib.o \
scsi_scan.o scsi_syms.o scsi_sysfs.o
scsi_mod-$(CONFIG_PROC_FS) += scsi_proc.o
scsi_mod-$(CONFIG_X86_PC9800) += scsi_pc98.o
sd_mod-objs := sd.o
sr_mod-objs := sr.o sr_ioctl.o sr_vendor.o
......
......@@ -60,7 +60,7 @@
#define AAC_DRIVERNAME "aacraid"
MODULE_AUTHOR("Red Hat Inc and Adaptec");
MODULE_DESCRIPTION("Supports Dell PERC2, 2/Si, 3/Si, 3/Di, Adaptec 2120S, 2200S, 5400S, and HP NetRAID-4M devices. http://domsch.com/linux/ or http://linux.adaptec.com");
MODULE_DESCRIPTION("Supports Dell PERC2, 2/Si, 3/Si, 3/Di, PERC 320/DC, Adaptec 2120S, 2200S, 5400S, and HP NetRAID-4M devices. http://domsch.com/linux/ or http://linux.adaptec.com");
MODULE_LICENSE("GPL");
MODULE_PARM(nondasd, "i");
MODULE_PARM_DESC(nondasd, "Control scanning of hba for nondasd devices. 0=off, 1=on");
......@@ -96,6 +96,7 @@ static struct aac_driver_ident aac_drivers[] = {
{ 0x9005, 0x0285, 0x9005, 0x0286, aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 2120S ", 1 }, /* Adaptec 2120S (Crusader)*/
{ 0x9005, 0x0285, 0x9005, 0x0285, aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 2200S ", 2 }, /* Adaptec 2200S (Vulcan)*/
{ 0x9005, 0x0285, 0x9005, 0x0287, aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 2200S ", 2 }, /* Adaptec 2200S (Vulcan-2m)*/
{ 0x9005, 0x0285, 0x1028, 0x0287, aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2 }, /* Dell PERC 320/DC */
{ 0x1011, 0x0046, 0x9005, 0x0365, aac_sa_init, "aacraid", "ADAPTEC ", "Adaptec 5400S ", 4 }, /* Adaptec 5400S (Mustang)*/
{ 0x1011, 0x0046, 0x9005, 0x0364, aac_sa_init, "aacraid", "ADAPTEC ", "AAC-364 ", 4 }, /* Adaptec 5400S (Mustang)*/
{ 0x1011, 0x0046, 0x9005, 0x1364, aac_sa_init, "percraid", "DELL ", "PERCRAID ", 4 }, /* Dell PERC2 "Quad Channel" */
......@@ -110,10 +111,10 @@ static int aac_cfg_open(struct inode * inode, struct file * file);
static int aac_cfg_release(struct inode * inode,struct file * file);
static struct file_operations aac_cfg_fops = {
owner: THIS_MODULE,
ioctl: aac_cfg_ioctl,
open: aac_cfg_open,
release: aac_cfg_release
.owner = THIS_MODULE,
.ioctl = aac_cfg_ioctl,
.open = aac_cfg_open,
.release = aac_cfg_release
};
static int aac_detect(Scsi_Host_Template *);
......
......@@ -2663,7 +2663,7 @@ static void datai_run(struct Scsi_Host *shpnt)
* STCNT to trigger ENSWRAP interrupt, instead of
* polling for DFIFOFULL
*/
the_time=jiffies + 10*HZ;
the_time=jiffies + 100*HZ;
while(TESTLO(DMASTAT, DFIFOFULL|INTSTAT) && time_before(jiffies,the_time))
barrier();
......@@ -2676,7 +2676,7 @@ static void datai_run(struct Scsi_Host *shpnt)
if(TESTHI(DMASTAT, DFIFOFULL)) {
fifodata = 128;
} else {
the_time=jiffies + 10*HZ;
the_time=jiffies + 100*HZ;
while(TESTLO(SSTAT2, SEMPTY) && time_before(jiffies,the_time))
barrier();
......@@ -2832,7 +2832,7 @@ static void datao_run(struct Scsi_Host *shpnt)
CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length;
}
the_time=jiffies + 10*HZ;
the_time=jiffies + 100*HZ;
while(TESTLO(DMASTAT, DFIFOEMP|INTSTAT) && time_before(jiffies,the_time))
barrier();
......
......@@ -86,7 +86,7 @@ static dpt_sig_S DPTI_sig = {
#elif defined(__alpha__)
PROC_ALPHA ,
#else
(-1),
(-1),(-1)
#endif
FT_HBADRVR, 0, OEM_DPT, OS_LINUX, CAP_OVERLAP, DEV_ALL,
ADF_ALL_SC5, 0, 0, DPT_VERSION, DPT_REVISION, DPT_SUBREVISION,
......@@ -1135,7 +1135,8 @@ static int adpt_i2o_post_wait(adpt_hba* pHba, u32* msg, int len, int timeout)
// to support async LCT get
wait_data->next = adpt_post_wait_queue;
adpt_post_wait_queue = wait_data;
adpt_post_wait_id = (++adpt_post_wait_id & 0x7fff);
adpt_post_wait_id++;
adpt_post_wait_id &= 0x7fff;
wait_data->id = adpt_post_wait_id;
spin_unlock_irqrestore(&adpt_post_wait_lock, flags);
......
......@@ -725,13 +725,13 @@ static int fdomain_isa_detect( int *irq, int *iobase )
switch (Quantum) {
case 2: /* ISA_200S */
case 3: /* ISA_250MG */
base = readb(bios_base + 0x1fa2) + (readb(bios_base + 0x1fa3) << 8);
base = isa_readb(bios_base + 0x1fa2) + (isa_readb(bios_base + 0x1fa3) << 8);
break;
case 4: /* ISA_200S (another one) */
base = readb(bios_base + 0x1fa3) + (readb(bios_base + 0x1fa4) << 8);
base = isa_readb(bios_base + 0x1fa3) + (isa_readb(bios_base + 0x1fa4) << 8);
break;
default:
base = readb(bios_base + 0x1fcc) + (readb(bios_base + 0x1fcd) << 8);
base = isa_readb(bios_base + 0x1fcc) + (isa_readb(bios_base + 0x1fcd) << 8);
break;
}
......@@ -1777,7 +1777,7 @@ static int fdomain_16x0_biosparam(struct scsi_device *sdev,
offset = bios_base + 0x1f31 + drive * 25;
break;
}
memcpy_fromio( &i, offset, sizeof( struct drive_info ) );
isa_memcpy_fromio( &i, offset, sizeof( struct drive_info ) );
info_array[0] = i.heads;
info_array[1] = i.sectors;
info_array[2] = i.cylinders;
......
......@@ -270,21 +270,6 @@ int scsi_remove_host(struct Scsi_Host *shost)
if (scsi_check_device_busy(sdev))
return 1;
/*
* Next we detach the high level drivers from the Scsi_Device
* structures
*/
list_for_each_entry(sdev, &shost->my_devices, siblings) {
scsi_detach_device(sdev);
/* If something still attached, punt */
if (sdev->attached) {
printk(KERN_ERR "Attached usage count = %d\n",
sdev->attached);
return 1;
}
}
scsi_forget_host(shost);
return 0;
}
......
......@@ -2,7 +2,7 @@
A driver for Future Domain-compatible PCMCIA SCSI cards
fdomain_cs.c 1.43 2000/06/12 21:27:25
fdomain_cs.c 1.47 2001/10/13 00:08:52
The contents of this file are subject to the Mozilla Public
License Version 1.1 (the "License"); you may not use this file
......@@ -19,8 +19,8 @@
are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
Alternatively, the contents of this file may be used under the
terms of the GNU General Public License version 2 (the "GPL"), in which
case the provisions of the GPL are applicable instead of the
terms of the GNU General Public License version 2 (the "GPL"), in
which case the provisions of the GPL are applicable instead of the
above. If you wish to allow the use of your version of this file
only under the terms of the GPL and not to allow others to use
your version of this file under the MPL, indicate your decision
......@@ -53,27 +53,30 @@
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
#ifdef PCMCIA_DEBUG
static int pc_debug = PCMCIA_DEBUG;
MODULE_PARM(pc_debug, "i");
#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
static char *version =
"fdomain_cs.c 1.43 2000/06/12 21:27:25 (David Hinds)";
#else
#define DEBUG(n, args...)
#endif
/*====================================================================*/
/* Parameters that can be set with 'insmod' */
/* Module parameters */
MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
MODULE_DESCRIPTION("Future Domain PCMCIA SCSI driver");
MODULE_LICENSE("Dual MPL/GPL");
#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
/* Bit map of interrupts to choose from */
static u_int irq_mask = 0xdeb8;
INT_MODULE_PARM(irq_mask, 0xdeb8);
static int irq_list[4] = { -1 };
MODULE_PARM(irq_mask, "i");
MODULE_PARM(irq_list, "1-4i");
#ifdef PCMCIA_DEBUG
INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
static char *version =
"fdomain_cs.c 1.47 2001/10/13 00:08:52 (David Hinds)";
#else
#define DEBUG(n, args...)
#endif
/*====================================================================*/
typedef struct scsi_info_t {
......@@ -213,6 +216,7 @@ static void fdomain_config(dev_link_t *link)
u_char tuple_data[64];
Scsi_Device *dev;
dev_node_t *node, **tail;
char str[16];
struct Scsi_Host *host;
DEBUG(0, "fdomain_config(0x%p)\n", link);
......@@ -253,7 +257,8 @@ static void fdomain_config(dev_link_t *link)
ints[0] = 2;
ints[1] = link->io.BasePort1;
ints[2] = link->irq.AssignedIRQ;
fdomain_setup("PCMCIA setup", ints);
sprintf(str, "%d,%d", link->io.BasePort1, link->irq.AssignedIRQ);
fdomain_setup(str, ints);
scsi_register_host(&driver_template);
......
......@@ -503,8 +503,9 @@ static inline void scsi_proc_host_rm(struct Scsi_Host *);
/*
* Prototypes for functions in scsi_scan.c
*/
extern int scsi_add_single_device(uint, uint, uint, uint);
extern int scsi_remove_single_device(uint, uint, uint, uint);
extern struct scsi_device *scsi_add_device(struct Scsi_Host *,
uint, uint, uint);
extern int scsi_remove_device(struct scsi_device *);
extern u64 scsi_calculate_bounce_limit(struct Scsi_Host *);
/*
......
/*
* Copyright (C) 2003 Osamu Tomita <tomita@cinet.co.jp>
*
* PC9801 BIOS geometry handling.
*/
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/genhd.h>
#include <linux/blk.h>
#include <asm/pc9800.h>
#include "scsi.h"
#include "hosts.h"
/* XXX - For now, we assume the first (i.e. having the least host_no)
real (i.e. non-emulated) host adapter shall be BIOS-controlled one.
We *SHOULD* invent another way. */
static inline struct Scsi_Host *first_real_host(void)
{
struct Scsi_Host *shost = NULL;
while ((shost = scsi_host_get_next(shost))) {
if (!shost->hostt->emulated)
break;
}
return shost;
}
static int pc98_first_bios_param(struct scsi_device *sdev, int *ip)
{
const u8 *p = (&__PC9800SCA(u8, PC9800SCA_SCSI_PARAMS) + sdev->id * 4);
ip[0] = p[1]; /* # of heads */
ip[1] = p[0]; /* # of sectors/track */
ip[2] = *(u16 *)&p[2] & 0x0fff; /* # of cylinders */
if (p[3] & (1 << 6)) { /* #-of-cylinders is 16-bit */
ip[2] |= (ip[0] & 0xf0) << 8;
ip[0] &= 0x0f;
}
return 0;
}
int pc98_bios_param(struct scsi_device *sdev, struct block_device *bdev,
sector_t capacity, int *ip)
{
static struct Scsi_Host *first_real = first_real_host();
if (sdev->host == first_real && sdev->id < 7 &&
__PC9800SCA_TEST_BIT(PC9800SCA_DISK_EQUIPS, sdev->id))
return pc98_first_bios_param(sdev, ip);
/* Assume PC-9801-92 compatible parameters for HAs without BIOS. */
ip[0] = 8;
ip[1] = 32;
ip[2] = capacity / (8 * 32);
if (ip[2] > 65535) { /* if capacity >= 8GB */
/* Recent on-board adapters seem to use this parameter. */
ip[1] = 128;
ip[2] = capacity / (8 * 128);
if (ip[2] > 65535) { /* if capacity >= 32GB */
/* Clip the number of cylinders. Currently
this is the limit that we deal with. */
ip[2] = 65535;
}
}
return 0;
}
EXPORT_SYMBOL(pc98_bios_param);
......@@ -398,6 +398,50 @@ static void scsi_dump_status(int level)
}
#endif /* CONFIG_SCSI_LOGGING */
static int scsi_add_single_device(uint host, uint channel, uint id, uint lun)
{
struct Scsi_Host *shost;
struct scsi_device *sdev;
int error = -ENODEV;
shost = scsi_host_hn_get(host);
if (!shost)
return -ENODEV;
if (!scsi_find_device(shost, channel, id, lun)) {
sdev = scsi_add_device(shost, channel, id, lun);
if (IS_ERR(sdev))
error = PTR_ERR(sdev);
else
error = 0;
}
scsi_host_put(shost);
return error;
}
static int scsi_remove_single_device(uint host, uint channel, uint id, uint lun)
{
struct scsi_device *sdev;
struct Scsi_Host *shost;
int error = -ENODEV;
shost = scsi_host_hn_get(host);
if (!shost)
return -ENODEV;
sdev = scsi_find_device(shost, channel, id, lun);
if (!sdev)
goto out;
if (sdev->access_count)
goto out;
error = scsi_remove_device(sdev);
out:
scsi_host_put(shost);
return error;
}
static int proc_scsi_gen_write(struct file * file, const char * buf,
unsigned long length, void *data)
{
......
......@@ -189,6 +189,8 @@ struct dev_info scsi_static_device_list[] __initdata = {
{"HITACHI", "DF500", "*", BLIST_SPARSELUN},
{"HITACHI", "DF600", "*", BLIST_SPARSELUN},
{"IBM", "ProFibre 4000R", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
{"SUN", "T300", "*", BLIST_SPARSELUN},
{"SUN", "T4", "*", BLIST_SPARSELUN},
{ NULL, NULL, NULL, 0 },
};
......@@ -1259,14 +1261,6 @@ static int scsi_add_lun(Scsi_Device *sdev, Scsi_Request *sreq,
return SCSI_SCAN_LUN_PRESENT;
}
static void scsi_remove_lun(struct scsi_device *sdev)
{
devfs_unregister(sdev->de);
scsi_device_unregister(sdev);
scsi_free_sdev(sdev);
}
/**
* scsi_probe_and_add_lun - probe a LUN, if a LUN is found add it
* @sdevscan: probe the LUN corresponding to this Scsi_Device
......@@ -1284,45 +1278,33 @@ static void scsi_remove_lun(struct scsi_device *sdev)
* SCSI_SCAN_LUN_PRESENT: a new Scsi_Device was allocated and initialized
**/
static int scsi_probe_and_add_lun(struct Scsi_Host *host,
struct request_queue **q, uint channel, uint id,
uint lun, int *bflagsp)
struct request_queue **q, uint channel, uint id, uint lun,
int *bflagsp, struct scsi_device **sdevp)
{
Scsi_Device *sdev = NULL;
Scsi_Request *sreq = NULL;
unsigned char *scsi_result = NULL;
int bflags;
int res;
struct scsi_device *sdev;
struct scsi_request *sreq;
unsigned char *result;
int bflags, res = SCSI_SCAN_NO_RESPONSE;
sdev = scsi_alloc_sdev(host, q, channel, id, lun);
if (sdev == NULL)
return SCSI_SCAN_NO_RESPONSE;
if (!sdev)
goto out;
sreq = scsi_allocate_request(sdev);
if (sreq == NULL) {
printk(ALLOC_FAILURE_MSG, __FUNCTION__);
res = SCSI_SCAN_NO_RESPONSE;
goto bail_out;
}
/*
* The sreq is for use only with sdevscan.
*/
scsi_result = kmalloc(256, GFP_ATOMIC |
(host->unchecked_isa_dma) ?
GFP_DMA : 0);
if (scsi_result == NULL) {
printk(ALLOC_FAILURE_MSG, __FUNCTION__);
res = SCSI_SCAN_NO_RESPONSE;
goto bail_out;
}
scsi_probe_lun(sreq, scsi_result, &bflags);
if (!sreq)
goto out_free_sdev;
result = kmalloc(256, GFP_ATOMIC |
(host->unchecked_isa_dma) ? __GFP_DMA : 0);
if (!result)
goto out_free_sreq;
scsi_probe_lun(sreq, result, &bflags);
if (sreq->sr_result)
res = SCSI_SCAN_NO_RESPONSE;
else {
goto out_free_result;
/*
* scsi_result contains valid SCSI INQUIRY data.
* result contains valid SCSI INQUIRY data.
*/
if ((scsi_result[0] >> 5) == 3) {
if ((result[0] >> 5) == 3) {
/*
* For a Peripheral qualifier 3 (011b), the SCSI
* spec says: The device server is not capable of
......@@ -1337,37 +1319,36 @@ static int scsi_probe_and_add_lun(struct Scsi_Host *host,
"scsi scan: peripheral qualifier of 3,"
" no device added\n"));
res = SCSI_SCAN_TARGET_PRESENT;
} else {
res = scsi_add_lun(sdev, sreq, scsi_result, &bflags);
goto out_free_result;
}
res = scsi_add_lun(sdev, sreq, result, &bflags);
if (res == SCSI_SCAN_LUN_PRESENT) {
if ((bflags & BLIST_KEY) != 0) {
if (bflags & BLIST_KEY) {
sdev->lockable = 0;
scsi_unlock_floptical(sreq,
scsi_result);
/*
* scsi_result no longer contains
* the INQUIRY data.
*/
scsi_unlock_floptical(sreq, result);
}
if (bflagsp != NULL)
if (bflagsp)
*bflagsp = bflags;
}
}
}
bail_out:
if (scsi_result != NULL)
kfree(scsi_result);
if (sreq != NULL)
out_free_result:
kfree(result);
out_free_sreq:
scsi_release_request(sreq);
if (res != SCSI_SCAN_LUN_PRESENT) {
if(q) {
out_free_sdev:
if (res == SCSI_SCAN_LUN_PRESENT) {
if (*sdevp)
*sdevp = sdev;
} else {
if (q) {
*q = sdev->request_queue;
sdev->request_queue = NULL;
}
scsi_free_sdev(sdev);
}
out:
return res;
}
/**
......@@ -1453,8 +1434,8 @@ static void scsi_sequential_lun_scan(struct Scsi_Host *shost,
* sparse_lun.
*/
for (lun = 1; lun < max_dev_lun; ++lun)
if ((scsi_probe_and_add_lun(shost, q, channel, id, lun, NULL)
!= SCSI_SCAN_LUN_PRESENT) && !sparse_lun)
if ((scsi_probe_and_add_lun(shost, q, channel, id, lun,
NULL, NULL) != SCSI_SCAN_LUN_PRESENT) && !sparse_lun)
return;
}
......@@ -1669,7 +1650,7 @@ static int scsi_report_lun_scan(Scsi_Device *sdev, struct request_queue **q,
int res;
res = scsi_probe_and_add_lun(sdev->host, q,
sdev->channel, sdev->id, lun, NULL);
sdev->channel, sdev->id, lun, NULL, NULL);
if (res == SCSI_SCAN_NO_RESPONSE) {
/*
* Got some results, but now none, abort.
......@@ -1691,55 +1672,33 @@ static int scsi_report_lun_scan(Scsi_Device *sdev, struct request_queue **q,
}
int scsi_add_single_device(uint host, uint channel, uint id, uint lun)
struct scsi_device *scsi_add_device(struct Scsi_Host *shost,
uint channel, uint id, uint lun)
{
struct Scsi_Host *shost;
int error = -ENODEV;
struct scsi_device *sdev;
int error = -ENODEV, res;
shost = scsi_host_hn_get(host);
if (!shost)
return -ENODEV;
if(scsi_find_device(shost, channel, id, lun) != NULL)
goto out;
res = scsi_probe_and_add_lun(shost, NULL, channel, id, lun,
NULL, &sdev);
if (res == SCSI_SCAN_LUN_PRESENT)
error = scsi_attach_device(sdev);
if (scsi_probe_and_add_lun(shost, NULL, channel, id, lun, NULL) ==
SCSI_SCAN_LUN_PRESENT) {
error = 0;
sdev = scsi_find_device(shost, channel, id, lun);
scsi_attach_device(sdev);
}
out:
scsi_host_put(shost);
return error;
if (error)
sdev = ERR_PTR(error);
return sdev;
}
int scsi_remove_single_device(uint host, uint channel, uint id, uint lun)
int scsi_remove_device(struct scsi_device *sdev)
{
struct scsi_device *sdev;
struct Scsi_Host *shost;
int error = -ENODEV;
shost = scsi_host_hn_get(host);
if (!shost)
return -ENODEV;
sdev = scsi_find_device(shost, channel, id, lun);
if (!sdev)
goto out;
error = -EBUSY;
if (sdev->access_count)
goto out;
scsi_detach_device(sdev);
if (sdev->attached)
goto out;
return -EINVAL;
scsi_remove_lun(sdev);
error = 0;
devfs_unregister(sdev->de);
scsi_device_unregister(sdev);
out:
scsi_host_put(shost);
return error;
scsi_free_sdev(sdev);
return 0;
}
/**
......@@ -1778,9 +1737,8 @@ static void scsi_scan_target(struct Scsi_Host *shost, struct request_queue **q,
* Scan LUN 0, if there is some response, scan further. Ideally, we
* would not configure LUN 0 until all LUNs are scanned.
*/
res = scsi_probe_and_add_lun(shost, q, channel, id, 0, &bflags);
res = scsi_probe_and_add_lun(shost, q, channel, id, 0, &bflags, &sdev);
if (res == SCSI_SCAN_LUN_PRESENT) {
sdev = scsi_find_device(shost, channel, id, 0);
if (scsi_report_lun_scan(sdev, q, bflags) != 0)
/*
* The REPORT LUN did not scan the target,
......@@ -1846,9 +1804,13 @@ void scsi_scan_host(struct Scsi_Host *shost)
void scsi_forget_host(struct Scsi_Host *shost)
{
struct list_head *le, *lh;
struct scsi_device *sdev;
list_for_each_safe(le, lh, &shost->my_devices) {
sdev = list_entry(le, struct scsi_device, siblings);
list_for_each_safe(le, lh, &shost->my_devices)
scsi_remove_lun(list_entry(le, struct scsi_device, siblings));
scsi_remove_device(sdev);
}
}
/*
......
......@@ -78,6 +78,8 @@ EXPORT_SYMBOL(scsi_slave_attach);
EXPORT_SYMBOL(scsi_slave_detach);
EXPORT_SYMBOL(scsi_device_get);
EXPORT_SYMBOL(scsi_device_put);
EXPORT_SYMBOL(scsi_add_device);
EXPORT_SYMBOL(scsi_remove_device);
EXPORT_SYMBOL(scsi_set_device_offline);
/*
......
......@@ -4,10 +4,13 @@
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
* 1999 Andrew R. Baker (andrewb@uab.edu)
* - Support for 2nd SCSI controller on Indigo2
* 2001 Florian Lohoff (flo@rfc822.org)
* - Delete HPC scatter gather (Read corruption on
* multiple disks)
* - Cleanup wback cache handling
*
* (In all truth, Jed Schimmel wrote all this code.)
*
* $Id: sgiwd93.c,v 1.19 2000/02/04 07:40:47 ralf Exp $
*/
#include <linux/init.h>
#include <linux/types.h>
......@@ -36,32 +39,13 @@
struct hpc_chunk {
struct hpc_dma_desc desc;
unsigned long padding;
u32 _padding; /* align to quadword boundary */
};
struct Scsi_Host *sgiwd93_host = NULL;
struct Scsi_Host *sgiwd93_host1 = NULL;
/* Wuff wuff, wuff, wd33c93.c, wuff wuff, object oriented, bow wow. */
static inline void write_wd33c93_count(const wd33c93_regs regs,
unsigned long value)
{
*regs.SASR = WD_TRANSFER_COUNT_MSB;
*regs.SCMD = ((value >> 16) & 0xff);
*regs.SCMD = ((value >> 8) & 0xff);
*regs.SCMD = ((value >> 0) & 0xff);
}
static inline unsigned long read_wd33c93_count(const wd33c93_regs regs)
{
unsigned long value;
*regs.SASR = WD_TRANSFER_COUNT_MSB;
value = (*regs.SCMD << 16);
value |= (*regs.SCMD << 8);
value |= (*regs.SCMD << 0);
return value;
}
/* XXX woof! */
static void sgiwd93_intr(int irq, void *dev_id, struct pt_regs *regs)
......@@ -82,7 +66,6 @@ void fill_hpc_entries (struct hpc_chunk **hcp, char *addr, unsigned long len)
unsigned long physaddr;
unsigned long count;
dma_cache_wback_inv((unsigned long)addr,len);
physaddr = PHYSADDR(addr);
while (len) {
/*
......@@ -101,7 +84,6 @@ void fill_hpc_entries (struct hpc_chunk **hcp, char *addr, unsigned long len)
static int dma_setup(Scsi_Cmnd *cmd, int datainp)
{
struct WD33C93_hostdata *hdata = (struct WD33C93_hostdata *)cmd->host->hostdata;
const wd33c93_regs regs = hdata->regs;
struct hpc3_scsiregs *hregs = (struct hpc3_scsiregs *) cmd->host->base;
struct hpc_chunk *hcp = (struct hpc_chunk *) hdata->dma_bounce_buffer;
......@@ -112,34 +94,6 @@ static int dma_setup(Scsi_Cmnd *cmd, int datainp)
hdata->dma_dir = datainp;
if(cmd->SCp.buffers_residual) {
struct scatterlist *slp = cmd->SCp.buffer;
int i, totlen = 0;
#ifdef DEBUG_DMA
printk("SCLIST<");
#endif
for(i = 0; i <= cmd->SCp.buffers_residual; i++) {
#ifdef DEBUG_DMA
printk("[%p,%d]",
page_address(slp[i].page) + slp[i].offset,
slp[i].length);
#endif
fill_hpc_entries (&hcp,
page_address(slp[i].page) + slp[i].offset,
slp[i].length);
totlen += slp[i].length;
}
#ifdef DEBUG_DMA
printk(">tlen<%d>", totlen);
#endif
hdata->dma_bounce_len = totlen; /* a trick... */
write_wd33c93_count(regs, totlen);
} else {
/* Non-scattered dma. */
#ifdef DEBUG_DMA
printk("ONEBUF<%p,%d>", cmd->SCp.ptr, cmd->SCp.this_residual);
#endif
/*
* wd33c93 shouldn't pass us bogus dma_setups, but
* it does:-( The other wd33c93 drivers deal with
......@@ -149,9 +103,8 @@ static int dma_setup(Scsi_Cmnd *cmd, int datainp)
*/
if (cmd->SCp.ptr == NULL)
return 1;
fill_hpc_entries (&hcp, cmd->SCp.ptr,cmd->SCp.this_residual);
write_wd33c93_count(regs, cmd->SCp.this_residual);
}
/* To make sure, if we trip an HPC bug, that we transfer
* every single byte, we tag on an extra zero length dma
......@@ -166,10 +119,14 @@ static int dma_setup(Scsi_Cmnd *cmd, int datainp)
/* Start up the HPC. */
hregs->ndptr = PHYSADDR(hdata->dma_bounce_buffer);
if(datainp)
if(datainp) {
dma_cache_inv((unsigned long) cmd->SCp.ptr, cmd->SCp.this_residual);
hregs->ctrl = (HPC3_SCTRL_ACTIVE);
else
} else {
dma_cache_wback_inv((unsigned long) cmd->SCp.ptr, cmd->SCp.this_residual);
hregs->ctrl = (HPC3_SCTRL_ACTIVE | HPC3_SCTRL_DIR);
}
return 0;
}
......@@ -177,7 +134,6 @@ static void dma_stop(struct Scsi_Host *instance, Scsi_Cmnd *SCpnt,
int status)
{
struct WD33C93_hostdata *hdata = (struct WD33C93_hostdata *)instance->hostdata;
const wd33c93_regs regs = hdata->regs;
struct hpc3_scsiregs *hregs;
if (!SCpnt)
......@@ -197,44 +153,6 @@ static void dma_stop(struct Scsi_Host *instance, Scsi_Cmnd *SCpnt,
}
hregs->ctrl = 0;
/* See how far we got and update scatterlist state if necessary. */
if(SCpnt->SCp.buffers_residual) {
struct scatterlist *slp = SCpnt->SCp.buffer;
int totlen, wd93_residual, transferred, i;
/* Yep, we were doing the scatterlist thang. */
totlen = hdata->dma_bounce_len;
wd93_residual = read_wd33c93_count(regs);
transferred = totlen - wd93_residual;
#ifdef DEBUG_DMA
printk("tlen<%d>resid<%d>transf<%d> ",
totlen, wd93_residual, transferred);
#endif
/* Avoid long winded partial-transfer search for common case. */
if(transferred != totlen) {
/* This is the nut case. */
#ifdef DEBUG_DMA
printk("Jed was here...");
#endif
for(i = 0; i <= SCpnt->SCp.buffers_residual; i++) {
if(slp[i].length >= transferred)
break;
transferred -= slp[i].length;
}
} else {
/* This is the common case. */
#ifdef DEBUG_DMA
printk("did it all...");
#endif
i = SCpnt->SCp.buffers_residual;
}
SCpnt->SCp.buffer = &slp[i];
SCpnt->SCp.buffers_residual = SCpnt->SCp.buffers_residual - i;
SCpnt->SCp.ptr = (char *) page_address(slp[i].page) + slp[i].offset;
SCpnt->SCp.this_residual = slp[i].length;
}
#ifdef DEBUG_DMA
printk("\n");
#endif
......@@ -264,6 +182,9 @@ static inline void init_hpc_chain(uchar *buf)
};
hcp--;
hcp->desc.pnext = PHYSADDR(buf);
/* Force flush to memory */
dma_cache_wback_inv((unsigned long) buf, PAGE_SIZE);
}
int __init sgiwd93_detect(Scsi_Host_Template *SGIblows)
......@@ -273,8 +194,8 @@ int __init sgiwd93_detect(Scsi_Host_Template *SGIblows)
struct hpc3_scsiregs *hregs1 = &hpc3c0->scsi_chan1;
struct WD33C93_hostdata *hdata;
struct WD33C93_hostdata *hdata1;
uchar *buf;
wd33c93_regs regs;
uchar *buf;
if(called)
return 0; /* Should bitch on the console about this... */
......@@ -294,10 +215,10 @@ int __init sgiwd93_detect(Scsi_Host_Template *SGIblows)
return 0;
}
init_hpc_chain(buf);
dma_cache_wback_inv((unsigned long) buf, PAGE_SIZE);
/* HPC_SCSI_REG0 | 0x03 | KSEG1 */
regs.SASR = (volatile unsigned char *)KSEG1ADDR (0x1fbc0003);
regs.SCMD = (volatile unsigned char *)KSEG1ADDR (0x1fbc0007);
regs.SASR = (unsigned char*) KSEG1ADDR (0x1fbc0003);
regs.SCMD = (unsigned char*) KSEG1ADDR (0x1fbc0007);
wd33c93_init(sgiwd93_host, regs, dma_setup, dma_stop, WD33C93_FS_16_20);
hdata = (struct WD33C93_hostdata *)sgiwd93_host->hostdata;
......@@ -329,17 +250,16 @@ int __init sgiwd93_detect(Scsi_Host_Template *SGIblows)
return 1; /* We registered host0 so return success*/
}
init_hpc_chain(buf);
dma_cache_wback_inv((unsigned long) buf, PAGE_SIZE);
/* HPC_SCSI_REG1 | 0x03 | KSEG1 */
regs.SASR = (volatile unsigned char *)KSEG1ADDR (0x1fbc8003);
regs.SCMD = (volatile unsigned char *)KSEG1ADDR (0x1fbc8007);
regs.SASR = (unsigned char*) KSEG1ADDR(0x1fbc8003);
regs.SCMD = (unsigned char*) KSEG1ADDR(0x1fbc8007);
wd33c93_init(sgiwd93_host1, regs, dma_setup, dma_stop,
WD33C93_FS_16_20);
hdata1 = (struct WD33C93_hostdata *)sgiwd93_host1->hostdata;
hdata1->no_sync = 0;
hdata1->dma_bounce_buffer = (uchar *) (KSEG1ADDR(buf));
dma_cache_wback_inv((unsigned long) buf, PAGE_SIZE);
if (request_irq(SGI_WD93_1_IRQ, sgiwd93_intr, 0, "SGI WD93", (void *) sgiwd93_host1)) {
printk(KERN_WARNING "sgiwd93: Could not allocate irq %d (for host1).\n", SGI_WD93_1_IRQ);
......
......@@ -543,7 +543,7 @@ static int sun3scsi_dma_finish(int write_flag)
#if 1
// check to empty the fifo on a read
if(!write_flag) {
int tmo = 200000; /* 2 sec */
int tmo = 20000; /* .2 sec */
while(1) {
if(dregs->csr & CSR_FIFO_EMPTY)
......
......@@ -6984,7 +6984,7 @@ static void ncr_soft_reset(ncb_p np)
INW (nc_sist);
}
else if (istat & DIP) {
if (INB (nc_dstat) & ABRT);
if (INB (nc_dstat) & ABRT)
break;
}
UDELAY(5);
......
......@@ -125,7 +125,7 @@ void sym_mdelay(int ms) { mdelay(ms); }
*
* The whole SCSI sub-system under Linux is basically single-threaded.
* Everything, including low-level driver interrupt routine, happens
* whith the `io_request_lock' held.
* with the `io_request_lock' held.
* The sym53c8xx-1.x drivers series ran their interrupt code using a
* spin mutex per controller. This added complexity without improving
* scalability significantly. the sym-2 driver still use a spinlock
......
......@@ -234,7 +234,7 @@ static void sym_soft_reset (hcb_p np)
INW (nc_sist);
}
else if (istat & DIP) {
if (INB (nc_dstat) & ABRT);
if (INB (nc_dstat) & ABRT)
break;
}
UDELAY(5);
......
/*
* wd33c93.c - Linux-68k device driver for the Commodore
* Amiga A2091/590 SCSI controller card
*
* Copyright (c) 1996 John Shifflett, GeoLog Consulting
* john@geolog.com
* jshiffle@netcom.com
......@@ -15,8 +12,9 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
*/
/*
* Drew Eckhardt's excellent 'Generic NCR5380' sources from Linux-PC
* provided much of the inspiration and some of the code for this
* driver. Everything I know about Amiga DMA was gleaned from careful
......@@ -76,38 +74,26 @@
#include <linux/config.h>
#include <linux/module.h>
#include <asm/system.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/delay.h>
#include <linux/version.h>
#include <linux/init.h>
#include <asm/irq.h>
#include <linux/blk.h>
#include <asm/irq.h>
#include "scsi.h"
#include "hosts.h"
#define WD33C93_VERSION "1.25"
#define WD33C93_DATE "09/Jul/1997"
/* NOTE: 1.25 for m68k is related to in2000-1.31 for x86 */
/*
* Note - the following defines have been moved to 'wd33c93.h':
*
* PROC_INTERFACE
* PROC_STATISTICS
* SYNC_DEBUG
* DEBUGGING_ON
* DEBUG_DEFAULTS
*
*/
#include "wd33c93.h"
#define WD33C93_VERSION "1.26"
#define WD33C93_DATE "22/Feb/2003"
MODULE_AUTHOR("John Shifflett");
MODULE_DESCRIPTION("Generic WD33C93 SCSI driver");
MODULE_LICENSE("GPL");
/*
* 'setup_strings' is a single string used to pass operating parameters and
......@@ -163,65 +149,111 @@
*/
/* Normally, no defaults are specified */
static char *setup_args[] =
{"","","","","","","","",""};
static char *setup_args[] = { "", "", "", "", "", "", "", "", "" };
/* filled in by 'insmod' */
static char *setup_strings = 0;
#ifdef MODULE_PARM
static char *setup_strings;
MODULE_PARM(setup_strings, "s");
#endif
static void wd33c93_execute(struct Scsi_Host *instance);
#ifdef CONFIG_WD33C93_PIO
static inline uchar
read_wd33c93(const wd33c93_regs regs, uchar reg_num)
{
uchar data;
outb(reg_num, *regs.SASR);
data = inb(*regs.SCMD);
return data;
}
static inline uchar read_wd33c93(const wd33c93_regs regs, uchar reg_num)
static inline unsigned long
read_wd33c93_count(const wd33c93_regs regs)
{
*regs.SASR = reg_num;
mb();
return(*regs.SCMD);
unsigned long value;
outb(WD_TRANSFER_COUNT_MSB, *regs.SASR);
value = inb(*regs.SCMD) << 16;
value |= inb(*regs.SCMD) << 8;
value |= inb(*regs.SCMD);
return value;
}
static inline uchar
read_aux_stat(const wd33c93_regs regs)
{
return inb(*regs.SASR);
}
#define READ_AUX_STAT() (*regs.SASR)
static inline void
write_wd33c93(const wd33c93_regs regs, uchar reg_num, uchar value)
{
outb(reg_num, *regs.SASR);
outb(value, *regs.SCMD);
}
static inline void
write_wd33c93_count(const wd33c93_regs regs, unsigned long value)
{
outb(WD_TRANSFER_COUNT_MSB, *regs.SASR);
outb((value >> 16) & 0xff, *regs.SCMD);
outb((value >> 8) & 0xff, *regs.SCMD);
outb( value & 0xff, *regs.SCMD);
}
#define write_wd33c93_cmd(regs, cmd) \
write_wd33c93((regs), WD_COMMAND, (cmd))
static inline void write_wd33c93(const wd33c93_regs regs, uchar reg_num,
uchar value)
static inline void
write_wd33c93_cdb(const wd33c93_regs regs, uint len, uchar cmnd[])
{
int i;
outb(WD_CDB_1, *regs.SASR);
for (i=0; i<len; i++)
outb(cmnd[i], *regs.SCMD);
}
#else /* CONFIG_WD33C93_PIO */
static inline uchar
read_wd33c93(const wd33c93_regs regs, uchar reg_num)
{
*regs.SASR = reg_num;
mb();
*regs.SCMD = value;
mb();
return (*regs.SCMD);
}
static inline void write_wd33c93_cmd(const wd33c93_regs regs, uchar cmd)
static unsigned long
read_wd33c93_count(const wd33c93_regs regs)
{
*regs.SASR = WD_COMMAND;
unsigned long value;
*regs.SASR = WD_TRANSFER_COUNT_MSB;
mb();
*regs.SCMD = cmd;
value = *regs.SCMD << 16;
value |= *regs.SCMD << 8;
value |= *regs.SCMD;
mb();
return value;
}
static inline uchar read_1_byte(const wd33c93_regs regs)
static inline uchar
read_aux_stat(const wd33c93_regs regs)
{
uchar asr;
uchar x = 0;
write_wd33c93(regs, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
write_wd33c93_cmd(regs, WD_CMD_TRANS_INFO|0x80);
do {
asr = READ_AUX_STAT();
if (asr & ASR_DBR)
x = read_wd33c93(regs, WD_DATA);
} while (!(asr & ASR_INT));
return x;
return *regs.SASR;
}
static inline void
write_wd33c93(const wd33c93_regs regs, uchar reg_num, uchar value)
{
*regs.SASR = reg_num;
mb();
*regs.SCMD = value;
mb();
}
static void write_wd33c93_count(const wd33c93_regs regs, unsigned long value)
static void
write_wd33c93_count(const wd33c93_regs regs, unsigned long value)
{
*regs.SASR = WD_TRANSFER_COUNT_MSB;
mb();
......@@ -231,101 +263,106 @@ static void write_wd33c93_count(const wd33c93_regs regs, unsigned long value)
mb();
}
static unsigned long read_wd33c93_count(const wd33c93_regs regs)
static inline void
write_wd33c93_cmd(const wd33c93_regs regs, uchar cmd)
{
unsigned long value;
*regs.SASR = WD_TRANSFER_COUNT_MSB;
*regs.SASR = WD_COMMAND;
mb();
value = *regs.SCMD << 16;
value |= *regs.SCMD << 8;
value |= *regs.SCMD;
*regs.SCMD = cmd;
mb();
return value;
}
static inline void
write_wd33c93_cdb(const wd33c93_regs regs, uint len, uchar cmnd[])
{
int i;
*regs.SASR = WD_CDB_1;
for (i = 0; i < len; i++)
*regs.SCMD = cmnd[i];
}
#endif /* CONFIG_WD33C93_PIO */
static inline uchar
read_1_byte(const wd33c93_regs regs)
{
uchar asr;
uchar x = 0;
write_wd33c93(regs, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
write_wd33c93_cmd(regs, WD_CMD_TRANS_INFO | 0x80);
do {
asr = read_aux_stat(regs);
if (asr & ASR_DBR)
x = read_wd33c93(regs, WD_DATA);
} while (!(asr & ASR_INT));
return x;
}
/* The 33c93 needs to be told which direction a command transfers its
* data; we use this function to figure it out. Returns true if there
* will be a DATA_OUT phase with this command, false otherwise.
* (Thanks to Joerg Dorchain for the research and suggestion.)
*/
static int is_dir_out(Scsi_Cmnd *cmd)
static inline int
is_dir_out(Scsi_Cmnd * cmd)
{
switch (cmd->cmnd[0]) {
case WRITE_6: case WRITE_10: case WRITE_12:
case WRITE_LONG: case WRITE_SAME: case WRITE_BUFFER:
case WRITE_VERIFY: case WRITE_VERIFY_12:
case COMPARE: case COPY: case COPY_VERIFY:
case SEARCH_EQUAL: case SEARCH_HIGH: case SEARCH_LOW:
case SEARCH_EQUAL_12: case SEARCH_HIGH_12: case SEARCH_LOW_12:
case FORMAT_UNIT: case REASSIGN_BLOCKS: case RESERVE:
case MODE_SELECT: case MODE_SELECT_10: case LOG_SELECT:
case SEND_DIAGNOSTIC: case CHANGE_DEFINITION: case UPDATE_BLOCK:
case SET_WINDOW: case MEDIUM_SCAN: case SEND_VOLUME_TAG:
case 0xea:
return 1;
default:
return 0;
}
return cmd->sc_data_direction == SCSI_DATA_WRITE;
}
static struct sx_period sx_table[] = {
{ 1, 0x20},
{1, 0x20},
{252, 0x20},
{376, 0x30},
{500, 0x40},
{624, 0x50},
{752, 0x60},
{876, 0x70},
{1000,0x00},
{0, 0} };
{1000, 0x00},
{0, 0}
};
static int round_period(unsigned int period)
static int
round_period(unsigned int period)
{
int x;
int x;
for (x=1; sx_table[x].period_ns; x++) {
if ((period <= sx_table[x-0].period_ns) &&
(period > sx_table[x-1].period_ns)) {
for (x = 1; sx_table[x].period_ns; x++) {
if ((period <= sx_table[x - 0].period_ns) &&
(period > sx_table[x - 1].period_ns)) {
return x;
}
}
return 7;
}
static uchar calc_sync_xfer(unsigned int period, unsigned int offset)
static uchar
calc_sync_xfer(unsigned int period, unsigned int offset)
{
uchar result;
uchar result;
period *= 4; /* convert SDTR code to ns */
result = sx_table[round_period(period)].reg_value;
result |= (offset < OPTIMUM_SX_OFF)?offset:OPTIMUM_SX_OFF;
result |= (offset < OPTIMUM_SX_OFF) ? offset : OPTIMUM_SX_OFF;
return result;
}
static void wd33c93_execute(struct Scsi_Host *instance);
int wd33c93_queuecommand (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
int
wd33c93_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
{
struct WD33C93_hostdata *hostdata;
Scsi_Cmnd *tmp;
hostdata = (struct WD33C93_hostdata *)cmd->host->hostdata;
hostdata = (struct WD33C93_hostdata *) cmd->device->host->hostdata;
DB(DB_QUEUE_COMMAND,printk("Q-%d-%02x-%ld( ",cmd->target,cmd->cmnd[0],cmd->pid))
DB(DB_QUEUE_COMMAND,
printk("Q-%d-%02x-%ld( ", cmd->device->id, cmd->cmnd[0], cmd->pid))
/* Set up a few fields in the Scsi_Cmnd structure for our own use:
* - host_scribble is the pointer to the next cmd in the input queue
* - scsi_done points to the routine we call when a cmd is finished
* - result is what you'd expect
*/
cmd->host_scribble = NULL;
cmd->scsi_done = done;
cmd->result = 0;
......@@ -346,16 +383,15 @@ DB(DB_QUEUE_COMMAND,printk("Q-%d-%02x-%ld( ",cmd->target,cmd->cmnd[0],cmd->pid))
*/
if (cmd->use_sg) {
cmd->SCp.buffer = (struct scatterlist *)cmd->buffer;
cmd->SCp.buffer = (struct scatterlist *) cmd->buffer;
cmd->SCp.buffers_residual = cmd->use_sg - 1;
cmd->SCp.ptr = page_address(cmd->SCp.buffer->page)+
cmd->SCp.ptr = page_address(cmd->SCp.buffer->page) +
cmd->SCp.buffer->offset;
cmd->SCp.this_residual = cmd->SCp.buffer->length;
}
else {
} else {
cmd->SCp.buffer = NULL;
cmd->SCp.buffers_residual = 0;
cmd->SCp.ptr = (char *)cmd->request_buffer;
cmd->SCp.ptr = (char *) cmd->request_buffer;
cmd->SCp.this_residual = cmd->request_bufflen;
}
......@@ -387,30 +423,26 @@ DB(DB_QUEUE_COMMAND,printk("Q-%d-%02x-%ld( ",cmd->target,cmd->cmnd[0],cmd->pid))
spin_lock_irq(&hostdata->lock);
if (!(hostdata->input_Q) || (cmd->cmnd[0] == REQUEST_SENSE)) {
cmd->host_scribble = (uchar *)hostdata->input_Q;
cmd->host_scribble = (uchar *) hostdata->input_Q;
hostdata->input_Q = cmd;
}
else { /* find the end of the queue */
for (tmp=(Scsi_Cmnd *)hostdata->input_Q; tmp->host_scribble;
tmp=(Scsi_Cmnd *)tmp->host_scribble)
;
tmp->host_scribble = (uchar *)cmd;
} else { /* find the end of the queue */
for (tmp = (Scsi_Cmnd *) hostdata->input_Q; tmp->host_scribble;
tmp = (Scsi_Cmnd *) tmp->host_scribble) ;
tmp->host_scribble = (uchar *) cmd;
}
/* We know that there's at least one command in 'input_Q' now.
* Go see if any of them are runnable!
*/
wd33c93_execute(cmd->host);
wd33c93_execute(cmd->device->host);
DB(DB_QUEUE_COMMAND,printk(")Q-%ld ",cmd->pid))
DB(DB_QUEUE_COMMAND, printk(")Q-%ld ", cmd->pid))
spin_unlock_irq(&hostdata->lock);
return 0;
}
/*
* This routine attempts to start a scsi command. If the host_card is
* already connected, we give up immediately. Otherwise, look through
......@@ -421,19 +453,17 @@ DB(DB_QUEUE_COMMAND,printk(")Q-%ld ",cmd->pid))
* the wd33c93_intr itself, which means that a wd33c93 interrupt
* cannot occur while we are in here.
*/
static void wd33c93_execute (struct Scsi_Host *instance)
static void
wd33c93_execute(struct Scsi_Host *instance)
{
struct WD33C93_hostdata *hostdata = (struct WD33C93_hostdata *)instance->hostdata;
const wd33c93_regs regs = hostdata->regs;
Scsi_Cmnd *cmd, *prev;
int i;
DB(DB_EXECUTE,printk("EX("))
struct WD33C93_hostdata *hostdata =
(struct WD33C93_hostdata *) instance->hostdata;
const wd33c93_regs regs = hostdata->regs;
Scsi_Cmnd *cmd, *prev;
DB(DB_EXECUTE, printk("EX("))
if (hostdata->selecting || hostdata->connected) {
DB(DB_EXECUTE,printk(")EX-0 "))
DB(DB_EXECUTE, printk(")EX-0 "))
return;
}
......@@ -442,21 +472,19 @@ DB(DB_EXECUTE,printk(")EX-0 "))
* for an idle target/lun.
*/
cmd = (Scsi_Cmnd *)hostdata->input_Q;
cmd = (Scsi_Cmnd *) hostdata->input_Q;
prev = 0;
while (cmd) {
if (!(hostdata->busy[cmd->target] & (1 << cmd->lun)))
if (!(hostdata->busy[cmd->device->id] & (1 << cmd->device->lun)))
break;
prev = cmd;
cmd = (Scsi_Cmnd *)cmd->host_scribble;
cmd = (Scsi_Cmnd *) cmd->host_scribble;
}
/* quit if queue empty or all possible targets are busy */
if (!cmd) {
DB(DB_EXECUTE,printk(")EX-1 "))
DB(DB_EXECUTE, printk(")EX-1 "))
return;
}
......@@ -465,10 +493,10 @@ DB(DB_EXECUTE,printk(")EX-1 "))
if (prev)
prev->host_scribble = cmd->host_scribble;
else
hostdata->input_Q = (Scsi_Cmnd *)cmd->host_scribble;
hostdata->input_Q = (Scsi_Cmnd *) cmd->host_scribble;
#ifdef PROC_STATISTICS
hostdata->cmd_cnt[cmd->target]++;
hostdata->cmd_cnt[cmd->device->id]++;
#endif
/*
......@@ -476,9 +504,9 @@ DB(DB_EXECUTE,printk(")EX-1 "))
*/
if (is_dir_out(cmd))
write_wd33c93(regs, WD_DESTINATION_ID, cmd->target);
write_wd33c93(regs, WD_DESTINATION_ID, cmd->device->id);
else
write_wd33c93(regs, WD_DESTINATION_ID, cmd->target | DSTID_DPD);
write_wd33c93(regs, WD_DESTINATION_ID, cmd->device->id | DSTID_DPD);
/* Now we need to figure out whether or not this command is a good
* candidate for disconnect/reselect. We guess to the best of our
......@@ -514,34 +542,37 @@ DB(DB_EXECUTE,printk(")EX-1 "))
goto yes;
if (!(hostdata->input_Q)) /* input_Q empty? */
goto no;
for (prev=(Scsi_Cmnd *)hostdata->input_Q; prev;
prev=(Scsi_Cmnd *)prev->host_scribble) {
if ((prev->target != cmd->target) || (prev->lun != cmd->lun)) {
for (prev=(Scsi_Cmnd *)hostdata->input_Q; prev;
prev=(Scsi_Cmnd *)prev->host_scribble)
for (prev = (Scsi_Cmnd *) hostdata->input_Q; prev;
prev = (Scsi_Cmnd *) prev->host_scribble) {
if ((prev->device->id != cmd->device->id) ||
(prev->device->lun != cmd->device->lun)) {
for (prev = (Scsi_Cmnd *) hostdata->input_Q; prev;
prev = (Scsi_Cmnd *) prev->host_scribble)
prev->SCp.phase = 1;
goto yes;
}
}
goto no;
yes:
yes:
cmd->SCp.phase = 1;
#ifdef PROC_STATISTICS
hostdata->disc_allowed_cnt[cmd->target]++;
hostdata->disc_allowed_cnt[cmd->device->id]++;
#endif
no:
no:
write_wd33c93(regs, WD_SOURCE_ID, ((cmd->SCp.phase)?SRCID_ER:0));
write_wd33c93(regs, WD_SOURCE_ID, ((cmd->SCp.phase) ? SRCID_ER : 0));
write_wd33c93(regs, WD_TARGET_LUN, cmd->lun);
write_wd33c93(regs, WD_SYNCHRONOUS_TRANSFER,hostdata->sync_xfer[cmd->target]);
hostdata->busy[cmd->target] |= (1 << cmd->lun);
write_wd33c93(regs, WD_TARGET_LUN, cmd->device->lun);
write_wd33c93(regs, WD_SYNCHRONOUS_TRANSFER,
hostdata->sync_xfer[cmd->device->id]);
hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
if ((hostdata->level2 == L2_NONE) ||
(hostdata->sync_stat[cmd->target] == SS_UNSET)) {
(hostdata->sync_stat[cmd->device->id] == SS_UNSET)) {
/*
* Do a 'Select-With-ATN' command. This will end with
......@@ -565,14 +596,12 @@ DB(DB_EXECUTE,printk(")EX-1 "))
* later, but at that time we'll negotiate for async by specifying a
* sync fifo depth of 0.
*/
if (hostdata->sync_stat[cmd->target] == SS_UNSET)
hostdata->sync_stat[cmd->target] = SS_FIRST;
if (hostdata->sync_stat[cmd->device->id] == SS_UNSET)
hostdata->sync_stat[cmd->device->id] = SS_FIRST;
hostdata->state = S_SELECTING;
write_wd33c93_count(regs, 0); /* guarantee a DATA_PHASE interrupt */
write_wd33c93_cmd(regs, WD_CMD_SEL_ATN);
}
else {
} else {
/*
* Do a 'Select-With-ATN-Xfer' command. This will end with
......@@ -589,9 +618,7 @@ DB(DB_EXECUTE,printk(")EX-1 "))
* (take advantage of auto-incrementing)
*/
*regs.SASR = WD_CDB_1;
for (i=0; i<cmd->cmd_len; i++)
*regs.SCMD = cmd->cmnd[i];
write_wd33c93_cdb(regs, cmd->cmd_len, cmd->cmnd);
/* The wd33c93 only knows about Group 0, 1, and 5 commands when
* it's doing a 'select-and-transfer'. To be safe, we write the
......@@ -608,15 +635,17 @@ DB(DB_EXECUTE,printk(")EX-1 "))
if ((cmd->SCp.phase == 0) && (hostdata->no_dma == 0)) {
if (hostdata->dma_setup(cmd,
(is_dir_out(cmd))?DATA_OUT_DIR:DATA_IN_DIR))
(is_dir_out(cmd)) ? DATA_OUT_DIR
: DATA_IN_DIR))
write_wd33c93_count(regs, 0); /* guarantee a DATA_PHASE interrupt */
else {
write_wd33c93_count(regs, cmd->SCp.this_residual);
write_wd33c93(regs, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_DMA);
write_wd33c93_count(regs,
cmd->SCp.this_residual);
write_wd33c93(regs, WD_CONTROL,
CTRL_IDI | CTRL_EDI | CTRL_DMA);
hostdata->dma = D_DMA_RUNNING;
}
}
else
} else
write_wd33c93_count(regs, 0); /* guarantee a DATA_PHASE interrupt */
hostdata->state = S_RUNNING_LEVEL2;
......@@ -630,31 +659,31 @@ DB(DB_EXECUTE,printk(")EX-1 "))
* to search the input_Q again...
*/
DB(DB_EXECUTE,printk("%s%ld)EX-2 ",(cmd->SCp.phase)?"d:":"",cmd->pid))
DB(DB_EXECUTE,
printk("%s%ld)EX-2 ", (cmd->SCp.phase) ? "d:" : "", cmd->pid))
}
static void transfer_pio(const wd33c93_regs regs, uchar *buf, int cnt,
static void
transfer_pio(const wd33c93_regs regs, uchar * buf, int cnt,
int data_in_dir, struct WD33C93_hostdata *hostdata)
{
uchar asr;
uchar asr;
DB(DB_TRANSFER,printk("(%p,%d,%s:",buf,cnt,data_in_dir?"in":"out"))
DB(DB_TRANSFER,
printk("(%p,%d,%s:", buf, cnt, data_in_dir ? "in" : "out"))
write_wd33c93(regs, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
write_wd33c93_count(regs, cnt);
write_wd33c93_cmd(regs, WD_CMD_TRANS_INFO);
if (data_in_dir) {
do {
asr = READ_AUX_STAT();
asr = read_aux_stat(regs);
if (asr & ASR_DBR)
*buf++ = read_wd33c93(regs, WD_DATA);
} while (!(asr & ASR_INT));
}
else {
} else {
do {
asr = READ_AUX_STAT();
asr = read_aux_stat(regs);
if (asr & ASR_DBR)
write_wd33c93(regs, WD_DATA, *buf++);
} while (!(asr & ASR_INT));
......@@ -669,15 +698,13 @@ DB(DB_TRANSFER,printk("(%p,%d,%s:",buf,cnt,data_in_dir?"in":"out"))
}
static void transfer_bytes(const wd33c93_regs regs, Scsi_Cmnd *cmd,
int data_in_dir)
static void
transfer_bytes(const wd33c93_regs regs, Scsi_Cmnd * cmd, int data_in_dir)
{
struct WD33C93_hostdata *hostdata;
unsigned long length;
struct WD33C93_hostdata *hostdata;
unsigned long length;
hostdata = (struct WD33C93_hostdata *)cmd->host->hostdata;
hostdata = (struct WD33C93_hostdata *) cmd->device->host->hostdata;
/* Normally, you'd expect 'this_residual' to be non-zero here.
* In a series of scatter-gather transfers, however, this
......@@ -691,30 +718,23 @@ unsigned long length;
++cmd->SCp.buffer;
--cmd->SCp.buffers_residual;
cmd->SCp.this_residual = cmd->SCp.buffer->length;
cmd->SCp.ptr = page_address(cmd->SCp.buffer->page)+
cmd->SCp.ptr = page_address(cmd->SCp.buffer->page) +
cmd->SCp.buffer->offset;
}
write_wd33c93(regs, WD_SYNCHRONOUS_TRANSFER,hostdata->sync_xfer[cmd->target]);
write_wd33c93(regs, WD_SYNCHRONOUS_TRANSFER,
hostdata->sync_xfer[cmd->device->id]);
/* 'hostdata->no_dma' is TRUE if we don't even want to try DMA.
* Update 'this_residual' and 'ptr' after 'transfer_pio()' returns.
*/
if (hostdata->no_dma)
goto use_transfer_pio;
/* 'dma_setup()' will return TRUE if we can't do DMA.
* Update 'this_residual' and 'ptr' after 'transfer_pio()' returns.
*/
else if (hostdata->dma_setup(cmd, data_in_dir)) {
use_transfer_pio:
if (hostdata->no_dma || hostdata->dma_setup(cmd, data_in_dir)) {
#ifdef PROC_STATISTICS
hostdata->pio_cnt++;
#endif
transfer_pio(regs, (uchar *)cmd->SCp.ptr, cmd->SCp.this_residual,
data_in_dir, hostdata);
transfer_pio(regs, (uchar *) cmd->SCp.ptr,
cmd->SCp.this_residual, data_in_dir, hostdata);
length = cmd->SCp.this_residual;
cmd->SCp.this_residual = read_wd33c93_count(regs);
cmd->SCp.ptr += (length - cmd->SCp.this_residual);
......@@ -741,25 +761,24 @@ unsigned long length;
write_wd33c93(regs, WD_COMMAND_PHASE, 0x45);
write_wd33c93_cmd(regs, WD_CMD_SEL_ATN_XFER);
hostdata->state = S_RUNNING_LEVEL2;
}
else
} else
write_wd33c93_cmd(regs, WD_CMD_TRANS_INFO);
hostdata->dma = D_DMA_RUNNING;
}
}
void wd33c93_intr (struct Scsi_Host *instance)
void
wd33c93_intr(struct Scsi_Host *instance)
{
struct WD33C93_hostdata *hostdata = (struct WD33C93_hostdata *)instance->hostdata;
const wd33c93_regs regs = hostdata->regs;
Scsi_Cmnd *patch, *cmd;
uchar asr, sr, phs, id, lun, *ucp, msg;
unsigned long length, flags;
asr = READ_AUX_STAT();
struct WD33C93_hostdata *hostdata =
(struct WD33C93_hostdata *) instance->hostdata;
const wd33c93_regs regs = hostdata->regs;
Scsi_Cmnd *patch, *cmd;
uchar asr, sr, phs, id, lun, *ucp, msg;
unsigned long length, flags;
asr = read_aux_stat(regs);
if (!(asr & ASR_INT) || (asr & ASR_BSY))
return;
......@@ -769,11 +788,11 @@ unsigned long length, flags;
hostdata->int_cnt++;
#endif
cmd = (Scsi_Cmnd *)hostdata->connected; /* assume we're connected */
cmd = (Scsi_Cmnd *) hostdata->connected; /* assume we're connected */
sr = read_wd33c93(regs, WD_SCSI_STATUS); /* clear the interrupt */
phs = read_wd33c93(regs, WD_COMMAND_PHASE);
DB(DB_INTR,printk("{%02x:%02x-",asr,sr))
DB(DB_INTR, printk("{%02x:%02x-", asr, sr))
/* After starting a DMA transfer, the next interrupt
* is guaranteed to be in response to completion of
......@@ -789,33 +808,32 @@ DB(DB_INTR,printk("{%02x:%02x-",asr,sr))
* whatever is needed, we go on and service the WD3393
* interrupt normally.
*/
if (hostdata->dma == D_DMA_RUNNING) {
DB(DB_TRANSFER,printk("[%p/%d:",cmd->SCp.ptr,cmd->SCp.this_residual))
hostdata->dma_stop(cmd->host, cmd, 1);
DB(DB_TRANSFER,
printk("[%p/%d:", cmd->SCp.ptr, cmd->SCp.this_residual))
hostdata->dma_stop(cmd->device->host, cmd, 1);
hostdata->dma = D_DMA_OFF;
length = cmd->SCp.this_residual;
cmd->SCp.this_residual = read_wd33c93_count(regs);
cmd->SCp.ptr += (length - cmd->SCp.this_residual);
DB(DB_TRANSFER,printk("%p/%d]",cmd->SCp.ptr,cmd->SCp.this_residual))
DB(DB_TRANSFER,
printk("%p/%d]", cmd->SCp.ptr, cmd->SCp.this_residual))
}
/* Respond to the specific WD3393 interrupt - there are quite a few! */
switch (sr) {
case CSR_TIMEOUT:
DB(DB_INTR,printk("TIMEOUT"))
DB(DB_INTR, printk("TIMEOUT"))
if (hostdata->state == S_RUNNING_LEVEL2)
hostdata->connected = NULL;
else {
cmd = (Scsi_Cmnd *)hostdata->selecting; /* get a valid cmd */
cmd = (Scsi_Cmnd *) hostdata->selecting; /* get a valid cmd */
hostdata->selecting = NULL;
}
cmd->result = DID_NO_CONNECT << 16;
hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
hostdata->state = S_UNCONNECTED;
cmd->scsi_done(cmd);
......@@ -838,27 +856,26 @@ DB(DB_INTR,printk("TIMEOUT"))
wd33c93_execute(instance);
break;
/* Note: this interrupt should not occur in a LEVEL2 command */
case CSR_SELECT:
DB(DB_INTR,printk("SELECT"))
hostdata->connected = cmd = (Scsi_Cmnd *)hostdata->selecting;
DB(DB_INTR, printk("SELECT"))
hostdata->connected = cmd =
(Scsi_Cmnd *) hostdata->selecting;
hostdata->selecting = NULL;
/* construct an IDENTIFY message with correct disconnect bit */
hostdata->outgoing_msg[0] = (0x80 | 0x00 | cmd->lun);
hostdata->outgoing_msg[0] = (0x80 | 0x00 | cmd->device->lun);
if (cmd->SCp.phase)
hostdata->outgoing_msg[0] |= 0x40;
if (hostdata->sync_stat[cmd->target] == SS_FIRST) {
if (hostdata->sync_stat[cmd->device->id] == SS_FIRST) {
#ifdef SYNC_DEBUG
printk(" sending SDTR ");
printk(" sending SDTR ");
#endif
hostdata->sync_stat[cmd->target] = SS_WAITING;
hostdata->sync_stat[cmd->device->id] = SS_WAITING;
/* Tack on a 2nd message to ask about synchronous transfers. If we've
* been asked to do only asynchronous transfers on this device, we
......@@ -869,82 +886,79 @@ printk(" sending SDTR ");
hostdata->outgoing_msg[1] = EXTENDED_MESSAGE;
hostdata->outgoing_msg[2] = 3;
hostdata->outgoing_msg[3] = EXTENDED_SDTR;
if (hostdata->no_sync & (1 << cmd->target)) {
hostdata->outgoing_msg[4] = hostdata->default_sx_per/4;
if (hostdata->no_sync & (1 << cmd->device->id)) {
hostdata->outgoing_msg[4] =
hostdata->default_sx_per / 4;
hostdata->outgoing_msg[5] = 0;
}
else {
hostdata->outgoing_msg[4] = OPTIMUM_SX_PER/4;
} else {
hostdata->outgoing_msg[4] = OPTIMUM_SX_PER / 4;
hostdata->outgoing_msg[5] = OPTIMUM_SX_OFF;
}
hostdata->outgoing_len = 6;
}
else
} else
hostdata->outgoing_len = 1;
hostdata->state = S_CONNECTED;
spin_unlock_irqrestore(&hostdata->lock, flags);
break;
case CSR_XFER_DONE|PHS_DATA_IN:
case CSR_UNEXP |PHS_DATA_IN:
case CSR_SRV_REQ |PHS_DATA_IN:
DB(DB_INTR,printk("IN-%d.%d",cmd->SCp.this_residual,cmd->SCp.buffers_residual))
case CSR_XFER_DONE | PHS_DATA_IN:
case CSR_UNEXP | PHS_DATA_IN:
case CSR_SRV_REQ | PHS_DATA_IN:
DB(DB_INTR,
printk("IN-%d.%d", cmd->SCp.this_residual,
cmd->SCp.buffers_residual))
transfer_bytes(regs, cmd, DATA_IN_DIR);
if (hostdata->state != S_RUNNING_LEVEL2)
hostdata->state = S_CONNECTED;
spin_unlock_irqrestore(&hostdata->lock, flags);
break;
case CSR_XFER_DONE|PHS_DATA_OUT:
case CSR_UNEXP |PHS_DATA_OUT:
case CSR_SRV_REQ |PHS_DATA_OUT:
DB(DB_INTR,printk("OUT-%d.%d",cmd->SCp.this_residual,cmd->SCp.buffers_residual))
case CSR_XFER_DONE | PHS_DATA_OUT:
case CSR_UNEXP | PHS_DATA_OUT:
case CSR_SRV_REQ | PHS_DATA_OUT:
DB(DB_INTR,
printk("OUT-%d.%d", cmd->SCp.this_residual,
cmd->SCp.buffers_residual))
transfer_bytes(regs, cmd, DATA_OUT_DIR);
if (hostdata->state != S_RUNNING_LEVEL2)
hostdata->state = S_CONNECTED;
spin_unlock_irqrestore(&hostdata->lock, flags);
break;
/* Note: this interrupt should not occur in a LEVEL2 command */
case CSR_XFER_DONE|PHS_COMMAND:
case CSR_UNEXP |PHS_COMMAND:
case CSR_SRV_REQ |PHS_COMMAND:
DB(DB_INTR,printk("CMND-%02x,%ld",cmd->cmnd[0],cmd->pid))
transfer_pio(regs, cmd->cmnd, cmd->cmd_len, DATA_OUT_DIR, hostdata);
case CSR_XFER_DONE | PHS_COMMAND:
case CSR_UNEXP | PHS_COMMAND:
case CSR_SRV_REQ | PHS_COMMAND:
DB(DB_INTR, printk("CMND-%02x,%ld", cmd->cmnd[0], cmd->pid))
transfer_pio(regs, cmd->cmnd, cmd->cmd_len, DATA_OUT_DIR,
hostdata);
hostdata->state = S_CONNECTED;
spin_unlock_irqrestore(&hostdata->lock, flags);
break;
case CSR_XFER_DONE|PHS_STATUS:
case CSR_UNEXP |PHS_STATUS:
case CSR_SRV_REQ |PHS_STATUS:
DB(DB_INTR,printk("STATUS="))
case CSR_XFER_DONE | PHS_STATUS:
case CSR_UNEXP | PHS_STATUS:
case CSR_SRV_REQ | PHS_STATUS:
DB(DB_INTR, printk("STATUS="))
cmd->SCp.Status = read_1_byte(regs);
DB(DB_INTR,printk("%02x",cmd->SCp.Status))
DB(DB_INTR, printk("%02x", cmd->SCp.Status))
if (hostdata->level2 >= L2_BASIC) {
sr = read_wd33c93(regs, WD_SCSI_STATUS); /* clear interrupt */
hostdata->state = S_RUNNING_LEVEL2;
write_wd33c93(regs, WD_COMMAND_PHASE, 0x50);
write_wd33c93_cmd(regs, WD_CMD_SEL_ATN_XFER);
}
else {
} else {
hostdata->state = S_CONNECTED;
}
spin_unlock_irqrestore(&hostdata->lock, flags);
break;
case CSR_XFER_DONE|PHS_MESS_IN:
case CSR_UNEXP |PHS_MESS_IN:
case CSR_SRV_REQ |PHS_MESS_IN:
DB(DB_INTR,printk("MSG_IN="))
case CSR_XFER_DONE | PHS_MESS_IN:
case CSR_UNEXP | PHS_MESS_IN:
case CSR_SRV_REQ | PHS_MESS_IN:
DB(DB_INTR, printk("MSG_IN="))
msg = read_1_byte(regs);
sr = read_wd33c93(regs, WD_SCSI_STATUS); /* clear interrupt */
......@@ -959,55 +973,54 @@ DB(DB_INTR,printk("MSG_IN="))
switch (msg) {
case COMMAND_COMPLETE:
DB(DB_INTR,printk("CCMP-%ld",cmd->pid))
DB(DB_INTR, printk("CCMP-%ld", cmd->pid))
write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK);
hostdata->state = S_PRE_CMP_DISC;
break;
case SAVE_POINTERS:
DB(DB_INTR,printk("SDP"))
DB(DB_INTR, printk("SDP"))
write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK);
hostdata->state = S_CONNECTED;
break;
case RESTORE_POINTERS:
DB(DB_INTR,printk("RDP"))
DB(DB_INTR, printk("RDP"))
if (hostdata->level2 >= L2_BASIC) {
write_wd33c93(regs, WD_COMMAND_PHASE, 0x45);
write_wd33c93_cmd(regs, WD_CMD_SEL_ATN_XFER);
hostdata->state = S_RUNNING_LEVEL2;
}
else {
} else {
write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK);
hostdata->state = S_CONNECTED;
}
break;
case DISCONNECT:
DB(DB_INTR,printk("DIS"))
DB(DB_INTR, printk("DIS"))
cmd->device->disconnect = 1;
write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK);
hostdata->state = S_PRE_TMP_DISC;
break;
case MESSAGE_REJECT:
DB(DB_INTR,printk("REJ"))
DB(DB_INTR, printk("REJ"))
#ifdef SYNC_DEBUG
printk("-REJ-");
printk("-REJ-");
#endif
if (hostdata->sync_stat[cmd->target] == SS_WAITING)
hostdata->sync_stat[cmd->target] = SS_SET;
if (hostdata->sync_stat[cmd->device->id] == SS_WAITING)
hostdata->sync_stat[cmd->device->id] = SS_SET;
write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK);
hostdata->state = S_CONNECTED;
break;
case EXTENDED_MESSAGE:
DB(DB_INTR,printk("EXT"))
DB(DB_INTR, printk("EXT"))
ucp = hostdata->incoming_msg;
#ifdef SYNC_DEBUG
printk("%02x",ucp[hostdata->incoming_ptr]);
printk("%02x", ucp[hostdata->incoming_ptr]);
#endif
/* Is this the last byte of the extended message? */
......@@ -1016,8 +1029,9 @@ printk("%02x",ucp[hostdata->incoming_ptr]);
switch (ucp[2]) { /* what's the EXTENDED code? */
case EXTENDED_SDTR:
id = calc_sync_xfer(ucp[3],ucp[4]);
if (hostdata->sync_stat[cmd->target] != SS_WAITING) {
id = calc_sync_xfer(ucp[3], ucp[4]);
if (hostdata->sync_stat[cmd->device->id] !=
SS_WAITING) {
/* A device has sent an unsolicited SDTR message; rather than go
* through the effort of decoding it and then figuring out what
......@@ -1029,42 +1043,57 @@ printk("%02x",ucp[hostdata->incoming_ptr]);
*/
write_wd33c93_cmd(regs, WD_CMD_ASSERT_ATN); /* want MESS_OUT */
hostdata->outgoing_msg[0] = EXTENDED_MESSAGE;
hostdata->outgoing_msg[0] =
EXTENDED_MESSAGE;
hostdata->outgoing_msg[1] = 3;
hostdata->outgoing_msg[2] = EXTENDED_SDTR;
hostdata->outgoing_msg[3] = hostdata->default_sx_per/4;
hostdata->outgoing_msg[2] =
EXTENDED_SDTR;
hostdata->outgoing_msg[3] =
hostdata->default_sx_per /
4;
hostdata->outgoing_msg[4] = 0;
hostdata->outgoing_len = 5;
hostdata->sync_xfer[cmd->target] =
calc_sync_xfer(hostdata->default_sx_per/4,0);
}
else {
hostdata->sync_xfer[cmd->target] = id;
hostdata->sync_xfer[cmd->device->id] =
calc_sync_xfer(hostdata->
default_sx_per
/ 4, 0);
} else {
hostdata->sync_xfer[cmd->device->id] = id;
}
#ifdef SYNC_DEBUG
printk("sync_xfer=%02x",hostdata->sync_xfer[cmd->target]);
printk("sync_xfer=%02x",
hostdata->sync_xfer[cmd->device->id]);
#endif
hostdata->sync_stat[cmd->target] = SS_SET;
write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK);
hostdata->sync_stat[cmd->device->id] =
SS_SET;
write_wd33c93_cmd(regs,
WD_CMD_NEGATE_ACK);
hostdata->state = S_CONNECTED;
break;
case EXTENDED_WDTR:
write_wd33c93_cmd(regs, WD_CMD_ASSERT_ATN); /* want MESS_OUT */
printk("sending WDTR ");
hostdata->outgoing_msg[0] = EXTENDED_MESSAGE;
hostdata->outgoing_msg[0] =
EXTENDED_MESSAGE;
hostdata->outgoing_msg[1] = 2;
hostdata->outgoing_msg[2] = EXTENDED_WDTR;
hostdata->outgoing_msg[2] =
EXTENDED_WDTR;
hostdata->outgoing_msg[3] = 0; /* 8 bit transfer width */
hostdata->outgoing_len = 4;
write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK);
write_wd33c93_cmd(regs,
WD_CMD_NEGATE_ACK);
hostdata->state = S_CONNECTED;
break;
default:
write_wd33c93_cmd(regs, WD_CMD_ASSERT_ATN); /* want MESS_OUT */
printk("Rejecting Unknown Extended Message(%02x). ",ucp[2]);
hostdata->outgoing_msg[0] = MESSAGE_REJECT;
printk
("Rejecting Unknown Extended Message(%02x). ",
ucp[2]);
hostdata->outgoing_msg[0] =
MESSAGE_REJECT;
hostdata->outgoing_len = 1;
write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK);
write_wd33c93_cmd(regs,
WD_CMD_NEGATE_ACK);
hostdata->state = S_CONNECTED;
break;
}
......@@ -1081,7 +1110,7 @@ printk("sync_xfer=%02x",hostdata->sync_xfer[cmd->target]);
break;
default:
printk("Rejecting Unknown Message(%02x) ",msg);
printk("Rejecting Unknown Message(%02x) ", msg);
write_wd33c93_cmd(regs, WD_CMD_ASSERT_ATN); /* want MESS_OUT */
hostdata->outgoing_msg[0] = MESSAGE_REJECT;
hostdata->outgoing_len = 1;
......@@ -1091,7 +1120,6 @@ printk("sync_xfer=%02x",hostdata->sync_xfer[cmd->target]);
spin_unlock_irqrestore(&hostdata->lock, flags);
break;
/* Note: this interrupt will occur only after a LEVEL2 command */
case CSR_SEL_XFER_DONE:
......@@ -1102,19 +1130,23 @@ printk("sync_xfer=%02x",hostdata->sync_xfer[cmd->target]);
write_wd33c93(regs, WD_SOURCE_ID, SRCID_ER);
if (phs == 0x60) {
DB(DB_INTR,printk("SX-DONE-%ld",cmd->pid))
DB(DB_INTR, printk("SX-DONE-%ld", cmd->pid))
cmd->SCp.Message = COMMAND_COMPLETE;
lun = read_wd33c93(regs, WD_TARGET_LUN);
DB(DB_INTR,printk(":%d.%d",cmd->SCp.Status,lun))
DB(DB_INTR, printk(":%d.%d", cmd->SCp.Status, lun))
hostdata->connected = NULL;
hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
hostdata->state = S_UNCONNECTED;
if (cmd->SCp.Status == ILLEGAL_STATUS_BYTE)
cmd->SCp.Status = lun;
if (cmd->cmnd[0] == REQUEST_SENSE && cmd->SCp.Status != GOOD)
cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
if (cmd->cmnd[0] == REQUEST_SENSE
&& cmd->SCp.Status != GOOD)
cmd->result =
(cmd->
result & 0x00ffff) | (DID_ERROR << 16);
else
cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
cmd->result =
cmd->SCp.Status | (cmd->SCp.Message << 8);
cmd->scsi_done(cmd);
/* We are no longer connected to a target - check to see if
......@@ -1122,29 +1154,28 @@ DB(DB_INTR,printk(":%d.%d",cmd->SCp.Status,lun))
*/
spin_unlock_irqrestore(&hostdata->lock, flags);
wd33c93_execute(instance);
}
else {
printk("%02x:%02x:%02x-%ld: Unknown SEL_XFER_DONE phase!!---",asr,sr,phs,cmd->pid);
} else {
printk
("%02x:%02x:%02x-%ld: Unknown SEL_XFER_DONE phase!!---",
asr, sr, phs, cmd->pid);
spin_unlock_irqrestore(&hostdata->lock, flags);
}
break;
/* Note: this interrupt will occur only after a LEVEL2 command */
case CSR_SDP:
DB(DB_INTR,printk("SDP"))
DB(DB_INTR, printk("SDP"))
hostdata->state = S_RUNNING_LEVEL2;
write_wd33c93(regs, WD_COMMAND_PHASE, 0x41);
write_wd33c93_cmd(regs, WD_CMD_SEL_ATN_XFER);
spin_unlock_irqrestore(&hostdata->lock, flags);
break;
case CSR_XFER_DONE|PHS_MESS_OUT:
case CSR_UNEXP |PHS_MESS_OUT:
case CSR_SRV_REQ |PHS_MESS_OUT:
DB(DB_INTR,printk("MSG_OUT="))
case CSR_XFER_DONE | PHS_MESS_OUT:
case CSR_UNEXP | PHS_MESS_OUT:
case CSR_SRV_REQ | PHS_MESS_OUT:
DB(DB_INTR, printk("MSG_OUT="))
/* To get here, we've probably requested MESSAGE_OUT and have
* already put the correct bytes in outgoing_msg[] and filled
......@@ -1158,20 +1189,18 @@ DB(DB_INTR,printk("MSG_OUT="))
* NOP messages in these situations results in no harm and
* makes everyone happy.
*/
if (hostdata->outgoing_len == 0) {
hostdata->outgoing_len = 1;
hostdata->outgoing_msg[0] = NOP;
}
transfer_pio(regs, hostdata->outgoing_msg, hostdata->outgoing_len,
DATA_OUT_DIR, hostdata);
DB(DB_INTR,printk("%02x",hostdata->outgoing_msg[0]))
transfer_pio(regs, hostdata->outgoing_msg,
hostdata->outgoing_len, DATA_OUT_DIR, hostdata);
DB(DB_INTR, printk("%02x", hostdata->outgoing_msg[0]))
hostdata->outgoing_len = 0;
hostdata->state = S_CONNECTED;
spin_unlock_irqrestore(&hostdata->lock, flags);
break;
case CSR_UNEXP_DISC:
/* I think I've seen this after a request-sense that was in response
......@@ -1193,12 +1222,13 @@ DB(DB_INTR,printk("%02x",hostdata->outgoing_msg[0]))
spin_unlock_irqrestore(&hostdata->lock, flags);
return;
}
DB(DB_INTR,printk("UNEXP_DISC-%ld",cmd->pid))
DB(DB_INTR, printk("UNEXP_DISC-%ld", cmd->pid))
hostdata->connected = NULL;
hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
hostdata->state = S_UNCONNECTED;
if (cmd->cmnd[0] == REQUEST_SENSE && cmd->SCp.Status != GOOD)
cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
cmd->result =
(cmd->result & 0x00ffff) | (DID_ERROR << 16);
else
cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
cmd->scsi_done(cmd);
......@@ -1211,7 +1241,6 @@ DB(DB_INTR,printk("UNEXP_DISC-%ld",cmd->pid))
wd33c93_execute(instance);
break;
case CSR_DISC:
/* Make sure that reselection is enabled at this point - it may
......@@ -1219,7 +1248,7 @@ DB(DB_INTR,printk("UNEXP_DISC-%ld",cmd->pid))
*/
write_wd33c93(regs, WD_SOURCE_ID, SRCID_ER);
DB(DB_INTR,printk("DISC-%ld",cmd->pid))
DB(DB_INTR, printk("DISC-%ld", cmd->pid))
if (cmd == NULL) {
printk(" - Already disconnected! ");
hostdata->state = S_UNCONNECTED;
......@@ -1227,24 +1256,28 @@ DB(DB_INTR,printk("DISC-%ld",cmd->pid))
switch (hostdata->state) {
case S_PRE_CMP_DISC:
hostdata->connected = NULL;
hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
hostdata->state = S_UNCONNECTED;
DB(DB_INTR,printk(":%d",cmd->SCp.Status))
if (cmd->cmnd[0] == REQUEST_SENSE && cmd->SCp.Status != GOOD)
cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
DB(DB_INTR, printk(":%d", cmd->SCp.Status))
if (cmd->cmnd[0] == REQUEST_SENSE
&& cmd->SCp.Status != GOOD)
cmd->result =
(cmd->
result & 0x00ffff) | (DID_ERROR << 16);
else
cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
cmd->result =
cmd->SCp.Status | (cmd->SCp.Message << 8);
cmd->scsi_done(cmd);
break;
case S_PRE_TMP_DISC:
case S_RUNNING_LEVEL2:
cmd->host_scribble = (uchar *)hostdata->disconnected_Q;
cmd->host_scribble = (uchar *) hostdata->disconnected_Q;
hostdata->disconnected_Q = cmd;
hostdata->connected = NULL;
hostdata->state = S_UNCONNECTED;
#ifdef PROC_STATISTICS
hostdata->disc_done_cnt[cmd->target]++;
hostdata->disc_done_cnt[cmd->device->id]++;
#endif
break;
......@@ -1260,10 +1293,9 @@ DB(DB_INTR,printk(":%d",cmd->SCp.Status))
wd33c93_execute(instance);
break;
case CSR_RESEL_AM:
case CSR_RESEL:
DB(DB_INTR,printk("RESEL%s", sr == CSR_RESEL_AM ? "_AM" : ""))
DB(DB_INTR, printk("RESEL%s", sr == CSR_RESEL_AM ? "_AM" : ""))
/* Old chips (pre -A ???) don't have advanced features and will
* generate CSR_RESEL. In that case we have to extract the LUN the
......@@ -1272,14 +1304,14 @@ DB(DB_INTR,printk("RESEL%s", sr == CSR_RESEL_AM ? "_AM" : ""))
* happen during Arbitration/Selection of some other device.
* If yes, put losing command back on top of input_Q.
*/
if (hostdata->level2 <= L2_NONE) {
if (hostdata->selecting) {
cmd = (Scsi_Cmnd *)hostdata->selecting;
cmd = (Scsi_Cmnd *) hostdata->selecting;
hostdata->selecting = NULL;
hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
cmd->host_scribble = (uchar *)hostdata->input_Q;
hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
cmd->host_scribble =
(uchar *) hostdata->input_Q;
hostdata->input_Q = cmd;
}
}
......@@ -1288,12 +1320,15 @@ DB(DB_INTR,printk("RESEL%s", sr == CSR_RESEL_AM ? "_AM" : ""))
if (cmd) {
if (phs == 0x00) {
hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
cmd->host_scribble = (uchar *)hostdata->input_Q;
hostdata->busy[cmd->device->id] &=
~(1 << cmd->device->lun);
cmd->host_scribble =
(uchar *) hostdata->input_Q;
hostdata->input_Q = cmd;
}
else {
printk("---%02x:%02x:%02x-TROUBLE: Intrusive ReSelect!---",asr,sr,phs);
} else {
printk
("---%02x:%02x:%02x-TROUBLE: Intrusive ReSelect!---",
asr, sr, phs);
while (1)
printk("\r");
}
......@@ -1316,19 +1351,18 @@ DB(DB_INTR,printk("RESEL%s", sr == CSR_RESEL_AM ? "_AM" : ""))
if (hostdata->level2 < L2_RESELECT)
write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK);
lun &= 7;
}
else {
} else {
/* Old chip; wait for msgin phase to pick up the LUN. */
for (lun = 255; lun; lun--) {
if ((asr = READ_AUX_STAT()) & ASR_INT)
if ((asr = read_aux_stat(regs)) & ASR_INT)
break;
udelay(10);
}
if (!(asr & ASR_INT)) {
printk("wd33c93: Reselected without IDENTIFY\n");
printk
("wd33c93: Reselected without IDENTIFY\n");
lun = 0;
}
else {
} else {
/* Verify this is a change to MSG_IN and read the message */
sr = read_wd33c93(regs, WD_SCSI_STATUS);
if (sr == (CSR_ABORT | PHS_MESS_IN) ||
......@@ -1337,23 +1371,27 @@ DB(DB_INTR,printk("RESEL%s", sr == CSR_RESEL_AM ? "_AM" : ""))
/* Got MSG_IN, grab target LUN */
lun = read_1_byte(regs);
/* Now we expect a 'paused with ACK asserted' int.. */
asr = READ_AUX_STAT();
asr = read_aux_stat(regs);
if (!(asr & ASR_INT)) {
udelay(10);
asr = READ_AUX_STAT();
asr = read_aux_stat(regs);
if (!(asr & ASR_INT))
printk("wd33c93: No int after LUN on RESEL (%02x)\n",
printk
("wd33c93: No int after LUN on RESEL (%02x)\n",
asr);
}
sr = read_wd33c93(regs, WD_SCSI_STATUS);
if (sr != CSR_MSGIN)
printk("wd33c93: Not paused with ACK on RESEL (%02x)\n",
printk
("wd33c93: Not paused with ACK on RESEL (%02x)\n",
sr);
lun &= 7;
write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK);
}
else {
printk("wd33c93: Not MSG_IN on reselect (%02x)\n", sr);
write_wd33c93_cmd(regs,
WD_CMD_NEGATE_ACK);
} else {
printk
("wd33c93: Not MSG_IN on reselect (%02x)\n",
sr);
lun = 0;
}
}
......@@ -1361,19 +1399,21 @@ DB(DB_INTR,printk("RESEL%s", sr == CSR_RESEL_AM ? "_AM" : ""))
/* Now we look for the command that's reconnecting. */
cmd = (Scsi_Cmnd *)hostdata->disconnected_Q;
cmd = (Scsi_Cmnd *) hostdata->disconnected_Q;
patch = NULL;
while (cmd) {
if (id == cmd->target && lun == cmd->lun)
if (id == cmd->device->id && lun == cmd->device->lun)
break;
patch = cmd;
cmd = (Scsi_Cmnd *)cmd->host_scribble;
cmd = (Scsi_Cmnd *) cmd->host_scribble;
}
/* Hmm. Couldn't find a valid command.... What to do? */
if (!cmd) {
printk("---TROUBLE: target %d.%d not in disconnect queue---",id,lun);
printk
("---TROUBLE: target %d.%d not in disconnect queue---",
id, lun);
spin_unlock_irqrestore(&hostdata->lock, flags);
return;
}
......@@ -1383,7 +1423,8 @@ DB(DB_INTR,printk("RESEL%s", sr == CSR_RESEL_AM ? "_AM" : ""))
if (patch)
patch->host_scribble = cmd->host_scribble;
else
hostdata->disconnected_Q = (Scsi_Cmnd *)cmd->host_scribble;
hostdata->disconnected_Q =
(Scsi_Cmnd *) cmd->host_scribble;
hostdata->connected = cmd;
/* We don't need to worry about 'initialize_SCp()' or 'hostdata->busy[]'
......@@ -1392,43 +1433,43 @@ DB(DB_INTR,printk("RESEL%s", sr == CSR_RESEL_AM ? "_AM" : ""))
*/
if (is_dir_out(cmd))
write_wd33c93(regs, WD_DESTINATION_ID, cmd->target);
write_wd33c93(regs, WD_DESTINATION_ID, cmd->device->id);
else
write_wd33c93(regs, WD_DESTINATION_ID, cmd->target | DSTID_DPD);
write_wd33c93(regs, WD_DESTINATION_ID,
cmd->device->id | DSTID_DPD);
if (hostdata->level2 >= L2_RESELECT) {
write_wd33c93_count(regs, 0); /* we want a DATA_PHASE interrupt */
write_wd33c93(regs, WD_COMMAND_PHASE, 0x45);
write_wd33c93_cmd(regs, WD_CMD_SEL_ATN_XFER);
hostdata->state = S_RUNNING_LEVEL2;
}
else
} else
hostdata->state = S_CONNECTED;
DB(DB_INTR,printk("-%ld",cmd->pid))
DB(DB_INTR, printk("-%ld", cmd->pid))
spin_unlock_irqrestore(&hostdata->lock, flags);
break;
default:
printk("--UNKNOWN INTERRUPT:%02x:%02x:%02x--",asr,sr,phs);
printk("--UNKNOWN INTERRUPT:%02x:%02x:%02x--", asr, sr, phs);
spin_unlock_irqrestore(&hostdata->lock, flags);
}
DB(DB_INTR,printk("} "))
DB(DB_INTR, printk("} "))
}
void reset_wd33c93(struct Scsi_Host *instance)
static void
reset_wd33c93(struct Scsi_Host *instance)
{
struct WD33C93_hostdata *hostdata = (struct WD33C93_hostdata *)instance->hostdata;
const wd33c93_regs regs = hostdata->regs;
uchar sr;
struct WD33C93_hostdata *hostdata =
(struct WD33C93_hostdata *) instance->hostdata;
const wd33c93_regs regs = hostdata->regs;
uchar sr;
#ifdef CONFIG_SGI_IP22
{
int busycount = 0;
extern void sgiwd93_reset(unsigned long);
{
int busycount = 0;
extern void sgiwd93_reset(unsigned long);
/* wait 'til the chip gets some time for us */
while ((READ_AUX_STAT() & ASR_BSY) && busycount++ < 100)
udelay (10);
......@@ -1442,20 +1483,23 @@ extern void sgiwd93_reset(unsigned long);
/* still busy ? */
if (READ_AUX_STAT() & ASR_BSY)
sgiwd93_reset(instance->base); /* yeah, give it the hard one */
}
}
#endif
write_wd33c93(regs, WD_OWN_ID, OWNID_EAF | OWNID_RAF |
instance->this_id | hostdata->clock_freq);
write_wd33c93(regs, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
write_wd33c93(regs, WD_SYNCHRONOUS_TRANSFER,
calc_sync_xfer(hostdata->default_sx_per/4,DEFAULT_SX_OFF));
calc_sync_xfer(hostdata->default_sx_per / 4,
DEFAULT_SX_OFF));
write_wd33c93(regs, WD_COMMAND, WD_CMD_RESET);
#ifdef CONFIG_MVME147_SCSI
udelay(25); /* The old wd33c93 on MVME147 needs this, at least */
#endif
while (!(READ_AUX_STAT() & ASR_INT))
while (!(read_aux_stat(regs) & ASR_INT))
;
sr = read_wd33c93(regs, WD_SCSI_STATUS);
......@@ -1468,35 +1512,33 @@ extern void sgiwd93_reset(unsigned long);
if (sr == 0xa5) {
hostdata->chip = C_WD33C93B;
write_wd33c93(regs, WD_QUEUE_TAG, 0);
}
else
} else
hostdata->chip = C_WD33C93A;
}
else
} else
hostdata->chip = C_UNKNOWN_CHIP;
write_wd33c93(regs, WD_TIMEOUT_PERIOD, TIMEOUT_PERIOD_VALUE);
write_wd33c93(regs, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
}
int wd33c93_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
int
wd33c93_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags)
{
struct Scsi_Host *instance;
struct WD33C93_hostdata *hostdata;
int i;
struct Scsi_Host *instance;
struct WD33C93_hostdata *hostdata;
int i;
instance = SCpnt->host;
hostdata = (struct WD33C93_hostdata *)instance->hostdata;
instance = SCpnt->device->host;
hostdata = (struct WD33C93_hostdata *) instance->hostdata;
printk("scsi%d: reset. ", instance->host_no);
disable_irq(instance->irq);
((struct WD33C93_hostdata *)instance->hostdata)->dma_stop(instance,NULL,0);
hostdata->dma_stop(instance, NULL, 0);
for (i = 0; i < 8; i++) {
hostdata->busy[i] = 0;
hostdata->sync_xfer[i] = calc_sync_xfer(DEFAULT_SX_PER/4,DEFAULT_SX_OFF);
hostdata->sync_xfer[i] =
calc_sync_xfer(DEFAULT_SX_PER / 4, DEFAULT_SX_OFF);
hostdata->sync_stat[i] = SS_UNSET; /* using default sync values */
}
hostdata->input_Q = NULL;
......@@ -1514,19 +1556,18 @@ int i;
return 0;
}
int wd33c93_abort (Scsi_Cmnd *cmd)
int
wd33c93_abort(Scsi_Cmnd * cmd)
{
struct Scsi_Host *instance;
struct WD33C93_hostdata *hostdata;
wd33c93_regs regs;
Scsi_Cmnd *tmp, *prev;
struct Scsi_Host *instance;
struct WD33C93_hostdata *hostdata;
wd33c93_regs regs;
Scsi_Cmnd *tmp, *prev;
disable_irq(cmd->host->irq);
disable_irq(cmd->device->host->irq);
instance = cmd->host;
hostdata = (struct WD33C93_hostdata *)instance->hostdata;
instance = cmd->device->host;
hostdata = (struct WD33C93_hostdata *) instance->hostdata;
regs = hostdata->regs;
/*
......@@ -1534,24 +1575,26 @@ Scsi_Cmnd *tmp, *prev;
* from the input_Q.
*/
tmp = (Scsi_Cmnd *)hostdata->input_Q;
tmp = (Scsi_Cmnd *) hostdata->input_Q;
prev = 0;
while (tmp) {
if (tmp == cmd) {
if (prev)
prev->host_scribble = cmd->host_scribble;
else
hostdata->input_Q = (Scsi_Cmnd *)cmd->host_scribble;
hostdata->input_Q =
(Scsi_Cmnd *) cmd->host_scribble;
cmd->host_scribble = NULL;
cmd->result = DID_ABORT << 16;
printk("scsi%d: Abort - removing command %ld from input_Q. ",
printk
("scsi%d: Abort - removing command %ld from input_Q. ",
instance->host_no, cmd->pid);
enable_irq(cmd->host->irq);
enable_irq(cmd->device->host->irq);
cmd->scsi_done(cmd);
return SCSI_ABORT_SUCCESS;
}
prev = tmp;
tmp = (Scsi_Cmnd *)tmp->host_scribble;
tmp = (Scsi_Cmnd *) tmp->host_scribble;
}
/*
......@@ -1579,7 +1622,8 @@ Scsi_Cmnd *tmp, *prev;
}
printk("sending wd33c93 ABORT command - ");
write_wd33c93(regs, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
write_wd33c93(regs, WD_CONTROL,
CTRL_IDI | CTRL_EDI | CTRL_POLLED);
write_wd33c93_cmd(regs, WD_CMD_ABORT);
/* Now we have to attempt to flush out the FIFO... */
......@@ -1587,12 +1631,13 @@ Scsi_Cmnd *tmp, *prev;
printk("flushing fifo - ");
timeout = 1000000;
do {
asr = READ_AUX_STAT();
asr = read_aux_stat(regs);
if (asr & ASR_DBR)
read_wd33c93(regs, WD_DATA);
} while (!(asr & ASR_INT) && timeout-- > 0);
sr = read_wd33c93(regs, WD_SCSI_STATUS);
printk("asr=%02x, sr=%02x, %ld bytes un-transferred (timeout=%ld) - ",
printk
("asr=%02x, sr=%02x, %ld bytes un-transferred (timeout=%ld) - ",
asr, sr, read_wd33c93_count(regs), timeout);
/*
......@@ -1605,21 +1650,21 @@ Scsi_Cmnd *tmp, *prev;
write_wd33c93_cmd(regs, WD_CMD_DISCONNECT);
timeout = 1000000;
asr = READ_AUX_STAT();
asr = read_aux_stat(regs);
while ((asr & ASR_CIP) && timeout-- > 0)
asr = READ_AUX_STAT();
asr = read_aux_stat(regs);
sr = read_wd33c93(regs, WD_SCSI_STATUS);
printk("asr=%02x, sr=%02x.",asr,sr);
printk("asr=%02x, sr=%02x.", asr, sr);
hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
hostdata->connected = NULL;
hostdata->state = S_UNCONNECTED;
cmd->result = DID_ABORT << 16;
/* sti();*/
wd33c93_execute (instance);
wd33c93_execute(instance);
enable_irq(cmd->host->irq);
enable_irq(cmd->device->host->irq);
cmd->scsi_done(cmd);
return SCSI_ABORT_SUCCESS;
}
......@@ -1630,16 +1675,17 @@ Scsi_Cmnd *tmp, *prev;
* an ABORT_SNOOZE and hope for the best...
*/
tmp = (Scsi_Cmnd *)hostdata->disconnected_Q;
tmp = (Scsi_Cmnd *) hostdata->disconnected_Q;
while (tmp) {
if (tmp == cmd) {
printk("scsi%d: Abort - command %ld found on disconnected_Q - ",
printk
("scsi%d: Abort - command %ld found on disconnected_Q - ",
instance->host_no, cmd->pid);
printk("returning ABORT_SNOOZE. ");
enable_irq(cmd->host->irq);
enable_irq(cmd->device->host->irq);
return SCSI_ABORT_SNOOZE;
}
tmp = (Scsi_Cmnd *)tmp->host_scribble;
tmp = (Scsi_Cmnd *) tmp->host_scribble;
}
/*
......@@ -1653,16 +1699,14 @@ Scsi_Cmnd *tmp, *prev;
*/
/* sti();*/
wd33c93_execute (instance);
wd33c93_execute(instance);
enable_irq(cmd->host->irq);
enable_irq(cmd->device->host->irq);
printk("scsi%d: warning : SCSI command probably completed successfully"
" before abortion. ", instance->host_no);
return SCSI_ABORT_NOT_RUNNING;
}
#define MAX_WD33C93_HOSTS 4
#define MAX_SETUP_ARGS ((int)(sizeof(setup_args) / sizeof(char *)))
#define SETUP_BUFFER_SIZE 200
......@@ -1670,10 +1714,11 @@ static char setup_buffer[SETUP_BUFFER_SIZE];
static char setup_used[MAX_SETUP_ARGS];
static int done_setup = 0;
int wd33c93_setup (char *str)
int
wd33c93_setup(char *str)
{
int i;
char *p1,*p2;
char *p1, *p2;
/* The kernel does some processing of the command-line before calling
* this function: If it begins with any decimal or hex number arguments,
......@@ -1686,17 +1731,6 @@ int wd33c93_setup (char *str)
p1 = setup_buffer;
*p1 = '\0';
#if 0
/*
* Old style command line arguments are now dead
*/
if (ints[0]) {
for (i=0; i<ints[0]; i++) {
x = vsprintf(p1,"nosync:0x%02x,",&(ints[i+1]));
p1 += x;
}
}
#endif
if (str)
strncpy(p1, str, SETUP_BUFFER_SIZE - strlen(setup_buffer));
setup_buffer[SETUP_BUFFER_SIZE - 1] = '\0';
......@@ -1710,31 +1744,28 @@ int wd33c93_setup (char *str)
setup_args[i] = p1;
p1 = p2 + 1;
i++;
}
else {
} else {
setup_args[i] = p1;
break;
}
}
for (i=0; i<MAX_SETUP_ARGS; i++)
for (i = 0; i < MAX_SETUP_ARGS; i++)
setup_used[i] = 0;
done_setup = 1;
return 1;
}
__setup("wd33c93", wd33c93_setup);
__setup("wd33c9=", wd33c93_setup);
/* check_setup_args() returns index if key found, 0 if not
*/
static int check_setup_args(char *key, int *flags, int *val, char *buf)
static int
check_setup_args(char *key, int *flags, int *val, char *buf)
{
int x;
char *cp;
int x;
char *cp;
for (x=0; x<MAX_SETUP_ARGS; x++) {
for (x = 0; x < MAX_SETUP_ARGS; x++) {
if (setup_used[x])
continue;
if (!strncmp(setup_args[x], key, strlen(key)))
......@@ -1751,26 +1782,25 @@ char *cp;
return ++x;
cp++;
if ((*cp >= '0') && (*cp <= '9')) {
*val = simple_strtoul(cp,NULL,0);
*val = simple_strtoul(cp, NULL, 0);
}
return ++x;
}
void wd33c93_init(struct Scsi_Host *instance, const wd33c93_regs regs,
void
wd33c93_init(struct Scsi_Host *instance, const wd33c93_regs regs,
dma_setup_t setup, dma_stop_t stop, int clock_freq)
{
struct WD33C93_hostdata *hostdata;
int i;
int flags;
int val;
char buf[32];
struct WD33C93_hostdata *hostdata;
int i;
int flags;
int val;
char buf[32];
if (!done_setup && setup_strings)
wd33c93_setup(setup_strings);
hostdata = (struct WD33C93_hostdata *)instance->hostdata;
hostdata = (struct WD33C93_hostdata *) instance->hostdata;
hostdata->regs = regs;
hostdata->clock_freq = clock_freq;
......@@ -1780,7 +1810,8 @@ char buf[32];
hostdata->dma_bounce_len = 0;
for (i = 0; i < 8; i++) {
hostdata->busy[i] = 0;
hostdata->sync_xfer[i] = calc_sync_xfer(DEFAULT_SX_PER/4,DEFAULT_SX_OFF);
hostdata->sync_xfer[i] =
calc_sync_xfer(DEFAULT_SX_PER / 4, DEFAULT_SX_OFF);
hostdata->sync_stat[i] = SS_UNSET; /* using default sync values */
#ifdef PROC_STATISTICS
hostdata->cmd_cnt[i] = 0;
......@@ -1804,9 +1835,8 @@ char buf[32];
hostdata->no_dma = 0; /* default is DMA enabled */
#ifdef PROC_INTERFACE
hostdata->proc = PR_VERSION|PR_INFO|PR_STATISTICS|
PR_CONNECTED|PR_INPUTQ|PR_DISCQ|
PR_STOP;
hostdata->proc = PR_VERSION | PR_INFO | PR_STATISTICS |
PR_CONNECTED | PR_INPUTQ | PR_DISCQ | PR_STOP;
#ifdef PROC_STATISTICS
hostdata->dma_cnt = 0;
hostdata->pio_cnt = 0;
......@@ -1814,94 +1844,94 @@ char buf[32];
#endif
#endif
if (check_setup_args("nosync",&flags,&val,buf))
if (check_setup_args("nosync", &flags, &val, buf))
hostdata->no_sync = val;
if (check_setup_args("nodma",&flags,&val,buf))
if (check_setup_args("nodma", &flags, &val, buf))
hostdata->no_dma = (val == -1) ? 1 : val;
if (check_setup_args("period",&flags,&val,buf))
hostdata->default_sx_per = sx_table[round_period((unsigned int)val)].period_ns;
if (check_setup_args("period", &flags, &val, buf))
hostdata->default_sx_per =
sx_table[round_period((unsigned int) val)].period_ns;
if (check_setup_args("disconnect",&flags,&val,buf)) {
if (check_setup_args("disconnect", &flags, &val, buf)) {
if ((val >= DIS_NEVER) && (val <= DIS_ALWAYS))
hostdata->disconnect = val;
else
hostdata->disconnect = DIS_ADAPTIVE;
}
if (check_setup_args("level2",&flags,&val,buf))
if (check_setup_args("level2", &flags, &val, buf))
hostdata->level2 = val;
if (check_setup_args("debug",&flags,&val,buf))
if (check_setup_args("debug", &flags, &val, buf))
hostdata->args = val & DB_MASK;
if (check_setup_args("clock",&flags,&val,buf)) {
if (val>7 && val<11)
if (check_setup_args("clock", &flags, &val, buf)) {
if (val > 7 && val < 11)
val = WD33C93_FS_8_10;
else if (val>11 && val<16)
else if (val > 11 && val < 16)
val = WD33C93_FS_12_15;
else if (val>15 && val<21)
else if (val > 15 && val < 21)
val = WD33C93_FS_16_20;
else
val = WD33C93_FS_8_10;
hostdata->clock_freq = val;
}
if ((i = check_setup_args("next",&flags,&val,buf))) {
if ((i = check_setup_args("next", &flags, &val, buf))) {
while (i)
setup_used[--i] = 1;
}
#ifdef PROC_INTERFACE
if (check_setup_args("proc",&flags,&val,buf))
if (check_setup_args("proc", &flags, &val, buf))
hostdata->proc = val;
#endif
spin_lock_irq(&hostdata->lock);
reset_wd33c93(instance);
spin_unlock_irq(&hostdata->lock);
printk("wd33c93-%d: chip=%s/%d no_sync=0x%x no_dma=%d",instance->host_no,
(hostdata->chip==C_WD33C93)?"WD33c93":
(hostdata->chip==C_WD33C93A)?"WD33c93A":
(hostdata->chip==C_WD33C93B)?"WD33c93B":"unknown",
hostdata->microcode,hostdata->no_sync,hostdata->no_dma);
printk("wd33c93-%d: chip=%s/%d no_sync=0x%x no_dma=%d",
instance->host_no,
(hostdata->chip == C_WD33C93) ? "WD33c93" : (hostdata->chip ==
C_WD33C93A) ?
"WD33c93A" : (hostdata->chip ==
C_WD33C93B) ? "WD33c93B" : "unknown",
hostdata->microcode, hostdata->no_sync, hostdata->no_dma);
#ifdef DEBUGGING_ON
printk(" debug_flags=0x%02x\n",hostdata->args);
printk(" debug_flags=0x%02x\n", hostdata->args);
#else
printk(" debugging=OFF\n");
#endif
printk(" setup_args=");
for (i=0; i<MAX_SETUP_ARGS; i++)
printk("%s,",setup_args[i]);
for (i = 0; i < MAX_SETUP_ARGS; i++)
printk("%s,", setup_args[i]);
printk("\n");
printk(" Version %s - %s, Compiled %s at %s\n",
WD33C93_VERSION,WD33C93_DATE,__DATE__,__TIME__);
WD33C93_VERSION, WD33C93_DATE, __DATE__, __TIME__);
}
int wd33c93_proc_info(char *buf, char **start, off_t off, int len, int hn, int in)
int
wd33c93_proc_info(char *buf, char **start, off_t off, int len, int hn, int in)
{
#ifdef PROC_INTERFACE
char *bp;
char tbuf[128];
struct Scsi_Host *instance;
struct WD33C93_hostdata *hd;
Scsi_Cmnd *cmd;
int x,i;
static int stop = 0;
char *bp;
char tbuf[128];
struct Scsi_Host *instance;
struct WD33C93_hostdata *hd;
Scsi_Cmnd *cmd;
int x, i;
static int stop = 0;
instance = scsi_host_hn_get(hn);
if (!instance) {
printk("*** Hmm... Can't find host #%d!\n",hn);
printk("*** Hmm... Can't find host #%d!\n", hn);
return (-ESRCH);
}
hd = (struct WD33C93_hostdata *)instance->hostdata;
hd = (struct WD33C93_hostdata *) instance->hostdata;
/* If 'in' is TRUE we need to _read_ the proc file. We accept the following
* keywords (same format as command-line, but only ONE per read):
......@@ -1916,40 +1946,35 @@ static int stop = 0;
if (in) {
buf[len] = '\0';
bp = buf;
if (!strncmp(bp,"debug:",6)) {
if (!strncmp(bp, "debug:", 6)) {
bp += 6;
hd->args = simple_strtoul(bp,NULL,0) & DB_MASK;
}
else if (!strncmp(bp,"disconnect:",11)) {
hd->args = simple_strtoul(bp, NULL, 0) & DB_MASK;
} else if (!strncmp(bp, "disconnect:", 11)) {
bp += 11;
x = simple_strtoul(bp,NULL,0);
x = simple_strtoul(bp, NULL, 0);
if (x < DIS_NEVER || x > DIS_ALWAYS)
x = DIS_ADAPTIVE;
hd->disconnect = x;
}
else if (!strncmp(bp,"period:",7)) {
} else if (!strncmp(bp, "period:", 7)) {
bp += 7;
x = simple_strtoul(bp,NULL,0);
hd->default_sx_per = sx_table[round_period((unsigned int)x)].period_ns;
}
else if (!strncmp(bp,"resync:",7)) {
x = simple_strtoul(bp, NULL, 0);
hd->default_sx_per =
sx_table[round_period((unsigned int) x)].period_ns;
} else if (!strncmp(bp, "resync:", 7)) {
bp += 7;
x = simple_strtoul(bp,NULL,0);
for (i=0; i<7; i++)
if (x & (1<<i))
x = simple_strtoul(bp, NULL, 0);
for (i = 0; i < 7; i++)
if (x & (1 << i))
hd->sync_stat[i] = SS_UNSET;
}
else if (!strncmp(bp,"proc:",5)) {
} else if (!strncmp(bp, "proc:", 5)) {
bp += 5;
hd->proc = simple_strtoul(bp,NULL,0);
}
else if (!strncmp(bp,"nodma:",6)) {
hd->proc = simple_strtoul(bp, NULL, 0);
} else if (!strncmp(bp, "nodma:", 6)) {
bp += 6;
hd->no_dma = simple_strtoul(bp,NULL,0);
}
else if (!strncmp(bp,"level2:",7)) {
hd->no_dma = simple_strtoul(bp, NULL, 0);
} else if (!strncmp(bp, "level2:", 7)) {
bp += 7;
hd->level2 = simple_strtoul(bp,NULL,0);
hd->level2 = simple_strtoul(bp, NULL, 0);
}
return len;
}
......@@ -1958,77 +1983,78 @@ static int stop = 0;
bp = buf;
*bp = '\0';
if (hd->proc & PR_VERSION) {
sprintf(tbuf,"\nVersion %s - %s. Compiled %s %s",
WD33C93_VERSION,WD33C93_DATE,__DATE__,__TIME__);
strcat(bp,tbuf);
sprintf(tbuf, "\nVersion %s - %s. Compiled %s %s",
WD33C93_VERSION, WD33C93_DATE, __DATE__, __TIME__);
strcat(bp, tbuf);
}
if (hd->proc & PR_INFO) {
sprintf(tbuf,"\nclock_freq=%02x no_sync=%02x no_dma=%d",
hd->clock_freq,hd->no_sync,hd->no_dma);
strcat(bp,tbuf);
strcat(bp,"\nsync_xfer[] = ");
for (x=0; x<7; x++) {
sprintf(tbuf,"\t%02x",hd->sync_xfer[x]);
strcat(bp,tbuf);
sprintf(tbuf, "\nclock_freq=%02x no_sync=%02x no_dma=%d",
hd->clock_freq, hd->no_sync, hd->no_dma);
strcat(bp, tbuf);
strcat(bp, "\nsync_xfer[] = ");
for (x = 0; x < 7; x++) {
sprintf(tbuf, "\t%02x", hd->sync_xfer[x]);
strcat(bp, tbuf);
}
strcat(bp,"\nsync_stat[] = ");
for (x=0; x<7; x++) {
sprintf(tbuf,"\t%02x",hd->sync_stat[x]);
strcat(bp,tbuf);
strcat(bp, "\nsync_stat[] = ");
for (x = 0; x < 7; x++) {
sprintf(tbuf, "\t%02x", hd->sync_stat[x]);
strcat(bp, tbuf);
}
}
#ifdef PROC_STATISTICS
if (hd->proc & PR_STATISTICS) {
strcat(bp,"\ncommands issued: ");
for (x=0; x<7; x++) {
sprintf(tbuf,"\t%ld",hd->cmd_cnt[x]);
strcat(bp,tbuf);
}
strcat(bp,"\ndisconnects allowed:");
for (x=0; x<7; x++) {
sprintf(tbuf,"\t%ld",hd->disc_allowed_cnt[x]);
strcat(bp,tbuf);
}
strcat(bp,"\ndisconnects done: ");
for (x=0; x<7; x++) {
sprintf(tbuf,"\t%ld",hd->disc_done_cnt[x]);
strcat(bp,tbuf);
}
sprintf(tbuf,"\ninterrupts: %ld, DATA_PHASE ints: %ld DMA, %ld PIO",
hd->int_cnt,hd->dma_cnt,hd->pio_cnt);
strcat(bp,tbuf);
strcat(bp, "\ncommands issued: ");
for (x = 0; x < 7; x++) {
sprintf(tbuf, "\t%ld", hd->cmd_cnt[x]);
strcat(bp, tbuf);
}
strcat(bp, "\ndisconnects allowed:");
for (x = 0; x < 7; x++) {
sprintf(tbuf, "\t%ld", hd->disc_allowed_cnt[x]);
strcat(bp, tbuf);
}
strcat(bp, "\ndisconnects done: ");
for (x = 0; x < 7; x++) {
sprintf(tbuf, "\t%ld", hd->disc_done_cnt[x]);
strcat(bp, tbuf);
}
sprintf(tbuf,
"\ninterrupts: %ld, DATA_PHASE ints: %ld DMA, %ld PIO",
hd->int_cnt, hd->dma_cnt, hd->pio_cnt);
strcat(bp, tbuf);
}
#endif
if (hd->proc & PR_CONNECTED) {
strcat(bp,"\nconnected: ");
strcat(bp, "\nconnected: ");
if (hd->connected) {
cmd = (Scsi_Cmnd *)hd->connected;
sprintf(tbuf," %ld-%d:%d(%02x)",
cmd->pid, cmd->target, cmd->lun, cmd->cmnd[0]);
strcat(bp,tbuf);
cmd = (Scsi_Cmnd *) hd->connected;
sprintf(tbuf, " %ld-%d:%d(%02x)",
cmd->pid, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
strcat(bp, tbuf);
}
}
if (hd->proc & PR_INPUTQ) {
strcat(bp,"\ninput_Q: ");
cmd = (Scsi_Cmnd *)hd->input_Q;
strcat(bp, "\ninput_Q: ");
cmd = (Scsi_Cmnd *) hd->input_Q;
while (cmd) {
sprintf(tbuf," %ld-%d:%d(%02x)",
cmd->pid, cmd->target, cmd->lun, cmd->cmnd[0]);
strcat(bp,tbuf);
cmd = (Scsi_Cmnd *)cmd->host_scribble;
sprintf(tbuf, " %ld-%d:%d(%02x)",
cmd->pid, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
strcat(bp, tbuf);
cmd = (Scsi_Cmnd *) cmd->host_scribble;
}
}
if (hd->proc & PR_DISCQ) {
strcat(bp,"\ndisconnected_Q:");
cmd = (Scsi_Cmnd *)hd->disconnected_Q;
strcat(bp, "\ndisconnected_Q:");
cmd = (Scsi_Cmnd *) hd->disconnected_Q;
while (cmd) {
sprintf(tbuf," %ld-%d:%d(%02x)",
cmd->pid, cmd->target, cmd->lun, cmd->cmnd[0]);
strcat(bp,tbuf);
cmd = (Scsi_Cmnd *)cmd->host_scribble;
sprintf(tbuf, " %ld-%d:%d(%02x)",
cmd->pid, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
strcat(bp, tbuf);
cmd = (Scsi_Cmnd *) cmd->host_scribble;
}
}
strcat(bp,"\n");
strcat(bp, "\n");
spin_unlock_irq(&hd->lock);
*start = buf;
if (stop) {
......@@ -2049,12 +2075,14 @@ static int stop = 0;
}
#ifdef MODULE
int init_module(void) { return 0; }
void cleanup_module(void) {}
#endif
void wd33c93_release(void)
void
wd33c93_release(void)
{
}
MODULE_LICENSE("GPL");
EXPORT_SYMBOL(wd33c93_reset);
EXPORT_SYMBOL(wd33c93_init);
EXPORT_SYMBOL(wd33c93_release);
EXPORT_SYMBOL(wd33c93_abort);
EXPORT_SYMBOL(wd33c93_queuecommand);
EXPORT_SYMBOL(wd33c93_intr);
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