Commit 9096518f authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://linux-scsi.bkbits.net/scsi-dledford

into home.transmeta.com:/home/torvalds/v2.5/linux
parents fd4b35fd 5605a515
...@@ -252,7 +252,7 @@ ...@@ -252,7 +252,7 @@
#include <linux/config.h> /* for CONFIG_PCI */ #include <linux/config.h> /* for CONFIG_PCI */
#define AIC7XXX_C_VERSION "5.2.5" #define AIC7XXX_C_VERSION "5.2.6"
#define NUMBER(arr) (sizeof(arr) / sizeof(arr[0])) #define NUMBER(arr) (sizeof(arr) / sizeof(arr[0]))
#define MIN(a,b) (((a) < (b)) ? (a) : (b)) #define MIN(a,b) (((a) < (b)) ? (a) : (b))
...@@ -274,30 +274,20 @@ ...@@ -274,30 +274,20 @@
#endif #endif
/* /*
* You can try raising me if tagged queueing is enabled, or lowering * You can try raising me for better performance or lowering me if you have
* me if you only have 4 SCBs. * flaky devices that go off the scsi bus when hit with too many tagged
* commands (like some IBM SCSI-3 LVD drives).
*/ */
#define AIC7XXX_CMDS_PER_DEVICE 32 #define AIC7XXX_CMDS_PER_DEVICE 32
/*
* *** Determining commands per LUN ***
*
* When AIC7XXX_CMDS_PER_DEVICE is not defined, the driver will use its
* own algorithm to determine the commands/LUN. If SCB paging is
* enabled, which is always now, the default is 8 commands per lun
* that indicates it supports tagged queueing. All non-tagged devices
* use an internal queue depth of 3, with no more than one of those
* three commands active at one time.
*/
typedef struct typedef struct
{ {
unsigned char tag_commands[16]; /* Allow for wide/twin adapters. */ unsigned char tag_commands[16]; /* Allow for wide/twin adapters. */
} adapter_tag_info_t; } adapter_tag_info_t;
/* /*
* Make a define that will tell the driver not to use tagged queueing * Make a define that will tell the driver not to the default tag depth
* by default. * everywhere.
*/ */
#define DEFAULT_TAG_COMMANDS {0, 0, 0, 0, 0, 0, 0, 0,\ #define DEFAULT_TAG_COMMANDS {0, 0, 0, 0, 0, 0, 0, 0,\
0, 0, 0, 0, 0, 0, 0, 0} 0, 0, 0, 0, 0, 0, 0, 0}
...@@ -878,7 +868,6 @@ struct aic_dev_data { ...@@ -878,7 +868,6 @@ struct aic_dev_data {
volatile unsigned short temp_q_depth; volatile unsigned short temp_q_depth;
unsigned short max_q_depth; unsigned short max_q_depth;
volatile unsigned char active_cmds; volatile unsigned char active_cmds;
unsigned char cmds_sent;
/* /*
* Statistics Kept: * Statistics Kept:
* *
...@@ -891,6 +880,9 @@ struct aic_dev_data { ...@@ -891,6 +880,9 @@ struct aic_dev_data {
*/ */
long w_total; /* total writes */ long w_total; /* total writes */
long r_total; /* total reads */ long r_total; /* total reads */
long barrier_total; /* total num of REQ_BARRIER commands */
long ordered_total; /* How many REQ_BARRIER commands we
used ordered tags to satisfy */
long w_bins[6]; /* binned write */ long w_bins[6]; /* binned write */
long r_bins[6]; /* binned reads */ long r_bins[6]; /* binned reads */
transinfo_type cur; transinfo_type cur;
...@@ -998,7 +990,7 @@ struct aic7xxx_host { ...@@ -998,7 +990,7 @@ struct aic7xxx_host {
unsigned short sc_size; unsigned short sc_size;
struct aic7xxx_host *next; /* allow for multiple IRQs */ struct aic7xxx_host *next; /* allow for multiple IRQs */
struct Scsi_Host *host; /* pointer to scsi host */ struct Scsi_Host *host; /* pointer to scsi host */
struct list_head aic_devs; /* all aic devs on host */ struct list_head aic_devs; /* all aic_dev structs on host */
int host_no; /* SCSI host number */ int host_no; /* SCSI host number */
unsigned long mbase; /* I/O memory address */ unsigned long mbase; /* I/O memory address */
ahc_chip chip; /* chip type */ ahc_chip chip; /* chip type */
...@@ -1066,6 +1058,10 @@ static struct aic7xxx_syncrate { ...@@ -1066,6 +1058,10 @@ static struct aic7xxx_syncrate {
* rule are noted in the comments. * rule are noted in the comments.
*/ */
/*
* Use this as the default queue depth when setting tagged queueing on.
*/
static unsigned int aic7xxx_default_queue_depth = AIC7XXX_CMDS_PER_DEVICE;
/* /*
* Skip the scsi bus reset. Non 0 make us skip the reset at startup. This * Skip the scsi bus reset. Non 0 make us skip the reset at startup. This
...@@ -1369,6 +1365,7 @@ aic7xxx_setup(char *s) ...@@ -1369,6 +1365,7 @@ aic7xxx_setup(char *s)
{ "pci_parity", &aic7xxx_pci_parity }, { "pci_parity", &aic7xxx_pci_parity },
{ "dump_card", &aic7xxx_dump_card }, { "dump_card", &aic7xxx_dump_card },
{ "dump_sequencer", &aic7xxx_dump_sequencer }, { "dump_sequencer", &aic7xxx_dump_sequencer },
{ "default_queue_depth", &aic7xxx_default_queue_depth },
{ "scbram", &aic7xxx_scbram }, { "scbram", &aic7xxx_scbram },
{ "seltime", &aic7xxx_seltime }, { "seltime", &aic7xxx_seltime },
{ "tag_info", NULL } { "tag_info", NULL }
...@@ -2636,6 +2633,7 @@ aic7xxx_allocate_scb(struct aic7xxx_host *p) ...@@ -2636,6 +2633,7 @@ aic7xxx_allocate_scb(struct aic7xxx_host *p)
static void static void
aic7xxx_queue_cmd_complete(struct aic7xxx_host *p, Scsi_Cmnd *cmd) aic7xxx_queue_cmd_complete(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
{ {
aic7xxx_position(cmd) = SCB_LIST_NULL;
cmd->host_scribble = (char *)p->completeq.head; cmd->host_scribble = (char *)p->completeq.head;
p->completeq.head = cmd; p->completeq.head = cmd;
} }
...@@ -2869,6 +2867,12 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb) ...@@ -2869,6 +2867,12 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
aic_dev->r_total++; aic_dev->r_total++;
ptr = aic_dev->r_bins; ptr = aic_dev->r_bins;
} }
if(cmd->device->simple_tags && cmd->request->flags & REQ_BARRIER)
{
aic_dev->barrier_total++;
if(scb->tag_action == MSG_ORDERED_Q_TAG)
aic_dev->ordered_total++;
}
x = scb->sg_length; x = scb->sg_length;
x >>= 10; x >>= 10;
for(i=0; i<6; i++) for(i=0; i<6; i++)
...@@ -3130,23 +3134,41 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel, ...@@ -3130,23 +3134,41 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel,
{ {
struct aic7xxx_scb *scbp, *prev_scbp; struct aic7xxx_scb *scbp, *prev_scbp;
struct scsi_device *sd; struct scsi_device *sd;
unsigned char active_scb, tcl; unsigned char active_scb, tcl, scb_tag;
int i = 0, init_lists = FALSE; int i = 0, init_lists = FALSE;
struct list_head *list_item, *list_head; struct aic_dev_data *aic_dev, *remove_aic_dev = NULL;
struct aic_dev_data *aic_dev;
/* /*
* Restore this when we're done * Restore this when we're done
*/ */
active_scb = aic_inb(p, SCBPTR); active_scb = aic_inb(p, SCBPTR);
/*
* If we are still scanning devices, this device may not be linked into
* our host controller yet. So, we grab the temporary aic_dev that we
* allocate during the device scan (by getting device->hostdata for the
* active device) and if the list struct in the aic_dev is empty, we
* add it to p->aic_devs. Then at the end of the function, if we added
* the aic_dev to our host struct so our loop would work, then we just
* remove it.
*/
scb_tag = aic_inb(p, SCB_TAG);
if(scb_tag < p->scb_data->numscbs)
{
scbp = p->scb_data->scb_array[scb_tag];
remove_aic_dev = (struct aic_dev_data *)scbp->cmd->device->hostdata;
if(list_empty(&remove_aic_dev->list))
list_add_tail(&remove_aic_dev->list, &p->aic_devs);
else
remove_aic_dev = NULL;
}
if (aic7xxx_verbose & (VERBOSE_RESET_PROCESS | VERBOSE_ABORT_PROCESS)) if (aic7xxx_verbose & (VERBOSE_RESET_PROCESS | VERBOSE_ABORT_PROCESS))
{ {
printk(INFO_LEAD "Reset device, active_scb %d\n", printk(INFO_LEAD "Reset device, hardware_scb %d, aic_dev %p,\n",
p->host_no, channel, target, lun, active_scb); p->host_no, channel, target, lun, active_scb, remove_aic_dev);
printk(INFO_LEAD "Current scb_tag %d, SEQADDR 0x%x, LASTPHASE " printk(INFO_LEAD "Current scb %d, SEQADDR 0x%x, LASTPHASE "
"0x%x\n", "0x%x\n",
p->host_no, channel, target, lun, aic_inb(p, SCB_TAG), p->host_no, channel, target, lun, scb_tag,
aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8), aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
aic_inb(p, LASTPHASE)); aic_inb(p, LASTPHASE));
printk(INFO_LEAD "SG_CACHEPTR 0x%x, SG_COUNT %d, SCSISIGI 0x%x\n", printk(INFO_LEAD "SG_CACHEPTR 0x%x, SG_COUNT %d, SCSISIGI 0x%x\n",
...@@ -3157,13 +3179,15 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel, ...@@ -3157,13 +3179,15 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel,
p->host_no, channel, target, lun, aic_inb(p, SSTAT0), p->host_no, channel, target, lun, aic_inb(p, SSTAT0),
aic_inb(p, SSTAT1), aic_inb(p, SSTAT2)); aic_inb(p, SSTAT1), aic_inb(p, SSTAT2));
} }
/* /*
* Deal with the busy target and linked next issues. * Deal with the busy target and linked next issues.
*/ */
list_head = &p->aic_devs; list_for_each_entry(aic_dev, &p->aic_devs, list)
list_for_each(list_item, list_head)
{ {
aic_dev = list_entry(list_item, struct aic_dev_data, list); if (aic7xxx_verbose & (VERBOSE_RESET_PROCESS | VERBOSE_ABORT_PROCESS))
printk(INFO_LEAD "processing aic_dev %p\n", p->host_no, channel, target,
lun, aic_dev);
sd = aic_dev->SDptr; sd = aic_dev->SDptr;
if((target != ALL_TARGETS && target != sd->id) || if((target != ALL_TARGETS && target != sd->id) ||
...@@ -3205,6 +3229,8 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel, ...@@ -3205,6 +3229,8 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel,
} }
} }
} }
if (remove_aic_dev)
list_del(&remove_aic_dev->list);
if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS)) if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
printk(INFO_LEAD "Cleaning QINFIFO.\n", p->host_no, channel, target, lun ); printk(INFO_LEAD "Cleaning QINFIFO.\n", p->host_no, channel, target, lun );
...@@ -6526,22 +6552,19 @@ do_aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs) ...@@ -6526,22 +6552,19 @@ do_aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
/*+F************************************************************************* /*+F*************************************************************************
* Function: * Function:
* aic7xxx_init_aic_dev * aic7xxx_init_transinfo
* *
* Description: * Description:
* Set up the initial aic_dev values from the BIOS settings and data * Set up the initial aic_dev values from the BIOS settings and from
* we got back from INQUIRY commands. * INQUIRY results
*-F*************************************************************************/ *-F*************************************************************************/
static void static void
aic7xxx_init_aic_dev(struct aic7xxx_host *p, struct aic_dev_data *aic_dev) aic7xxx_init_transinfo(struct aic7xxx_host *p, struct aic_dev_data *aic_dev)
{ {
struct scsi_device *sdpnt = aic_dev->SDptr; Scsi_Device *sdpnt = aic_dev->SDptr;
unsigned char tindex; unsigned char tindex;
tindex = sdpnt->id | (sdpnt->channel << 3); tindex = sdpnt->id | (sdpnt->channel << 3);
scbq_init(&aic_dev->delayed_scbs);
if (!(aic_dev->flags & DEVICE_DTR_SCANNED)) if (!(aic_dev->flags & DEVICE_DTR_SCANNED))
{ {
aic_dev->flags |= DEVICE_DTR_SCANNED; aic_dev->flags |= DEVICE_DTR_SCANNED;
...@@ -6597,6 +6620,31 @@ aic7xxx_init_aic_dev(struct aic7xxx_host *p, struct aic_dev_data *aic_dev) ...@@ -6597,6 +6620,31 @@ aic7xxx_init_aic_dev(struct aic7xxx_host *p, struct aic_dev_data *aic_dev)
} }
} }
/*+F*************************************************************************
* Function:
* aic7xxx_alloc_aic_dev
*
* Description:
* Set up the initial aic_dev struct pointers
*-F*************************************************************************/
static struct aic_dev_data *
aic7xxx_alloc_aic_dev(struct aic7xxx_host *p, Scsi_Device *SDptr)
{
struct aic_dev_data *aic_dev;
aic_dev = kmalloc(sizeof(struct aic_dev_data), GFP_ATOMIC | GFP_KERNEL);
if(!aic_dev)
return aic_dev;
memset(aic_dev, 0, sizeof(struct aic_dev_data));
SDptr->hostdata = aic_dev;
aic_dev->SDptr = SDptr;
aic_dev->max_q_depth = 1;
aic_dev->temp_q_depth = 1;
scbq_init(&aic_dev->delayed_scbs);
INIT_LIST_HEAD(&aic_dev->list);
return aic_dev;
}
/*+F************************************************************************* /*+F*************************************************************************
* Function: * Function:
* aic7xxx_device_queue_depth * aic7xxx_device_queue_depth
...@@ -6605,7 +6653,11 @@ aic7xxx_init_aic_dev(struct aic7xxx_host *p, struct aic_dev_data *aic_dev) ...@@ -6605,7 +6653,11 @@ aic7xxx_init_aic_dev(struct aic7xxx_host *p, struct aic_dev_data *aic_dev)
* Determines the queue depth for a given device. There are two ways * Determines the queue depth for a given device. There are two ways
* a queue depth can be obtained for a tagged queueing device. One * a queue depth can be obtained for a tagged queueing device. One
* way is the default queue depth which is determined by whether * way is the default queue depth which is determined by whether
* AIC7XXX_CMDS_PER_DEVICE is defined. If it is defined, then it is used * aic7xxx_default_queue_depth. The other is by the aic7xxx_tag_info
* array.
*
* If tagged queueing isn't supported on the device, then we set the
* depth to p->host->hostt->cmd_per_lun for internal driver queueing.
* as the default queue depth. Otherwise, we use either 4 or 8 as the * as the default queue depth. Otherwise, we use either 4 or 8 as the
* default queue depth (dependent on the number of hardware SCBs). * default queue depth (dependent on the number of hardware SCBs).
* The other way we determine queue depth is through the use of the * The other way we determine queue depth is through the use of the
...@@ -6617,7 +6669,7 @@ aic7xxx_init_aic_dev(struct aic7xxx_host *p, struct aic_dev_data *aic_dev) ...@@ -6617,7 +6669,7 @@ aic7xxx_init_aic_dev(struct aic7xxx_host *p, struct aic_dev_data *aic_dev)
static void static void
aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device) aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device)
{ {
int default_depth = p->host->hostt->cmd_per_lun; int tag_enabled = FALSE;
struct aic_dev_data *aic_dev = device->hostdata; struct aic_dev_data *aic_dev = device->hostdata;
unsigned char tindex; unsigned char tindex;
...@@ -6626,14 +6678,9 @@ aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device) ...@@ -6626,14 +6678,9 @@ aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device)
if (device->simple_tags) if (device->simple_tags)
return; // We've already enabled this device return; // We've already enabled this device
aic_dev->temp_q_depth = 1;
aic_dev->max_q_depth = 1;
if (device->tagged_supported) if (device->tagged_supported)
{ {
int tag_enabled = TRUE; tag_enabled = TRUE;
default_depth = AIC7XXX_CMDS_PER_DEVICE;
if (!(p->discenable & (1 << tindex))) if (!(p->discenable & (1 << tindex)))
{ {
...@@ -6641,6 +6688,7 @@ aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device) ...@@ -6641,6 +6688,7 @@ aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device)
printk(INFO_LEAD "Disconnection disabled, unable to " printk(INFO_LEAD "Disconnection disabled, unable to "
"enable tagged queueing.\n", "enable tagged queueing.\n",
p->host_no, device->channel, device->id, device->lun); p->host_no, device->channel, device->id, device->lun);
tag_enabled = FALSE;
} }
else else
{ {
...@@ -6655,7 +6703,8 @@ aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device) ...@@ -6655,7 +6703,8 @@ aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device)
" the aic7xxx.c source file.\n"); " the aic7xxx.c source file.\n");
print_warning = FALSE; print_warning = FALSE;
} }
aic_dev->max_q_depth = aic_dev->temp_q_depth = default_depth; aic_dev->max_q_depth = aic_dev->temp_q_depth =
aic7xxx_default_queue_depth;
} }
else else
{ {
...@@ -6666,7 +6715,8 @@ aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device) ...@@ -6666,7 +6715,8 @@ aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device)
} }
else if (aic7xxx_tag_info[p->instance].tag_commands[tindex] == 0) else if (aic7xxx_tag_info[p->instance].tag_commands[tindex] == 0)
{ {
aic_dev->max_q_depth = aic_dev->temp_q_depth = default_depth; aic_dev->max_q_depth = aic_dev->temp_q_depth =
aic7xxx_default_queue_depth;
} }
else else
{ {
...@@ -6674,17 +6724,27 @@ aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device) ...@@ -6674,17 +6724,27 @@ aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device)
aic7xxx_tag_info[p->instance].tag_commands[tindex]; aic7xxx_tag_info[p->instance].tag_commands[tindex];
} }
} }
}
}
if (tag_enabled) if (tag_enabled)
{ {
if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
{ {
printk(INFO_LEAD "Enabled tagged queuing, queue depth %d.\n", printk(INFO_LEAD "Tagged queuing enabled, queue depth %d.\n",
p->host_no, device->channel, device->id, p->host_no, device->channel, device->id,
device->lun, aic_dev->max_q_depth); device->lun, aic_dev->max_q_depth);
} }
scsi_adjust_queue_depth(device, MSG_ORDERED_TAG, aic_dev->max_q_depth); scsi_adjust_queue_depth(device, MSG_ORDERED_TAG, aic_dev->max_q_depth);
} }
else
{
if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
{
printk(INFO_LEAD "Tagged queuing disabled, queue depth %d.\n",
p->host_no, device->channel, device->id,
device->lun, device->host->cmd_per_lun);
} }
scsi_adjust_queue_depth(device, 0, device->host->cmd_per_lun);
} }
return; return;
} }
...@@ -6722,28 +6782,22 @@ aic7xxx_slave_attach(Scsi_Device *sdpnt) ...@@ -6722,28 +6782,22 @@ aic7xxx_slave_attach(Scsi_Device *sdpnt)
struct aic7xxx_host *p = (struct aic7xxx_host *) sdpnt->host->hostdata; struct aic7xxx_host *p = (struct aic7xxx_host *) sdpnt->host->hostdata;
struct aic_dev_data *aic_dev; struct aic_dev_data *aic_dev;
int scbnum; int scbnum;
struct list_head *list_ptr, *list_head;
if(!sdpnt->hostdata) {
sdpnt->hostdata = kmalloc(sizeof(struct aic_dev_data), GFP_ATOMIC);
if(!sdpnt->hostdata)
return 1;
memset(sdpnt->hostdata, 0, sizeof(struct aic_dev_data));
}
aic_dev = sdpnt->hostdata;
aic_dev->SDptr = sdpnt;
aic7xxx_init_aic_dev(p, aic_dev); aic_dev = (struct aic_dev_data *)sdpnt->hostdata;
list_add(&aic_dev->list, &p->aic_devs); if(!aic_dev) {
aic_dev = aic7xxx_alloc_aic_dev(p, sdpnt);
}
if(!aic_dev)
return 1;
aic7xxx_init_transinfo(p, aic_dev);
aic7xxx_device_queue_depth(p, sdpnt); aic7xxx_device_queue_depth(p, sdpnt);
if(list_empty(&aic_dev->list))
list_add_tail(&aic_dev->list, &p->aic_devs);
scbnum = 0; scbnum = 0;
list_head = &p->aic_devs; list_for_each_entry(aic_dev, &p->aic_devs, list) {
list_for_each(list_ptr, list_head) {
aic_dev = list_entry(list_ptr, struct aic_dev_data, list);
scbnum += aic_dev->max_q_depth; scbnum += aic_dev->max_q_depth;
} }
while (scbnum > p->scb_data->numscbs) while (scbnum > p->scb_data->numscbs)
...@@ -7878,6 +7932,7 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p, ...@@ -7878,6 +7932,7 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
p->completeq.tail = NULL; p->completeq.tail = NULL;
scbq_init(&p->scb_data->free_scbs); scbq_init(&p->scb_data->free_scbs);
scbq_init(&p->waiting_scbs); scbq_init(&p->waiting_scbs);
INIT_LIST_HEAD(&p->aic_devs);
/* /*
* We currently have no commands of any type * We currently have no commands of any type
...@@ -10117,30 +10172,6 @@ aic7xxx_detect(Scsi_Host_Template *template) ...@@ -10117,30 +10172,6 @@ aic7xxx_detect(Scsi_Host_Template *template)
return (found); return (found);
} }
#ifdef AIC7XXX_VERBOSE_DEBUGGING
/*+F*************************************************************************
* Function:
* aic7xxx_print_scb
*
* Description:
* Dump the byte codes for an about to be sent SCB.
*-F*************************************************************************/
static void
aic7xxx_print_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
{
int i;
unsigned char *x;
x = (unsigned char *)&scb->hscb->control;
for(i=0; i<32; i++)
{
printk("%02x ", x[i]);
}
printk("\n");
}
#endif
/*+F************************************************************************* /*+F*************************************************************************
* Function: * Function:
* aic7xxx_buildscb * aic7xxx_buildscb
...@@ -10157,6 +10188,7 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd, ...@@ -10157,6 +10188,7 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
struct aic_dev_data *aic_dev = cmd->device->hostdata; struct aic_dev_data *aic_dev = cmd->device->hostdata;
struct scsi_device *sdptr = cmd->device; struct scsi_device *sdptr = cmd->device;
unsigned char tindex = TARGET_INDEX(cmd); unsigned char tindex = TARGET_INDEX(cmd);
struct request *req = cmd->request;
mask = (0x01 << tindex); mask = (0x01 << tindex);
hscb = scb->hscb; hscb = scb->hscb;
...@@ -10171,16 +10203,17 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd, ...@@ -10171,16 +10203,17 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
if (p->discenable & mask) if (p->discenable & mask)
{ {
hscb->control |= DISCENB; hscb->control |= DISCENB;
if ( (sdptr->simple_tags) && /* We always force TEST_UNIT_READY to untagged */
(cmd->cmnd[0] != TEST_UNIT_READY) ) if (cmd->cmnd[0] != TEST_UNIT_READY && sdptr->simple_tags)
{
if (req->flags & REQ_BARRIER)
{ {
aic_dev->cmds_sent++; if(sdptr->ordered_tags)
if (aic_dev->cmds_sent >= 254 && sdptr->ordered_tags)
{ {
aic_dev->cmds_sent = 0;
hscb->control |= MSG_ORDERED_Q_TAG; hscb->control |= MSG_ORDERED_Q_TAG;
scb->tag_action = MSG_ORDERED_Q_TAG; scb->tag_action = MSG_ORDERED_Q_TAG;
} }
}
else else
{ {
hscb->control |= MSG_SIMPLE_Q_TAG; hscb->control |= MSG_SIMPLE_Q_TAG;
...@@ -10306,19 +10339,25 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *)) ...@@ -10306,19 +10339,25 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
struct aic7xxx_host *p; struct aic7xxx_host *p;
struct aic7xxx_scb *scb; struct aic7xxx_scb *scb;
struct aic_dev_data *aic_dev; struct aic_dev_data *aic_dev;
#ifdef AIC7XXX_VERBOSE_DEBUGGING
int tindex = TARGET_INDEX(cmd);
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
unsigned long cpu_flags = 0;
#endif
p = (struct aic7xxx_host *) cmd->host->hostdata; p = (struct aic7xxx_host *) cmd->host->hostdata;
aic_dev = cmd->device->hostdata;
if(!aic_dev) {
aic_dev = aic7xxx_alloc_aic_dev(p, cmd->device);
if(!aic_dev)
return 1;
}
else
{
aic_dev = AIC_DEV(cmd);
}
#ifdef AIC7XXX_VERBOSE_DEBUGGING
/* /*
* Check to see if channel was scanned. * Check to see if channel was scanned.
*/ */
#ifdef AIC7XXX_VERBOSE_DEBUGGING
if (!(p->flags & AHC_A_SCANNED) && (cmd->channel == 0)) if (!(p->flags & AHC_A_SCANNED) && (cmd->channel == 0))
{ {
if (aic7xxx_verbose & VERBOSE_PROBE2) if (aic7xxx_verbose & VERBOSE_PROBE2)
...@@ -10337,25 +10376,15 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *)) ...@@ -10337,25 +10376,15 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
} }
} }
if (p->dev_active_cmds[tindex] > (cmd->device->queue_depth + 1)) if (aic_dev->active_cmds > aic_dev->max_q_depth)
{ {
printk(WARN_LEAD "Commands queued exceeds queue " printk(WARN_LEAD "Commands queued exceeds queue "
"depth, active=%d\n", "depth, active=%d\n",
p->host_no, CTL_OF_CMD(cmd), p->host_no, CTL_OF_CMD(cmd),
p->dev_active_cmds[tindex]); aic_dev->active_cmds);
if ( p->dev_active_cmds[tindex] > 220 )
p->dev_active_cmds[tindex] = 0;
} }
#endif #endif
if(!cmd->device->hostdata) {
aic_dev = kmalloc(sizeof(struct aic_dev_data), GFP_ATOMIC);
if(!aic_dev)
return 1;
memset(aic_dev, 0, sizeof(struct aic_dev_data));
cmd->device->hostdata = aic_dev;
}
scb = scbq_remove_head(&p->scb_data->free_scbs); scb = scbq_remove_head(&p->scb_data->free_scbs);
if (scb == NULL) if (scb == NULL)
{ {
...@@ -10369,13 +10398,13 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *)) ...@@ -10369,13 +10398,13 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
} }
} }
scb->cmd = cmd; scb->cmd = cmd;
aic7xxx_position(cmd) = scb->hscb->tag;
/* /*
* Make sure the Scsi_Cmnd pointer is saved, the struct it points to * Make sure the Scsi_Cmnd pointer is saved, the struct it points to
* is set up properly, and the parity error flag is reset, then send * is set up properly, and the parity error flag is reset, then send
* the SCB to the sequencer and watch the fun begin. * the SCB to the sequencer and watch the fun begin.
*/ */
aic7xxx_position(cmd) = scb->hscb->tag;
cmd->scsi_done = fn; cmd->scsi_done = fn;
cmd->result = DID_OK; cmd->result = DID_OK;
memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer)); memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
...@@ -10392,10 +10421,7 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *)) ...@@ -10392,10 +10421,7 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
scb->flags |= SCB_ACTIVE | SCB_WAITINGQ; scb->flags |= SCB_ACTIVE | SCB_WAITINGQ;
scbq_insert_tail(&p->waiting_scbs, scb); scbq_insert_tail(&p->waiting_scbs, scb);
if ( (p->flags & (AHC_IN_ISR | AHC_IN_ABORT | AHC_IN_RESET)) == 0)
{
aic7xxx_run_waiting_queues(p); aic7xxx_run_waiting_queues(p);
}
return (0); return (0);
} }
...@@ -10410,21 +10436,40 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *)) ...@@ -10410,21 +10436,40 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
* aborted, then we will reset the channel and have all devices renegotiate. * aborted, then we will reset the channel and have all devices renegotiate.
* Returns an enumerated type that indicates the status of the operation. * Returns an enumerated type that indicates the status of the operation.
*-F*************************************************************************/ *-F*************************************************************************/
static int int
aic7xxx_bus_device_reset(struct aic7xxx_host *p, Scsi_Cmnd *cmd) aic7xxx_bus_device_reset(Scsi_Cmnd *cmd)
{ {
struct aic7xxx_host *p;
struct aic7xxx_scb *scb; struct aic7xxx_scb *scb;
struct aic7xxx_hwscb *hscb; struct aic7xxx_hwscb *hscb;
int result = -1;
int channel; int channel;
unsigned char saved_scbptr, lastphase; unsigned char saved_scbptr, lastphase;
unsigned char hscb_index; unsigned char hscb_index;
int disconnected; int disconnected;
struct aic_dev_data *aic_dev = AIC_DEV(cmd); struct aic_dev_data *aic_dev;
if(cmd == NULL)
{
printk(KERN_ERR "aic7xxx_bus_device_reset: called with NULL cmd!\n");
return FAILED;
}
p = (struct aic7xxx_host *)cmd->host->hostdata;
aic_dev = AIC_DEV(cmd);
if(aic7xxx_position(cmd) < p->scb_data->numscbs)
scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]); scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
else
return FAILED;
hscb = scb->hscb; hscb = scb->hscb;
aic7xxx_isr(p->irq, (void *)p, NULL);
aic7xxx_done_cmds_complete(p);
/* If the command was already complete or just completed, then we didn't
* do a reset, return FAILED */
if(!scb->flags & SCB_ACTIVE)
return FAILED;
pause_sequencer(p);
lastphase = aic_inb(p, LASTPHASE); lastphase = aic_inb(p, LASTPHASE);
if (aic7xxx_verbose & VERBOSE_RESET_PROCESS) if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
{ {
...@@ -10494,12 +10539,19 @@ aic7xxx_bus_device_reset(struct aic7xxx_host *p, Scsi_Cmnd *cmd) ...@@ -10494,12 +10539,19 @@ aic7xxx_bus_device_reset(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
printk(WARN_LEAD "Invalid SCB ID %d is active, " printk(WARN_LEAD "Invalid SCB ID %d is active, "
"SCB flags = 0x%x.\n", p->host_no, "SCB flags = 0x%x.\n", p->host_no,
CTL_OF_CMD(cmd), scb->hscb->tag, scb->flags); CTL_OF_CMD(cmd), scb->hscb->tag, scb->flags);
return(SCSI_RESET_ERROR); unpause_sequencer(p, FALSE);
return FAILED;
} }
if (scb->hscb->tag == aic_inb(p, SCB_TAG)) if (scb->hscb->tag == aic_inb(p, SCB_TAG))
{ {
if ( (lastphase != P_MESGOUT) && (lastphase != P_MESGIN) ) if ( (lastphase == P_MESGOUT) || (lastphase == P_MESGIN) )
{ {
printk(WARN_LEAD "Device reset, Message buffer "
"in use\n", p->host_no, CTL_OF_SCB(scb));
unpause_sequencer(p, FALSE);
return FAILED;
}
if (aic7xxx_verbose & VERBOSE_RESET_PROCESS) if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
printk(INFO_LEAD "Device reset message in " printk(INFO_LEAD "Device reset message in "
"message buffer\n", p->host_no, CTL_OF_SCB(scb)); "message buffer\n", p->host_no, CTL_OF_SCB(scb));
...@@ -10509,86 +10561,73 @@ aic7xxx_bus_device_reset(struct aic7xxx_host *p, Scsi_Cmnd *cmd) ...@@ -10509,86 +10561,73 @@ aic7xxx_bus_device_reset(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
/* Send the abort message to the active SCB. */ /* Send the abort message to the active SCB. */
aic_outb(p, HOST_MSG, MSG_OUT); aic_outb(p, HOST_MSG, MSG_OUT);
aic_outb(p, lastphase | ATNO, SCSISIGO); aic_outb(p, lastphase | ATNO, SCSISIGO);
return(SCSI_RESET_PENDING); unpause_sequencer(p, FALSE);
} spin_unlock_irq(p->host->host_lock);
scsi_sleep(HZ);
spin_lock_irq(p->host->host_lock);
if(aic_dev->flags & BUS_DEVICE_RESET_PENDING)
return FAILED;
else else
{ return SUCCESS;
/* We want to send out the message, but it could screw an already */
/* in place and being used message. Instead, we return an error */
/* to try and start the bus reset phase since this command is */
/* probably hung (aborts failed, and now reset is failing). We */
/* also make sure to set BUS_DEVICE_RESET_PENDING so we won't try */
/* any more on this device, but instead will escalate to a bus or */
/* host reset (additionally, we won't try to abort any more). */
printk(WARN_LEAD "Device reset, Message buffer "
"in use\n", p->host_no, CTL_OF_SCB(scb));
scb->flags |= SCB_RESET | SCB_DEVICE_RESET;
aic7xxx_error(cmd) = DID_RESET;
aic_dev->flags |= BUS_DEVICE_RESET_PENDING;
return(SCSI_RESET_ERROR);
}
} }
} /* if (last_phase != P_BUSFREE).....indicates we are idle and can work */ } /* if (last_phase != P_BUSFREE).....indicates we are idle and can work */
hscb_index = aic7xxx_find_scb(p, scb);
if (hscb_index == SCB_LIST_NULL)
{
disconnected = (aic7xxx_scb_on_qoutfifo(p, scb)) ? FALSE : TRUE;
}
else
{
aic_outb(p, hscb_index, SCBPTR);
if (aic_inb(p, SCB_CONTROL) & DISCONNECTED)
{
disconnected = TRUE;
}
}
if (disconnected)
{
/* /*
* Simply set the MK_MESSAGE flag and the SEQINT handler will do * Simply set the MK_MESSAGE flag and the SEQINT handler will do
* the rest on a reconnect. * the rest on a reconnect/connect.
*/ */
scb->hscb->control |= MK_MESSAGE; scb->hscb->control |= MK_MESSAGE;
scb->flags |= SCB_RESET | SCB_DEVICE_RESET; scb->flags |= SCB_RESET | SCB_DEVICE_RESET;
aic_dev->flags |= BUS_DEVICE_RESET_PENDING; aic_dev->flags |= BUS_DEVICE_RESET_PENDING;
if (hscb_index != SCB_LIST_NULL) /*
* Check to see if the command is on the qinfifo. If it is, then we will
* not need to queue the command again since the card should start it soon
*/
if (aic7xxx_search_qinfifo(p, cmd->channel, cmd->target, cmd->lun, hscb->tag,
0, TRUE, NULL) == 0)
{
disconnected = TRUE;
if ((hscb_index = aic7xxx_find_scb(p, scb)) != SCB_LIST_NULL)
{ {
unsigned char scb_control; unsigned char scb_control;
aic_outb(p, hscb_index, SCBPTR); aic_outb(p, hscb_index, SCBPTR);
scb_control = aic_inb(p, SCB_CONTROL); scb_control = aic_inb(p, SCB_CONTROL);
/*
* If the DISCONNECTED bit is not set in SCB_CONTROL, then we are
* actually on the waiting list, not disconnected, and we don't
* need to requeue the command.
*/
disconnected = (scb_control & DISCONNECTED);
aic_outb(p, scb_control | MK_MESSAGE, SCB_CONTROL); aic_outb(p, scb_control | MK_MESSAGE, SCB_CONTROL);
} }
if (disconnected)
{
/* /*
* Actually requeue this SCB in case we can select the * Actually requeue this SCB in case we can select the
* device before it reconnects. If the transaction we * device before it reconnects. This can result in the command
* want to abort is not tagged, then this will be the only * being on the qinfifo twice, but we don't care because it will
* outstanding command and we can simply shove it on the * all get cleaned up if/when the reset takes place.
* qoutfifo and be done. If it is tagged, then it goes right
* in with all the others, no problem :) We need to add it
* to the qinfifo and let the sequencer know it is there.
* Now, the only problem left to deal with is, *IF* this
* command completes, in spite of the MK_MESSAGE bit in the
* control byte, then we need to pick that up in the interrupt
* routine and clean things up. This *shouldn't* ever happen.
*/ */
if (aic7xxx_verbose & VERBOSE_RESET_PROCESS) if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
printk(INFO_LEAD "Queueing device reset " printk(INFO_LEAD "Queueing device reset command.\n", p->host_no,
"command.\n", p->host_no, CTL_OF_SCB(scb)); CTL_OF_SCB(scb));
p->qinfifo[p->qinfifonext++] = scb->hscb->tag; p->qinfifo[p->qinfifonext++] = scb->hscb->tag;
if (p->features & AHC_QUEUE_REGS) if (p->features & AHC_QUEUE_REGS)
aic_outb(p, p->qinfifonext, HNSCB_QOFF); aic_outb(p, p->qinfifonext, HNSCB_QOFF);
else else
aic_outb(p, p->qinfifonext, KERNEL_QINPOS); aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
scb->flags |= SCB_QUEUED_ABORT; scb->flags |= SCB_QUEUED_ABORT;
result = SCSI_RESET_PENDING;
} }
else if (result == -1)
{
result = SCSI_RESET_ERROR;
} }
aic_outb(p, saved_scbptr, SCBPTR); aic_outb(p, saved_scbptr, SCBPTR);
return (result); unpause_sequencer(p, FALSE);
spin_unlock_irq(p->host->host_lock);
scsi_sleep(HZ/4);
spin_lock_irq(p->host->host_lock);
if(aic_dev->flags & BUS_DEVICE_RESET_PENDING)
return FAILED;
else
return SUCCESS;
} }
...@@ -10630,12 +10669,30 @@ aic7xxx_abort(Scsi_Cmnd *cmd) ...@@ -10630,12 +10669,30 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
{ {
struct aic7xxx_scb *scb = NULL; struct aic7xxx_scb *scb = NULL;
struct aic7xxx_host *p; struct aic7xxx_host *p;
struct aic_dev_data *aic_dev = AIC_DEV(cmd); int found=0, disconnected;
int result, found=0; unsigned char saved_hscbptr, hscbptr, scb_control;
unsigned char tmp_char, saved_hscbptr, next_hscbptr, prev_hscbptr; struct aic_dev_data *aic_dev;
p = (struct aic7xxx_host *) cmd->host->hostdata; if(cmd == NULL)
{
printk(KERN_ERR "aic7xxx_abort: called with NULL cmd!\n");
return FAILED;
}
p = (struct aic7xxx_host *)cmd->host->hostdata;
aic_dev = AIC_DEV(cmd);
if(aic7xxx_position(cmd) < p->scb_data->numscbs)
scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]); scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
else
return FAILED;
aic7xxx_isr(p->irq, (void *)p, NULL);
aic7xxx_done_cmds_complete(p);
/* If the command was already complete or just completed, then we didn't
* do a reset, return FAILED */
if(!scb->flags & SCB_ACTIVE)
return FAILED;
pause_sequencer(p);
/* /*
* I added a new config option to the driver: "panic_on_abort" that will * I added a new config option to the driver: "panic_on_abort" that will
...@@ -10648,92 +10705,6 @@ aic7xxx_abort(Scsi_Cmnd *cmd) ...@@ -10648,92 +10705,6 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
if (aic7xxx_panic_on_abort) if (aic7xxx_panic_on_abort)
aic7xxx_panic_abort(p, cmd); aic7xxx_panic_abort(p, cmd);
/*
* Run the isr to grab any command in the QOUTFIFO and any other misc.
* assundry tasks. This should also set up the bh handler if there is
* anything to be done, but it won't run until we are done here since
* we are following a straight code path without entering the scheduler
* code.
*/
pause_sequencer(p);
while ( (aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR))
{
aic7xxx_isr(p->irq, p, (void *)NULL);
pause_sequencer(p);
}
aic7xxx_done_cmds_complete(p);
if (scb == NULL)
{
if (aic7xxx_verbose & VERBOSE_ABORT_MID)
printk(INFO_LEAD "Abort called with bogus Scsi_Cmnd "
"pointer.\n", p->host_no, CTL_OF_CMD(cmd));
unpause_sequencer(p, FALSE);
return(SCSI_ABORT_NOT_RUNNING);
}
if (scb->cmd != cmd) /* Hmmm...either this SCB is currently free with a */
{ /* NULL cmd pointer (NULLed out when freed) or it */
/* has already been recycled for another command */
/* Either way, this SCB has nothing to do with this*/
/* command and we need to deal with cmd without */
/* touching the SCB. */
/* The theory here is to return a value that will */
/* make the queued for complete command actually */
/* finish successfully, or to indicate that we */
/* don't have this cmd any more and the mid level */
/* code needs to find it. */
if (aic7xxx_verbose & VERBOSE_ABORT_MID)
printk(INFO_LEAD "Abort called for already completed"
" command.\n", p->host_no, CTL_OF_CMD(cmd));
unpause_sequencer(p, FALSE);
return(SCSI_ABORT_NOT_RUNNING);
}
/* At this point we know the following:
* the SCB pointer is valid
* the command pointer passed in to us and the scb->cmd pointer match
* this then means that the command we need to abort is the same as the
* command held by the scb pointer and is a valid abort request.
* Now, we just have to figure out what to do from here. Current plan is:
* if we have already been here on this command, escalate to a reset
* if scb is on waiting list or QINFIFO, send it back as aborted, but
* we also need to be aware of the possibility that we could be using
* a faked negotiation command that is holding this command up, if
* so we need to take care of that command instead, which means we
* would then treat this one like it was sitting around disconnected
* instead.
* if scb is on WAITING_SCB list in sequencer, free scb and send back
* if scb is disconnected and not completed, abort with abort message
* if scb is currently running, then it may be causing the bus to hang
* so we want a return value that indicates a reset would be appropriate
* if the command does not finish shortly
* if scb is already complete but not on completeq, we're screwed because
* this can't happen (except if the command is in the QOUTFIFO, in which
* case we would like it to complete successfully instead of having to
* to be re-done)
* All other scenarios already dealt with by previous code.
*/
if ( scb->flags & (SCB_ABORT | SCB_RESET | SCB_QUEUED_ABORT) )
{
if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
printk(INFO_LEAD "SCB aborted once already, "
"escalating.\n", p->host_no, CTL_OF_SCB(scb));
unpause_sequencer(p, FALSE);
return(SCSI_ABORT_SNOOZE);
}
if ( (p->flags & (AHC_RESET_PENDING | AHC_ABORT_PENDING)) ||
(aic_dev->flags & BUS_DEVICE_RESET_PENDING) )
{
if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
printk(INFO_LEAD "Reset/Abort pending for this "
"device, not wasting our time.\n", p->host_no, CTL_OF_SCB(scb));
unpause_sequencer(p, FALSE);
return(SCSI_ABORT_PENDING);
}
found = 0;
p->flags |= AHC_IN_ABORT;
if (aic7xxx_verbose & VERBOSE_ABORT) if (aic7xxx_verbose & VERBOSE_ABORT)
{ {
printk(INFO_LEAD "Aborting scb %d, flags 0x%x, SEQADDR 0x%x, LASTPHASE " printk(INFO_LEAD "Aborting scb %d, flags 0x%x, SEQADDR 0x%x, LASTPHASE "
...@@ -10750,56 +10721,8 @@ aic7xxx_abort(Scsi_Cmnd *cmd) ...@@ -10750,56 +10721,8 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
aic_inb(p, SSTAT1), aic_inb(p, SSTAT2)); aic_inb(p, SSTAT1), aic_inb(p, SSTAT2));
} }
/* if (scb->flags & SCB_WAITINGQ)
* First, let's check to see if the currently running command is our target
* since if it is, the return is fairly easy and quick since we don't want
* to touch the command in case it might complete, but we do want a timeout
* in case it's actually hung, so we really do nothing, but tell the mid
* level code to reset the timeout.
*/
if ( scb->hscb->tag == aic_inb(p, SCB_TAG) )
{ {
/*
* Check to see if the sequencer is just sitting on this command, or
* if it's actively being run.
*/
result = aic_inb(p, LASTPHASE);
switch (result)
{
case P_DATAOUT: /* For any of these cases, we can assume we are */
case P_DATAIN: /* an active command and act according. For */
case P_COMMAND: /* anything else we are going to fall on through*/
case P_STATUS: /* The SCSI_ABORT_SNOOZE will give us two abort */
case P_MESGOUT: /* chances to finish and then escalate to a */
case P_MESGIN: /* reset call */
if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
printk(INFO_LEAD "SCB is currently active. "
"Waiting on completion.\n", p->host_no, CTL_OF_SCB(scb));
printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 "
"0x%x\n", p->host_no, CTL_OF_SCB(scb),
aic_inb(p, SCSISIGI),
aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
aic_inb(p, SSTAT0), aic_inb(p, SSTAT1));
printk(INFO_LEAD "SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%x\n",
p->host_no, CTL_OF_SCB(scb),
(p->features & AHC_ULTRA2) ? aic_inb(p, SG_CACHEPTR) : 0,
aic_inb(p, SSTAT2), aic_inb(p, STCNT + 2) << 16 |
aic_inb(p, STCNT + 1) << 8 | aic_inb(p, STCNT));
unpause_sequencer(p, FALSE);
p->flags &= ~AHC_IN_ABORT;
scb->flags |= SCB_RECOVERY_SCB; /* Note the fact that we've been */
p->flags |= AHC_ABORT_PENDING; /* here so we will know not to */
return(SCSI_ABORT_PENDING); /* one doesn't complete and clear */
break; /* out. */
default:
break;
}
}
if ((found == 0) && (scb->flags & SCB_WAITINGQ))
{
if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
printk(INFO_LEAD "SCB found on waiting list and " printk(INFO_LEAD "SCB found on waiting list and "
"aborted.\n", p->host_no, CTL_OF_SCB(scb)); "aborted.\n", p->host_no, CTL_OF_SCB(scb));
...@@ -10809,95 +10732,123 @@ aic7xxx_abort(Scsi_Cmnd *cmd) ...@@ -10809,95 +10732,123 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
p->activescbs++; p->activescbs++;
scb->flags &= ~(SCB_WAITINGQ | SCB_ACTIVE); scb->flags &= ~(SCB_WAITINGQ | SCB_ACTIVE);
scb->flags |= SCB_ABORT | SCB_QUEUED_FOR_DONE; scb->flags |= SCB_ABORT | SCB_QUEUED_FOR_DONE;
found = 1; goto success;
} }
/* /*
* We just checked the waiting_q, now for the QINFIFO * We just checked the waiting_q, now for the QINFIFO
*/ */
if ( found == 0 ) if ( ((found = aic7xxx_search_qinfifo(p, cmd->target, cmd->channel,
{
if ( ((found = aic7xxx_search_qinfifo(p, cmd->target,
cmd->channel,
cmd->lun, scb->hscb->tag, SCB_ABORT | SCB_QUEUED_FOR_DONE, cmd->lun, scb->hscb->tag, SCB_ABORT | SCB_QUEUED_FOR_DONE,
FALSE, NULL)) != 0) && FALSE, NULL)) != 0) &&
(aic7xxx_verbose & VERBOSE_ABORT_PROCESS)) (aic7xxx_verbose & VERBOSE_ABORT_PROCESS))
printk(INFO_LEAD "SCB found in QINFIFO and " {
"aborted.\n", p->host_no, CTL_OF_SCB(scb)); printk(INFO_LEAD "SCB found in QINFIFO and aborted.\n", p->host_no,
CTL_OF_SCB(scb));
goto success;
} }
/* /*
* QINFIFO, waitingq, completeq done. Next, check WAITING_SCB list in card * QINFIFO, waitingq, completeq done. Next, check WAITING_SCB list in card
*/ */
if ( found == 0 )
{
unsigned char scb_next_ptr;
prev_hscbptr = SCB_LIST_NULL;
saved_hscbptr = aic_inb(p, SCBPTR); saved_hscbptr = aic_inb(p, SCBPTR);
next_hscbptr = aic_inb(p, WAITING_SCBH); if ((hscbptr = aic7xxx_find_scb(p, scb)) != SCB_LIST_NULL)
while ( next_hscbptr != SCB_LIST_NULL )
{
aic_outb(p, next_hscbptr, SCBPTR );
if ( scb->hscb->tag == aic_inb(p, SCB_TAG) )
{ {
found = 1; aic_outb(p, hscbptr, SCBPTR);
scb_control = aic_inb(p, SCB_CONTROL);
disconnected = scb_control & DISCONNECTED;
/*
* If the DISCONNECTED bit is not set in SCB_CONTROL, then we are
* either currently active or on the waiting list.
*/
if(!disconnected && aic_inb(p, LASTPHASE) == P_BUSFREE) {
if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
printk(INFO_LEAD "SCB found on hardware waiting" printk(INFO_LEAD "SCB found on hardware waiting"
" list and aborted.\n", p->host_no, CTL_OF_SCB(scb)); " list and aborted.\n", p->host_no, CTL_OF_SCB(scb));
if ( prev_hscbptr == SCB_LIST_NULL ) /* If we are the only waiting command, stop the selection engine */
if (aic_inb(p, WAITING_SCBH) == hscbptr && aic_inb(p, SCB_NEXT) ==
SCB_LIST_NULL)
{ {
aic_outb(p, aic_inb(p, SCB_NEXT), WAITING_SCBH);
/* stop the selection since we just
* grabbed the scb out from under the
* card
*/
aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ); aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ);
aic_outb(p, CLRSELTIMEO, CLRSINT1); aic_outb(p, CLRSELTIMEO, CLRSINT1);
aic_outb(p, SCB_LIST_NULL, WAITING_SCBH);
} }
else else
{ {
scb_next_ptr = aic_inb(p, SCB_NEXT); unsigned char prev, next;
aic_outb(p, prev_hscbptr, SCBPTR); prev = SCB_LIST_NULL;
aic_outb(p, scb_next_ptr, SCB_NEXT); next = aic_inb(p, WAITING_SCBH);
aic_outb(p, next_hscbptr, SCBPTR); while(next != SCB_LIST_NULL)
{
aic_outb(p, next, SCBPTR);
if (next == hscbptr)
{
next = aic_inb(p, SCB_NEXT);
if (prev != SCB_LIST_NULL)
{
aic_outb(p, prev, SCBPTR);
aic_outb(p, next, SCB_NEXT);
}
else
aic_outb(p, next, WAITING_SCBH);
aic_outb(p, hscbptr, SCBPTR);
next = SCB_LIST_NULL;
}
else
{
prev = next;
next = aic_inb(p, SCB_NEXT);
}
}
} }
aic_outb(p, SCB_LIST_NULL, SCB_TAG); aic_outb(p, SCB_LIST_NULL, SCB_TAG);
aic_outb(p, 0, SCB_CONTROL); aic_outb(p, 0, SCB_CONTROL);
aic7xxx_add_curscb_to_free_list(p); aic7xxx_add_curscb_to_free_list(p);
scb->flags = SCB_ABORT | SCB_QUEUED_FOR_DONE; scb->flags = SCB_ABORT | SCB_QUEUED_FOR_DONE;
break; goto success;
}
else if (!disconnected)
{
/*
* We are the currently active command
*/
if((aic_inb(p, LASTPHASE) == P_MESGIN) ||
(aic_inb(p, LASTPHASE) == P_MESGOUT))
{
/*
* Message buffer busy, unable to abort
*/
printk(INFO_LEAD "message buffer busy, unable to abort.\n",
p->host_no, CTL_OF_SCB(scb));
unpause_sequencer(p, FALSE);
return FAILED;
}
/* Fallthrough to below, set ATNO after we set SCB_CONTROL */
} }
prev_hscbptr = next_hscbptr; aic_outb(p, scb_control | MK_MESSAGE, SCB_CONTROL);
next_hscbptr = aic_inb(p, SCB_NEXT); if(!disconnected)
{
aic_outb(p, HOST_MSG, MSG_OUT);
aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO);
} }
aic_outb(p, saved_hscbptr, SCBPTR ); aic_outb(p, saved_hscbptr, SCBPTR);
} }
else
/* {
* Hmmm...completeq, QOUTFIFO, QINFIFO, WAITING_SCBH, waitingq all checked. /*
* OK...the sequencer's paused, interrupts are off, and we haven't found the * The scb isn't in the card at all and it is active and it isn't in
* command anyplace where it could be easily aborted. Time for the hard * any of the queues, so it must be disconnected and paged out. Fall
* work. We also know the command is valid. This essentially means the * through to the code below.
* command is disconnected, or connected but not into any phases yet, which
* we know due to the tests we ran earlier on the current active scb phase.
* At this point we can queue the abort tag and go on with life.
*/ */
disconnected = 1;
}
if ( found == 0 )
{
p->flags |= AHC_ABORT_PENDING; p->flags |= AHC_ABORT_PENDING;
scb->flags |= SCB_QUEUED_ABORT | SCB_ABORT | SCB_RECOVERY_SCB; scb->flags |= SCB_QUEUED_ABORT | SCB_ABORT | SCB_RECOVERY_SCB;
scb->hscb->control |= MK_MESSAGE; scb->hscb->control |= MK_MESSAGE;
result=aic7xxx_find_scb(p, scb); if(disconnected)
if ( result != SCB_LIST_NULL )
{ {
saved_hscbptr = aic_inb(p, SCBPTR);
aic_outb(p, result, SCBPTR);
tmp_char = aic_inb(p, SCB_CONTROL);
aic_outb(p, tmp_char | MK_MESSAGE, SCB_CONTROL);
aic_outb(p, saved_hscbptr, SCBPTR);
}
if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
printk(INFO_LEAD "SCB disconnected. Queueing Abort" printk(INFO_LEAD "SCB disconnected. Queueing Abort"
" SCB.\n", p->host_no, CTL_OF_SCB(scb)); " SCB.\n", p->host_no, CTL_OF_SCB(scb));
...@@ -10907,31 +10858,30 @@ aic7xxx_abort(Scsi_Cmnd *cmd) ...@@ -10907,31 +10858,30 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
else else
aic_outb(p, p->qinfifonext, KERNEL_QINPOS); aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
} }
if (found) unpause_sequencer(p, FALSE);
spin_unlock_irq(p->host->host_lock);
scsi_sleep(HZ/4);
spin_lock_irq(p->host->host_lock);
if (p->flags & AHC_ABORT_PENDING)
{ {
aic7xxx_run_done_queue(p, TRUE); if (aic7xxx_verbose & VERBOSE_ABORT_RETURN)
aic7xxx_run_waiting_queues(p); printk(INFO_LEAD "Abort never delivered, returning FAILED\n", p->host_no,
CTL_OF_CMD(cmd));
p->flags &= ~AHC_ABORT_PENDING;
return FAILED;
} }
p->flags &= ~AHC_IN_ABORT; if (aic7xxx_verbose & VERBOSE_ABORT_RETURN)
unpause_sequencer(p, FALSE); printk(INFO_LEAD "Abort successful.\n", p->host_no, CTL_OF_CMD(cmd));
return SUCCESS;
/* success:
* On the return value. If we found the command and aborted it, then we know if (aic7xxx_verbose & VERBOSE_ABORT_RETURN)
* it's already sent back and there is no reason for a further timeout, so printk(INFO_LEAD "Abort successful.\n", p->host_no, CTL_OF_CMD(cmd));
* we use SCSI_ABORT_SUCCESS. On the queued abort side, we aren't so certain aic7xxx_run_done_queue(p, TRUE);
* there hasn't been a bus hang or something that might keep the abort from unpause_sequencer(p, FALSE);
* from completing. Therefore, we use SCSI_ABORT_PENDING. The first time this return SUCCESS;
* is passed back, the timeout on the command gets extended, the second time
* we pass this back, the mid level SCSI code calls our reset function, which
* would shake loose a hung bus.
*/
if ( found != 0 )
return(SCSI_ABORT_SUCCESS);
else
return(SCSI_ABORT_PENDING);
} }
/*+F************************************************************************* /*+F*************************************************************************
* Function: * Function:
* aic7xxx_reset * aic7xxx_reset
...@@ -10943,38 +10893,24 @@ aic7xxx_abort(Scsi_Cmnd *cmd) ...@@ -10943,38 +10893,24 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
* the SCSI bus reset line. * the SCSI bus reset line.
*-F*************************************************************************/ *-F*************************************************************************/
int int
aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags) aic7xxx_reset(Scsi_Cmnd *cmd)
{ {
struct aic7xxx_scb *scb = NULL; struct aic7xxx_scb *scb;
struct aic7xxx_host *p; struct aic7xxx_host *p;
struct aic_dev_data *aic_dev; struct aic_dev_data *aic_dev;
int tindex;
int result = -1;
#define DEVICE_RESET 0x01
#define BUS_RESET 0x02
#define HOST_RESET 0x04
#define RESET_DELAY 0x08
int action;
if ( cmd == NULL )
{
printk(KERN_WARNING "(scsi?:?:?:?) Reset called with NULL Scsi_Cmnd "
"pointer, failing.\n");
return(SCSI_RESET_SNOOZE);
}
p = (struct aic7xxx_host *) cmd->host->hostdata; p = (struct aic7xxx_host *) cmd->host->hostdata;
aic_dev = AIC_DEV(cmd); aic_dev = AIC_DEV(cmd);
if(aic_dev) if(aic7xxx_position(cmd) < p->scb_data->numscbs)
{ {
scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]); scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
if (scb->cmd != cmd)
scb = NULL;
} }
else else
{ {
scb = NULL; scb = NULL;
} }
tindex = TARGET_INDEX(cmd);
/* /*
* I added a new config option to the driver: "panic_on_abort" that will * I added a new config option to the driver: "panic_on_abort" that will
...@@ -10989,44 +10925,6 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags) ...@@ -10989,44 +10925,6 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
pause_sequencer(p); pause_sequencer(p);
if(flags & SCSI_RESET_SYNCHRONOUS)
{
if (aic7xxx_verbose & VERBOSE_RESET_MID)
printk(INFO_LEAD "Reset called for a SYNCHRONOUS reset, flags 0x%x, "
"cmd->result 0x%x.\n", p->host_no, CTL_OF_CMD(cmd), flags,
cmd->result);
scb = NULL;
action = HOST_RESET;
}
else if ((scb == NULL) || (scb->cmd != cmd))
{
if (aic7xxx_verbose & VERBOSE_RESET_MID)
printk(INFO_LEAD "Reset called with bogus Scsi_Cmnd"
"->SCB mapping, failing.\n", p->host_no, CTL_OF_CMD(cmd));
aic7xxx_done_cmds_complete(p);
aic7xxx_run_waiting_queues(p);
unpause_sequencer(p, FALSE);
return(SCSI_RESET_NOT_RUNNING);
}
else
{
if (aic7xxx_verbose & VERBOSE_RESET_MID)
printk(INFO_LEAD "Reset called, scb %d, flags "
"0x%x\n", p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags);
if ( flags & SCSI_RESET_SUGGEST_HOST_RESET )
{
action = HOST_RESET;
}
else if ( flags & SCSI_RESET_SUGGEST_BUS_RESET )
{
action = BUS_RESET;
}
else
{
action = DEVICE_RESET;
}
}
while((aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR)) while((aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR))
{ {
aic7xxx_isr(p->irq, p, (void *)NULL ); aic7xxx_isr(p->irq, p, (void *)NULL );
...@@ -11040,134 +10938,32 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags) ...@@ -11040,134 +10938,32 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
* We just completed the command when we ran the isr stuff, so we no * We just completed the command when we ran the isr stuff, so we no
* longer have it. * longer have it.
*/ */
aic7xxx_run_waiting_queues(p);
unpause_sequencer(p, FALSE); unpause_sequencer(p, FALSE);
return(SCSI_RESET_SUCCESS); return SUCCESS;
} }
if ( (action & DEVICE_RESET) &&
(aic_dev->flags & BUS_DEVICE_RESET_PENDING) )
{
if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
printk(INFO_LEAD "Bus device reset already sent to "
"device, escalating.\n", p->host_no, CTL_OF_CMD(cmd));
action = BUS_RESET;
}
if ( (action & DEVICE_RESET) &&
(scb->flags & SCB_QUEUED_ABORT) )
{
if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
{
printk(INFO_LEAD "Have already attempted to reach "
"device with queued\n", p->host_no, CTL_OF_CMD(cmd));
printk(INFO_LEAD "message, will escalate to bus "
"reset.\n", p->host_no, CTL_OF_CMD(cmd));
}
action = BUS_RESET;
}
if ( (action & DEVICE_RESET) &&
(p->flags & (AHC_RESET_PENDING | AHC_ABORT_PENDING)) )
{
if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
printk(INFO_LEAD "Bus device reset stupid when "
"other action has failed.\n", p->host_no, CTL_OF_CMD(cmd));
action = BUS_RESET;
}
if ( (action & BUS_RESET) && !(p->features & AHC_TWIN) )
{
action = HOST_RESET;
}
if ( (aic_dev->flags & DEVICE_RESET_DELAY) &&
!(action & (HOST_RESET | BUS_RESET)))
{
if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
{
printk(INFO_LEAD "Reset called too soon after last "
"reset without requesting\n", p->host_no, CTL_OF_CMD(cmd));
printk(INFO_LEAD "bus or host reset, escalating.\n", p->host_no,
CTL_OF_CMD(cmd));
}
action = BUS_RESET;
}
if ( (p->flags & AHC_RESET_DELAY) &&
(action & (HOST_RESET | BUS_RESET)) )
{
if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
printk(INFO_LEAD "Reset called too soon after "
"last bus reset, delaying.\n", p->host_no, CTL_OF_CMD(cmd));
action = RESET_DELAY;
}
/* /*
* By this point, we want to already know what we are going to do and * By this point, we want to already know what we are going to do and
* only have the following code implement our course of action. * only have the following code implement our course of action.
*/ */
switch (action)
{
case RESET_DELAY:
aic7xxx_run_waiting_queues(p);
unpause_sequencer(p, FALSE);
if(scb == NULL)
return(SCSI_RESET_PUNT);
else
return(SCSI_RESET_PENDING);
break;
case DEVICE_RESET:
p->flags |= AHC_IN_RESET;
result = aic7xxx_bus_device_reset(p, cmd);
aic7xxx_run_done_queue(p, TRUE);
/* We can't rely on run_waiting_queues to unpause the sequencer for
* PCI based controllers since we use AAP */
aic7xxx_run_waiting_queues(p);
unpause_sequencer(p, FALSE);
p->flags &= ~AHC_IN_RESET;
return(result);
break;
case BUS_RESET:
case HOST_RESET:
default:
p->flags |= AHC_IN_RESET | AHC_RESET_DELAY;
aic7xxx_reset_channel(p, cmd->channel, TRUE); aic7xxx_reset_channel(p, cmd->channel, TRUE);
if ( (p->features & AHC_TWIN) && (action & HOST_RESET) ) if (p->features & AHC_TWIN)
{ {
aic7xxx_reset_channel(p, cmd->channel ^ 0x01, TRUE); aic7xxx_reset_channel(p, cmd->channel ^ 0x01, TRUE);
restart_sequencer(p); restart_sequencer(p);
} }
if (action != HOST_RESET) aic_outb(p, aic_inb(p, SIMODE1) & ~(ENREQINIT|ENBUSFREE), SIMODE1);
result = SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET;
else
{
result = SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET;
aic_outb(p, aic_inb(p, SIMODE1) & ~(ENREQINIT|ENBUSFREE),
SIMODE1);
aic7xxx_clear_intstat(p); aic7xxx_clear_intstat(p);
p->flags &= ~AHC_HANDLING_REQINITS; p->flags &= ~AHC_HANDLING_REQINITS;
p->msg_type = MSG_TYPE_NONE; p->msg_type = MSG_TYPE_NONE;
p->msg_index = 0; p->msg_index = 0;
p->msg_len = 0; p->msg_len = 0;
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
if(flags & SCSI_RESET_SYNCHRONOUS)
{
cmd->result = DID_RESET << 16;
cmd->done(cmd);
}
#endif
aic7xxx_run_done_queue(p, TRUE); aic7xxx_run_done_queue(p, TRUE);
p->flags &= ~AHC_IN_RESET;
/*
* We can't rely on run_waiting_queues to unpause the sequencer for
* PCI based controllers since we use AAP. NOTE: this also sets
* the timer for the one command we might have queued in the case
* of a synch reset.
*/
aic7xxx_run_waiting_queues(p);
unpause_sequencer(p, FALSE); unpause_sequencer(p, FALSE);
if(scb == NULL) spin_unlock_irq(p->host->host_lock);
return(SCSI_RESET_SUCCESS|SCSI_RESET_HOST_RESET); scsi_sleep(2 * HZ);
else spin_lock_irq(p->host->host_lock);
return(result); return SUCCESS;
break;
}
} }
/*+F************************************************************************* /*+F*************************************************************************
......
...@@ -38,6 +38,9 @@ ...@@ -38,6 +38,9 @@
slave_attach: aic7xxx_slave_attach, \ slave_attach: aic7xxx_slave_attach, \
slave_detach: aic7xxx_slave_detach, \ slave_detach: aic7xxx_slave_detach, \
bios_param: aic7xxx_biosparam, \ bios_param: aic7xxx_biosparam, \
eh_abort_handler: aic7xxx_abort, \
eh_device_reset_handler: aic7xxx_bus_device_reset, \
eh_host_reset_handler: aic7xxx_reset, \
can_queue: 255, /* max simultaneous cmds */\ can_queue: 255, /* max simultaneous cmds */\
this_id: -1, /* scsi id of host adapter */\ this_id: -1, /* scsi id of host adapter */\
sg_tablesize: 0, /* max scatter-gather cmds */\ sg_tablesize: 0, /* max scatter-gather cmds */\
...@@ -55,6 +58,9 @@ extern int aic7xxx_command(Scsi_Cmnd *); ...@@ -55,6 +58,9 @@ extern int aic7xxx_command(Scsi_Cmnd *);
extern int aic7xxx_release(struct Scsi_Host *); extern int aic7xxx_release(struct Scsi_Host *);
extern int aic7xxx_slave_attach(Scsi_Device *); extern int aic7xxx_slave_attach(Scsi_Device *);
extern void aic7xxx_slave_detach(Scsi_Device *); extern void aic7xxx_slave_detach(Scsi_Device *);
extern int aic7xxx_abort(Scsi_Cmnd *);
extern int aic7xxx_bus_device_reset(Scsi_Cmnd *);
extern int aic7xxx_reset(Scsi_Cmnd *);
extern const char *aic7xxx_info(struct Scsi_Host *); extern const char *aic7xxx_info(struct Scsi_Host *);
......
...@@ -90,7 +90,6 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length, ...@@ -90,7 +90,6 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
int size = 0; int size = 0;
unsigned char i; unsigned char i;
unsigned char tindex; unsigned char tindex;
struct list_head *list_item;
HBAptr = NULL; HBAptr = NULL;
...@@ -132,10 +131,8 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length, ...@@ -132,10 +131,8 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
*/ */
size = 4096; size = 4096;
list_for_each(list_item, &p->aic_devs) list_for_each_entry(aic_dev, &p->aic_devs, list)
{
size += 512; size += 512;
}
if (aic7xxx_buffer_size != size) if (aic7xxx_buffer_size != size)
{ {
if (aic7xxx_buffer != NULL) if (aic7xxx_buffer != NULL)
...@@ -157,13 +154,6 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length, ...@@ -157,13 +154,6 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
size += sprintf(BLS, "Adaptec AIC7xxx driver version: "); size += sprintf(BLS, "Adaptec AIC7xxx driver version: ");
size += sprintf(BLS, "%s/", AIC7XXX_C_VERSION); size += sprintf(BLS, "%s/", AIC7XXX_C_VERSION);
size += sprintf(BLS, "%s", AIC7XXX_H_VERSION); size += sprintf(BLS, "%s", AIC7XXX_H_VERSION);
size += sprintf(BLS, "\n");
size += sprintf(BLS, "Compile Options:\n");
#ifdef CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT
size += sprintf(BLS, " TCQ Enabled By Default : Enabled\n");
#else
size += sprintf(BLS, " TCQ Enabled By Default : Disabled\n");
#endif
size += sprintf(BLS, "\n"); size += sprintf(BLS, "\n");
size += sprintf(BLS, "Adapter Configuration:\n"); size += sprintf(BLS, "Adapter Configuration:\n");
size += sprintf(BLS, " SCSI Adapter: %s\n", size += sprintf(BLS, " SCSI Adapter: %s\n",
...@@ -263,7 +253,7 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length, ...@@ -263,7 +253,7 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
{ {
size += sprintf(BLS, " Ultra Enable Flags: 0x%04x\n", p->ultraenb); size += sprintf(BLS, " Ultra Enable Flags: 0x%04x\n", p->ultraenb);
} }
size += sprintf(BLS, "Default Tag Queue Depth: %d\n", AIC7XXX_CMDS_PER_DEVICE); size += sprintf(BLS, "Default Tag Queue Depth: %d\n", aic7xxx_default_queue_depth);
size += sprintf(BLS, " Tagged Queue By Device array for aic7xxx host " size += sprintf(BLS, " Tagged Queue By Device array for aic7xxx host "
"instance %d:\n", p->instance); "instance %d:\n", p->instance);
size += sprintf(BLS, " {"); size += sprintf(BLS, " {");
...@@ -273,9 +263,8 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length, ...@@ -273,9 +263,8 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
size += sprintf(BLS, "\n"); size += sprintf(BLS, "\n");
size += sprintf(BLS, "Statistics:\n\n"); size += sprintf(BLS, "Statistics:\n\n");
list_for_each(list_item, &p->aic_devs) list_for_each_entry(aic_dev, &p->aic_devs, list)
{ {
aic_dev = list_entry(list_item, struct aic_dev_data, list);
sdptr = aic_dev->SDptr; sdptr = aic_dev->SDptr;
tindex = sdptr->channel << 3 | sdptr->id; tindex = sdptr->channel << 3 | sdptr->id;
size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n", size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n",
...@@ -322,24 +311,32 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length, ...@@ -322,24 +311,32 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
p->user[tindex].offset, p->user[tindex].offset,
p->user[tindex].width, p->user[tindex].width,
p->user[tindex].options); p->user[tindex].options);
size += sprintf(BLS, " Total transfers %ld (%ld reads and %ld writes)\n", if(sdptr->simple_tags)
aic_dev->r_total + aic_dev->w_total, aic_dev->r_total, aic_dev->w_total); {
size += sprintf(BLS, " Tagged Command Queueing Enabled, Ordered Tags %s\n", sdptr->ordered_tags ? "Enabled" : "Disabled");
}
if(aic_dev->barrier_total)
size += sprintf(BLS, " Total transfers %ld:\n (%ld/%ld/%ld/%ld reads/writes/REQ_BARRIER/Ordered Tags)\n",
aic_dev->r_total+aic_dev->w_total, aic_dev->r_total, aic_dev->w_total,
aic_dev->barrier_total, aic_dev->ordered_total);
else
size += sprintf(BLS, " Total transfers %ld:\n (%ld/%ld reads/writes)\n",
aic_dev->r_total+aic_dev->w_total, aic_dev->r_total, aic_dev->w_total);
size += sprintf(BLS, "%s\n", HDRB); size += sprintf(BLS, "%s\n", HDRB);
size += sprintf(BLS, " Reads:"); size += sprintf(BLS, " Reads:");
for (i = 0; i < NUMBER(aic_dev->r_bins); i++) for (i = 0; i < NUMBER(aic_dev->r_bins); i++)
{ {
size += sprintf(BLS, " %7ld", aic_dev->r_bins[i]); size += sprintf(BLS, " %10ld", aic_dev->r_bins[i]);
} }
size += sprintf(BLS, "\n"); size += sprintf(BLS, "\n");
size += sprintf(BLS, " Writes:"); size += sprintf(BLS, " Writes:");
for (i = 0; i < NUMBER(aic_dev->w_bins); i++) for (i = 0; i < NUMBER(aic_dev->w_bins); i++)
{ {
size += sprintf(BLS, " %7ld", aic_dev->w_bins[i]); size += sprintf(BLS, " %10ld", aic_dev->w_bins[i]);
} }
size += sprintf(BLS, "\n"); size += sprintf(BLS, "\n");
size += sprintf(BLS, "\n\n"); size += sprintf(BLS, "\n\n");
} }
if (size >= aic7xxx_buffer_size) if (size >= aic7xxx_buffer_size)
{ {
printk(KERN_WARNING "aic7xxx: Overflow in aic7xxx_proc.c\n"); printk(KERN_WARNING "aic7xxx: Overflow in aic7xxx_proc.c\n");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment