#include <linux/module.h>
#include <asm/irq.h>
#include <linux/io.h>
#include <linux/blkdev.h>
#include <linux/completion.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/wait.h>
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/proc_fs.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/isapnp.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/list.h>
#include <linux/slab.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_dbg.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_eh.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_tcq.h>
#include <scsi/scsi_transport_spi.h>
#include <scsi/scsicam.h>
#include "aha152x.h"
static LIST_HEAD(aha152x_host_list);
#if defined(AHA152X_PCMCIA) || defined(MODULE)
#if !defined(AUTOCONF)
#define AUTOCONF
#endif
#endif
#if !defined(AUTOCONF) && !defined(SETUP0)
#error define AUTOCONF or SETUP0
#endif
#define DO_LOCK(flags) …
#define DO_UNLOCK(flags) …
#define LEAD …
#define INFO_LEAD …
#define CMDINFO(cmd) …
static inline void
CMD_INC_RESID(struct scsi_cmnd *cmd, int inc)
{ … }
#define DELAY_DEFAULT …
#if defined(AHA152X_PCMCIA)
#define IRQ_MIN …
#define IRQ_MAX …
#else
#define IRQ_MIN …
#if defined(__PPC)
#define IRQ_MAX …
#else
#define IRQ_MAX …
#endif
#endif
enum { … };
struct aha152x_cmd_priv { … };
static struct aha152x_cmd_priv *aha152x_priv(struct scsi_cmnd *cmd)
{ … }
MODULE_AUTHOR(…) …;
MODULE_DESCRIPTION(…);
MODULE_LICENSE(…) …;
#if !defined(AHA152X_PCMCIA)
#if defined(MODULE)
static int io[] = {0, 0};
module_param_hw_array(io, int, ioport, NULL, 0);
MODULE_PARM_DESC(io,"base io address of controller");
static int irq[] = {0, 0};
module_param_hw_array(irq, int, irq, NULL, 0);
MODULE_PARM_DESC(irq,"interrupt for controller");
static int scsiid[] = {7, 7};
module_param_array(scsiid, int, NULL, 0);
MODULE_PARM_DESC(scsiid,"scsi id of controller");
static int reconnect[] = {1, 1};
module_param_array(reconnect, int, NULL, 0);
MODULE_PARM_DESC(reconnect,"allow targets to disconnect");
static int parity[] = {1, 1};
module_param_array(parity, int, NULL, 0);
MODULE_PARM_DESC(parity,"use scsi parity");
static int sync[] = {1, 1};
module_param_array(sync, int, NULL, 0);
MODULE_PARM_DESC(sync,"use synchronous transfers");
static int delay[] = {DELAY_DEFAULT, DELAY_DEFAULT};
module_param_array(delay, int, NULL, 0);
MODULE_PARM_DESC(delay,"scsi reset delay");
static int exttrans[] = {0, 0};
module_param_array(exttrans, int, NULL, 0);
MODULE_PARM_DESC(exttrans,"use extended translation");
static int aha152x[] = {0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0};
module_param_array(aha152x, int, NULL, 0);
MODULE_PARM_DESC(aha152x, "parameters for first controller");
static int aha152x1[] = {0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0};
module_param_array(aha152x1, int, NULL, 0);
MODULE_PARM_DESC(aha152x1, "parameters for second controller");
#endif
#ifdef __ISAPNP__
static struct isapnp_device_id id_table[] = {
{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1502), 0 },
{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1505), 0 },
{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1510), 0 },
{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1515), 0 },
{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1520), 0 },
{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x2015), 0 },
{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1522), 0 },
{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x2215), 0 },
{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1530), 0 },
{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x3015), 0 },
{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1532), 0 },
{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x3215), 0 },
{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x6360), 0 },
{ ISAPNP_DEVICE_SINGLE_END, }
};
MODULE_DEVICE_TABLE(isapnp, id_table);
#endif
#endif
static const struct scsi_host_template aha152x_driver_template;
enum aha152x_state { … };
struct aha152x_hostdata { … };
struct aha152x_scdata { … };
#define HOSTDATA(shpnt) …
#define HOSTNO …
#define CURRENT_SC …
#define DONE_SC …
#define ISSUE_SC …
#define DISCONNECTED_SC …
#define QLOCK …
#define QLOCKER …
#define QLOCKERL …
#define STATE …
#define PREVSTATE …
#define LASTSTATE …
#define RECONN_TARGET …
#define CMD_I …
#define MSGO(i) …
#define MSGO_I …
#define MSGOLEN …
#define ADDMSGO(x) …
#define MSGI(i) …
#define MSGILEN …
#define ADDMSGI(x) …
#define DATA_LEN …
#define SYNCRATE …
#define SYNCNEG …
#define DELAY …
#define EXT_TRANS …
#define TC1550 …
#define RECONNECT …
#define PARITY …
#define SYNCHRONOUS …
#define HOSTIOPORT0 …
#define HOSTIOPORT1 …
#define SCDATA(SCpnt) …
#define SCNEXT(SCpnt) …
#define SCSEM(SCpnt) …
#define SG_ADDRESS(buffer) …
static void seldi_run(struct Scsi_Host *shpnt);
static void seldo_run(struct Scsi_Host *shpnt);
static void selto_run(struct Scsi_Host *shpnt);
static void busfree_run(struct Scsi_Host *shpnt);
static void msgo_init(struct Scsi_Host *shpnt);
static void msgo_run(struct Scsi_Host *shpnt);
static void msgo_end(struct Scsi_Host *shpnt);
static void cmd_init(struct Scsi_Host *shpnt);
static void cmd_run(struct Scsi_Host *shpnt);
static void cmd_end(struct Scsi_Host *shpnt);
static void datai_init(struct Scsi_Host *shpnt);
static void datai_run(struct Scsi_Host *shpnt);
static void datai_end(struct Scsi_Host *shpnt);
static void datao_init(struct Scsi_Host *shpnt);
static void datao_run(struct Scsi_Host *shpnt);
static void datao_end(struct Scsi_Host *shpnt);
static void status_run(struct Scsi_Host *shpnt);
static void msgi_run(struct Scsi_Host *shpnt);
static void msgi_end(struct Scsi_Host *shpnt);
static void parerr_run(struct Scsi_Host *shpnt);
static void rsti_run(struct Scsi_Host *shpnt);
static void is_complete(struct Scsi_Host *shpnt);
static struct { … } states[] = …;
static irqreturn_t intr(int irq, void *dev_id);
static void reset_ports(struct Scsi_Host *shpnt);
static void aha152x_error(struct Scsi_Host *shpnt, char *msg);
static void done(struct Scsi_Host *shpnt, unsigned char status_byte,
unsigned char host_byte);
static void show_command(struct scsi_cmnd * ptr);
static void show_queues(struct Scsi_Host *shpnt);
static void disp_enintr(struct Scsi_Host *shpnt);
static inline void append_SC(struct scsi_cmnd **SC, struct scsi_cmnd *new_SC)
{ … }
static inline struct scsi_cmnd *remove_first_SC(struct scsi_cmnd ** SC)
{ … }
static inline struct scsi_cmnd *remove_lun_SC(struct scsi_cmnd ** SC,
int target, int lun)
{ … }
static inline struct scsi_cmnd *remove_SC(struct scsi_cmnd **SC,
struct scsi_cmnd *SCp)
{ … }
static irqreturn_t swintr(int irqno, void *dev_id)
{ … }
struct Scsi_Host *aha152x_probe_one(struct aha152x_setup *setup)
{ … }
void aha152x_release(struct Scsi_Host *shpnt)
{ … }
static int setup_expected_interrupts(struct Scsi_Host *shpnt)
{ … }
static int aha152x_internal_queue(struct scsi_cmnd *SCpnt,
struct completion *complete, int phase)
{ … }
static int aha152x_queue_lck(struct scsi_cmnd *SCpnt)
{ … }
static DEF_SCSI_QCMD(aha152x_queue)
static void reset_done(struct scsi_cmnd *SCpnt)
{ … }
static void aha152x_scsi_done(struct scsi_cmnd *SCpnt)
{ … }
static int aha152x_abort(struct scsi_cmnd *SCpnt)
{ … }
static int aha152x_device_reset(struct scsi_cmnd * SCpnt)
{ … }
static void free_hard_reset_SCs(struct Scsi_Host *shpnt,
struct scsi_cmnd **SCs)
{ … }
static int aha152x_bus_reset_host(struct Scsi_Host *shpnt)
{ … }
static int aha152x_bus_reset(struct scsi_cmnd *SCpnt)
{ … }
static void reset_ports(struct Scsi_Host *shpnt)
{ … }
int aha152x_host_reset_host(struct Scsi_Host *shpnt)
{ … }
static int aha152x_biosparam(struct scsi_device *sdev, struct block_device *bdev,
sector_t capacity, int *info_array)
{ … }
static void done(struct Scsi_Host *shpnt, unsigned char status_byte,
unsigned char host_byte)
{ … }
static struct work_struct aha152x_tq;
static void run(struct work_struct *work)
{ … }
static irqreturn_t intr(int irqno, void *dev_id)
{ … }
static void busfree_run(struct Scsi_Host *shpnt)
{ … }
static void seldo_run(struct Scsi_Host *shpnt)
{ … }
static void selto_run(struct Scsi_Host *shpnt)
{ … }
static void seldi_run(struct Scsi_Host *shpnt)
{ … }
static void msgi_run(struct Scsi_Host *shpnt)
{ … }
static void msgi_end(struct Scsi_Host *shpnt)
{ … }
static void msgo_init(struct Scsi_Host *shpnt)
{ … }
static void msgo_run(struct Scsi_Host *shpnt)
{ … }
static void msgo_end(struct Scsi_Host *shpnt)
{ … }
static void cmd_init(struct Scsi_Host *shpnt)
{ … }
static void cmd_run(struct Scsi_Host *shpnt)
{ … }
static void cmd_end(struct Scsi_Host *shpnt)
{ … }
static void status_run(struct Scsi_Host *shpnt)
{ … }
static void datai_init(struct Scsi_Host *shpnt)
{ … }
static void datai_run(struct Scsi_Host *shpnt)
{ … }
static void datai_end(struct Scsi_Host *shpnt)
{ … }
static void datao_init(struct Scsi_Host *shpnt)
{ … }
static void datao_run(struct Scsi_Host *shpnt)
{ … }
static void datao_end(struct Scsi_Host *shpnt)
{ … }
static int update_state(struct Scsi_Host *shpnt)
{ … }
static void parerr_run(struct Scsi_Host *shpnt)
{ … }
static void rsti_run(struct Scsi_Host *shpnt)
{ … }
static void is_complete(struct Scsi_Host *shpnt)
{ … }
static void aha152x_error(struct Scsi_Host *shpnt, char *msg)
{ … }
static void disp_enintr(struct Scsi_Host *shpnt)
{ … }
static void show_command(struct scsi_cmnd *ptr)
{ … }
static void show_queues(struct Scsi_Host *shpnt)
{ … }
static void get_command(struct seq_file *m, struct scsi_cmnd * ptr)
{ … }
static void get_ports(struct seq_file *m, struct Scsi_Host *shpnt)
{ … }
static int aha152x_set_info(struct Scsi_Host *shpnt, char *buffer, int length)
{ … }
static int aha152x_show_info(struct seq_file *m, struct Scsi_Host *shpnt)
{ … }
static const struct scsi_host_template aha152x_driver_template = …;
#if !defined(AHA152X_PCMCIA)
static int setup_count;
static struct aha152x_setup setup[2];
static unsigned short ports[] = { 0x340, 0x140 };
#if !defined(SKIP_BIOSTEST)
static unsigned int addresses[] =
{
0xdc000,
0xc8000,
0xcc000,
0xd0000,
0xd4000,
0xd8000,
0xe0000,
0xeb800,
0xf0000,
};
static struct signature {
unsigned char *signature;
int sig_offset;
int sig_length;
} signatures[] =
{
{ "Adaptec AHA-1520 BIOS", 0x102e, 21 },
{ "Adaptec AHA-1520B", 0x000b, 17 },
{ "Adaptec AHA-1520B", 0x0026, 17 },
{ "Adaptec ASW-B626 BIOS", 0x1029, 21 },
{ "Adaptec BIOS: ASW-B626", 0x000f, 22 },
{ "Adaptec ASW-B626 S2", 0x2e6c, 19 },
{ "Adaptec BIOS:AIC-6360", 0x000c, 21 },
{ "ScsiPro SP-360 BIOS", 0x2873, 19 },
{ "GA-400 LOCAL BUS SCSI BIOS", 0x102e, 26 },
{ "Adaptec BIOS:AVA-282X", 0x000c, 21 },
{ "Adaptec IBM Dock II SCSI", 0x2edd, 24 },
{ "Adaptec BIOS:AHA-1532P", 0x001c, 22 },
{ "DTC3520A Host Adapter BIOS", 0x318a, 26 },
};
#endif
static int aha152x_porttest(int io_port)
{
int i;
SETPORT(io_port + O_DMACNTRL1, 0);
for (i = 0; i < 16; i++)
SETPORT(io_port + O_STACK, i);
SETPORT(io_port + O_DMACNTRL1, 0);
for (i = 0; i < 16 && GETPORT(io_port + O_STACK) == i; i++)
;
return (i == 16);
}
static int tc1550_porttest(int io_port)
{
int i;
SETPORT(io_port + O_TC_DMACNTRL1, 0);
for (i = 0; i < 16; i++)
SETPORT(io_port + O_STACK, i);
SETPORT(io_port + O_TC_DMACNTRL1, 0);
for (i = 0; i < 16 && GETPORT(io_port + O_TC_STACK) == i; i++)
;
return (i == 16);
}
static int checksetup(struct aha152x_setup *setup)
{
int i;
for (i = 0; i < ARRAY_SIZE(ports) && (setup->io_port != ports[i]); i++)
;
if (i == ARRAY_SIZE(ports))
return 0;
if (!request_region(setup->io_port, IO_RANGE, "aha152x")) {
printk(KERN_ERR "aha152x: io port 0x%x busy.\n", setup->io_port);
return 0;
}
if( aha152x_porttest(setup->io_port) ) {
setup->tc1550=0;
} else if( tc1550_porttest(setup->io_port) ) {
setup->tc1550=1;
} else {
release_region(setup->io_port, IO_RANGE);
return 0;
}
release_region(setup->io_port, IO_RANGE);
if ((setup->irq < IRQ_MIN) || (setup->irq > IRQ_MAX))
return 0;
if ((setup->scsiid < 0) || (setup->scsiid > 7))
return 0;
if ((setup->reconnect < 0) || (setup->reconnect > 1))
return 0;
if ((setup->parity < 0) || (setup->parity > 1))
return 0;
if ((setup->synchronous < 0) || (setup->synchronous > 1))
return 0;
if ((setup->ext_trans < 0) || (setup->ext_trans > 1))
return 0;
return 1;
}
static int __init aha152x_init(void)
{
int i, j, ok;
#if defined(AUTOCONF)
aha152x_config conf;
#endif
#ifdef __ISAPNP__
struct pnp_dev *dev=NULL, *pnpdev[2] = {NULL, NULL};
#endif
if ( setup_count ) {
printk(KERN_INFO "aha152x: processing commandline: ");
for (i = 0; i<setup_count; i++) {
if (!checksetup(&setup[i])) {
printk(KERN_ERR "\naha152x: %s\n", setup[i].conf);
printk(KERN_ERR "aha152x: invalid line\n");
}
}
printk("ok\n");
}
#if defined(SETUP0)
if (setup_count < ARRAY_SIZE(setup)) {
struct aha152x_setup override = SETUP0;
if (setup_count == 0 || (override.io_port != setup[0].io_port)) {
if (!checksetup(&override)) {
printk(KERN_ERR "\naha152x: invalid override SETUP0={0x%x,%d,%d,%d,%d,%d,%d,%d}\n",
override.io_port,
override.irq,
override.scsiid,
override.reconnect,
override.parity,
override.synchronous,
override.delay,
override.ext_trans);
} else
setup[setup_count++] = override;
}
}
#endif
#if defined(SETUP1)
if (setup_count < ARRAY_SIZE(setup)) {
struct aha152x_setup override = SETUP1;
if (setup_count == 0 || (override.io_port != setup[0].io_port)) {
if (!checksetup(&override)) {
printk(KERN_ERR "\naha152x: invalid override SETUP1={0x%x,%d,%d,%d,%d,%d,%d,%d}\n",
override.io_port,
override.irq,
override.scsiid,
override.reconnect,
override.parity,
override.synchronous,
override.delay,
override.ext_trans);
} else
setup[setup_count++] = override;
}
}
#endif
#if defined(MODULE)
if (setup_count<ARRAY_SIZE(setup) && (aha152x[0]!=0 || io[0]!=0 || irq[0]!=0)) {
if(aha152x[0]!=0) {
setup[setup_count].conf = "";
setup[setup_count].io_port = aha152x[0];
setup[setup_count].irq = aha152x[1];
setup[setup_count].scsiid = aha152x[2];
setup[setup_count].reconnect = aha152x[3];
setup[setup_count].parity = aha152x[4];
setup[setup_count].synchronous = aha152x[5];
setup[setup_count].delay = aha152x[6];
setup[setup_count].ext_trans = aha152x[7];
} else if (io[0] != 0 || irq[0] != 0) {
if(io[0]!=0) setup[setup_count].io_port = io[0];
if(irq[0]!=0) setup[setup_count].irq = irq[0];
setup[setup_count].scsiid = scsiid[0];
setup[setup_count].reconnect = reconnect[0];
setup[setup_count].parity = parity[0];
setup[setup_count].synchronous = sync[0];
setup[setup_count].delay = delay[0];
setup[setup_count].ext_trans = exttrans[0];
}
if (checksetup(&setup[setup_count]))
setup_count++;
else
printk(KERN_ERR "aha152x: invalid module params io=0x%x, irq=%d,scsiid=%d,reconnect=%d,parity=%d,sync=%d,delay=%d,exttrans=%d\n",
setup[setup_count].io_port,
setup[setup_count].irq,
setup[setup_count].scsiid,
setup[setup_count].reconnect,
setup[setup_count].parity,
setup[setup_count].synchronous,
setup[setup_count].delay,
setup[setup_count].ext_trans);
}
if (setup_count<ARRAY_SIZE(setup) && (aha152x1[0]!=0 || io[1]!=0 || irq[1]!=0)) {
if(aha152x1[0]!=0) {
setup[setup_count].conf = "";
setup[setup_count].io_port = aha152x1[0];
setup[setup_count].irq = aha152x1[1];
setup[setup_count].scsiid = aha152x1[2];
setup[setup_count].reconnect = aha152x1[3];
setup[setup_count].parity = aha152x1[4];
setup[setup_count].synchronous = aha152x1[5];
setup[setup_count].delay = aha152x1[6];
setup[setup_count].ext_trans = aha152x1[7];
} else if (io[1] != 0 || irq[1] != 0) {
if(io[1]!=0) setup[setup_count].io_port = io[1];
if(irq[1]!=0) setup[setup_count].irq = irq[1];
setup[setup_count].scsiid = scsiid[1];
setup[setup_count].reconnect = reconnect[1];
setup[setup_count].parity = parity[1];
setup[setup_count].synchronous = sync[1];
setup[setup_count].delay = delay[1];
setup[setup_count].ext_trans = exttrans[1];
}
if (checksetup(&setup[setup_count]))
setup_count++;
else
printk(KERN_ERR "aha152x: invalid module params io=0x%x, irq=%d,scsiid=%d,reconnect=%d,parity=%d,sync=%d,delay=%d,exttrans=%d\n",
setup[setup_count].io_port,
setup[setup_count].irq,
setup[setup_count].scsiid,
setup[setup_count].reconnect,
setup[setup_count].parity,
setup[setup_count].synchronous,
setup[setup_count].delay,
setup[setup_count].ext_trans);
}
#endif
#ifdef __ISAPNP__
for(i=0; setup_count<ARRAY_SIZE(setup) && id_table[i].vendor; i++) {
while ( setup_count<ARRAY_SIZE(setup) &&
(dev=pnp_find_dev(NULL, id_table[i].vendor, id_table[i].function, dev)) ) {
if (pnp_device_attach(dev) < 0)
continue;
if (pnp_activate_dev(dev) < 0) {
pnp_device_detach(dev);
continue;
}
if (!pnp_port_valid(dev, 0)) {
pnp_device_detach(dev);
continue;
}
if (setup_count==1 && pnp_port_start(dev, 0)==setup[0].io_port) {
pnp_device_detach(dev);
continue;
}
setup[setup_count].io_port = pnp_port_start(dev, 0);
setup[setup_count].irq = pnp_irq(dev, 0);
setup[setup_count].scsiid = 7;
setup[setup_count].reconnect = 1;
setup[setup_count].parity = 1;
setup[setup_count].synchronous = 1;
setup[setup_count].delay = DELAY_DEFAULT;
setup[setup_count].ext_trans = 0;
#if defined(__ISAPNP__)
pnpdev[setup_count] = dev;
#endif
printk (KERN_INFO
"aha152x: found ISAPnP adapter at io=0x%03x, irq=%d\n",
setup[setup_count].io_port, setup[setup_count].irq);
setup_count++;
}
}
#endif
#if defined(AUTOCONF)
if (setup_count<ARRAY_SIZE(setup)) {
#if !defined(SKIP_BIOSTEST)
ok = 0;
for (i = 0; i < ARRAY_SIZE(addresses) && !ok; i++) {
void __iomem *p = ioremap(addresses[i], 0x4000);
if (!p)
continue;
for (j = 0; j<ARRAY_SIZE(signatures) && !ok; j++)
ok = check_signature(p + signatures[j].sig_offset,
signatures[j].signature, signatures[j].sig_length);
iounmap(p);
}
if (!ok && setup_count == 0)
return -ENODEV;
printk(KERN_INFO "aha152x: BIOS test: passed, ");
#else
printk(KERN_INFO "aha152x: ");
#endif
ok = 0;
for (i = 0; i < ARRAY_SIZE(ports) && setup_count < 2; i++) {
if ((setup_count == 1) && (setup[0].io_port == ports[i]))
continue;
if (!request_region(ports[i], IO_RANGE, "aha152x")) {
printk(KERN_ERR "aha152x: io port 0x%x busy.\n", ports[i]);
continue;
}
if (aha152x_porttest(ports[i])) {
setup[setup_count].tc1550 = 0;
conf.cf_port =
(GETPORT(ports[i] + O_PORTA) << 8) + GETPORT(ports[i] + O_PORTB);
} else if (tc1550_porttest(ports[i])) {
setup[setup_count].tc1550 = 1;
conf.cf_port =
(GETPORT(ports[i] + O_TC_PORTA) << 8) + GETPORT(ports[i] + O_TC_PORTB);
} else {
release_region(ports[i], IO_RANGE);
continue;
}
release_region(ports[i], IO_RANGE);
ok++;
setup[setup_count].io_port = ports[i];
setup[setup_count].irq = IRQ_MIN + conf.cf_irq;
setup[setup_count].scsiid = conf.cf_id;
setup[setup_count].reconnect = conf.cf_tardisc;
setup[setup_count].parity = !conf.cf_parity;
setup[setup_count].synchronous = conf.cf_syncneg;
setup[setup_count].delay = DELAY_DEFAULT;
setup[setup_count].ext_trans = 0;
setup_count++;
}
if (ok)
printk("auto configuration: ok, ");
}
#endif
printk("%d controller(s) configured\n", setup_count);
for (i=0; i<setup_count; i++) {
if ( request_region(setup[i].io_port, IO_RANGE, "aha152x") ) {
struct Scsi_Host *shpnt = aha152x_probe_one(&setup[i]);
if( !shpnt ) {
release_region(setup[i].io_port, IO_RANGE);
#if defined(__ISAPNP__)
} else if( pnpdev[i] ) {
HOSTDATA(shpnt)->pnpdev=pnpdev[i];
pnpdev[i]=NULL;
#endif
}
} else {
printk(KERN_ERR "aha152x: io port 0x%x busy.\n", setup[i].io_port);
}
#if defined(__ISAPNP__)
if( pnpdev[i] )
pnp_device_detach(pnpdev[i]);
#endif
}
return 0;
}
static void __exit aha152x_exit(void)
{
struct aha152x_hostdata *hd, *tmp;
list_for_each_entry_safe(hd, tmp, &aha152x_host_list, host_list) {
struct Scsi_Host *shost = container_of((void *)hd, struct Scsi_Host, hostdata);
aha152x_release(shost);
}
}
module_init(aha152x_init);
module_exit(aha152x_exit);
#if !defined(MODULE)
static int __init aha152x_setup(char *str)
{
int ints[10];
get_options(str, ARRAY_SIZE(ints), ints);
if(setup_count>=ARRAY_SIZE(setup)) {
printk(KERN_ERR "aha152x: you can only configure up to two controllers\n");
return 1;
}
setup[setup_count].conf = str;
setup[setup_count].io_port = ints[0] >= 1 ? ints[1] : 0x340;
setup[setup_count].irq = ints[0] >= 2 ? ints[2] : 11;
setup[setup_count].scsiid = ints[0] >= 3 ? ints[3] : 7;
setup[setup_count].reconnect = ints[0] >= 4 ? ints[4] : 1;
setup[setup_count].parity = ints[0] >= 5 ? ints[5] : 1;
setup[setup_count].synchronous = ints[0] >= 6 ? ints[6] : 1;
setup[setup_count].delay = ints[0] >= 7 ? ints[7] : DELAY_DEFAULT;
setup[setup_count].ext_trans = ints[0] >= 8 ? ints[8] : 0;
if (ints[0] > 8)
printk(KERN_NOTICE "aha152x: usage: aha152x=<IOBASE>[,<IRQ>[,<SCSI ID>"
"[,<RECONNECT>[,<PARITY>[,<SYNCHRONOUS>[,<DELAY>[,<EXT_TRANS>]]]]]]]\n");
else
setup_count++;
return 1;
}
__setup("aha152x=", aha152x_setup);
#endif
#endif