提交 7a93aef7 编写于 作者: J James Bottomley

Merge HEAD from ../scsi-misc-2.6-tmp

==================================================================== ====================================================================
= Adaptec Aic7xxx Fast -> Ultra160 Family Manager Set v6.2.28 = = Adaptec Aic7xxx Fast -> Ultra160 Family Manager Set v7.0 =
= README for = = README for =
= The Linux Operating System = = The Linux Operating System =
==================================================================== ====================================================================
...@@ -131,6 +131,10 @@ The following information is available in this file: ...@@ -131,6 +131,10 @@ The following information is available in this file:
SCSI "stub" effects. SCSI "stub" effects.
2. Version History 2. Version History
7.0 (4th August, 2005)
- Updated driver to use SCSI transport class infrastructure
- Upported sequencer and core fixes from last adaptec released
version of the driver.
6.2.36 (June 3rd, 2003) 6.2.36 (June 3rd, 2003)
- Correct code that disables PCI parity error checking. - Correct code that disables PCI parity error checking.
- Correct and simplify handling of the ignore wide residue - Correct and simplify handling of the ignore wide residue
......
...@@ -824,6 +824,13 @@ L: emu10k1-devel@lists.sourceforge.net ...@@ -824,6 +824,13 @@ L: emu10k1-devel@lists.sourceforge.net
W: http://sourceforge.net/projects/emu10k1/ W: http://sourceforge.net/projects/emu10k1/
S: Maintained S: Maintained
EMULEX LPFC FC SCSI DRIVER
P: James Smart
M: james.smart@emulex.com
L: linux-scsi@vger.kernel.org
W: http://sourceforge.net/projects/lpfcxxxx
S: Supported
EPSON 1355 FRAMEBUFFER DRIVER EPSON 1355 FRAMEBUFFER DRIVER
P: Christopher Hoover P: Christopher Hoover
M: ch@murgatroid.com, ch@hpl.hp.com M: ch@murgatroid.com, ch@hpl.hp.com
......
...@@ -58,6 +58,7 @@ attribute_container_register(struct attribute_container *cont) ...@@ -58,6 +58,7 @@ attribute_container_register(struct attribute_container *cont)
{ {
INIT_LIST_HEAD(&cont->node); INIT_LIST_HEAD(&cont->node);
INIT_LIST_HEAD(&cont->containers); INIT_LIST_HEAD(&cont->containers);
spin_lock_init(&cont->containers_lock);
down(&attribute_container_mutex); down(&attribute_container_mutex);
list_add_tail(&cont->node, &attribute_container_list); list_add_tail(&cont->node, &attribute_container_list);
...@@ -77,11 +78,13 @@ attribute_container_unregister(struct attribute_container *cont) ...@@ -77,11 +78,13 @@ attribute_container_unregister(struct attribute_container *cont)
{ {
int retval = -EBUSY; int retval = -EBUSY;
down(&attribute_container_mutex); down(&attribute_container_mutex);
spin_lock(&cont->containers_lock);
if (!list_empty(&cont->containers)) if (!list_empty(&cont->containers))
goto out; goto out;
retval = 0; retval = 0;
list_del(&cont->node); list_del(&cont->node);
out: out:
spin_unlock(&cont->containers_lock);
up(&attribute_container_mutex); up(&attribute_container_mutex);
return retval; return retval;
...@@ -151,7 +154,9 @@ attribute_container_add_device(struct device *dev, ...@@ -151,7 +154,9 @@ attribute_container_add_device(struct device *dev,
fn(cont, dev, &ic->classdev); fn(cont, dev, &ic->classdev);
else else
attribute_container_add_class_device(&ic->classdev); attribute_container_add_class_device(&ic->classdev);
spin_lock(&cont->containers_lock);
list_add_tail(&ic->node, &cont->containers); list_add_tail(&ic->node, &cont->containers);
spin_unlock(&cont->containers_lock);
} }
up(&attribute_container_mutex); up(&attribute_container_mutex);
} }
...@@ -189,6 +194,7 @@ attribute_container_remove_device(struct device *dev, ...@@ -189,6 +194,7 @@ attribute_container_remove_device(struct device *dev,
if (!cont->match(cont, dev)) if (!cont->match(cont, dev))
continue; continue;
spin_lock(&cont->containers_lock);
list_for_each_entry_safe(ic, tmp, &cont->containers, node) { list_for_each_entry_safe(ic, tmp, &cont->containers, node) {
if (dev != ic->classdev.dev) if (dev != ic->classdev.dev)
continue; continue;
...@@ -200,6 +206,7 @@ attribute_container_remove_device(struct device *dev, ...@@ -200,6 +206,7 @@ attribute_container_remove_device(struct device *dev,
class_device_unregister(&ic->classdev); class_device_unregister(&ic->classdev);
} }
} }
spin_unlock(&cont->containers_lock);
} }
up(&attribute_container_mutex); up(&attribute_container_mutex);
} }
...@@ -230,10 +237,17 @@ attribute_container_device_trigger(struct device *dev, ...@@ -230,10 +237,17 @@ attribute_container_device_trigger(struct device *dev,
if (!cont->match(cont, dev)) if (!cont->match(cont, dev))
continue; continue;
if (attribute_container_no_classdevs(cont)) {
fn(cont, dev, NULL);
continue;
}
spin_lock(&cont->containers_lock);
list_for_each_entry_safe(ic, tmp, &cont->containers, node) { list_for_each_entry_safe(ic, tmp, &cont->containers, node) {
if (dev == ic->classdev.dev) if (dev == ic->classdev.dev)
fn(cont, dev, &ic->classdev); fn(cont, dev, &ic->classdev);
} }
spin_unlock(&cont->containers_lock);
} }
up(&attribute_container_mutex); up(&attribute_container_mutex);
} }
...@@ -368,6 +382,35 @@ attribute_container_class_device_del(struct class_device *classdev) ...@@ -368,6 +382,35 @@ attribute_container_class_device_del(struct class_device *classdev)
} }
EXPORT_SYMBOL_GPL(attribute_container_class_device_del); EXPORT_SYMBOL_GPL(attribute_container_class_device_del);
/**
* attribute_container_find_class_device - find the corresponding class_device
*
* @cont: the container
* @dev: the generic device
*
* Looks up the device in the container's list of class devices and returns
* the corresponding class_device.
*/
struct class_device *
attribute_container_find_class_device(struct attribute_container *cont,
struct device *dev)
{
struct class_device *cdev = NULL;
struct internal_container *ic;
spin_lock(&cont->containers_lock);
list_for_each_entry(ic, &cont->containers, node) {
if (ic->classdev.dev == dev) {
cdev = &ic->classdev;
break;
}
}
spin_unlock(&cont->containers_lock);
return cdev;
}
EXPORT_SYMBOL_GPL(attribute_container_find_class_device);
int __init int __init
attribute_container_init(void) attribute_container_init(void)
{ {
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* This file is licensed under GPLv2 * This file is licensed under GPLv2
* *
* The basic idea here is to allow any "device controller" (which * The basic idea here is to allow any "device controller" (which
* would most often be a Host Bus Adapter" to use the services of one * would most often be a Host Bus Adapter to use the services of one
* or more tranport classes for performing transport specific * or more tranport classes for performing transport specific
* services. Transport specific services are things that the generic * services. Transport specific services are things that the generic
* command layer doesn't want to know about (speed settings, line * command layer doesn't want to know about (speed settings, line
...@@ -64,7 +64,9 @@ void transport_class_unregister(struct transport_class *tclass) ...@@ -64,7 +64,9 @@ void transport_class_unregister(struct transport_class *tclass)
} }
EXPORT_SYMBOL_GPL(transport_class_unregister); EXPORT_SYMBOL_GPL(transport_class_unregister);
static int anon_transport_dummy_function(struct device *dev) static int anon_transport_dummy_function(struct transport_container *tc,
struct device *dev,
struct class_device *cdev)
{ {
/* do nothing */ /* do nothing */
return 0; return 0;
...@@ -115,9 +117,10 @@ static int transport_setup_classdev(struct attribute_container *cont, ...@@ -115,9 +117,10 @@ static int transport_setup_classdev(struct attribute_container *cont,
struct class_device *classdev) struct class_device *classdev)
{ {
struct transport_class *tclass = class_to_transport_class(cont->class); struct transport_class *tclass = class_to_transport_class(cont->class);
struct transport_container *tcont = attribute_container_to_transport_container(cont);
if (tclass->setup) if (tclass->setup)
tclass->setup(dev); tclass->setup(tcont, dev, classdev);
return 0; return 0;
} }
...@@ -178,12 +181,14 @@ void transport_add_device(struct device *dev) ...@@ -178,12 +181,14 @@ void transport_add_device(struct device *dev)
EXPORT_SYMBOL_GPL(transport_add_device); EXPORT_SYMBOL_GPL(transport_add_device);
static int transport_configure(struct attribute_container *cont, static int transport_configure(struct attribute_container *cont,
struct device *dev) struct device *dev,
struct class_device *cdev)
{ {
struct transport_class *tclass = class_to_transport_class(cont->class); struct transport_class *tclass = class_to_transport_class(cont->class);
struct transport_container *tcont = attribute_container_to_transport_container(cont);
if (tclass->configure) if (tclass->configure)
tclass->configure(dev); tclass->configure(tcont, dev, cdev);
return 0; return 0;
} }
...@@ -202,7 +207,7 @@ static int transport_configure(struct attribute_container *cont, ...@@ -202,7 +207,7 @@ static int transport_configure(struct attribute_container *cont,
*/ */
void transport_configure_device(struct device *dev) void transport_configure_device(struct device *dev)
{ {
attribute_container_trigger(dev, transport_configure); attribute_container_device_trigger(dev, transport_configure);
} }
EXPORT_SYMBOL_GPL(transport_configure_device); EXPORT_SYMBOL_GPL(transport_configure_device);
...@@ -215,7 +220,7 @@ static int transport_remove_classdev(struct attribute_container *cont, ...@@ -215,7 +220,7 @@ static int transport_remove_classdev(struct attribute_container *cont,
struct transport_class *tclass = class_to_transport_class(cont->class); struct transport_class *tclass = class_to_transport_class(cont->class);
if (tclass->remove) if (tclass->remove)
tclass->remove(dev); tclass->remove(tcont, dev, classdev);
if (tclass->remove != anon_transport_dummy_function) { if (tclass->remove != anon_transport_dummy_function) {
if (tcont->statistics) if (tcont->statistics)
......
...@@ -133,6 +133,7 @@ struct inquiry_data { ...@@ -133,6 +133,7 @@ struct inquiry_data {
static unsigned long aac_build_sg(struct scsi_cmnd* scsicmd, struct sgmap* sgmap); static unsigned long aac_build_sg(struct scsi_cmnd* scsicmd, struct sgmap* sgmap);
static unsigned long aac_build_sg64(struct scsi_cmnd* scsicmd, struct sgmap64* psg); static unsigned long aac_build_sg64(struct scsi_cmnd* scsicmd, struct sgmap64* psg);
static unsigned long aac_build_sgraw(struct scsi_cmnd* scsicmd, struct sgmapraw* psg);
static int aac_send_srb_fib(struct scsi_cmnd* scsicmd); static int aac_send_srb_fib(struct scsi_cmnd* scsicmd);
#ifdef AAC_DETAILED_STATUS_INFO #ifdef AAC_DETAILED_STATUS_INFO
static char *aac_get_status_string(u32 status); static char *aac_get_status_string(u32 status);
...@@ -348,6 +349,27 @@ static void aac_io_done(struct scsi_cmnd * scsicmd) ...@@ -348,6 +349,27 @@ static void aac_io_done(struct scsi_cmnd * scsicmd)
spin_unlock_irqrestore(host->host_lock, cpu_flags); spin_unlock_irqrestore(host->host_lock, cpu_flags);
} }
static void aac_internal_transfer(struct scsi_cmnd *scsicmd, void *data, unsigned int offset, unsigned int len)
{
void *buf;
unsigned int transfer_len;
struct scatterlist *sg = scsicmd->request_buffer;
if (scsicmd->use_sg) {
buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
transfer_len = min(sg->length, len + offset);
} else {
buf = scsicmd->request_buffer;
transfer_len = min(scsicmd->request_bufflen, len + offset);
}
memcpy(buf + offset, data, transfer_len - offset);
if (scsicmd->use_sg)
kunmap_atomic(buf - sg->offset, KM_IRQ0);
}
static void get_container_name_callback(void *context, struct fib * fibptr) static void get_container_name_callback(void *context, struct fib * fibptr)
{ {
struct aac_get_name_resp * get_name_reply; struct aac_get_name_resp * get_name_reply;
...@@ -363,18 +385,22 @@ static void get_container_name_callback(void *context, struct fib * fibptr) ...@@ -363,18 +385,22 @@ static void get_container_name_callback(void *context, struct fib * fibptr)
/* Failure is irrelevant, using default value instead */ /* Failure is irrelevant, using default value instead */
if ((le32_to_cpu(get_name_reply->status) == CT_OK) if ((le32_to_cpu(get_name_reply->status) == CT_OK)
&& (get_name_reply->data[0] != '\0')) { && (get_name_reply->data[0] != '\0')) {
int count; char *sp = get_name_reply->data;
char * dp;
char * sp = get_name_reply->data;
sp[sizeof(((struct aac_get_name_resp *)NULL)->data)-1] = '\0'; sp[sizeof(((struct aac_get_name_resp *)NULL)->data)-1] = '\0';
while (*sp == ' ') while (*sp == ' ')
++sp; ++sp;
count = sizeof(((struct inquiry_data *)NULL)->inqd_pid); if (*sp) {
dp = ((struct inquiry_data *)scsicmd->request_buffer)->inqd_pid; char d[sizeof(((struct inquiry_data *)NULL)->inqd_pid)];
if (*sp) do { int count = sizeof(d);
*dp++ = (*sp) ? *sp++ : ' '; char *dp = d;
} while (--count > 0); do {
*dp++ = (*sp) ? *sp++ : ' ';
} while (--count > 0);
aac_internal_transfer(scsicmd, d,
offsetof(struct inquiry_data, inqd_pid), sizeof(d));
}
} }
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
fib_complete(fibptr); fib_complete(fibptr);
...@@ -777,34 +803,36 @@ int aac_get_adapter_info(struct aac_dev* dev) ...@@ -777,34 +803,36 @@ int aac_get_adapter_info(struct aac_dev* dev)
/* /*
* 57 scatter gather elements * 57 scatter gather elements
*/ */
dev->scsi_host_ptr->sg_tablesize = (dev->max_fib_size - if (!(dev->raw_io_interface)) {
sizeof(struct aac_fibhdr) - dev->scsi_host_ptr->sg_tablesize = (dev->max_fib_size -
sizeof(struct aac_write) + sizeof(struct sgmap)) /
sizeof(struct sgmap);
if (dev->dac_support) {
/*
* 38 scatter gather elements
*/
dev->scsi_host_ptr->sg_tablesize =
(dev->max_fib_size -
sizeof(struct aac_fibhdr) - sizeof(struct aac_fibhdr) -
sizeof(struct aac_write64) + sizeof(struct aac_write) + sizeof(struct sgmap)) /
sizeof(struct sgmap64)) / sizeof(struct sgmap);
sizeof(struct sgmap64); if (dev->dac_support) {
} /*
dev->scsi_host_ptr->max_sectors = AAC_MAX_32BIT_SGBCOUNT; * 38 scatter gather elements
if(!(dev->adapter_info.options & AAC_OPT_NEW_COMM)) { */
/* dev->scsi_host_ptr->sg_tablesize =
* Worst case size that could cause sg overflow when (dev->max_fib_size -
* we break up SG elements that are larger than 64KB. sizeof(struct aac_fibhdr) -
* Would be nice if we could tell the SCSI layer what sizeof(struct aac_write64) +
* the maximum SG element size can be. Worst case is sizeof(struct sgmap64)) /
* (sg_tablesize-1) 4KB elements with one 64KB sizeof(struct sgmap64);
* element. }
* 32bit -> 468 or 238KB 64bit -> 424 or 212KB dev->scsi_host_ptr->max_sectors = AAC_MAX_32BIT_SGBCOUNT;
*/ if(!(dev->adapter_info.options & AAC_OPT_NEW_COMM)) {
dev->scsi_host_ptr->max_sectors = /*
(dev->scsi_host_ptr->sg_tablesize * 8) + 112; * Worst case size that could cause sg overflow when
* we break up SG elements that are larger than 64KB.
* Would be nice if we could tell the SCSI layer what
* the maximum SG element size can be. Worst case is
* (sg_tablesize-1) 4KB elements with one 64KB
* element.
* 32bit -> 468 or 238KB 64bit -> 424 or 212KB
*/
dev->scsi_host_ptr->max_sectors =
(dev->scsi_host_ptr->sg_tablesize * 8) + 112;
}
} }
fib_complete(fibptr); fib_complete(fibptr);
...@@ -814,12 +842,11 @@ int aac_get_adapter_info(struct aac_dev* dev) ...@@ -814,12 +842,11 @@ int aac_get_adapter_info(struct aac_dev* dev)
} }
static void read_callback(void *context, struct fib * fibptr) static void io_callback(void *context, struct fib * fibptr)
{ {
struct aac_dev *dev; struct aac_dev *dev;
struct aac_read_reply *readreply; struct aac_read_reply *readreply;
struct scsi_cmnd *scsicmd; struct scsi_cmnd *scsicmd;
u32 lba;
u32 cid; u32 cid;
scsicmd = (struct scsi_cmnd *) context; scsicmd = (struct scsi_cmnd *) context;
...@@ -827,8 +854,7 @@ static void read_callback(void *context, struct fib * fibptr) ...@@ -827,8 +854,7 @@ static void read_callback(void *context, struct fib * fibptr)
dev = (struct aac_dev *)scsicmd->device->host->hostdata; dev = (struct aac_dev *)scsicmd->device->host->hostdata;
cid = ID_LUN_TO_CONTAINER(scsicmd->device->id, scsicmd->device->lun); cid = ID_LUN_TO_CONTAINER(scsicmd->device->id, scsicmd->device->lun);
lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3]; dprintk((KERN_DEBUG "io_callback[cpu %d]: lba = %u, t = %ld.\n", smp_processor_id(), ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3], jiffies));
dprintk((KERN_DEBUG "read_callback[cpu %d]: lba = %u, t = %ld.\n", smp_processor_id(), lba, jiffies));
if (fibptr == NULL) if (fibptr == NULL)
BUG(); BUG();
...@@ -847,7 +873,7 @@ static void read_callback(void *context, struct fib * fibptr) ...@@ -847,7 +873,7 @@ static void read_callback(void *context, struct fib * fibptr)
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
else { else {
#ifdef AAC_DETAILED_STATUS_INFO #ifdef AAC_DETAILED_STATUS_INFO
printk(KERN_WARNING "read_callback: io failed, status = %d\n", printk(KERN_WARNING "io_callback: io failed, status = %d\n",
le32_to_cpu(readreply->status)); le32_to_cpu(readreply->status));
#endif #endif
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION; scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
...@@ -867,53 +893,6 @@ static void read_callback(void *context, struct fib * fibptr) ...@@ -867,53 +893,6 @@ static void read_callback(void *context, struct fib * fibptr)
aac_io_done(scsicmd); aac_io_done(scsicmd);
} }
static void write_callback(void *context, struct fib * fibptr)
{
struct aac_dev *dev;
struct aac_write_reply *writereply;
struct scsi_cmnd *scsicmd;
u32 lba;
u32 cid;
scsicmd = (struct scsi_cmnd *) context;
dev = (struct aac_dev *)scsicmd->device->host->hostdata;
cid = ID_LUN_TO_CONTAINER(scsicmd->device->id, scsicmd->device->lun);
lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3];
dprintk((KERN_DEBUG "write_callback[cpu %d]: lba = %u, t = %ld.\n", smp_processor_id(), lba, jiffies));
if (fibptr == NULL)
BUG();
if(scsicmd->use_sg)
pci_unmap_sg(dev->pdev,
(struct scatterlist *)scsicmd->buffer,
scsicmd->use_sg,
scsicmd->sc_data_direction);
else if(scsicmd->request_bufflen)
pci_unmap_single(dev->pdev, scsicmd->SCp.dma_handle,
scsicmd->request_bufflen,
scsicmd->sc_data_direction);
writereply = (struct aac_write_reply *) fib_data(fibptr);
if (le32_to_cpu(writereply->status) == ST_OK)
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
else {
printk(KERN_WARNING "write_callback: write failed, status = %d\n", writereply->status);
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
set_sense((u8 *) &dev->fsa_dev[cid].sense_data,
HARDWARE_ERROR,
SENCODE_INTERNAL_TARGET_FAILURE,
ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0,
0, 0);
memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
sizeof(struct sense_data));
}
fib_complete(fibptr);
fib_free(fibptr);
aac_io_done(scsicmd);
}
static int aac_read(struct scsi_cmnd * scsicmd, int cid) static int aac_read(struct scsi_cmnd * scsicmd, int cid)
{ {
u32 lba; u32 lba;
...@@ -954,7 +933,32 @@ static int aac_read(struct scsi_cmnd * scsicmd, int cid) ...@@ -954,7 +933,32 @@ static int aac_read(struct scsi_cmnd * scsicmd, int cid)
fib_init(cmd_fibcontext); fib_init(cmd_fibcontext);
if (dev->dac_support == 1) { if (dev->raw_io_interface) {
struct aac_raw_io *readcmd;
readcmd = (struct aac_raw_io *) fib_data(cmd_fibcontext);
readcmd->block[0] = cpu_to_le32(lba);
readcmd->block[1] = 0;
readcmd->count = cpu_to_le32(count<<9);
readcmd->cid = cpu_to_le16(cid);
readcmd->flags = cpu_to_le16(1);
readcmd->bpTotal = 0;
readcmd->bpComplete = 0;
aac_build_sgraw(scsicmd, &readcmd->sg);
fibsize = sizeof(struct aac_raw_io) + ((le32_to_cpu(readcmd->sg.count) - 1) * sizeof (struct sgentryraw));
if (fibsize > (dev->max_fib_size - sizeof(struct aac_fibhdr)))
BUG();
/*
* Now send the Fib to the adapter
*/
status = fib_send(ContainerRawIo,
cmd_fibcontext,
fibsize,
FsaNormal,
0, 1,
(fib_callback) io_callback,
(void *) scsicmd);
} else if (dev->dac_support == 1) {
struct aac_read64 *readcmd; struct aac_read64 *readcmd;
readcmd = (struct aac_read64 *) fib_data(cmd_fibcontext); readcmd = (struct aac_read64 *) fib_data(cmd_fibcontext);
readcmd->command = cpu_to_le32(VM_CtHostRead64); readcmd->command = cpu_to_le32(VM_CtHostRead64);
...@@ -978,7 +982,7 @@ static int aac_read(struct scsi_cmnd * scsicmd, int cid) ...@@ -978,7 +982,7 @@ static int aac_read(struct scsi_cmnd * scsicmd, int cid)
fibsize, fibsize,
FsaNormal, FsaNormal,
0, 1, 0, 1,
(fib_callback) read_callback, (fib_callback) io_callback,
(void *) scsicmd); (void *) scsicmd);
} else { } else {
struct aac_read *readcmd; struct aac_read *readcmd;
...@@ -1002,7 +1006,7 @@ static int aac_read(struct scsi_cmnd * scsicmd, int cid) ...@@ -1002,7 +1006,7 @@ static int aac_read(struct scsi_cmnd * scsicmd, int cid)
fibsize, fibsize,
FsaNormal, FsaNormal,
0, 1, 0, 1,
(fib_callback) read_callback, (fib_callback) io_callback,
(void *) scsicmd); (void *) scsicmd);
} }
...@@ -1061,7 +1065,32 @@ static int aac_write(struct scsi_cmnd * scsicmd, int cid) ...@@ -1061,7 +1065,32 @@ static int aac_write(struct scsi_cmnd * scsicmd, int cid)
} }
fib_init(cmd_fibcontext); fib_init(cmd_fibcontext);
if(dev->dac_support == 1) { if (dev->raw_io_interface) {
struct aac_raw_io *writecmd;
writecmd = (struct aac_raw_io *) fib_data(cmd_fibcontext);
writecmd->block[0] = cpu_to_le32(lba);
writecmd->block[1] = 0;
writecmd->count = cpu_to_le32(count<<9);
writecmd->cid = cpu_to_le16(cid);
writecmd->flags = 0;
writecmd->bpTotal = 0;
writecmd->bpComplete = 0;
aac_build_sgraw(scsicmd, &writecmd->sg);
fibsize = sizeof(struct aac_raw_io) + ((le32_to_cpu(writecmd->sg.count) - 1) * sizeof (struct sgentryraw));
if (fibsize > (dev->max_fib_size - sizeof(struct aac_fibhdr)))
BUG();
/*
* Now send the Fib to the adapter
*/
status = fib_send(ContainerRawIo,
cmd_fibcontext,
fibsize,
FsaNormal,
0, 1,
(fib_callback) io_callback,
(void *) scsicmd);
} else if (dev->dac_support == 1) {
struct aac_write64 *writecmd; struct aac_write64 *writecmd;
writecmd = (struct aac_write64 *) fib_data(cmd_fibcontext); writecmd = (struct aac_write64 *) fib_data(cmd_fibcontext);
writecmd->command = cpu_to_le32(VM_CtHostWrite64); writecmd->command = cpu_to_le32(VM_CtHostWrite64);
...@@ -1085,7 +1114,7 @@ static int aac_write(struct scsi_cmnd * scsicmd, int cid) ...@@ -1085,7 +1114,7 @@ static int aac_write(struct scsi_cmnd * scsicmd, int cid)
fibsize, fibsize,
FsaNormal, FsaNormal,
0, 1, 0, 1,
(fib_callback) write_callback, (fib_callback) io_callback,
(void *) scsicmd); (void *) scsicmd);
} else { } else {
struct aac_write *writecmd; struct aac_write *writecmd;
...@@ -1111,7 +1140,7 @@ static int aac_write(struct scsi_cmnd * scsicmd, int cid) ...@@ -1111,7 +1140,7 @@ static int aac_write(struct scsi_cmnd * scsicmd, int cid)
fibsize, fibsize,
FsaNormal, FsaNormal,
0, 1, 0, 1,
(fib_callback) write_callback, (fib_callback) io_callback,
(void *) scsicmd); (void *) scsicmd);
} }
...@@ -1340,44 +1369,45 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) ...@@ -1340,44 +1369,45 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
switch (scsicmd->cmnd[0]) { switch (scsicmd->cmnd[0]) {
case INQUIRY: case INQUIRY:
{ {
struct inquiry_data *inq_data_ptr; struct inquiry_data inq_data;
dprintk((KERN_DEBUG "INQUIRY command, ID: %d.\n", scsicmd->device->id)); dprintk((KERN_DEBUG "INQUIRY command, ID: %d.\n", scsicmd->device->id));
inq_data_ptr = (struct inquiry_data *)scsicmd->request_buffer; memset(&inq_data, 0, sizeof (struct inquiry_data));
memset(inq_data_ptr, 0, sizeof (struct inquiry_data));
inq_data_ptr->inqd_ver = 2; /* claim compliance to SCSI-2 */ inq_data.inqd_ver = 2; /* claim compliance to SCSI-2 */
inq_data_ptr->inqd_dtq = 0x80; /* set RMB bit to one indicating that the medium is removable */ inq_data.inqd_dtq = 0x80; /* set RMB bit to one indicating that the medium is removable */
inq_data_ptr->inqd_rdf = 2; /* A response data format value of two indicates that the data shall be in the format specified in SCSI-2 */ inq_data.inqd_rdf = 2; /* A response data format value of two indicates that the data shall be in the format specified in SCSI-2 */
inq_data_ptr->inqd_len = 31; inq_data.inqd_len = 31;
/*Format for "pad2" is RelAdr | WBus32 | WBus16 | Sync | Linked |Reserved| CmdQue | SftRe */ /*Format for "pad2" is RelAdr | WBus32 | WBus16 | Sync | Linked |Reserved| CmdQue | SftRe */
inq_data_ptr->inqd_pad2= 0x32 ; /*WBus16|Sync|CmdQue */ inq_data.inqd_pad2= 0x32 ; /*WBus16|Sync|CmdQue */
/* /*
* Set the Vendor, Product, and Revision Level * Set the Vendor, Product, and Revision Level
* see: <vendor>.c i.e. aac.c * see: <vendor>.c i.e. aac.c
*/ */
if (scsicmd->device->id == host->this_id) { if (scsicmd->device->id == host->this_id) {
setinqstr(cardtype, (void *) (inq_data_ptr->inqd_vid), (sizeof(container_types)/sizeof(char *))); setinqstr(cardtype, (void *) (inq_data.inqd_vid), (sizeof(container_types)/sizeof(char *)));
inq_data_ptr->inqd_pdt = INQD_PDT_PROC; /* Processor device */ inq_data.inqd_pdt = INQD_PDT_PROC; /* Processor device */
aac_internal_transfer(scsicmd, &inq_data, 0, sizeof(inq_data));
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
scsicmd->scsi_done(scsicmd); scsicmd->scsi_done(scsicmd);
return 0; return 0;
} }
setinqstr(cardtype, (void *) (inq_data_ptr->inqd_vid), fsa_dev_ptr[cid].type); setinqstr(cardtype, (void *) (inq_data.inqd_vid), fsa_dev_ptr[cid].type);
inq_data_ptr->inqd_pdt = INQD_PDT_DA; /* Direct/random access device */ inq_data.inqd_pdt = INQD_PDT_DA; /* Direct/random access device */
aac_internal_transfer(scsicmd, &inq_data, 0, sizeof(inq_data));
return aac_get_container_name(scsicmd, cid); return aac_get_container_name(scsicmd, cid);
} }
case READ_CAPACITY: case READ_CAPACITY:
{ {
u32 capacity; u32 capacity;
char *cp; char cp[8];
dprintk((KERN_DEBUG "READ CAPACITY command.\n")); dprintk((KERN_DEBUG "READ CAPACITY command.\n"));
if (fsa_dev_ptr[cid].size <= 0x100000000LL) if (fsa_dev_ptr[cid].size <= 0x100000000LL)
capacity = fsa_dev_ptr[cid].size - 1; capacity = fsa_dev_ptr[cid].size - 1;
else else
capacity = (u32)-1; capacity = (u32)-1;
cp = scsicmd->request_buffer;
cp[0] = (capacity >> 24) & 0xff; cp[0] = (capacity >> 24) & 0xff;
cp[1] = (capacity >> 16) & 0xff; cp[1] = (capacity >> 16) & 0xff;
cp[2] = (capacity >> 8) & 0xff; cp[2] = (capacity >> 8) & 0xff;
...@@ -1386,6 +1416,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) ...@@ -1386,6 +1416,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
cp[5] = 0; cp[5] = 0;
cp[6] = 2; cp[6] = 2;
cp[7] = 0; cp[7] = 0;
aac_internal_transfer(scsicmd, cp, 0, sizeof(cp));
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
scsicmd->scsi_done(scsicmd); scsicmd->scsi_done(scsicmd);
...@@ -1395,15 +1426,15 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) ...@@ -1395,15 +1426,15 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
case MODE_SENSE: case MODE_SENSE:
{ {
char *mode_buf; char mode_buf[4];
dprintk((KERN_DEBUG "MODE SENSE command.\n")); dprintk((KERN_DEBUG "MODE SENSE command.\n"));
mode_buf = scsicmd->request_buffer;
mode_buf[0] = 3; /* Mode data length */ mode_buf[0] = 3; /* Mode data length */
mode_buf[1] = 0; /* Medium type - default */ mode_buf[1] = 0; /* Medium type - default */
mode_buf[2] = 0; /* Device-specific param, bit 8: 0/1 = write enabled/protected */ mode_buf[2] = 0; /* Device-specific param, bit 8: 0/1 = write enabled/protected */
mode_buf[3] = 0; /* Block descriptor length */ mode_buf[3] = 0; /* Block descriptor length */
aac_internal_transfer(scsicmd, mode_buf, 0, sizeof(mode_buf));
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
scsicmd->scsi_done(scsicmd); scsicmd->scsi_done(scsicmd);
...@@ -1411,10 +1442,9 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) ...@@ -1411,10 +1442,9 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
} }
case MODE_SENSE_10: case MODE_SENSE_10:
{ {
char *mode_buf; char mode_buf[8];
dprintk((KERN_DEBUG "MODE SENSE 10 byte command.\n")); dprintk((KERN_DEBUG "MODE SENSE 10 byte command.\n"));
mode_buf = scsicmd->request_buffer;
mode_buf[0] = 0; /* Mode data length (MSB) */ mode_buf[0] = 0; /* Mode data length (MSB) */
mode_buf[1] = 6; /* Mode data length (LSB) */ mode_buf[1] = 6; /* Mode data length (LSB) */
mode_buf[2] = 0; /* Medium type - default */ mode_buf[2] = 0; /* Medium type - default */
...@@ -1423,6 +1453,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) ...@@ -1423,6 +1453,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
mode_buf[5] = 0; /* reserved */ mode_buf[5] = 0; /* reserved */
mode_buf[6] = 0; /* Block descriptor length (MSB) */ mode_buf[6] = 0; /* Block descriptor length (MSB) */
mode_buf[7] = 0; /* Block descriptor length (LSB) */ mode_buf[7] = 0; /* Block descriptor length (LSB) */
aac_internal_transfer(scsicmd, mode_buf, 0, sizeof(mode_buf));
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
scsicmd->scsi_done(scsicmd); scsicmd->scsi_done(scsicmd);
...@@ -1894,7 +1925,7 @@ static int aac_send_srb_fib(struct scsi_cmnd* scsicmd) ...@@ -1894,7 +1925,7 @@ static int aac_send_srb_fib(struct scsi_cmnd* scsicmd)
srbcmd->id = cpu_to_le32(scsicmd->device->id); srbcmd->id = cpu_to_le32(scsicmd->device->id);
srbcmd->lun = cpu_to_le32(scsicmd->device->lun); srbcmd->lun = cpu_to_le32(scsicmd->device->lun);
srbcmd->flags = cpu_to_le32(flag); srbcmd->flags = cpu_to_le32(flag);
timeout = (scsicmd->timeout-jiffies)/HZ; timeout = scsicmd->timeout_per_command/HZ;
if(timeout == 0){ if(timeout == 0){
timeout = 1; timeout = 1;
} }
...@@ -2077,6 +2108,76 @@ static unsigned long aac_build_sg64(struct scsi_cmnd* scsicmd, struct sgmap64* p ...@@ -2077,6 +2108,76 @@ static unsigned long aac_build_sg64(struct scsi_cmnd* scsicmd, struct sgmap64* p
return byte_count; return byte_count;
} }
static unsigned long aac_build_sgraw(struct scsi_cmnd* scsicmd, struct sgmapraw* psg)
{
struct Scsi_Host *host = scsicmd->device->host;
struct aac_dev *dev = (struct aac_dev *)host->hostdata;
unsigned long byte_count = 0;
// Get rid of old data
psg->count = 0;
psg->sg[0].next = 0;
psg->sg[0].prev = 0;
psg->sg[0].addr[0] = 0;
psg->sg[0].addr[1] = 0;
psg->sg[0].count = 0;
psg->sg[0].flags = 0;
if (scsicmd->use_sg) {
struct scatterlist *sg;
int i;
int sg_count;
sg = (struct scatterlist *) scsicmd->request_buffer;
sg_count = pci_map_sg(dev->pdev, sg, scsicmd->use_sg,
scsicmd->sc_data_direction);
for (i = 0; i < sg_count; i++) {
int count = sg_dma_len(sg);
u64 addr = sg_dma_address(sg);
psg->sg[i].next = 0;
psg->sg[i].prev = 0;
psg->sg[i].addr[1] = cpu_to_le32((u32)(addr>>32));
psg->sg[i].addr[0] = cpu_to_le32((u32)(addr & 0xffffffff));
psg->sg[i].count = cpu_to_le32(count);
psg->sg[i].flags = 0;
byte_count += count;
sg++;
}
psg->count = cpu_to_le32(sg_count);
/* hba wants the size to be exact */
if(byte_count > scsicmd->request_bufflen){
u32 temp = le32_to_cpu(psg->sg[i-1].count) -
(byte_count - scsicmd->request_bufflen);
psg->sg[i-1].count = cpu_to_le32(temp);
byte_count = scsicmd->request_bufflen;
}
/* Check for command underflow */
if(scsicmd->underflow && (byte_count < scsicmd->underflow)){
printk(KERN_WARNING"aacraid: cmd len %08lX cmd underflow %08X\n",
byte_count, scsicmd->underflow);
}
}
else if(scsicmd->request_bufflen) {
int count;
u64 addr;
scsicmd->SCp.dma_handle = pci_map_single(dev->pdev,
scsicmd->request_buffer,
scsicmd->request_bufflen,
scsicmd->sc_data_direction);
addr = scsicmd->SCp.dma_handle;
count = scsicmd->request_bufflen;
psg->count = cpu_to_le32(1);
psg->sg[0].next = 0;
psg->sg[0].prev = 0;
psg->sg[0].addr[1] = cpu_to_le32((u32)(addr>>32));
psg->sg[0].addr[0] = cpu_to_le32((u32)(addr & 0xffffffff));
psg->sg[0].count = cpu_to_le32(count);
psg->sg[0].flags = 0;
byte_count = scsicmd->request_bufflen;
}
return byte_count;
}
#ifdef AAC_DETAILED_STATUS_INFO #ifdef AAC_DETAILED_STATUS_INFO
struct aac_srb_status_info { struct aac_srb_status_info {
......
...@@ -110,6 +110,22 @@ struct user_sgentry64 { ...@@ -110,6 +110,22 @@ struct user_sgentry64 {
u32 count; /* Length. */ u32 count; /* Length. */
}; };
struct sgentryraw {
__le32 next; /* reserved for F/W use */
__le32 prev; /* reserved for F/W use */
__le32 addr[2];
__le32 count;
__le32 flags; /* reserved for F/W use */
};
struct user_sgentryraw {
u32 next; /* reserved for F/W use */
u32 prev; /* reserved for F/W use */
u32 addr[2];
u32 count;
u32 flags; /* reserved for F/W use */
};
/* /*
* SGMAP * SGMAP
* *
...@@ -137,6 +153,16 @@ struct user_sgmap64 { ...@@ -137,6 +153,16 @@ struct user_sgmap64 {
struct user_sgentry64 sg[1]; struct user_sgentry64 sg[1];
}; };
struct sgmapraw {
__le32 count;
struct sgentryraw sg[1];
};
struct user_sgmapraw {
u32 count;
struct user_sgentryraw sg[1];
};
struct creation_info struct creation_info
{ {
u8 buildnum; /* e.g., 588 */ u8 buildnum; /* e.g., 588 */
...@@ -351,6 +377,7 @@ struct hw_fib { ...@@ -351,6 +377,7 @@ struct hw_fib {
*/ */
#define ContainerCommand 500 #define ContainerCommand 500
#define ContainerCommand64 501 #define ContainerCommand64 501
#define ContainerRawIo 502
/* /*
* Cluster Commands * Cluster Commands
*/ */
...@@ -456,6 +483,7 @@ struct adapter_ops ...@@ -456,6 +483,7 @@ struct adapter_ops
{ {
void (*adapter_interrupt)(struct aac_dev *dev); void (*adapter_interrupt)(struct aac_dev *dev);
void (*adapter_notify)(struct aac_dev *dev, u32 event); void (*adapter_notify)(struct aac_dev *dev, u32 event);
void (*adapter_disable_int)(struct aac_dev *dev);
int (*adapter_sync_cmd)(struct aac_dev *dev, u32 command, u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6, u32 *status, u32 *r1, u32 *r2, u32 *r3, u32 *r4); int (*adapter_sync_cmd)(struct aac_dev *dev, u32 command, u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6, u32 *status, u32 *r1, u32 *r2, u32 *r3, u32 *r4);
int (*adapter_check_health)(struct aac_dev *dev); int (*adapter_check_health)(struct aac_dev *dev);
}; };
...@@ -981,6 +1009,9 @@ struct aac_dev ...@@ -981,6 +1009,9 @@ struct aac_dev
u8 nondasd_support; u8 nondasd_support;
u8 dac_support; u8 dac_support;
u8 raid_scsi_mode; u8 raid_scsi_mode;
/* macro side-effects BEWARE */
# define raw_io_interface \
init->InitStructRevision==cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION_4)
u8 printf_enabled; u8 printf_enabled;
}; };
...@@ -990,6 +1021,9 @@ struct aac_dev ...@@ -990,6 +1021,9 @@ struct aac_dev
#define aac_adapter_notify(dev, event) \ #define aac_adapter_notify(dev, event) \
(dev)->a_ops.adapter_notify(dev, event) (dev)->a_ops.adapter_notify(dev, event)
#define aac_adapter_disable_int(dev) \
(dev)->a_ops.adapter_disable_int(dev)
#define aac_adapter_sync_cmd(dev, command, p1, p2, p3, p4, p5, p6, status, r1, r2, r3, r4) \ #define aac_adapter_sync_cmd(dev, command, p1, p2, p3, p4, p5, p6, status, r1, r2, r3, r4) \
(dev)->a_ops.adapter_sync_cmd(dev, command, p1, p2, p3, p4, p5, p6, status, r1, r2, r3, r4) (dev)->a_ops.adapter_sync_cmd(dev, command, p1, p2, p3, p4, p5, p6, status, r1, r2, r3, r4)
...@@ -1156,6 +1190,17 @@ struct aac_write_reply ...@@ -1156,6 +1190,17 @@ struct aac_write_reply
__le32 committed; __le32 committed;
}; };
struct aac_raw_io
{
__le32 block[2];
__le32 count;
__le16 cid;
__le16 flags; /* 00 W, 01 R */
__le16 bpTotal; /* reserved for F/W use */
__le16 bpComplete; /* reserved for F/W use */
struct sgmapraw sg;
};
#define CT_FLUSH_CACHE 129 #define CT_FLUSH_CACHE 129
struct aac_synchronize { struct aac_synchronize {
__le32 command; /* VM_ContainerConfig */ __le32 command; /* VM_ContainerConfig */
...@@ -1196,7 +1241,7 @@ struct aac_srb ...@@ -1196,7 +1241,7 @@ struct aac_srb
}; };
/* /*
* This and assocated data structs are used by the * This and associated data structs are used by the
* ioctl caller and are in cpu order. * ioctl caller and are in cpu order.
*/ */
struct user_aac_srb struct user_aac_srb
...@@ -1508,11 +1553,12 @@ struct fib_ioctl ...@@ -1508,11 +1553,12 @@ struct fib_ioctl
struct revision struct revision
{ {
u32 compat; __le32 compat;
u32 version; __le32 version;
u32 build; __le32 build;
}; };
/* /*
* Ugly - non Linux like ioctl coding for back compat. * Ugly - non Linux like ioctl coding for back compat.
*/ */
...@@ -1733,3 +1779,4 @@ int aac_get_adapter_info(struct aac_dev* dev); ...@@ -1733,3 +1779,4 @@ int aac_get_adapter_info(struct aac_dev* dev);
int aac_send_shutdown(struct aac_dev *dev); int aac_send_shutdown(struct aac_dev *dev);
extern int numacb; extern int numacb;
extern int acbsize; extern int acbsize;
extern char aac_driver_version[];
...@@ -287,7 +287,6 @@ static int next_getadapter_fib(struct aac_dev * dev, void __user *arg) ...@@ -287,7 +287,6 @@ static int next_getadapter_fib(struct aac_dev * dev, void __user *arg)
kfree(fib->hw_fib); kfree(fib->hw_fib);
kfree(fib); kfree(fib);
status = 0; status = 0;
fibctx->jiffies = jiffies/HZ;
} else { } else {
spin_unlock_irqrestore(&dev->fib_lock, flags); spin_unlock_irqrestore(&dev->fib_lock, flags);
if (f.wait) { if (f.wait) {
...@@ -302,6 +301,7 @@ static int next_getadapter_fib(struct aac_dev * dev, void __user *arg) ...@@ -302,6 +301,7 @@ static int next_getadapter_fib(struct aac_dev * dev, void __user *arg)
status = -EAGAIN; status = -EAGAIN;
} }
} }
fibctx->jiffies = jiffies/HZ;
return status; return status;
} }
...@@ -405,10 +405,20 @@ static int close_getadapter_fib(struct aac_dev * dev, void __user *arg) ...@@ -405,10 +405,20 @@ static int close_getadapter_fib(struct aac_dev * dev, void __user *arg)
static int check_revision(struct aac_dev *dev, void __user *arg) static int check_revision(struct aac_dev *dev, void __user *arg)
{ {
struct revision response; struct revision response;
char *driver_version = aac_driver_version;
response.compat = 1; u32 version;
response.version = le32_to_cpu(dev->adapter_info.kernelrev);
response.build = le32_to_cpu(dev->adapter_info.kernelbuild); response.compat = cpu_to_le32(1);
version = (simple_strtol(driver_version,
&driver_version, 10) << 24) | 0x00000400;
version += simple_strtol(driver_version + 1, &driver_version, 10) << 16;
version += simple_strtol(driver_version + 1, NULL, 10);
response.version = cpu_to_le32(version);
# if (defined(AAC_DRIVER_BUILD))
response.build = cpu_to_le32(AAC_DRIVER_BUILD);
# else
response.build = cpu_to_le32(9999);
# endif
if (copy_to_user(arg, &response, sizeof(response))) if (copy_to_user(arg, &response, sizeof(response)))
return -EFAULT; return -EFAULT;
......
...@@ -44,7 +44,9 @@ ...@@ -44,7 +44,9 @@
#include "aacraid.h" #include "aacraid.h"
struct aac_common aac_config; struct aac_common aac_config = {
.irq_mod = 1
};
static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long commsize, unsigned long commalign) static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long commsize, unsigned long commalign)
{ {
......
...@@ -254,6 +254,7 @@ static void fib_dealloc(struct fib * fibptr) ...@@ -254,6 +254,7 @@ static void fib_dealloc(struct fib * fibptr)
static int aac_get_entry (struct aac_dev * dev, u32 qid, struct aac_entry **entry, u32 * index, unsigned long *nonotify) static int aac_get_entry (struct aac_dev * dev, u32 qid, struct aac_entry **entry, u32 * index, unsigned long *nonotify)
{ {
struct aac_queue * q; struct aac_queue * q;
unsigned long idx;
/* /*
* All of the queues wrap when they reach the end, so we check * All of the queues wrap when they reach the end, so we check
...@@ -263,10 +264,23 @@ static int aac_get_entry (struct aac_dev * dev, u32 qid, struct aac_entry **entr ...@@ -263,10 +264,23 @@ static int aac_get_entry (struct aac_dev * dev, u32 qid, struct aac_entry **entr
*/ */
q = &dev->queues->queue[qid]; q = &dev->queues->queue[qid];
*index = le32_to_cpu(*(q->headers.producer)); idx = *index = le32_to_cpu(*(q->headers.producer));
if ((*index - 2) == le32_to_cpu(*(q->headers.consumer))) /* Interrupt Moderation, only interrupt for first two entries */
if (idx != le32_to_cpu(*(q->headers.consumer))) {
if (--idx == 0) {
if (qid == AdapHighCmdQueue)
idx = ADAP_HIGH_CMD_ENTRIES;
else if (qid == AdapNormCmdQueue)
idx = ADAP_NORM_CMD_ENTRIES;
else if (qid == AdapHighRespQueue)
idx = ADAP_HIGH_RESP_ENTRIES;
else if (qid == AdapNormRespQueue)
idx = ADAP_NORM_RESP_ENTRIES;
}
if (idx != le32_to_cpu(*(q->headers.consumer)))
*nonotify = 1; *nonotify = 1;
}
if (qid == AdapHighCmdQueue) { if (qid == AdapHighCmdQueue) {
if (*index >= ADAP_HIGH_CMD_ENTRIES) if (*index >= ADAP_HIGH_CMD_ENTRIES)
......
...@@ -27,8 +27,11 @@ ...@@ -27,8 +27,11 @@
* Abstract: Linux Driver entry module for Adaptec RAID Array Controller * Abstract: Linux Driver entry module for Adaptec RAID Array Controller
*/ */
#define AAC_DRIVER_VERSION "1.1.2-lk2" #define AAC_DRIVER_VERSION "1.1-4"
#define AAC_DRIVER_BUILD_DATE __DATE__ #ifndef AAC_DRIVER_BRANCH
#define AAC_DRIVER_BRANCH ""
#endif
#define AAC_DRIVER_BUILD_DATE __DATE__ " " __TIME__
#define AAC_DRIVERNAME "aacraid" #define AAC_DRIVERNAME "aacraid"
#include <linux/compat.h> #include <linux/compat.h>
...@@ -58,16 +61,24 @@ ...@@ -58,16 +61,24 @@
#include "aacraid.h" #include "aacraid.h"
#ifdef AAC_DRIVER_BUILD
#define _str(x) #x
#define str(x) _str(x)
#define AAC_DRIVER_FULL_VERSION AAC_DRIVER_VERSION "[" str(AAC_DRIVER_BUILD) "]" AAC_DRIVER_BRANCH
#else
#define AAC_DRIVER_FULL_VERSION AAC_DRIVER_VERSION AAC_DRIVER_BRANCH " " AAC_DRIVER_BUILD_DATE
#endif
MODULE_AUTHOR("Red Hat Inc and Adaptec"); MODULE_AUTHOR("Red Hat Inc and Adaptec");
MODULE_DESCRIPTION("Dell PERC2, 2/Si, 3/Si, 3/Di, " MODULE_DESCRIPTION("Dell PERC2, 2/Si, 3/Si, 3/Di, "
"Adaptec Advanced Raid Products, " "Adaptec Advanced Raid Products, "
"and HP NetRAID-4M SCSI driver"); "and HP NetRAID-4M SCSI driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_VERSION(AAC_DRIVER_VERSION); MODULE_VERSION(AAC_DRIVER_FULL_VERSION);
static LIST_HEAD(aac_devices); static LIST_HEAD(aac_devices);
static int aac_cfg_major = -1; static int aac_cfg_major = -1;
char aac_driver_version[] = AAC_DRIVER_FULL_VERSION;
/* /*
* Because of the way Linux names scsi devices, the order in this table has * Because of the way Linux names scsi devices, the order in this table has
...@@ -109,36 +120,39 @@ static struct pci_device_id aac_pci_tbl[] = { ...@@ -109,36 +120,39 @@ static struct pci_device_id aac_pci_tbl[] = {
{ 0x9005, 0x0286, 0x9005, 0x02a3, 0, 0, 29 }, /* ICP5085AU (Hurricane) */ { 0x9005, 0x0286, 0x9005, 0x02a3, 0, 0, 29 }, /* ICP5085AU (Hurricane) */
{ 0x9005, 0x0285, 0x9005, 0x02a4, 0, 0, 30 }, /* ICP9085LI (Marauder-X) */ { 0x9005, 0x0285, 0x9005, 0x02a4, 0, 0, 30 }, /* ICP9085LI (Marauder-X) */
{ 0x9005, 0x0285, 0x9005, 0x02a5, 0, 0, 31 }, /* ICP5085BR (Marauder-E) */ { 0x9005, 0x0285, 0x9005, 0x02a5, 0, 0, 31 }, /* ICP5085BR (Marauder-E) */
{ 0x9005, 0x0287, 0x9005, 0x0800, 0, 0, 32 }, /* Themisto Jupiter Platform */ { 0x9005, 0x0286, 0x9005, 0x02a6, 0, 0, 32 }, /* ICP9067MA (Intruder-6) */
{ 0x9005, 0x0200, 0x9005, 0x0200, 0, 0, 32 }, /* Themisto Jupiter Platform */ { 0x9005, 0x0287, 0x9005, 0x0800, 0, 0, 33 }, /* Themisto Jupiter Platform */
{ 0x9005, 0x0286, 0x9005, 0x0800, 0, 0, 33 }, /* Callisto Jupiter Platform */ { 0x9005, 0x0200, 0x9005, 0x0200, 0, 0, 33 }, /* Themisto Jupiter Platform */
{ 0x9005, 0x0285, 0x9005, 0x028e, 0, 0, 34 }, /* ASR-2020SA SATA PCI-X ZCR (Skyhawk) */ { 0x9005, 0x0286, 0x9005, 0x0800, 0, 0, 34 }, /* Callisto Jupiter Platform */
{ 0x9005, 0x0285, 0x9005, 0x028f, 0, 0, 35 }, /* ASR-2025SA SATA SO-DIMM PCI-X ZCR (Terminator) */ { 0x9005, 0x0285, 0x9005, 0x028e, 0, 0, 35 }, /* ASR-2020SA SATA PCI-X ZCR (Skyhawk) */
{ 0x9005, 0x0285, 0x9005, 0x0290, 0, 0, 36 }, /* AAR-2410SA PCI SATA 4ch (Jaguar II) */ { 0x9005, 0x0285, 0x9005, 0x028f, 0, 0, 36 }, /* ASR-2025SA SATA SO-DIMM PCI-X ZCR (Terminator) */
{ 0x9005, 0x0285, 0x1028, 0x0291, 0, 0, 37 }, /* CERC SATA RAID 2 PCI SATA 6ch (DellCorsair) */ { 0x9005, 0x0285, 0x9005, 0x0290, 0, 0, 37 }, /* AAR-2410SA PCI SATA 4ch (Jaguar II) */
{ 0x9005, 0x0285, 0x9005, 0x0292, 0, 0, 38 }, /* AAR-2810SA PCI SATA 8ch (Corsair-8) */ { 0x9005, 0x0285, 0x1028, 0x0291, 0, 0, 38 }, /* CERC SATA RAID 2 PCI SATA 6ch (DellCorsair) */
{ 0x9005, 0x0285, 0x9005, 0x0293, 0, 0, 39 }, /* AAR-21610SA PCI SATA 16ch (Corsair-16) */ { 0x9005, 0x0285, 0x9005, 0x0292, 0, 0, 39 }, /* AAR-2810SA PCI SATA 8ch (Corsair-8) */
{ 0x9005, 0x0285, 0x9005, 0x0294, 0, 0, 40 }, /* ESD SO-DIMM PCI-X SATA ZCR (Prowler) */ { 0x9005, 0x0285, 0x9005, 0x0293, 0, 0, 40 }, /* AAR-21610SA PCI SATA 16ch (Corsair-16) */
{ 0x9005, 0x0285, 0x103C, 0x3227, 0, 0, 41 }, /* AAR-2610SA PCI SATA 6ch */ { 0x9005, 0x0285, 0x9005, 0x0294, 0, 0, 41 }, /* ESD SO-DIMM PCI-X SATA ZCR (Prowler) */
{ 0x9005, 0x0285, 0x9005, 0x0296, 0, 0, 42 }, /* ASR-2240S (SabreExpress) */ { 0x9005, 0x0285, 0x103C, 0x3227, 0, 0, 42 }, /* AAR-2610SA PCI SATA 6ch */
{ 0x9005, 0x0285, 0x9005, 0x0297, 0, 0, 43 }, /* ASR-4005SAS */ { 0x9005, 0x0285, 0x9005, 0x0296, 0, 0, 43 }, /* ASR-2240S (SabreExpress) */
{ 0x9005, 0x0285, 0x1014, 0x02F2, 0, 0, 44 }, /* IBM 8i (AvonPark) */ { 0x9005, 0x0285, 0x9005, 0x0297, 0, 0, 44 }, /* ASR-4005SAS */
{ 0x9005, 0x0285, 0x1014, 0x0312, 0, 0, 44 }, /* IBM 8i (AvonPark Lite) */ { 0x9005, 0x0285, 0x1014, 0x02F2, 0, 0, 45 }, /* IBM 8i (AvonPark) */
{ 0x9005, 0x0285, 0x9005, 0x0298, 0, 0, 45 }, /* ASR-4000SAS (BlackBird) */ { 0x9005, 0x0285, 0x1014, 0x0312, 0, 0, 45 }, /* IBM 8i (AvonPark Lite) */
{ 0x9005, 0x0285, 0x9005, 0x0299, 0, 0, 46 }, /* ASR-4800SAS (Marauder-X) */ { 0x9005, 0x0286, 0x1014, 0x9580, 0, 0, 46 }, /* IBM 8k/8k-l8 (Aurora) */
{ 0x9005, 0x0285, 0x9005, 0x029a, 0, 0, 47 }, /* ASR-4805SAS (Marauder-E) */ { 0x9005, 0x0286, 0x1014, 0x9540, 0, 0, 47 }, /* IBM 8k/8k-l4 (Aurora Lite) */
{ 0x9005, 0x0286, 0x9005, 0x02a2, 0, 0, 48 }, /* ASR-4810SAS (Hurricane */ { 0x9005, 0x0285, 0x9005, 0x0298, 0, 0, 48 }, /* ASR-4000SAS (BlackBird) */
{ 0x9005, 0x0285, 0x9005, 0x0299, 0, 0, 49 }, /* ASR-4800SAS (Marauder-X) */
{ 0x9005, 0x0285, 0x1028, 0x0287, 0, 0, 49 }, /* Perc 320/DC*/ { 0x9005, 0x0285, 0x9005, 0x029a, 0, 0, 50 }, /* ASR-4805SAS (Marauder-E) */
{ 0x1011, 0x0046, 0x9005, 0x0365, 0, 0, 50 }, /* Adaptec 5400S (Mustang)*/ { 0x9005, 0x0286, 0x9005, 0x02a2, 0, 0, 51 }, /* ASR-4810SAS (Hurricane */
{ 0x1011, 0x0046, 0x9005, 0x0364, 0, 0, 51 }, /* Adaptec 5400S (Mustang)*/
{ 0x1011, 0x0046, 0x9005, 0x1364, 0, 0, 52 }, /* Dell PERC2/QC */ { 0x9005, 0x0285, 0x1028, 0x0287, 0, 0, 52 }, /* Perc 320/DC*/
{ 0x1011, 0x0046, 0x103c, 0x10c2, 0, 0, 53 }, /* HP NetRAID-4M */ { 0x1011, 0x0046, 0x9005, 0x0365, 0, 0, 53 }, /* Adaptec 5400S (Mustang)*/
{ 0x1011, 0x0046, 0x9005, 0x0364, 0, 0, 54 }, /* Adaptec 5400S (Mustang)*/
{ 0x9005, 0x0285, 0x1028, PCI_ANY_ID, 0, 0, 54 }, /* Dell Catchall */ { 0x1011, 0x0046, 0x9005, 0x1364, 0, 0, 55 }, /* Dell PERC2/QC */
{ 0x9005, 0x0285, 0x17aa, PCI_ANY_ID, 0, 0, 55 }, /* Legend Catchall */ { 0x1011, 0x0046, 0x103c, 0x10c2, 0, 0, 56 }, /* HP NetRAID-4M */
{ 0x9005, 0x0285, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 56 }, /* Adaptec Catch All */
{ 0x9005, 0x0286, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 57 }, /* Adaptec Rocket Catch All */ { 0x9005, 0x0285, 0x1028, PCI_ANY_ID, 0, 0, 57 }, /* Dell Catchall */
{ 0x9005, 0x0285, 0x17aa, PCI_ANY_ID, 0, 0, 58 }, /* Legend Catchall */
{ 0x9005, 0x0285, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 59 }, /* Adaptec Catch All */
{ 0x9005, 0x0286, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 60 }, /* Adaptec Rocket Catch All */
{ 0,} { 0,}
}; };
MODULE_DEVICE_TABLE(pci, aac_pci_tbl); MODULE_DEVICE_TABLE(pci, aac_pci_tbl);
...@@ -180,8 +194,9 @@ static struct aac_driver_ident aac_drivers[] = { ...@@ -180,8 +194,9 @@ static struct aac_driver_ident aac_drivers[] = {
{ aac_rkt_init, "aacraid", "ICP ", "ICP9047MA ", 1 }, /* ICP9047MA (Lancer) */ { aac_rkt_init, "aacraid", "ICP ", "ICP9047MA ", 1 }, /* ICP9047MA (Lancer) */
{ aac_rkt_init, "aacraid", "ICP ", "ICP9087MA ", 1 }, /* ICP9087MA (Lancer) */ { aac_rkt_init, "aacraid", "ICP ", "ICP9087MA ", 1 }, /* ICP9087MA (Lancer) */
{ aac_rkt_init, "aacraid", "ICP ", "ICP5085AU ", 1 }, /* ICP5085AU (Hurricane) */ { aac_rkt_init, "aacraid", "ICP ", "ICP5085AU ", 1 }, /* ICP5085AU (Hurricane) */
{ aac_rkt_init, "aacraid", "ICP ", "ICP9085LI ", 1 }, /* ICP9085LI (Marauder-X) */ { aac_rx_init, "aacraid", "ICP ", "ICP9085LI ", 1 }, /* ICP9085LI (Marauder-X) */
{ aac_rkt_init, "aacraid", "ICP ", "ICP5085BR ", 1 }, /* ICP5085BR (Marauder-E) */ { aac_rx_init, "aacraid", "ICP ", "ICP5085BR ", 1 }, /* ICP5085BR (Marauder-E) */
{ aac_rkt_init, "aacraid", "ICP ", "ICP9067MA ", 1 }, /* ICP9067MA (Intruder-6) */
{ NULL , "aacraid", "ADAPTEC ", "Themisto ", 0, AAC_QUIRK_SLAVE }, /* Jupiter Platform */ { NULL , "aacraid", "ADAPTEC ", "Themisto ", 0, AAC_QUIRK_SLAVE }, /* Jupiter Platform */
{ aac_rkt_init, "aacraid", "ADAPTEC ", "Callisto ", 2, AAC_QUIRK_MASTER }, /* Jupiter Platform */ { aac_rkt_init, "aacraid", "ADAPTEC ", "Callisto ", 2, AAC_QUIRK_MASTER }, /* Jupiter Platform */
{ aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2020SA ", 1 }, /* ASR-2020SA SATA PCI-X ZCR (Skyhawk) */ { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2020SA ", 1 }, /* ASR-2020SA SATA PCI-X ZCR (Skyhawk) */
...@@ -195,10 +210,12 @@ static struct aac_driver_ident aac_drivers[] = { ...@@ -195,10 +210,12 @@ static struct aac_driver_ident aac_drivers[] = {
{ aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2240S ", 1 }, /* ASR-2240S (SabreExpress) */ { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2240S ", 1 }, /* ASR-2240S (SabreExpress) */
{ aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4005SAS ", 1 }, /* ASR-4005SAS */ { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4005SAS ", 1 }, /* ASR-4005SAS */
{ aac_rx_init, "ServeRAID","IBM ", "ServeRAID 8i ", 1 }, /* IBM 8i (AvonPark) */ { aac_rx_init, "ServeRAID","IBM ", "ServeRAID 8i ", 1 }, /* IBM 8i (AvonPark) */
{ aac_rkt_init, "ServeRAID","IBM ", "ServeRAID 8k-l8 ", 1 }, /* IBM 8k/8k-l8 (Aurora) */
{ aac_rkt_init, "ServeRAID","IBM ", "ServeRAID 8k-l4 ", 1 }, /* IBM 8k/8k-l4 (Aurora Lite) */
{ aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4000SAS ", 1 }, /* ASR-4000SAS (BlackBird & AvonPark) */ { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4000SAS ", 1 }, /* ASR-4000SAS (BlackBird & AvonPark) */
{ aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4800SAS ", 1 }, /* ASR-4800SAS (Marauder-X) */ { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4800SAS ", 1 }, /* ASR-4800SAS (Marauder-X) */
{ aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4805SAS ", 1 }, /* ASR-4805SAS (Marauder-E) */ { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4805SAS ", 1 }, /* ASR-4805SAS (Marauder-E) */
{ aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4810SAS ", 1 }, /* ASR-4810SAS (Hurricane) */ { aac_rkt_init, "aacraid", "ADAPTEC ", "ASR-4810SAS ", 1 }, /* ASR-4810SAS (Hurricane) */
{ aac_rx_init, "percraid", "DELL ", "PERC 320/DC ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Perc 320/DC*/ { aac_rx_init, "percraid", "DELL ", "PERC 320/DC ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Perc 320/DC*/
{ aac_sa_init, "aacraid", "ADAPTEC ", "Adaptec 5400S ", 4, AAC_QUIRK_34SG }, /* Adaptec 5400S (Mustang)*/ { aac_sa_init, "aacraid", "ADAPTEC ", "Adaptec 5400S ", 4, AAC_QUIRK_34SG }, /* Adaptec 5400S (Mustang)*/
...@@ -839,11 +856,12 @@ static int __devinit aac_probe_one(struct pci_dev *pdev, ...@@ -839,11 +856,12 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
return 0; return 0;
out_deinit: out_deinit:
kill_proc(aac->thread_pid, SIGKILL, 0); kill_proc(aac->thread_pid, SIGKILL, 0);
wait_for_completion(&aac->aif_completion); wait_for_completion(&aac->aif_completion);
aac_send_shutdown(aac); aac_send_shutdown(aac);
aac_adapter_disable_int(aac);
fib_map_free(aac); fib_map_free(aac);
pci_free_consistent(aac->pdev, aac->comm_size, aac->comm_addr, aac->comm_phys); pci_free_consistent(aac->pdev, aac->comm_size, aac->comm_addr, aac->comm_phys);
kfree(aac->queues); kfree(aac->queues);
...@@ -860,6 +878,13 @@ static int __devinit aac_probe_one(struct pci_dev *pdev, ...@@ -860,6 +878,13 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
return error; return error;
} }
static void aac_shutdown(struct pci_dev *dev)
{
struct Scsi_Host *shost = pci_get_drvdata(dev);
struct aac_dev *aac = (struct aac_dev *)shost->hostdata;
aac_send_shutdown(aac);
}
static void __devexit aac_remove_one(struct pci_dev *pdev) static void __devexit aac_remove_one(struct pci_dev *pdev)
{ {
struct Scsi_Host *shost = pci_get_drvdata(pdev); struct Scsi_Host *shost = pci_get_drvdata(pdev);
...@@ -871,6 +896,7 @@ static void __devexit aac_remove_one(struct pci_dev *pdev) ...@@ -871,6 +896,7 @@ static void __devexit aac_remove_one(struct pci_dev *pdev)
wait_for_completion(&aac->aif_completion); wait_for_completion(&aac->aif_completion);
aac_send_shutdown(aac); aac_send_shutdown(aac);
aac_adapter_disable_int(aac);
fib_map_free(aac); fib_map_free(aac);
pci_free_consistent(aac->pdev, aac->comm_size, aac->comm_addr, pci_free_consistent(aac->pdev, aac->comm_size, aac->comm_addr,
aac->comm_phys); aac->comm_phys);
...@@ -891,14 +917,15 @@ static struct pci_driver aac_pci_driver = { ...@@ -891,14 +917,15 @@ static struct pci_driver aac_pci_driver = {
.id_table = aac_pci_tbl, .id_table = aac_pci_tbl,
.probe = aac_probe_one, .probe = aac_probe_one,
.remove = __devexit_p(aac_remove_one), .remove = __devexit_p(aac_remove_one),
.shutdown = aac_shutdown,
}; };
static int __init aac_init(void) static int __init aac_init(void)
{ {
int error; int error;
printk(KERN_INFO "Red Hat/Adaptec aacraid driver (%s %s)\n", printk(KERN_INFO "Adaptec %s driver (%s)\n",
AAC_DRIVER_VERSION, AAC_DRIVER_BUILD_DATE); AAC_DRIVERNAME, aac_driver_version);
error = pci_module_init(&aac_pci_driver); error = pci_module_init(&aac_pci_driver);
if (error) if (error)
...@@ -909,6 +936,7 @@ static int __init aac_init(void) ...@@ -909,6 +936,7 @@ static int __init aac_init(void)
printk(KERN_WARNING printk(KERN_WARNING
"aacraid: unable to register \"aac\" device.\n"); "aacraid: unable to register \"aac\" device.\n");
} }
return 0; return 0;
} }
......
...@@ -87,6 +87,16 @@ static irqreturn_t aac_rkt_intr(int irq, void *dev_id, struct pt_regs *regs) ...@@ -87,6 +87,16 @@ static irqreturn_t aac_rkt_intr(int irq, void *dev_id, struct pt_regs *regs)
return IRQ_NONE; return IRQ_NONE;
} }
/**
* aac_rkt_disable_interrupt - Disable interrupts
* @dev: Adapter
*/
static void aac_rkt_disable_interrupt(struct aac_dev *dev)
{
rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff);
}
/** /**
* rkt_sync_cmd - send a command and wait * rkt_sync_cmd - send a command and wait
* @dev: Adapter * @dev: Adapter
...@@ -412,10 +422,19 @@ int aac_rkt_init(struct aac_dev *dev) ...@@ -412,10 +422,19 @@ int aac_rkt_init(struct aac_dev *dev)
* Fill in the function dispatch table. * Fill in the function dispatch table.
*/ */
dev->a_ops.adapter_interrupt = aac_rkt_interrupt_adapter; dev->a_ops.adapter_interrupt = aac_rkt_interrupt_adapter;
dev->a_ops.adapter_disable_int = aac_rkt_disable_interrupt;
dev->a_ops.adapter_notify = aac_rkt_notify_adapter; dev->a_ops.adapter_notify = aac_rkt_notify_adapter;
dev->a_ops.adapter_sync_cmd = rkt_sync_cmd; dev->a_ops.adapter_sync_cmd = rkt_sync_cmd;
dev->a_ops.adapter_check_health = aac_rkt_check_health; dev->a_ops.adapter_check_health = aac_rkt_check_health;
/*
* First clear out all interrupts. Then enable the one's that we
* can handle.
*/
rkt_writeb(dev, MUnit.OIMR, 0xff);
rkt_writel(dev, MUnit.ODR, 0xffffffff);
rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb);
if (aac_init_adapter(dev) == NULL) if (aac_init_adapter(dev) == NULL)
goto error_irq; goto error_irq;
/* /*
...@@ -438,6 +457,7 @@ int aac_rkt_init(struct aac_dev *dev) ...@@ -438,6 +457,7 @@ int aac_rkt_init(struct aac_dev *dev)
kfree(dev->queues); kfree(dev->queues);
error_irq: error_irq:
rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff);
free_irq(dev->scsi_host_ptr->irq, (void *)dev); free_irq(dev->scsi_host_ptr->irq, (void *)dev);
error_iounmap: error_iounmap:
......
...@@ -87,6 +87,16 @@ static irqreturn_t aac_rx_intr(int irq, void *dev_id, struct pt_regs *regs) ...@@ -87,6 +87,16 @@ static irqreturn_t aac_rx_intr(int irq, void *dev_id, struct pt_regs *regs)
return IRQ_NONE; return IRQ_NONE;
} }
/**
* aac_rx_disable_interrupt - Disable interrupts
* @dev: Adapter
*/
static void aac_rx_disable_interrupt(struct aac_dev *dev)
{
rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff);
}
/** /**
* rx_sync_cmd - send a command and wait * rx_sync_cmd - send a command and wait
* @dev: Adapter * @dev: Adapter
...@@ -412,10 +422,19 @@ int aac_rx_init(struct aac_dev *dev) ...@@ -412,10 +422,19 @@ int aac_rx_init(struct aac_dev *dev)
* Fill in the function dispatch table. * Fill in the function dispatch table.
*/ */
dev->a_ops.adapter_interrupt = aac_rx_interrupt_adapter; dev->a_ops.adapter_interrupt = aac_rx_interrupt_adapter;
dev->a_ops.adapter_disable_int = aac_rx_disable_interrupt;
dev->a_ops.adapter_notify = aac_rx_notify_adapter; dev->a_ops.adapter_notify = aac_rx_notify_adapter;
dev->a_ops.adapter_sync_cmd = rx_sync_cmd; dev->a_ops.adapter_sync_cmd = rx_sync_cmd;
dev->a_ops.adapter_check_health = aac_rx_check_health; dev->a_ops.adapter_check_health = aac_rx_check_health;
/*
* First clear out all interrupts. Then enable the one's that we
* can handle.
*/
rx_writeb(dev, MUnit.OIMR, 0xff);
rx_writel(dev, MUnit.ODR, 0xffffffff);
rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb);
if (aac_init_adapter(dev) == NULL) if (aac_init_adapter(dev) == NULL)
goto error_irq; goto error_irq;
/* /*
...@@ -438,6 +457,7 @@ int aac_rx_init(struct aac_dev *dev) ...@@ -438,6 +457,7 @@ int aac_rx_init(struct aac_dev *dev)
kfree(dev->queues); kfree(dev->queues);
error_irq: error_irq:
rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff);
free_irq(dev->scsi_host_ptr->irq, (void *)dev); free_irq(dev->scsi_host_ptr->irq, (void *)dev);
error_iounmap: error_iounmap:
......
...@@ -81,6 +81,16 @@ static irqreturn_t aac_sa_intr(int irq, void *dev_id, struct pt_regs *regs) ...@@ -81,6 +81,16 @@ static irqreturn_t aac_sa_intr(int irq, void *dev_id, struct pt_regs *regs)
return IRQ_NONE; return IRQ_NONE;
} }
/**
* aac_sa_disable_interrupt - disable interrupt
* @dev: Which adapter to enable.
*/
static void aac_sa_disable_interrupt (struct aac_dev *dev)
{
sa_writew(dev, SaDbCSR.PRISETIRQMASK, 0xffff);
}
/** /**
* aac_sa_notify_adapter - handle adapter notification * aac_sa_notify_adapter - handle adapter notification
* @dev: Adapter that notification is for * @dev: Adapter that notification is for
...@@ -214,9 +224,8 @@ static int sa_sync_cmd(struct aac_dev *dev, u32 command, ...@@ -214,9 +224,8 @@ static int sa_sync_cmd(struct aac_dev *dev, u32 command,
static void aac_sa_interrupt_adapter (struct aac_dev *dev) static void aac_sa_interrupt_adapter (struct aac_dev *dev)
{ {
u32 ret;
sa_sync_cmd(dev, BREAKPOINT_REQUEST, 0, 0, 0, 0, 0, 0, sa_sync_cmd(dev, BREAKPOINT_REQUEST, 0, 0, 0, 0, 0, 0,
&ret, NULL, NULL, NULL, NULL); NULL, NULL, NULL, NULL, NULL);
} }
/** /**
...@@ -352,10 +361,18 @@ int aac_sa_init(struct aac_dev *dev) ...@@ -352,10 +361,18 @@ int aac_sa_init(struct aac_dev *dev)
*/ */
dev->a_ops.adapter_interrupt = aac_sa_interrupt_adapter; dev->a_ops.adapter_interrupt = aac_sa_interrupt_adapter;
dev->a_ops.adapter_disable_int = aac_sa_disable_interrupt;
dev->a_ops.adapter_notify = aac_sa_notify_adapter; dev->a_ops.adapter_notify = aac_sa_notify_adapter;
dev->a_ops.adapter_sync_cmd = sa_sync_cmd; dev->a_ops.adapter_sync_cmd = sa_sync_cmd;
dev->a_ops.adapter_check_health = aac_sa_check_health; dev->a_ops.adapter_check_health = aac_sa_check_health;
/*
* First clear out all interrupts. Then enable the one's that
* we can handle.
*/
sa_writew(dev, SaDbCSR.PRISETIRQMASK, 0xffff);
sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, (PrintfReady | DOORBELL_1 |
DOORBELL_2 | DOORBELL_3 | DOORBELL_4));
if(aac_init_adapter(dev) == NULL) if(aac_init_adapter(dev) == NULL)
goto error_irq; goto error_irq;
...@@ -381,6 +398,7 @@ int aac_sa_init(struct aac_dev *dev) ...@@ -381,6 +398,7 @@ int aac_sa_init(struct aac_dev *dev)
kfree(dev->queues); kfree(dev->queues);
error_irq: error_irq:
sa_writew(dev, SaDbCSR.PRISETIRQMASK, 0xffff);
free_irq(dev->scsi_host_ptr->irq, (void *)dev); free_irq(dev->scsi_host_ptr->irq, (void *)dev);
error_iounmap: error_iounmap:
......
...@@ -9200,8 +9200,8 @@ asc_prt_scsi_cmnd(struct scsi_cmnd *s) ...@@ -9200,8 +9200,8 @@ asc_prt_scsi_cmnd(struct scsi_cmnd *s)
(unsigned) s->serial_number, s->retries, s->allowed); (unsigned) s->serial_number, s->retries, s->allowed);
printk( printk(
" timeout_per_command %d, timeout_total %d, timeout %d\n", " timeout_per_command %d\n",
s->timeout_per_command, s->timeout_total, s->timeout); s->timeout_per_command);
printk( printk(
" scsi_done 0x%lx, done 0x%lx, host_scribble 0x%lx, result 0x%x\n", " scsi_done 0x%lx, done 0x%lx, host_scribble 0x%lx, result 0x%x\n",
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
config SCSI_AIC79XX config SCSI_AIC79XX
tristate "Adaptec AIC79xx U320 support" tristate "Adaptec AIC79xx U320 support"
depends on PCI && SCSI depends on PCI && SCSI
select SCSI_SPI_ATTRS
help help
This driver supports all of Adaptec's Ultra 320 PCI-X This driver supports all of Adaptec's Ultra 320 PCI-X
based SCSI controllers. based SCSI controllers.
......
...@@ -126,7 +126,6 @@ aic7770_find_device(uint32_t id) ...@@ -126,7 +126,6 @@ aic7770_find_device(uint32_t id)
int int
aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry, u_int io) aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry, u_int io)
{ {
u_long l;
int error; int error;
int have_seeprom; int have_seeprom;
u_int hostconf; u_int hostconf;
......
...@@ -1247,9 +1247,6 @@ struct ahd_softc { ...@@ -1247,9 +1247,6 @@ struct ahd_softc {
uint16_t user_tagenable;/* Tagged Queuing allowed */ uint16_t user_tagenable;/* Tagged Queuing allowed */
}; };
TAILQ_HEAD(ahd_softc_tailq, ahd_softc);
extern struct ahd_softc_tailq ahd_tailq;
/*************************** IO Cell Configuration ****************************/ /*************************** IO Cell Configuration ****************************/
#define AHD_PRECOMP_SLEW_INDEX \ #define AHD_PRECOMP_SLEW_INDEX \
(AHD_ANNEXCOL_PRECOMP_SLEW - AHD_ANNEXCOL_PER_DEV0) (AHD_ANNEXCOL_PRECOMP_SLEW - AHD_ANNEXCOL_PER_DEV0)
...@@ -1374,8 +1371,6 @@ void ahd_enable_coalescing(struct ahd_softc *ahd, ...@@ -1374,8 +1371,6 @@ void ahd_enable_coalescing(struct ahd_softc *ahd,
void ahd_pause_and_flushwork(struct ahd_softc *ahd); void ahd_pause_and_flushwork(struct ahd_softc *ahd);
int ahd_suspend(struct ahd_softc *ahd); int ahd_suspend(struct ahd_softc *ahd);
int ahd_resume(struct ahd_softc *ahd); int ahd_resume(struct ahd_softc *ahd);
void ahd_softc_insert(struct ahd_softc *);
struct ahd_softc *ahd_find_softc(struct ahd_softc *ahd);
void ahd_set_unit(struct ahd_softc *, int); void ahd_set_unit(struct ahd_softc *, int);
void ahd_set_name(struct ahd_softc *, char *); void ahd_set_name(struct ahd_softc *, char *);
struct scb *ahd_get_scb(struct ahd_softc *ahd, u_int col_idx); struct scb *ahd_get_scb(struct ahd_softc *ahd, u_int col_idx);
...@@ -1524,7 +1519,6 @@ void ahd_print_scb(struct scb *scb); ...@@ -1524,7 +1519,6 @@ void ahd_print_scb(struct scb *scb);
void ahd_print_devinfo(struct ahd_softc *ahd, void ahd_print_devinfo(struct ahd_softc *ahd,
struct ahd_devinfo *devinfo); struct ahd_devinfo *devinfo);
void ahd_dump_sglist(struct scb *scb); void ahd_dump_sglist(struct scb *scb);
void ahd_dump_all_cards_state(void);
void ahd_dump_card_state(struct ahd_softc *ahd); void ahd_dump_card_state(struct ahd_softc *ahd);
int ahd_print_register(ahd_reg_parse_entry_t *table, int ahd_print_register(ahd_reg_parse_entry_t *table,
u_int num_entries, u_int num_entries,
......
...@@ -52,8 +52,6 @@ ...@@ -52,8 +52,6 @@
#include <dev/aic7xxx/aicasm/aicasm_insformat.h> #include <dev/aic7xxx/aicasm/aicasm_insformat.h>
#endif #endif
/******************************** Globals *************************************/
struct ahd_softc_tailq ahd_tailq = TAILQ_HEAD_INITIALIZER(ahd_tailq);
/***************************** Lookup Tables **********************************/ /***************************** Lookup Tables **********************************/
char *ahd_chip_names[] = char *ahd_chip_names[] =
...@@ -5179,74 +5177,6 @@ ahd_softc_init(struct ahd_softc *ahd) ...@@ -5179,74 +5177,6 @@ ahd_softc_init(struct ahd_softc *ahd)
return (0); return (0);
} }
void
ahd_softc_insert(struct ahd_softc *ahd)
{
struct ahd_softc *list_ahd;
#if AHD_PCI_CONFIG > 0
/*
* Second Function PCI devices need to inherit some
* settings from function 0.
*/
if ((ahd->features & AHD_MULTI_FUNC) != 0) {
TAILQ_FOREACH(list_ahd, &ahd_tailq, links) {
ahd_dev_softc_t list_pci;
ahd_dev_softc_t pci;
list_pci = list_ahd->dev_softc;
pci = ahd->dev_softc;
if (ahd_get_pci_slot(list_pci) == ahd_get_pci_slot(pci)
&& ahd_get_pci_bus(list_pci) == ahd_get_pci_bus(pci)) {
struct ahd_softc *master;
struct ahd_softc *slave;
if (ahd_get_pci_function(list_pci) == 0) {
master = list_ahd;
slave = ahd;
} else {
master = ahd;
slave = list_ahd;
}
slave->flags &= ~AHD_BIOS_ENABLED;
slave->flags |=
master->flags & AHD_BIOS_ENABLED;
break;
}
}
}
#endif
/*
* Insertion sort into our list of softcs.
*/
list_ahd = TAILQ_FIRST(&ahd_tailq);
while (list_ahd != NULL
&& ahd_softc_comp(ahd, list_ahd) <= 0)
list_ahd = TAILQ_NEXT(list_ahd, links);
if (list_ahd != NULL)
TAILQ_INSERT_BEFORE(list_ahd, ahd, links);
else
TAILQ_INSERT_TAIL(&ahd_tailq, ahd, links);
ahd->init_level++;
}
/*
* Verify that the passed in softc pointer is for a
* controller that is still configured.
*/
struct ahd_softc *
ahd_find_softc(struct ahd_softc *ahd)
{
struct ahd_softc *list_ahd;
TAILQ_FOREACH(list_ahd, &ahd_tailq, links) {
if (list_ahd == ahd)
return (ahd);
}
return (NULL);
}
void void
ahd_set_unit(struct ahd_softc *ahd, int unit) ahd_set_unit(struct ahd_softc *ahd, int unit)
{ {
...@@ -7902,18 +7832,10 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset) ...@@ -7902,18 +7832,10 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset)
static void static void
ahd_reset_poll(void *arg) ahd_reset_poll(void *arg)
{ {
struct ahd_softc *ahd; struct ahd_softc *ahd = arg;
u_int scsiseq1; u_int scsiseq1;
u_long l;
u_long s; u_long s;
ahd_list_lock(&l);
ahd = ahd_find_softc((struct ahd_softc *)arg);
if (ahd == NULL) {
printf("ahd_reset_poll: Instance %p no longer exists\n", arg);
ahd_list_unlock(&l);
return;
}
ahd_lock(ahd, &s); ahd_lock(ahd, &s);
ahd_pause(ahd); ahd_pause(ahd);
ahd_update_modes(ahd); ahd_update_modes(ahd);
...@@ -7924,7 +7846,6 @@ ahd_reset_poll(void *arg) ...@@ -7924,7 +7846,6 @@ ahd_reset_poll(void *arg)
ahd_reset_poll, ahd); ahd_reset_poll, ahd);
ahd_unpause(ahd); ahd_unpause(ahd);
ahd_unlock(ahd, &s); ahd_unlock(ahd, &s);
ahd_list_unlock(&l);
return; return;
} }
...@@ -7936,25 +7857,16 @@ ahd_reset_poll(void *arg) ...@@ -7936,25 +7857,16 @@ ahd_reset_poll(void *arg)
ahd->flags &= ~AHD_RESET_POLL_ACTIVE; ahd->flags &= ~AHD_RESET_POLL_ACTIVE;
ahd_unlock(ahd, &s); ahd_unlock(ahd, &s);
ahd_release_simq(ahd); ahd_release_simq(ahd);
ahd_list_unlock(&l);
} }
/**************************** Statistics Processing ***************************/ /**************************** Statistics Processing ***************************/
static void static void
ahd_stat_timer(void *arg) ahd_stat_timer(void *arg)
{ {
struct ahd_softc *ahd; struct ahd_softc *ahd = arg;
u_long l;
u_long s; u_long s;
int enint_coal; int enint_coal;
ahd_list_lock(&l);
ahd = ahd_find_softc((struct ahd_softc *)arg);
if (ahd == NULL) {
printf("ahd_stat_timer: Instance %p no longer exists\n", arg);
ahd_list_unlock(&l);
return;
}
ahd_lock(ahd, &s); ahd_lock(ahd, &s);
enint_coal = ahd->hs_mailbox & ENINT_COALESCE; enint_coal = ahd->hs_mailbox & ENINT_COALESCE;
...@@ -7981,7 +7893,6 @@ ahd_stat_timer(void *arg) ...@@ -7981,7 +7893,6 @@ ahd_stat_timer(void *arg)
ahd_timer_reset(&ahd->stat_timer, AHD_STAT_UPDATE_US, ahd_timer_reset(&ahd->stat_timer, AHD_STAT_UPDATE_US,
ahd_stat_timer, ahd); ahd_stat_timer, ahd);
ahd_unlock(ahd, &s); ahd_unlock(ahd, &s);
ahd_list_unlock(&l);
} }
/****************************** Status Processing *****************************/ /****************************** Status Processing *****************************/
...@@ -8745,16 +8656,6 @@ ahd_probe_stack_size(struct ahd_softc *ahd) ...@@ -8745,16 +8656,6 @@ ahd_probe_stack_size(struct ahd_softc *ahd)
return (last_probe); return (last_probe);
} }
void
ahd_dump_all_cards_state(void)
{
struct ahd_softc *list_ahd;
TAILQ_FOREACH(list_ahd, &ahd_tailq, links) {
ahd_dump_card_state(list_ahd);
}
}
int int
ahd_print_register(ahd_reg_parse_entry_t *table, u_int num_entries, ahd_print_register(ahd_reg_parse_entry_t *table, u_int num_entries,
const char *name, u_int address, u_int value, const char *name, u_int address, u_int value,
...@@ -9039,7 +8940,6 @@ ahd_dump_card_state(struct ahd_softc *ahd) ...@@ -9039,7 +8940,6 @@ ahd_dump_card_state(struct ahd_softc *ahd)
ahd_outb(ahd, STACK, (ahd->saved_stack[i] >> 8) & 0xFF); ahd_outb(ahd, STACK, (ahd->saved_stack[i] >> 8) & 0xFF);
} }
printf("\n<<<<<<<<<<<<<<<<< Dump Card State Ends >>>>>>>>>>>>>>>>>>\n"); printf("\n<<<<<<<<<<<<<<<<< Dump Card State Ends >>>>>>>>>>>>>>>>>>\n");
ahd_platform_dump_card_state(ahd);
ahd_restore_modes(ahd, saved_modes); ahd_restore_modes(ahd, saved_modes);
if (paused == 0) if (paused == 0)
ahd_unpause(ahd); ahd_unpause(ahd);
......
此差异已折叠。
...@@ -42,6 +42,7 @@ ...@@ -42,6 +42,7 @@
#ifndef _AIC79XX_LINUX_H_ #ifndef _AIC79XX_LINUX_H_
#define _AIC79XX_LINUX_H_ #define _AIC79XX_LINUX_H_
#include <linux/config.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/blkdev.h> #include <linux/blkdev.h>
#include <linux/delay.h> #include <linux/delay.h>
...@@ -49,18 +50,23 @@ ...@@ -49,18 +50,23 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/version.h> #include <linux/version.h>
#include <linux/interrupt.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/slab.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
#include <asm/io.h> #include <asm/io.h>
#include <linux/interrupt.h> /* For tasklet support. */ #include <scsi/scsi.h>
#include <linux/config.h> #include <scsi/scsi_cmnd.h>
#include <linux/slab.h> #include <scsi/scsi_eh.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_tcq.h>
#include <scsi/scsi_transport.h>
#include <scsi/scsi_transport_spi.h>
/* Core SCSI definitions */ /* Core SCSI definitions */
#define AIC_LIB_PREFIX ahd #define AIC_LIB_PREFIX ahd
#include "scsi.h"
#include <scsi/scsi_host.h>
/* Name space conflict with BSD queue macros */ /* Name space conflict with BSD queue macros */
#ifdef LIST_HEAD #ifdef LIST_HEAD
...@@ -95,7 +101,7 @@ ...@@ -95,7 +101,7 @@
/************************* Forward Declarations *******************************/ /************************* Forward Declarations *******************************/
struct ahd_softc; struct ahd_softc;
typedef struct pci_dev *ahd_dev_softc_t; typedef struct pci_dev *ahd_dev_softc_t;
typedef Scsi_Cmnd *ahd_io_ctx_t; typedef struct scsi_cmnd *ahd_io_ctx_t;
/******************************* Byte Order ***********************************/ /******************************* Byte Order ***********************************/
#define ahd_htobe16(x) cpu_to_be16(x) #define ahd_htobe16(x) cpu_to_be16(x)
...@@ -114,8 +120,7 @@ typedef Scsi_Cmnd *ahd_io_ctx_t; ...@@ -114,8 +120,7 @@ typedef Scsi_Cmnd *ahd_io_ctx_t;
/************************* Configuration Data *********************************/ /************************* Configuration Data *********************************/
extern uint32_t aic79xx_allow_memio; extern uint32_t aic79xx_allow_memio;
extern int aic79xx_detect_complete; extern struct scsi_host_template aic79xx_driver_template;
extern Scsi_Host_Template aic79xx_driver_template;
/***************************** Bus Space/DMA **********************************/ /***************************** Bus Space/DMA **********************************/
...@@ -145,11 +150,7 @@ struct ahd_linux_dma_tag ...@@ -145,11 +150,7 @@ struct ahd_linux_dma_tag
}; };
typedef struct ahd_linux_dma_tag* bus_dma_tag_t; typedef struct ahd_linux_dma_tag* bus_dma_tag_t;
struct ahd_linux_dmamap typedef dma_addr_t bus_dmamap_t;
{
dma_addr_t bus_addr;
};
typedef struct ahd_linux_dmamap* bus_dmamap_t;
typedef int bus_dma_filter_t(void*, dma_addr_t); typedef int bus_dma_filter_t(void*, dma_addr_t);
typedef void bus_dmamap_callback_t(void *, bus_dma_segment_t *, int, int); typedef void bus_dmamap_callback_t(void *, bus_dma_segment_t *, int, int);
...@@ -226,12 +227,12 @@ typedef struct timer_list ahd_timer_t; ...@@ -226,12 +227,12 @@ typedef struct timer_list ahd_timer_t;
#define ahd_timer_init init_timer #define ahd_timer_init init_timer
#define ahd_timer_stop del_timer_sync #define ahd_timer_stop del_timer_sync
typedef void ahd_linux_callback_t (u_long); typedef void ahd_linux_callback_t (u_long);
static __inline void ahd_timer_reset(ahd_timer_t *timer, u_int usec, static __inline void ahd_timer_reset(ahd_timer_t *timer, int usec,
ahd_callback_t *func, void *arg); ahd_callback_t *func, void *arg);
static __inline void ahd_scb_timer_reset(struct scb *scb, u_int usec); static __inline void ahd_scb_timer_reset(struct scb *scb, u_int usec);
static __inline void static __inline void
ahd_timer_reset(ahd_timer_t *timer, u_int usec, ahd_callback_t *func, void *arg) ahd_timer_reset(ahd_timer_t *timer, int usec, ahd_callback_t *func, void *arg)
{ {
struct ahd_softc *ahd; struct ahd_softc *ahd;
...@@ -252,43 +253,8 @@ ahd_scb_timer_reset(struct scb *scb, u_int usec) ...@@ -252,43 +253,8 @@ ahd_scb_timer_reset(struct scb *scb, u_int usec)
/***************************** SMP support ************************************/ /***************************** SMP support ************************************/
#include <linux/spinlock.h> #include <linux/spinlock.h>
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) || defined(SCSI_HAS_HOST_LOCK))
#define AHD_SCSI_HAS_HOST_LOCK 1
#else
#define AHD_SCSI_HAS_HOST_LOCK 0
#endif
#define AIC79XX_DRIVER_VERSION "1.3.11" #define AIC79XX_DRIVER_VERSION "1.3.11"
/**************************** Front End Queues ********************************/
/*
* Data structure used to cast the Linux struct scsi_cmnd to something
* that allows us to use the queue macros. The linux structure has
* plenty of space to hold the links fields as required by the queue
* macros, but the queue macors require them to have the correct type.
*/
struct ahd_cmd_internal {
/* Area owned by the Linux scsi layer. */
uint8_t private[offsetof(struct scsi_cmnd, SCp.Status)];
union {
STAILQ_ENTRY(ahd_cmd) ste;
LIST_ENTRY(ahd_cmd) le;
TAILQ_ENTRY(ahd_cmd) tqe;
} links;
uint32_t end;
};
struct ahd_cmd {
union {
struct ahd_cmd_internal icmd;
struct scsi_cmnd scsi_cmd;
} un;
};
#define acmd_icmd(cmd) ((cmd)->un.icmd)
#define acmd_scsi_cmd(cmd) ((cmd)->un.scsi_cmd)
#define acmd_links un.icmd.links
/*************************** Device Data Structures ***************************/ /*************************** Device Data Structures ***************************/
/* /*
* A per probed device structure used to deal with some error recovery * A per probed device structure used to deal with some error recovery
...@@ -297,22 +263,17 @@ struct ahd_cmd { ...@@ -297,22 +263,17 @@ struct ahd_cmd {
* after a successfully completed inquiry command to the target when * after a successfully completed inquiry command to the target when
* that inquiry data indicates a lun is present. * that inquiry data indicates a lun is present.
*/ */
TAILQ_HEAD(ahd_busyq, ahd_cmd);
typedef enum { typedef enum {
AHD_DEV_UNCONFIGURED = 0x01,
AHD_DEV_FREEZE_TIL_EMPTY = 0x02, /* Freeze queue until active == 0 */ AHD_DEV_FREEZE_TIL_EMPTY = 0x02, /* Freeze queue until active == 0 */
AHD_DEV_TIMER_ACTIVE = 0x04, /* Our timer is active */
AHD_DEV_ON_RUN_LIST = 0x08, /* Queued to be run later */
AHD_DEV_Q_BASIC = 0x10, /* Allow basic device queuing */ AHD_DEV_Q_BASIC = 0x10, /* Allow basic device queuing */
AHD_DEV_Q_TAGGED = 0x20, /* Allow full SCSI2 command queueing */ AHD_DEV_Q_TAGGED = 0x20, /* Allow full SCSI2 command queueing */
AHD_DEV_PERIODIC_OTAG = 0x40, /* Send OTAG to prevent starvation */ AHD_DEV_PERIODIC_OTAG = 0x40, /* Send OTAG to prevent starvation */
AHD_DEV_SLAVE_CONFIGURED = 0x80 /* slave_configure() has been called */
} ahd_linux_dev_flags; } ahd_linux_dev_flags;
struct ahd_linux_target; struct ahd_linux_target;
struct ahd_linux_device { struct ahd_linux_device {
TAILQ_ENTRY(ahd_linux_device) links; TAILQ_ENTRY(ahd_linux_device) links;
struct ahd_busyq busyq;
/* /*
* The number of transactions currently * The number of transactions currently
...@@ -388,62 +349,12 @@ struct ahd_linux_device { ...@@ -388,62 +349,12 @@ struct ahd_linux_device {
*/ */
u_int commands_since_idle_or_otag; u_int commands_since_idle_or_otag;
#define AHD_OTAG_THRESH 500 #define AHD_OTAG_THRESH 500
int lun;
Scsi_Device *scsi_device;
struct ahd_linux_target *target;
}; };
typedef enum {
AHD_DV_REQUIRED = 0x01,
AHD_INQ_VALID = 0x02,
AHD_BASIC_DV = 0x04,
AHD_ENHANCED_DV = 0x08
} ahd_linux_targ_flags;
/* DV States */
typedef enum {
AHD_DV_STATE_EXIT = 0,
AHD_DV_STATE_INQ_SHORT_ASYNC,
AHD_DV_STATE_INQ_ASYNC,
AHD_DV_STATE_INQ_ASYNC_VERIFY,
AHD_DV_STATE_TUR,
AHD_DV_STATE_REBD,
AHD_DV_STATE_INQ_VERIFY,
AHD_DV_STATE_WEB,
AHD_DV_STATE_REB,
AHD_DV_STATE_SU,
AHD_DV_STATE_BUSY
} ahd_dv_state;
struct ahd_linux_target { struct ahd_linux_target {
struct ahd_linux_device *devices[AHD_NUM_LUNS]; struct scsi_device *sdev[AHD_NUM_LUNS];
int channel;
int target;
int refcount;
struct ahd_transinfo last_tinfo; struct ahd_transinfo last_tinfo;
struct ahd_softc *ahd; struct ahd_softc *ahd;
ahd_linux_targ_flags flags;
struct scsi_inquiry_data *inq_data;
/*
* The next "fallback" period to use for narrow/wide transfers.
*/
uint8_t dv_next_narrow_period;
uint8_t dv_next_wide_period;
uint8_t dv_max_width;
uint8_t dv_max_ppr_options;
uint8_t dv_last_ppr_options;
u_int dv_echo_size;
ahd_dv_state dv_state;
u_int dv_state_retry;
uint8_t *dv_buffer;
uint8_t *dv_buffer1;
/*
* Cumulative counter of errors.
*/
u_long errors_detected;
u_long cmds_since_error;
}; };
/********************* Definitions Required by the Core ***********************/ /********************* Definitions Required by the Core ***********************/
...@@ -453,32 +364,16 @@ struct ahd_linux_target { ...@@ -453,32 +364,16 @@ struct ahd_linux_target {
* manner and are allocated below 4GB, the number of S/G segments is * manner and are allocated below 4GB, the number of S/G segments is
* unrestricted. * unrestricted.
*/ */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
/*
* We dynamically adjust the number of segments in pre-2.5 kernels to
* avoid fragmentation issues in the SCSI mid-layer's private memory
* allocator. See aic79xx_osm.c ahd_linux_size_nseg() for details.
*/
extern u_int ahd_linux_nseg;
#define AHD_NSEG ahd_linux_nseg
#define AHD_LINUX_MIN_NSEG 64
#else
#define AHD_NSEG 128 #define AHD_NSEG 128
#endif
/* /*
* Per-SCB OSM storage. * Per-SCB OSM storage.
*/ */
typedef enum {
AHD_SCB_UP_EH_SEM = 0x1
} ahd_linux_scb_flags;
struct scb_platform_data { struct scb_platform_data {
struct ahd_linux_device *dev; struct ahd_linux_device *dev;
dma_addr_t buf_busaddr; dma_addr_t buf_busaddr;
uint32_t xfer_len; uint32_t xfer_len;
uint32_t sense_resid; /* Auto-Sense residual */ uint32_t sense_resid; /* Auto-Sense residual */
ahd_linux_scb_flags flags;
}; };
/* /*
...@@ -487,44 +382,23 @@ struct scb_platform_data { ...@@ -487,44 +382,23 @@ struct scb_platform_data {
* alignment restrictions of the various platforms supported by * alignment restrictions of the various platforms supported by
* this driver. * this driver.
*/ */
typedef enum {
AHD_DV_WAIT_SIMQ_EMPTY = 0x01,
AHD_DV_WAIT_SIMQ_RELEASE = 0x02,
AHD_DV_ACTIVE = 0x04,
AHD_DV_SHUTDOWN = 0x08,
AHD_RUN_CMPLT_Q_TIMER = 0x10
} ahd_linux_softc_flags;
TAILQ_HEAD(ahd_completeq, ahd_cmd);
struct ahd_platform_data { struct ahd_platform_data {
/* /*
* Fields accessed from interrupt context. * Fields accessed from interrupt context.
*/ */
struct ahd_linux_target *targets[AHD_NUM_TARGETS]; struct scsi_target *starget[AHD_NUM_TARGETS];
TAILQ_HEAD(, ahd_linux_device) device_runq;
struct ahd_completeq completeq;
spinlock_t spin_lock; spinlock_t spin_lock;
struct tasklet_struct runq_tasklet;
u_int qfrozen; u_int qfrozen;
pid_t dv_pid;
struct timer_list completeq_timer;
struct timer_list reset_timer; struct timer_list reset_timer;
struct timer_list stats_timer;
struct semaphore eh_sem; struct semaphore eh_sem;
struct semaphore dv_sem;
struct semaphore dv_cmd_sem; /* XXX This needs to be in
* the target struct
*/
struct scsi_device *dv_scsi_dev;
struct Scsi_Host *host; /* pointer to scsi host */ struct Scsi_Host *host; /* pointer to scsi host */
#define AHD_LINUX_NOIRQ ((uint32_t)~0) #define AHD_LINUX_NOIRQ ((uint32_t)~0)
uint32_t irq; /* IRQ for this adapter */ uint32_t irq; /* IRQ for this adapter */
uint32_t bios_address; uint32_t bios_address;
uint32_t mem_busaddr; /* Mem Base Addr */ uint32_t mem_busaddr; /* Mem Base Addr */
uint64_t hw_dma_mask; #define AHD_SCB_UP_EH_SEM 0x1
ahd_linux_softc_flags flags; uint32_t flags;
}; };
/************************** OS Utility Wrappers *******************************/ /************************** OS Utility Wrappers *******************************/
...@@ -641,7 +515,7 @@ ahd_insb(struct ahd_softc * ahd, long port, uint8_t *array, int count) ...@@ -641,7 +515,7 @@ ahd_insb(struct ahd_softc * ahd, long port, uint8_t *array, int count)
/**************************** Initialization **********************************/ /**************************** Initialization **********************************/
int ahd_linux_register_host(struct ahd_softc *, int ahd_linux_register_host(struct ahd_softc *,
Scsi_Host_Template *); struct scsi_host_template *);
uint64_t ahd_linux_get_memsize(void); uint64_t ahd_linux_get_memsize(void);
...@@ -657,28 +531,6 @@ void ahd_format_transinfo(struct info_str *info, ...@@ -657,28 +531,6 @@ void ahd_format_transinfo(struct info_str *info,
struct ahd_transinfo *tinfo); struct ahd_transinfo *tinfo);
/******************************** Locking *************************************/ /******************************** Locking *************************************/
/* Lock protecting internal data structures */
static __inline void ahd_lockinit(struct ahd_softc *);
static __inline void ahd_lock(struct ahd_softc *, unsigned long *flags);
static __inline void ahd_unlock(struct ahd_softc *, unsigned long *flags);
/* Lock acquisition and release of the above lock in midlayer entry points. */
static __inline void ahd_midlayer_entrypoint_lock(struct ahd_softc *,
unsigned long *flags);
static __inline void ahd_midlayer_entrypoint_unlock(struct ahd_softc *,
unsigned long *flags);
/* Lock held during command compeletion to the upper layer */
static __inline void ahd_done_lockinit(struct ahd_softc *);
static __inline void ahd_done_lock(struct ahd_softc *, unsigned long *flags);
static __inline void ahd_done_unlock(struct ahd_softc *, unsigned long *flags);
/* Lock held during ahd_list manipulation and ahd softc frees */
extern spinlock_t ahd_list_spinlock;
static __inline void ahd_list_lockinit(void);
static __inline void ahd_list_lock(unsigned long *flags);
static __inline void ahd_list_unlock(unsigned long *flags);
static __inline void static __inline void
ahd_lockinit(struct ahd_softc *ahd) ahd_lockinit(struct ahd_softc *ahd)
{ {
...@@ -697,75 +549,6 @@ ahd_unlock(struct ahd_softc *ahd, unsigned long *flags) ...@@ -697,75 +549,6 @@ ahd_unlock(struct ahd_softc *ahd, unsigned long *flags)
spin_unlock_irqrestore(&ahd->platform_data->spin_lock, *flags); spin_unlock_irqrestore(&ahd->platform_data->spin_lock, *flags);
} }
static __inline void
ahd_midlayer_entrypoint_lock(struct ahd_softc *ahd, unsigned long *flags)
{
/*
* In 2.5.X and some 2.4.X versions, the midlayer takes our
* lock just before calling us, so we avoid locking again.
* For other kernel versions, the io_request_lock is taken
* just before our entry point is called. In this case, we
* trade the io_request_lock for our per-softc lock.
*/
#if AHD_SCSI_HAS_HOST_LOCK == 0
spin_unlock(&io_request_lock);
spin_lock(&ahd->platform_data->spin_lock);
#endif
}
static __inline void
ahd_midlayer_entrypoint_unlock(struct ahd_softc *ahd, unsigned long *flags)
{
#if AHD_SCSI_HAS_HOST_LOCK == 0
spin_unlock(&ahd->platform_data->spin_lock);
spin_lock(&io_request_lock);
#endif
}
static __inline void
ahd_done_lockinit(struct ahd_softc *ahd)
{
/*
* In 2.5.X, our own lock is held during completions.
* In previous versions, the io_request_lock is used.
* In either case, we can't initialize this lock again.
*/
}
static __inline void
ahd_done_lock(struct ahd_softc *ahd, unsigned long *flags)
{
#if AHD_SCSI_HAS_HOST_LOCK == 0
spin_lock(&io_request_lock);
#endif
}
static __inline void
ahd_done_unlock(struct ahd_softc *ahd, unsigned long *flags)
{
#if AHD_SCSI_HAS_HOST_LOCK == 0
spin_unlock(&io_request_lock);
#endif
}
static __inline void
ahd_list_lockinit(void)
{
spin_lock_init(&ahd_list_spinlock);
}
static __inline void
ahd_list_lock(unsigned long *flags)
{
spin_lock_irqsave(&ahd_list_spinlock, *flags);
}
static __inline void
ahd_list_unlock(unsigned long *flags)
{
spin_unlock_irqrestore(&ahd_list_spinlock, *flags);
}
/******************************* PCI Definitions ******************************/ /******************************* PCI Definitions ******************************/
/* /*
* PCIM_xxx: mask to locate subfield in register * PCIM_xxx: mask to locate subfield in register
...@@ -925,27 +708,17 @@ ahd_flush_device_writes(struct ahd_softc *ahd) ...@@ -925,27 +708,17 @@ ahd_flush_device_writes(struct ahd_softc *ahd)
} }
/**************************** Proc FS Support *********************************/ /**************************** Proc FS Support *********************************/
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
int ahd_linux_proc_info(char *, char **, off_t, int, int, int);
#else
int ahd_linux_proc_info(struct Scsi_Host *, char *, char **, int ahd_linux_proc_info(struct Scsi_Host *, char *, char **,
off_t, int, int); off_t, int, int);
#endif
/*************************** Domain Validation ********************************/
#define AHD_DV_CMD(cmd) ((cmd)->scsi_done == ahd_linux_dv_complete)
#define AHD_DV_SIMQ_FROZEN(ahd) \
((((ahd)->platform_data->flags & AHD_DV_ACTIVE) != 0) \
&& (ahd)->platform_data->qfrozen == 1)
/*********************** Transaction Access Wrappers **************************/ /*********************** Transaction Access Wrappers **************************/
static __inline void ahd_cmd_set_transaction_status(Scsi_Cmnd *, uint32_t); static __inline void ahd_cmd_set_transaction_status(struct scsi_cmnd *, uint32_t);
static __inline void ahd_set_transaction_status(struct scb *, uint32_t); static __inline void ahd_set_transaction_status(struct scb *, uint32_t);
static __inline void ahd_cmd_set_scsi_status(Scsi_Cmnd *, uint32_t); static __inline void ahd_cmd_set_scsi_status(struct scsi_cmnd *, uint32_t);
static __inline void ahd_set_scsi_status(struct scb *, uint32_t); static __inline void ahd_set_scsi_status(struct scb *, uint32_t);
static __inline uint32_t ahd_cmd_get_transaction_status(Scsi_Cmnd *cmd); static __inline uint32_t ahd_cmd_get_transaction_status(struct scsi_cmnd *cmd);
static __inline uint32_t ahd_get_transaction_status(struct scb *); static __inline uint32_t ahd_get_transaction_status(struct scb *);
static __inline uint32_t ahd_cmd_get_scsi_status(Scsi_Cmnd *cmd); static __inline uint32_t ahd_cmd_get_scsi_status(struct scsi_cmnd *cmd);
static __inline uint32_t ahd_get_scsi_status(struct scb *); static __inline uint32_t ahd_get_scsi_status(struct scb *);
static __inline void ahd_set_transaction_tag(struct scb *, int, u_int); static __inline void ahd_set_transaction_tag(struct scb *, int, u_int);
static __inline u_long ahd_get_transfer_length(struct scb *); static __inline u_long ahd_get_transfer_length(struct scb *);
...@@ -964,7 +737,7 @@ static __inline void ahd_platform_scb_free(struct ahd_softc *ahd, ...@@ -964,7 +737,7 @@ static __inline void ahd_platform_scb_free(struct ahd_softc *ahd,
static __inline void ahd_freeze_scb(struct scb *scb); static __inline void ahd_freeze_scb(struct scb *scb);
static __inline static __inline
void ahd_cmd_set_transaction_status(Scsi_Cmnd *cmd, uint32_t status) void ahd_cmd_set_transaction_status(struct scsi_cmnd *cmd, uint32_t status)
{ {
cmd->result &= ~(CAM_STATUS_MASK << 16); cmd->result &= ~(CAM_STATUS_MASK << 16);
cmd->result |= status << 16; cmd->result |= status << 16;
...@@ -977,7 +750,7 @@ void ahd_set_transaction_status(struct scb *scb, uint32_t status) ...@@ -977,7 +750,7 @@ void ahd_set_transaction_status(struct scb *scb, uint32_t status)
} }
static __inline static __inline
void ahd_cmd_set_scsi_status(Scsi_Cmnd *cmd, uint32_t status) void ahd_cmd_set_scsi_status(struct scsi_cmnd *cmd, uint32_t status)
{ {
cmd->result &= ~0xFFFF; cmd->result &= ~0xFFFF;
cmd->result |= status; cmd->result |= status;
...@@ -990,7 +763,7 @@ void ahd_set_scsi_status(struct scb *scb, uint32_t status) ...@@ -990,7 +763,7 @@ void ahd_set_scsi_status(struct scb *scb, uint32_t status)
} }
static __inline static __inline
uint32_t ahd_cmd_get_transaction_status(Scsi_Cmnd *cmd) uint32_t ahd_cmd_get_transaction_status(struct scsi_cmnd *cmd)
{ {
return ((cmd->result >> 16) & CAM_STATUS_MASK); return ((cmd->result >> 16) & CAM_STATUS_MASK);
} }
...@@ -1002,7 +775,7 @@ uint32_t ahd_get_transaction_status(struct scb *scb) ...@@ -1002,7 +775,7 @@ uint32_t ahd_get_transaction_status(struct scb *scb)
} }
static __inline static __inline
uint32_t ahd_cmd_get_scsi_status(Scsi_Cmnd *cmd) uint32_t ahd_cmd_get_scsi_status(struct scsi_cmnd *cmd)
{ {
return (cmd->result & 0xFFFF); return (cmd->result & 0xFFFF);
} }
...@@ -1117,7 +890,6 @@ void ahd_done(struct ahd_softc*, struct scb*); ...@@ -1117,7 +890,6 @@ void ahd_done(struct ahd_softc*, struct scb*);
void ahd_send_async(struct ahd_softc *, char channel, void ahd_send_async(struct ahd_softc *, char channel,
u_int target, u_int lun, ac_code, void *); u_int target, u_int lun, ac_code, void *);
void ahd_print_path(struct ahd_softc *, struct scb *); void ahd_print_path(struct ahd_softc *, struct scb *);
void ahd_platform_dump_card_state(struct ahd_softc *ahd);
#ifdef CONFIG_PCI #ifdef CONFIG_PCI
#define AHD_PCI_CONFIG 1 #define AHD_PCI_CONFIG 1
......
...@@ -92,27 +92,31 @@ struct pci_driver aic79xx_pci_driver = { ...@@ -92,27 +92,31 @@ struct pci_driver aic79xx_pci_driver = {
static void static void
ahd_linux_pci_dev_remove(struct pci_dev *pdev) ahd_linux_pci_dev_remove(struct pci_dev *pdev)
{ {
struct ahd_softc *ahd; struct ahd_softc *ahd = pci_get_drvdata(pdev);
u_long l; u_long s;
/* ahd_lock(ahd, &s);
* We should be able to just perform ahd_intr_enable(ahd, FALSE);
* the free directly, but check our ahd_unlock(ahd, &s);
* list for extra sanity. ahd_free(ahd);
*/ }
ahd_list_lock(&l);
ahd = ahd_find_softc((struct ahd_softc *)pci_get_drvdata(pdev)); static void
if (ahd != NULL) { ahd_linux_pci_inherit_flags(struct ahd_softc *ahd)
u_long s; {
struct pci_dev *pdev = ahd->dev_softc, *master_pdev;
TAILQ_REMOVE(&ahd_tailq, ahd, links); unsigned int master_devfn = PCI_DEVFN(PCI_SLOT(pdev->devfn), 0);
ahd_list_unlock(&l);
ahd_lock(ahd, &s); master_pdev = pci_get_slot(pdev->bus, master_devfn);
ahd_intr_enable(ahd, FALSE); if (master_pdev) {
ahd_unlock(ahd, &s); struct ahd_softc *master = pci_get_drvdata(master_pdev);
ahd_free(ahd); if (master) {
} else ahd->flags &= ~AHD_BIOS_ENABLED;
ahd_list_unlock(&l); ahd->flags |= master->flags & AHD_BIOS_ENABLED;
} else
printk(KERN_ERR "aic79xx: no multichannel peer found!\n");
pci_dev_put(master_pdev);
}
} }
static int static int
...@@ -125,22 +129,6 @@ ahd_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -125,22 +129,6 @@ ahd_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
char *name; char *name;
int error; int error;
/*
* Some BIOSen report the same device multiple times.
*/
TAILQ_FOREACH(ahd, &ahd_tailq, links) {
struct pci_dev *probed_pdev;
probed_pdev = ahd->dev_softc;
if (probed_pdev->bus->number == pdev->bus->number
&& probed_pdev->devfn == pdev->devfn)
break;
}
if (ahd != NULL) {
/* Skip duplicate. */
return (-ENODEV);
}
pci = pdev; pci = pdev;
entry = ahd_find_pci_device(pci); entry = ahd_find_pci_device(pci);
if (entry == NULL) if (entry == NULL)
...@@ -177,15 +165,12 @@ ahd_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -177,15 +165,12 @@ ahd_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (memsize >= 0x8000000000ULL if (memsize >= 0x8000000000ULL
&& pci_set_dma_mask(pdev, DMA_64BIT_MASK) == 0) { && pci_set_dma_mask(pdev, DMA_64BIT_MASK) == 0) {
ahd->flags |= AHD_64BIT_ADDRESSING; ahd->flags |= AHD_64BIT_ADDRESSING;
ahd->platform_data->hw_dma_mask = DMA_64BIT_MASK;
} else if (memsize > 0x80000000 } else if (memsize > 0x80000000
&& pci_set_dma_mask(pdev, mask_39bit) == 0) { && pci_set_dma_mask(pdev, mask_39bit) == 0) {
ahd->flags |= AHD_39BIT_ADDRESSING; ahd->flags |= AHD_39BIT_ADDRESSING;
ahd->platform_data->hw_dma_mask = mask_39bit;
} }
} else { } else {
pci_set_dma_mask(pdev, DMA_32BIT_MASK); pci_set_dma_mask(pdev, DMA_32BIT_MASK);
ahd->platform_data->hw_dma_mask = DMA_32BIT_MASK;
} }
ahd->dev_softc = pci; ahd->dev_softc = pci;
error = ahd_pci_config(ahd, entry); error = ahd_pci_config(ahd, entry);
...@@ -193,16 +178,17 @@ ahd_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -193,16 +178,17 @@ ahd_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
ahd_free(ahd); ahd_free(ahd);
return (-error); return (-error);
} }
/*
* Second Function PCI devices need to inherit some
* * settings from function 0.
*/
if ((ahd->features & AHD_MULTI_FUNC) && PCI_FUNC(pdev->devfn) != 0)
ahd_linux_pci_inherit_flags(ahd);
pci_set_drvdata(pdev, ahd); pci_set_drvdata(pdev, ahd);
if (aic79xx_detect_complete) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ahd_linux_register_host(ahd, &aic79xx_driver_template);
ahd_linux_register_host(ahd, &aic79xx_driver_template);
#else
printf("aic79xx: ignoring PCI device found after "
"initialization\n");
return (-ENODEV);
#endif
}
return (0); return (0);
} }
......
...@@ -283,7 +283,6 @@ int ...@@ -283,7 +283,6 @@ int
ahd_pci_config(struct ahd_softc *ahd, struct ahd_pci_identity *entry) ahd_pci_config(struct ahd_softc *ahd, struct ahd_pci_identity *entry)
{ {
struct scb_data *shared_scb_data; struct scb_data *shared_scb_data;
u_long l;
u_int command; u_int command;
uint32_t devconfig; uint32_t devconfig;
uint16_t subvendor; uint16_t subvendor;
...@@ -373,16 +372,9 @@ ahd_pci_config(struct ahd_softc *ahd, struct ahd_pci_identity *entry) ...@@ -373,16 +372,9 @@ ahd_pci_config(struct ahd_softc *ahd, struct ahd_pci_identity *entry)
* Allow interrupts now that we are completely setup. * Allow interrupts now that we are completely setup.
*/ */
error = ahd_pci_map_int(ahd); error = ahd_pci_map_int(ahd);
if (error != 0) if (!error)
return (error); ahd->init_level++;
return error;
ahd_list_lock(&l);
/*
* Link this softc in with all other ahd instances.
*/
ahd_softc_insert(ahd);
ahd_list_unlock(&l);
return (0);
} }
/* /*
......
...@@ -49,7 +49,7 @@ static void ahd_dump_target_state(struct ahd_softc *ahd, ...@@ -49,7 +49,7 @@ static void ahd_dump_target_state(struct ahd_softc *ahd,
u_int our_id, char channel, u_int our_id, char channel,
u_int target_id, u_int target_offset); u_int target_id, u_int target_offset);
static void ahd_dump_device_state(struct info_str *info, static void ahd_dump_device_state(struct info_str *info,
struct ahd_linux_device *dev); struct scsi_device *sdev);
static int ahd_proc_write_seeprom(struct ahd_softc *ahd, static int ahd_proc_write_seeprom(struct ahd_softc *ahd,
char *buffer, int length); char *buffer, int length);
...@@ -167,6 +167,7 @@ ahd_dump_target_state(struct ahd_softc *ahd, struct info_str *info, ...@@ -167,6 +167,7 @@ ahd_dump_target_state(struct ahd_softc *ahd, struct info_str *info,
u_int target_offset) u_int target_offset)
{ {
struct ahd_linux_target *targ; struct ahd_linux_target *targ;
struct scsi_target *starget;
struct ahd_initiator_tinfo *tinfo; struct ahd_initiator_tinfo *tinfo;
struct ahd_tmode_tstate *tstate; struct ahd_tmode_tstate *tstate;
int lun; int lun;
...@@ -176,20 +177,20 @@ ahd_dump_target_state(struct ahd_softc *ahd, struct info_str *info, ...@@ -176,20 +177,20 @@ ahd_dump_target_state(struct ahd_softc *ahd, struct info_str *info,
copy_info(info, "Target %d Negotiation Settings\n", target_id); copy_info(info, "Target %d Negotiation Settings\n", target_id);
copy_info(info, "\tUser: "); copy_info(info, "\tUser: ");
ahd_format_transinfo(info, &tinfo->user); ahd_format_transinfo(info, &tinfo->user);
targ = ahd->platform_data->targets[target_offset]; starget = ahd->platform_data->starget[target_offset];
if (targ == NULL) if (starget == NULL)
return; return;
targ = scsi_transport_target_data(starget);
copy_info(info, "\tGoal: "); copy_info(info, "\tGoal: ");
ahd_format_transinfo(info, &tinfo->goal); ahd_format_transinfo(info, &tinfo->goal);
copy_info(info, "\tCurr: "); copy_info(info, "\tCurr: ");
ahd_format_transinfo(info, &tinfo->curr); ahd_format_transinfo(info, &tinfo->curr);
copy_info(info, "\tTransmission Errors %ld\n", targ->errors_detected);
for (lun = 0; lun < AHD_NUM_LUNS; lun++) { for (lun = 0; lun < AHD_NUM_LUNS; lun++) {
struct ahd_linux_device *dev; struct scsi_device *dev;
dev = targ->devices[lun]; dev = targ->sdev[lun];
if (dev == NULL) if (dev == NULL)
continue; continue;
...@@ -199,10 +200,13 @@ ahd_dump_target_state(struct ahd_softc *ahd, struct info_str *info, ...@@ -199,10 +200,13 @@ ahd_dump_target_state(struct ahd_softc *ahd, struct info_str *info,
} }
static void static void
ahd_dump_device_state(struct info_str *info, struct ahd_linux_device *dev) ahd_dump_device_state(struct info_str *info, struct scsi_device *sdev)
{ {
struct ahd_linux_device *dev = scsi_transport_device_data(sdev);
copy_info(info, "\tChannel %c Target %d Lun %d Settings\n", copy_info(info, "\tChannel %c Target %d Lun %d Settings\n",
dev->target->channel + 'A', dev->target->target, dev->lun); sdev->sdev_target->channel + 'A',
sdev->sdev_target->id, sdev->lun);
copy_info(info, "\t\tCommands Queued %ld\n", dev->commands_issued); copy_info(info, "\t\tCommands Queued %ld\n", dev->commands_issued);
copy_info(info, "\t\tCommands Active %d\n", dev->active); copy_info(info, "\t\tCommands Active %d\n", dev->active);
...@@ -278,36 +282,16 @@ ahd_proc_write_seeprom(struct ahd_softc *ahd, char *buffer, int length) ...@@ -278,36 +282,16 @@ ahd_proc_write_seeprom(struct ahd_softc *ahd, char *buffer, int length)
* Return information to handle /proc support for the driver. * Return information to handle /proc support for the driver.
*/ */
int int
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
ahd_linux_proc_info(char *buffer, char **start, off_t offset,
int length, int hostno, int inout)
#else
ahd_linux_proc_info(struct Scsi_Host *shost, char *buffer, char **start, ahd_linux_proc_info(struct Scsi_Host *shost, char *buffer, char **start,
off_t offset, int length, int inout) off_t offset, int length, int inout)
#endif
{ {
struct ahd_softc *ahd; struct ahd_softc *ahd = *(struct ahd_softc **)shost->hostdata;
struct info_str info; struct info_str info;
char ahd_info[256]; char ahd_info[256];
u_long l;
u_int max_targ; u_int max_targ;
u_int i; u_int i;
int retval; int retval;
retval = -EINVAL;
ahd_list_lock(&l);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
TAILQ_FOREACH(ahd, &ahd_tailq, links) {
if (ahd->platform_data->host->host_no == hostno)
break;
}
#else
ahd = ahd_find_softc(*(struct ahd_softc **)shost->hostdata);
#endif
if (ahd == NULL)
goto done;
/* Has data been written to the file? */ /* Has data been written to the file? */
if (inout == TRUE) { if (inout == TRUE) {
retval = ahd_proc_write_seeprom(ahd, buffer, length); retval = ahd_proc_write_seeprom(ahd, buffer, length);
...@@ -357,6 +341,5 @@ ahd_linux_proc_info(struct Scsi_Host *shost, char *buffer, char **start, ...@@ -357,6 +341,5 @@ ahd_linux_proc_info(struct Scsi_Host *shost, char *buffer, char **start,
} }
retval = info.pos > info.offset ? info.pos - info.offset : 0; retval = info.pos > info.offset ? info.pos - info.offset : 0;
done: done:
ahd_list_unlock(&l);
return (retval); return (retval);
} }
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES. * POSSIBILITY OF SUCH DAMAGES.
* *
* $Id: //depot/aic7xxx/aic7xxx/aic7xxx.h#79 $ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.h#85 $
* *
* $FreeBSD$ * $FreeBSD$
*/ */
...@@ -243,7 +243,7 @@ typedef enum { ...@@ -243,7 +243,7 @@ typedef enum {
*/ */
AHC_AIC7850_FE = AHC_SPIOCAP|AHC_AUTOPAUSE|AHC_TARGETMODE|AHC_ULTRA, AHC_AIC7850_FE = AHC_SPIOCAP|AHC_AUTOPAUSE|AHC_TARGETMODE|AHC_ULTRA,
AHC_AIC7860_FE = AHC_AIC7850_FE, AHC_AIC7860_FE = AHC_AIC7850_FE,
AHC_AIC7870_FE = AHC_TARGETMODE, AHC_AIC7870_FE = AHC_TARGETMODE|AHC_AUTOPAUSE,
AHC_AIC7880_FE = AHC_AIC7870_FE|AHC_ULTRA, AHC_AIC7880_FE = AHC_AIC7870_FE|AHC_ULTRA,
/* /*
* Although we have space for both the initiator and * Although we have space for both the initiator and
......
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
* *
* $FreeBSD$ * $FreeBSD$
*/ */
VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#39 $" VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#40 $"
/* /*
* This file is processed by the aic7xxx_asm utility for use in assembling * This file is processed by the aic7xxx_asm utility for use in assembling
...@@ -1306,7 +1306,6 @@ scratch_ram { ...@@ -1306,7 +1306,6 @@ scratch_ram {
*/ */
MWI_RESIDUAL { MWI_RESIDUAL {
size 1 size 1
alias TARG_IMMEDIATE_SCB
} }
/* /*
* SCBID of the next SCB to be started by the controller. * SCBID of the next SCB to be started by the controller.
...@@ -1461,6 +1460,7 @@ scratch_ram { ...@@ -1461,6 +1460,7 @@ scratch_ram {
*/ */
LAST_MSG { LAST_MSG {
size 1 size 1
alias TARG_IMMEDIATE_SCB
} }
/* /*
......
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
* $FreeBSD$ * $FreeBSD$
*/ */
VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#56 $" VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#58 $"
PATCH_ARG_LIST = "struct ahc_softc *ahc" PATCH_ARG_LIST = "struct ahc_softc *ahc"
PREFIX = "ahc_" PREFIX = "ahc_"
...@@ -679,6 +679,7 @@ await_busfree: ...@@ -679,6 +679,7 @@ await_busfree:
clr SCSIBUSL; /* Prevent bit leakage durint SELTO */ clr SCSIBUSL; /* Prevent bit leakage durint SELTO */
} }
and SXFRCTL0, ~SPIOEN; and SXFRCTL0, ~SPIOEN;
mvi SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT;
test SSTAT1,REQINIT|BUSFREE jz .; test SSTAT1,REQINIT|BUSFREE jz .;
test SSTAT1, BUSFREE jnz poll_for_work; test SSTAT1, BUSFREE jnz poll_for_work;
mvi MISSED_BUSFREE call set_seqint; mvi MISSED_BUSFREE call set_seqint;
...@@ -1097,7 +1098,7 @@ ultra2_dmahalt: ...@@ -1097,7 +1098,7 @@ ultra2_dmahalt:
test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz dma_mid_sg; test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz dma_mid_sg;
if ((ahc->flags & AHC_TARGETROLE) != 0) { if ((ahc->flags & AHC_TARGETROLE) != 0) {
test SSTAT0, TARGET jz dma_last_sg; test SSTAT0, TARGET jz dma_last_sg;
if ((ahc->flags & AHC_TMODE_WIDEODD_BUG) != 0) { if ((ahc->bugs & AHC_TMODE_WIDEODD_BUG) != 0) {
test DMAPARAMS, DIRECTION jz dma_mid_sg; test DMAPARAMS, DIRECTION jz dma_mid_sg;
} }
} }
......
...@@ -28,9 +28,7 @@ ...@@ -28,9 +28,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE. * SUCH DAMAGE.
* *
* $Id: //depot/aic7xxx/aic7xxx/aic7xxx_93cx6.c#17 $ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_93cx6.c#19 $
*
* $FreeBSD$
*/ */
/* /*
...@@ -64,7 +62,6 @@ ...@@ -64,7 +62,6 @@
* is preceded by an initial zero (leading 0, followed by 16-bits, MSB * is preceded by an initial zero (leading 0, followed by 16-bits, MSB
* first). The clock cycling from low to high initiates the next data * first). The clock cycling from low to high initiates the next data
* bit to be sent from the chip. * bit to be sent from the chip.
*
*/ */
#ifdef __linux__ #ifdef __linux__
...@@ -81,14 +78,22 @@ ...@@ -81,14 +78,22 @@
* Right now, we only have to read the SEEPROM. But we make it easier to * Right now, we only have to read the SEEPROM. But we make it easier to
* add other 93Cx6 functions. * add other 93Cx6 functions.
*/ */
static struct seeprom_cmd { struct seeprom_cmd {
uint8_t len; uint8_t len;
uint8_t bits[9]; uint8_t bits[11];
} seeprom_read = {3, {1, 1, 0}}; };
/* Short opcodes for the c46 */
static struct seeprom_cmd seeprom_ewen = {9, {1, 0, 0, 1, 1, 0, 0, 0, 0}}; static struct seeprom_cmd seeprom_ewen = {9, {1, 0, 0, 1, 1, 0, 0, 0, 0}};
static struct seeprom_cmd seeprom_ewds = {9, {1, 0, 0, 0, 0, 0, 0, 0, 0}}; static struct seeprom_cmd seeprom_ewds = {9, {1, 0, 0, 0, 0, 0, 0, 0, 0}};
/* Long opcodes for the C56/C66 */
static struct seeprom_cmd seeprom_long_ewen = {11, {1, 0, 0, 1, 1, 0, 0, 0, 0}};
static struct seeprom_cmd seeprom_long_ewds = {11, {1, 0, 0, 0, 0, 0, 0, 0, 0}};
/* Common opcodes */
static struct seeprom_cmd seeprom_write = {3, {1, 0, 1}}; static struct seeprom_cmd seeprom_write = {3, {1, 0, 1}};
static struct seeprom_cmd seeprom_read = {3, {1, 1, 0}};
/* /*
* Wait for the SEERDY to go high; about 800 ns. * Wait for the SEERDY to go high; about 800 ns.
...@@ -222,12 +227,25 @@ int ...@@ -222,12 +227,25 @@ int
ahc_write_seeprom(struct seeprom_descriptor *sd, uint16_t *buf, ahc_write_seeprom(struct seeprom_descriptor *sd, uint16_t *buf,
u_int start_addr, u_int count) u_int start_addr, u_int count)
{ {
struct seeprom_cmd *ewen, *ewds;
uint16_t v; uint16_t v;
uint8_t temp; uint8_t temp;
int i, k; int i, k;
/* Place the chip into write-enable mode */ /* Place the chip into write-enable mode */
send_seeprom_cmd(sd, &seeprom_ewen); if (sd->sd_chip == C46) {
ewen = &seeprom_ewen;
ewds = &seeprom_ewds;
} else if (sd->sd_chip == C56_66) {
ewen = &seeprom_long_ewen;
ewds = &seeprom_long_ewds;
} else {
printf("ahc_write_seeprom: unsupported seeprom type %d\n",
sd->sd_chip);
return (0);
}
send_seeprom_cmd(sd, ewen);
reset_seeprom(sd); reset_seeprom(sd);
/* Write all requested data out to the seeprom. */ /* Write all requested data out to the seeprom. */
...@@ -277,7 +295,7 @@ ahc_write_seeprom(struct seeprom_descriptor *sd, uint16_t *buf, ...@@ -277,7 +295,7 @@ ahc_write_seeprom(struct seeprom_descriptor *sd, uint16_t *buf,
} }
/* Put the chip back into write-protect mode */ /* Put the chip back into write-protect mode */
send_seeprom_cmd(sd, &seeprom_ewds); send_seeprom_cmd(sd, ewds);
reset_seeprom(sd); reset_seeprom(sd);
return (1); return (1);
......
...@@ -37,9 +37,7 @@ ...@@ -37,9 +37,7 @@
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES. * POSSIBILITY OF SUCH DAMAGES.
* *
* $Id: //depot/aic7xxx/aic7xxx/aic7xxx.c#134 $ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.c#155 $
*
* $FreeBSD$
*/ */
#ifdef __linux__ #ifdef __linux__
...@@ -287,10 +285,19 @@ ahc_restart(struct ahc_softc *ahc) ...@@ -287,10 +285,19 @@ ahc_restart(struct ahc_softc *ahc)
ahc_outb(ahc, SEQ_FLAGS2, ahc_outb(ahc, SEQ_FLAGS2,
ahc_inb(ahc, SEQ_FLAGS2) & ~SCB_DMA); ahc_inb(ahc, SEQ_FLAGS2) & ~SCB_DMA);
} }
/*
* Clear any pending sequencer interrupt. It is no
* longer relevant since we're resetting the Program
* Counter.
*/
ahc_outb(ahc, CLRINT, CLRSEQINT);
ahc_outb(ahc, MWI_RESIDUAL, 0); ahc_outb(ahc, MWI_RESIDUAL, 0);
ahc_outb(ahc, SEQCTL, ahc->seqctl); ahc_outb(ahc, SEQCTL, ahc->seqctl);
ahc_outb(ahc, SEQADDR0, 0); ahc_outb(ahc, SEQADDR0, 0);
ahc_outb(ahc, SEQADDR1, 0); ahc_outb(ahc, SEQADDR1, 0);
ahc_unpause(ahc); ahc_unpause(ahc);
} }
...@@ -1174,19 +1181,20 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) ...@@ -1174,19 +1181,20 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
scb_index); scb_index);
} }
#endif #endif
/*
* Force a renegotiation with this target just in
* case the cable was pulled and will later be
* re-attached. The target may forget its negotiation
* settings with us should it attempt to reselect
* during the interruption. The target will not issue
* a unit attention in this case, so we must always
* renegotiate.
*/
ahc_scb_devinfo(ahc, &devinfo, scb); ahc_scb_devinfo(ahc, &devinfo, scb);
ahc_force_renegotiation(ahc, &devinfo);
ahc_set_transaction_status(scb, CAM_SEL_TIMEOUT); ahc_set_transaction_status(scb, CAM_SEL_TIMEOUT);
ahc_freeze_devq(ahc, scb); ahc_freeze_devq(ahc, scb);
/*
* Cancel any pending transactions on the device
* now that it seems to be missing. This will
* also revert us to async/narrow transfers until
* we can renegotiate with the device.
*/
ahc_handle_devreset(ahc, &devinfo,
CAM_SEL_TIMEOUT,
"Selection Timeout",
/*verbose_level*/1);
} }
ahc_outb(ahc, CLRINT, CLRSCSIINT); ahc_outb(ahc, CLRINT, CLRSCSIINT);
ahc_restart(ahc); ahc_restart(ahc);
...@@ -3763,8 +3771,9 @@ ahc_handle_devreset(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, ...@@ -3763,8 +3771,9 @@ ahc_handle_devreset(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
/*period*/0, /*offset*/0, /*ppr_options*/0, /*period*/0, /*offset*/0, /*ppr_options*/0,
AHC_TRANS_CUR, /*paused*/TRUE); AHC_TRANS_CUR, /*paused*/TRUE);
ahc_send_async(ahc, devinfo->channel, devinfo->target, if (status != CAM_SEL_TIMEOUT)
CAM_LUN_WILDCARD, AC_SENT_BDR, NULL); ahc_send_async(ahc, devinfo->channel, devinfo->target,
CAM_LUN_WILDCARD, AC_SENT_BDR, NULL);
if (message != NULL if (message != NULL
&& (verbose_level <= bootverbose)) && (verbose_level <= bootverbose))
...@@ -4003,14 +4012,6 @@ ahc_reset(struct ahc_softc *ahc, int reinit) ...@@ -4003,14 +4012,6 @@ ahc_reset(struct ahc_softc *ahc, int reinit)
* to disturb the integrity of the bus. * to disturb the integrity of the bus.
*/ */
ahc_pause(ahc); ahc_pause(ahc);
if ((ahc_inb(ahc, HCNTRL) & CHIPRST) != 0) {
/*
* The chip has not been initialized since
* PCI/EISA/VLB bus reset. Don't trust
* "left over BIOS data".
*/
ahc->flags |= AHC_NO_BIOS_INIT;
}
sxfrctl1_b = 0; sxfrctl1_b = 0;
if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7770) { if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7770) {
u_int sblkctl; u_int sblkctl;
...@@ -5036,14 +5037,23 @@ ahc_pause_and_flushwork(struct ahc_softc *ahc) ...@@ -5036,14 +5037,23 @@ ahc_pause_and_flushwork(struct ahc_softc *ahc)
ahc->flags |= AHC_ALL_INTERRUPTS; ahc->flags |= AHC_ALL_INTERRUPTS;
paused = FALSE; paused = FALSE;
do { do {
if (paused) if (paused) {
ahc_unpause(ahc); ahc_unpause(ahc);
/*
* Give the sequencer some time to service
* any active selections.
*/
ahc_delay(500);
}
ahc_intr(ahc); ahc_intr(ahc);
ahc_pause(ahc); ahc_pause(ahc);
paused = TRUE; paused = TRUE;
ahc_outb(ahc, SCSISEQ, ahc_inb(ahc, SCSISEQ) & ~ENSELO); ahc_outb(ahc, SCSISEQ, ahc_inb(ahc, SCSISEQ) & ~ENSELO);
ahc_clear_critical_section(ahc);
intstat = ahc_inb(ahc, INTSTAT); intstat = ahc_inb(ahc, INTSTAT);
if ((intstat & INT_PEND) == 0) {
ahc_clear_critical_section(ahc);
intstat = ahc_inb(ahc, INTSTAT);
}
} while (--maxloops } while (--maxloops
&& (intstat != 0xFF || (ahc->features & AHC_REMOVABLE) == 0) && (intstat != 0xFF || (ahc->features & AHC_REMOVABLE) == 0)
&& ((intstat & INT_PEND) != 0 && ((intstat & INT_PEND) != 0
......
...@@ -635,6 +635,8 @@ ahc_linux_slave_alloc(struct scsi_device *sdev) ...@@ -635,6 +635,8 @@ ahc_linux_slave_alloc(struct scsi_device *sdev)
targ->sdev[sdev->lun] = sdev; targ->sdev[sdev->lun] = sdev;
spi_period(starget) = 0;
return 0; return 0;
} }
...@@ -1612,9 +1614,9 @@ ahc_send_async(struct ahc_softc *ahc, char channel, ...@@ -1612,9 +1614,9 @@ ahc_send_async(struct ahc_softc *ahc, char channel,
if (channel == 'B') if (channel == 'B')
target_offset += 8; target_offset += 8;
starget = ahc->platform_data->starget[target_offset]; starget = ahc->platform_data->starget[target_offset];
targ = scsi_transport_target_data(starget); if (starget == NULL)
if (targ == NULL)
break; break;
targ = scsi_transport_target_data(starget);
target_ppr_options = target_ppr_options =
(spi_dt(starget) ? MSG_EXT_PPR_DT_REQ : 0) (spi_dt(starget) ? MSG_EXT_PPR_DT_REQ : 0)
...@@ -2329,8 +2331,6 @@ ahc_platform_dump_card_state(struct ahc_softc *ahc) ...@@ -2329,8 +2331,6 @@ ahc_platform_dump_card_state(struct ahc_softc *ahc)
{ {
} }
static void ahc_linux_exit(void);
static void ahc_linux_set_width(struct scsi_target *starget, int width) static void ahc_linux_set_width(struct scsi_target *starget, int width)
{ {
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
......
...@@ -265,7 +265,7 @@ ahc_scb_timer_reset(struct scb *scb, u_int usec) ...@@ -265,7 +265,7 @@ ahc_scb_timer_reset(struct scb *scb, u_int usec)
/***************************** SMP support ************************************/ /***************************** SMP support ************************************/
#include <linux/spinlock.h> #include <linux/spinlock.h>
#define AIC7XXX_DRIVER_VERSION "6.2.36" #define AIC7XXX_DRIVER_VERSION "7.0"
/*************************** Device Data Structures ***************************/ /*************************** Device Data Structures ***************************/
/* /*
......
...@@ -149,6 +149,27 @@ ahc_linux_pci_dev_remove(struct pci_dev *pdev) ...@@ -149,6 +149,27 @@ ahc_linux_pci_dev_remove(struct pci_dev *pdev)
ahc_free(ahc); ahc_free(ahc);
} }
static void
ahc_linux_pci_inherit_flags(struct ahc_softc *ahc)
{
struct pci_dev *pdev = ahc->dev_softc, *master_pdev;
unsigned int master_devfn = PCI_DEVFN(PCI_SLOT(pdev->devfn), 0);
master_pdev = pci_get_slot(pdev->bus, master_devfn);
if (master_pdev) {
struct ahc_softc *master = pci_get_drvdata(master_pdev);
if (master) {
ahc->flags &= ~AHC_BIOS_ENABLED;
ahc->flags |= master->flags & AHC_BIOS_ENABLED;
ahc->flags &= ~AHC_PRIMARY_CHANNEL;
ahc->flags |= master->flags & AHC_PRIMARY_CHANNEL;
} else
printk(KERN_ERR "aic7xxx: no multichannel peer found!\n");
pci_dev_put(master_pdev);
}
}
static int static int
ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{ {
...@@ -203,6 +224,14 @@ ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -203,6 +224,14 @@ ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
ahc_free(ahc); ahc_free(ahc);
return (-error); return (-error);
} }
/*
* Second Function PCI devices need to inherit some
* settings from function 0.
*/
if ((ahc->features & AHC_MULTI_FUNC) && PCI_FUNC(pdev->devfn) != 0)
ahc_linux_pci_inherit_flags(ahc);
pci_set_drvdata(pdev, ahc); pci_set_drvdata(pdev, ahc);
ahc_linux_register_host(ahc, &aic7xxx_driver_template); ahc_linux_register_host(ahc, &aic7xxx_driver_template);
return (0); return (0);
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
* DO NOT EDIT - This file is automatically generated * DO NOT EDIT - This file is automatically generated
* from the following source files: * from the following source files:
* *
* $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#56 $ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#58 $
* $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#39 $ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#40 $
*/ */
typedef int (ahc_reg_print_t)(u_int, u_int *, u_int); typedef int (ahc_reg_print_t)(u_int, u_int *, u_int);
typedef struct ahc_reg_parse_entry { typedef struct ahc_reg_parse_entry {
...@@ -1298,7 +1298,6 @@ ahc_reg_print_t ahc_sg_cache_pre_print; ...@@ -1298,7 +1298,6 @@ ahc_reg_print_t ahc_sg_cache_pre_print;
#define CMDSIZE_TABLE_TAIL 0x34 #define CMDSIZE_TABLE_TAIL 0x34
#define MWI_RESIDUAL 0x38 #define MWI_RESIDUAL 0x38
#define TARG_IMMEDIATE_SCB 0x38
#define NEXT_QUEUED_SCB 0x39 #define NEXT_QUEUED_SCB 0x39
...@@ -1380,6 +1379,7 @@ ahc_reg_print_t ahc_sg_cache_pre_print; ...@@ -1380,6 +1379,7 @@ ahc_reg_print_t ahc_sg_cache_pre_print;
#define RETURN_2 0x52 #define RETURN_2 0x52
#define LAST_MSG 0x53 #define LAST_MSG 0x53
#define TARG_IMMEDIATE_SCB 0x53
#define SCSISEQ_TEMPLATE 0x54 #define SCSISEQ_TEMPLATE 0x54
#define ENSELO 0x40 #define ENSELO 0x40
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
* DO NOT EDIT - This file is automatically generated * DO NOT EDIT - This file is automatically generated
* from the following source files: * from the following source files:
* *
* $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#56 $ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#58 $
* $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#39 $ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#40 $
*/ */
#include "aic7xxx_osm.h" #include "aic7xxx_osm.h"
......
此差异已折叠。
此差异已折叠。
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/blkdev.h> #include <linux/blkdev.h>
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/ioctl32.h> #include <linux/ioctl32.h>
#include <linux/compat.h> #include <linux/compat.h>
#include <linux/chio.h> /* here are all the ioctls */ #include <linux/chio.h> /* here are all the ioctls */
...@@ -940,8 +939,6 @@ static int ch_probe(struct device *dev) ...@@ -940,8 +939,6 @@ static int ch_probe(struct device *dev)
if (init) if (init)
ch_init_elem(ch); ch_init_elem(ch);
devfs_mk_cdev(MKDEV(SCSI_CHANGER_MAJOR,ch->minor),
S_IFCHR | S_IRUGO | S_IWUGO, ch->name);
class_device_create(ch_sysfs_class, class_device_create(ch_sysfs_class,
MKDEV(SCSI_CHANGER_MAJOR,ch->minor), MKDEV(SCSI_CHANGER_MAJOR,ch->minor),
dev, "s%s", ch->name); dev, "s%s", ch->name);
...@@ -974,7 +971,6 @@ static int ch_remove(struct device *dev) ...@@ -974,7 +971,6 @@ static int ch_remove(struct device *dev)
class_device_destroy(ch_sysfs_class, class_device_destroy(ch_sysfs_class,
MKDEV(SCSI_CHANGER_MAJOR,ch->minor)); MKDEV(SCSI_CHANGER_MAJOR,ch->minor));
devfs_remove(ch->name);
kfree(ch->dt); kfree(ch->dt);
kfree(ch); kfree(ch);
ch_devcount--; ch_devcount--;
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <scsi/scsi_host.h> #include <scsi/scsi_host.h>
#include <scsi/scsi_request.h> #include <scsi/scsi_request.h>
#include <scsi/scsi_eh.h> #include <scsi/scsi_eh.h>
#include <scsi/scsi_dbg.h>
......
...@@ -52,21 +52,80 @@ static struct class shost_class = { ...@@ -52,21 +52,80 @@ static struct class shost_class = {
}; };
/** /**
* scsi_host_cancel - cancel outstanding IO to this host * scsi_host_set_state - Take the given host through the host
* @shost: pointer to struct Scsi_Host * state model.
* recovery: recovery requested to run. * @shost: scsi host to change the state of.
* @state: state to change to.
*
* Returns zero if unsuccessful or an error if the requested
* transition is illegal.
**/ **/
static void scsi_host_cancel(struct Scsi_Host *shost, int recovery) int scsi_host_set_state(struct Scsi_Host *shost, enum scsi_host_state state)
{ {
struct scsi_device *sdev; enum scsi_host_state oldstate = shost->shost_state;
if (state == oldstate)
return 0;
switch (state) {
case SHOST_CREATED:
/* There are no legal states that come back to
* created. This is the manually initialised start
* state */
goto illegal;
case SHOST_RUNNING:
switch (oldstate) {
case SHOST_CREATED:
case SHOST_RECOVERY:
break;
default:
goto illegal;
}
break;
case SHOST_RECOVERY:
switch (oldstate) {
case SHOST_RUNNING:
break;
default:
goto illegal;
}
break;
case SHOST_CANCEL:
switch (oldstate) {
case SHOST_CREATED:
case SHOST_RUNNING:
break;
default:
goto illegal;
}
break;
case SHOST_DEL:
switch (oldstate) {
case SHOST_CANCEL:
break;
default:
goto illegal;
}
break;
set_bit(SHOST_CANCEL, &shost->shost_state);
shost_for_each_device(sdev, shost) {
scsi_device_cancel(sdev, recovery);
} }
wait_event(shost->host_wait, (!test_bit(SHOST_RECOVERY, shost->shost_state = state;
&shost->shost_state))); return 0;
illegal:
SCSI_LOG_ERROR_RECOVERY(1,
dev_printk(KERN_ERR, &shost->shost_gendev,
"Illegal host state transition"
"%s->%s\n",
scsi_host_state_name(oldstate),
scsi_host_state_name(state)));
return -EINVAL;
} }
EXPORT_SYMBOL(scsi_host_set_state);
/** /**
* scsi_remove_host - remove a scsi host * scsi_remove_host - remove a scsi host
...@@ -74,11 +133,13 @@ static void scsi_host_cancel(struct Scsi_Host *shost, int recovery) ...@@ -74,11 +133,13 @@ static void scsi_host_cancel(struct Scsi_Host *shost, int recovery)
**/ **/
void scsi_remove_host(struct Scsi_Host *shost) void scsi_remove_host(struct Scsi_Host *shost)
{ {
down(&shost->scan_mutex);
scsi_host_set_state(shost, SHOST_CANCEL);
up(&shost->scan_mutex);
scsi_forget_host(shost); scsi_forget_host(shost);
scsi_host_cancel(shost, 0);
scsi_proc_host_rm(shost); scsi_proc_host_rm(shost);
set_bit(SHOST_DEL, &shost->shost_state); scsi_host_set_state(shost, SHOST_DEL);
transport_unregister_device(&shost->shost_gendev); transport_unregister_device(&shost->shost_gendev);
class_device_unregister(&shost->shost_classdev); class_device_unregister(&shost->shost_classdev);
...@@ -115,7 +176,7 @@ int scsi_add_host(struct Scsi_Host *shost, struct device *dev) ...@@ -115,7 +176,7 @@ int scsi_add_host(struct Scsi_Host *shost, struct device *dev)
if (error) if (error)
goto out; goto out;
set_bit(SHOST_ADD, &shost->shost_state); scsi_host_set_state(shost, SHOST_RUNNING);
get_device(shost->shost_gendev.parent); get_device(shost->shost_gendev.parent);
error = class_device_add(&shost->shost_classdev); error = class_device_add(&shost->shost_classdev);
...@@ -226,6 +287,7 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) ...@@ -226,6 +287,7 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
spin_lock_init(&shost->default_lock); spin_lock_init(&shost->default_lock);
scsi_assign_lock(shost, &shost->default_lock); scsi_assign_lock(shost, &shost->default_lock);
shost->shost_state = SHOST_CREATED;
INIT_LIST_HEAD(&shost->__devices); INIT_LIST_HEAD(&shost->__devices);
INIT_LIST_HEAD(&shost->__targets); INIT_LIST_HEAD(&shost->__targets);
INIT_LIST_HEAD(&shost->eh_cmd_q); INIT_LIST_HEAD(&shost->eh_cmd_q);
...@@ -382,7 +444,7 @@ EXPORT_SYMBOL(scsi_host_lookup); ...@@ -382,7 +444,7 @@ EXPORT_SYMBOL(scsi_host_lookup);
**/ **/
struct Scsi_Host *scsi_host_get(struct Scsi_Host *shost) struct Scsi_Host *scsi_host_get(struct Scsi_Host *shost)
{ {
if (test_bit(SHOST_DEL, &shost->shost_state) || if ((shost->shost_state == SHOST_DEL) ||
!get_device(&shost->shost_gendev)) !get_device(&shost->shost_gendev))
return NULL; return NULL;
return shost; return shost;
......
此差异已折叠。
...@@ -342,9 +342,6 @@ struct lpfc_hba { ...@@ -342,9 +342,6 @@ struct lpfc_hba {
#define VPD_MASK 0xf /* mask for any vpd data */ #define VPD_MASK 0xf /* mask for any vpd data */
struct timer_list els_tmofunc; struct timer_list els_tmofunc;
void *link_stats;
/* /*
* stat counters * stat counters
*/ */
...@@ -370,6 +367,8 @@ struct lpfc_hba { ...@@ -370,6 +367,8 @@ struct lpfc_hba {
struct list_head freebufList; struct list_head freebufList;
struct list_head ctrspbuflist; struct list_head ctrspbuflist;
struct list_head rnidrspbuflist; struct list_head rnidrspbuflist;
struct fc_host_statistics link_stats;
}; };
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <scsi/scsi.h>
#include <scsi/scsi_device.h> #include <scsi/scsi_device.h>
#include <scsi/scsi_host.h> #include <scsi/scsi_host.h>
#include <scsi/scsi_tcq.h> #include <scsi/scsi_tcq.h>
...@@ -988,8 +989,7 @@ lpfc_get_stats(struct Scsi_Host *shost) ...@@ -988,8 +989,7 @@ lpfc_get_stats(struct Scsi_Host *shost)
{ {
struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata[0]; struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata[0];
struct lpfc_sli *psli = &phba->sli; struct lpfc_sli *psli = &phba->sli;
struct fc_host_statistics *hs = struct fc_host_statistics *hs = &phba->link_stats;
(struct fc_host_statistics *)phba->link_stats;
LPFC_MBOXQ_t *pmboxq; LPFC_MBOXQ_t *pmboxq;
MAILBOX_t *pmb; MAILBOX_t *pmb;
int rc=0; int rc=0;
...@@ -1020,6 +1020,8 @@ lpfc_get_stats(struct Scsi_Host *shost) ...@@ -1020,6 +1020,8 @@ lpfc_get_stats(struct Scsi_Host *shost)
return NULL; return NULL;
} }
memset(hs, 0, sizeof (struct fc_host_statistics));
hs->tx_frames = pmb->un.varRdStatus.xmitFrameCnt; hs->tx_frames = pmb->un.varRdStatus.xmitFrameCnt;
hs->tx_words = (pmb->un.varRdStatus.xmitByteCnt * 256); hs->tx_words = (pmb->un.varRdStatus.xmitByteCnt * 256);
hs->rx_frames = pmb->un.varRdStatus.rcvFrameCnt; hs->rx_frames = pmb->un.varRdStatus.rcvFrameCnt;
......
...@@ -27,8 +27,10 @@ ...@@ -27,8 +27,10 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/utsname.h> #include <linux/utsname.h>
#include <scsi/scsi.h>
#include <scsi/scsi_device.h> #include <scsi/scsi_device.h>
#include <scsi/scsi_host.h> #include <scsi/scsi_host.h>
#include <scsi/scsi_transport_fc.h>
#include "lpfc_hw.h" #include "lpfc_hw.h"
#include "lpfc_sli.h" #include "lpfc_sli.h"
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <scsi/scsi.h>
#include <scsi/scsi_device.h> #include <scsi/scsi_device.h>
#include <scsi/scsi_host.h> #include <scsi/scsi_host.h>
#include <scsi/scsi_transport_fc.h> #include <scsi/scsi_transport_fc.h>
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <scsi/scsi.h>
#include <scsi/scsi_device.h> #include <scsi/scsi_device.h>
#include <scsi/scsi_host.h> #include <scsi/scsi_host.h>
#include <scsi/scsi_transport_fc.h> #include <scsi/scsi_transport_fc.h>
...@@ -1135,6 +1136,8 @@ lpfc_nlp_list(struct lpfc_hba * phba, struct lpfc_nodelist * nlp, int list) ...@@ -1135,6 +1136,8 @@ lpfc_nlp_list(struct lpfc_hba * phba, struct lpfc_nodelist * nlp, int list)
switch(list) { switch(list) {
case NLP_NO_LIST: /* No list, just remove it */ case NLP_NO_LIST: /* No list, just remove it */
lpfc_nlp_remove(phba, nlp); lpfc_nlp_remove(phba, nlp);
/* as node removed - stop further transport calls */
rport_del = none;
break; break;
case NLP_UNUSED_LIST: case NLP_UNUSED_LIST:
spin_lock_irq(phba->host->host_lock); spin_lock_irq(phba->host->host_lock);
......
此差异已折叠。
...@@ -23,6 +23,11 @@ ...@@ -23,6 +23,11 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_transport_fc.h>
#include <scsi/scsi.h>
#include "lpfc_hw.h" #include "lpfc_hw.h"
#include "lpfc_sli.h" #include "lpfc_sli.h"
#include "lpfc_disc.h" #include "lpfc_disc.h"
......
此差异已折叠。
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <scsi/scsi.h>
#include <scsi/scsi_device.h> #include <scsi/scsi_device.h>
#include <scsi/scsi_host.h> #include <scsi/scsi_host.h>
#include <scsi/scsi_transport_fc.h> #include <scsi/scsi_transport_fc.h>
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册