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