Commit 62420867 authored by James Bottomley's avatar James Bottomley

Merge mulgrave.(none):/home/jejb/BK/53c700-new-tag-2.5

into mulgrave.(none):/home/jejb/BK/scsi-for-linus-2.5
parents 978c6cc5 88261001
...@@ -283,6 +283,7 @@ NCR_700_detect(Scsi_Host_Template *tpnt, ...@@ -283,6 +283,7 @@ NCR_700_detect(Scsi_Host_Template *tpnt,
tpnt->cmd_per_lun = NCR_700_MAX_TAGS; tpnt->cmd_per_lun = NCR_700_MAX_TAGS;
tpnt->use_clustering = DISABLE_CLUSTERING; tpnt->use_clustering = DISABLE_CLUSTERING;
tpnt->proc_info = NCR_700_proc_directory_info; tpnt->proc_info = NCR_700_proc_directory_info;
tpnt->use_blk_tcq = 1;
if(tpnt->name == NULL) if(tpnt->name == NULL)
tpnt->name = "53c700"; tpnt->name = "53c700";
...@@ -498,46 +499,12 @@ STATIC void ...@@ -498,46 +499,12 @@ STATIC void
free_slot(struct NCR_700_command_slot *slot, free_slot(struct NCR_700_command_slot *slot,
struct NCR_700_Host_Parameters *hostdata) struct NCR_700_Host_Parameters *hostdata)
{ {
int hash;
struct NCR_700_command_slot **forw, **back;
if((slot->state & NCR_700_SLOT_MASK) != NCR_700_SLOT_MAGIC) { if((slot->state & NCR_700_SLOT_MASK) != NCR_700_SLOT_MAGIC) {
printk(KERN_ERR "53c700: SLOT %p is not MAGIC!!!\n", slot); printk(KERN_ERR "53c700: SLOT %p is not MAGIC!!!\n", slot);
} }
if(slot->state == NCR_700_SLOT_FREE) { if(slot->state == NCR_700_SLOT_FREE) {
printk(KERN_ERR "53c700: SLOT %p is FREE!!!\n", slot); printk(KERN_ERR "53c700: SLOT %p is FREE!!!\n", slot);
} }
/* remove from queues */
if(slot->tag != NCR_700_NO_TAG) {
hash = hash_ITLQ(slot->cmnd->target, slot->cmnd->lun,
slot->tag);
if(slot->ITLQ_forw == NULL)
back = &hostdata->ITLQ_Hash_back[hash];
else
back = &slot->ITLQ_forw->ITLQ_back;
if(slot->ITLQ_back == NULL)
forw = &hostdata->ITLQ_Hash_forw[hash];
else
forw = &slot->ITLQ_back->ITLQ_forw;
*forw = slot->ITLQ_forw;
*back = slot->ITLQ_back;
}
hash = hash_ITL(slot->cmnd->target, slot->cmnd->lun);
if(slot->ITL_forw == NULL)
back = &hostdata->ITL_Hash_back[hash];
else
back = &slot->ITL_forw->ITL_back;
if(slot->ITL_back == NULL)
forw = &hostdata->ITL_Hash_forw[hash];
else
forw = &slot->ITL_back->ITL_forw;
*forw = slot->ITL_forw;
*back = slot->ITL_back;
slot->resume_offset = 0; slot->resume_offset = 0;
slot->cmnd = NULL; slot->cmnd = NULL;
...@@ -565,48 +532,6 @@ save_for_reselection(struct NCR_700_Host_Parameters *hostdata, ...@@ -565,48 +532,6 @@ save_for_reselection(struct NCR_700_Host_Parameters *hostdata,
hostdata->cmd = NULL; hostdata->cmd = NULL;
} }
/* Most likely nexus is the oldest in each case */
STATIC inline struct NCR_700_command_slot *
find_ITL_Nexus(struct NCR_700_Host_Parameters *hostdata, __u8 pun, __u8 lun)
{
int hash = hash_ITL(pun, lun);
struct NCR_700_command_slot *slot = hostdata->ITL_Hash_back[hash];
while(slot != NULL && !(slot->cmnd->target == pun &&
slot->cmnd->lun == lun))
slot = slot->ITL_back;
return slot;
}
STATIC inline struct NCR_700_command_slot *
find_ITLQ_Nexus(struct NCR_700_Host_Parameters *hostdata, __u8 pun,
__u8 lun, __u8 tag)
{
int hash = hash_ITLQ(pun, lun, tag);
struct NCR_700_command_slot *slot = hostdata->ITLQ_Hash_back[hash];
while(slot != NULL && !(slot->cmnd->target == pun
&& slot->cmnd->lun == lun && slot->tag == tag))
slot = slot->ITLQ_back;
#ifdef NCR_700_TAG_DEBUG
if(slot != NULL) {
struct NCR_700_command_slot *n = slot->ITLQ_back;
while(n != NULL && n->cmnd->target != pun
&& n->cmnd->lun != lun && n->tag != tag)
n = n->ITLQ_back;
if(n != NULL && n->cmnd->target == pun && n->cmnd->lun == lun
&& n->tag == tag) {
printk(KERN_WARNING "53c700: WARNING: DUPLICATE tag %d\n",
tag);
}
}
#endif
return slot;
}
/* This translates the SDTR message offset and period to a value /* This translates the SDTR message offset and period to a value
* which can be loaded into the SXFER_REG. * which can be loaded into the SXFER_REG.
* *
...@@ -696,7 +621,6 @@ NCR_700_scsi_done(struct NCR_700_Host_Parameters *hostdata, ...@@ -696,7 +621,6 @@ NCR_700_scsi_done(struct NCR_700_Host_Parameters *hostdata,
SCp->underflow = SCp->old_underflow; SCp->underflow = SCp->old_underflow;
} }
free_slot(slot, hostdata); free_slot(slot, hostdata);
#ifdef NCR_700_DEBUG #ifdef NCR_700_DEBUG
if(NCR_700_get_depth(SCp->device) == 0 || if(NCR_700_get_depth(SCp->device) == 0 ||
...@@ -1147,6 +1071,7 @@ process_script_interrupt(__u32 dsps, __u32 dsp, Scsi_Cmnd *SCp, ...@@ -1147,6 +1071,7 @@ process_script_interrupt(__u32 dsps, __u32 dsp, Scsi_Cmnd *SCp,
__u8 lun; __u8 lun;
struct NCR_700_command_slot *slot; struct NCR_700_command_slot *slot;
__u8 reselection_id = hostdata->reselection_id; __u8 reselection_id = hostdata->reselection_id;
Scsi_Device *SDp;
lun = hostdata->msgin[0] & 0x1f; lun = hostdata->msgin[0] & 0x1f;
...@@ -1154,34 +1079,39 @@ process_script_interrupt(__u32 dsps, __u32 dsp, Scsi_Cmnd *SCp, ...@@ -1154,34 +1079,39 @@ process_script_interrupt(__u32 dsps, __u32 dsp, Scsi_Cmnd *SCp,
DEBUG(("scsi%d: (%d:%d) RESELECTED!\n", DEBUG(("scsi%d: (%d:%d) RESELECTED!\n",
host->host_no, reselection_id, lun)); host->host_no, reselection_id, lun));
/* clear the reselection indicator */ /* clear the reselection indicator */
SDp = scsi_find_device(host, 0, reselection_id, lun);
if(unlikely(SDp == NULL)) {
printk(KERN_ERR "scsi%d: (%d:%d) HAS NO device\n",
host->host_no, reselection_id, lun);
BUG();
}
if(hostdata->msgin[1] == A_SIMPLE_TAG_MSG) { if(hostdata->msgin[1] == A_SIMPLE_TAG_MSG) {
slot = find_ITLQ_Nexus(hostdata, reselection_id, Scsi_Cmnd *SCp = scsi_find_tag(SDp, hostdata->msgin[2]);
lun, hostdata->msgin[2]); if(unlikely(SCp == NULL)) {
printk(KERN_ERR "scsi%d: (%d:%d) no saved request for tag %d\n",
host->host_no, reselection_id, lun, hostdata->msgin[2]);
BUG();
}
slot = (struct NCR_700_command_slot *)SCp->host_scribble;
DEBUG(("53c700: %d:%d:%d, reselection is tag %d, slot %p(%d)\n",
host->host_no, SDp->id, SDp->lun,
hostdata->msgin[2], slot, slot->tag));
} else { } else {
slot = find_ITL_Nexus(hostdata, reselection_id, lun); Scsi_Cmnd *SCp = scsi_find_tag(SDp, SCSI_NO_TAG);
if(unlikely(SCp == NULL)) {
printk(KERN_ERR "scsi%d: (%d:%d) no saved request for untagged cmd\n",
host->host_no, reselection_id, lun);
BUG();
}
slot = (struct NCR_700_command_slot *)SCp->host_scribble;
} }
retry:
if(slot == NULL) { if(slot == NULL) {
struct NCR_700_command_slot *s = find_ITL_Nexus(hostdata, reselection_id, lun);
printk(KERN_ERR "scsi%d: (%d:%d) RESELECTED but no saved command (MSG = %02x %02x %02x)!!\n", printk(KERN_ERR "scsi%d: (%d:%d) RESELECTED but no saved command (MSG = %02x %02x %02x)!!\n",
host->host_no, reselection_id, lun, host->host_no, reselection_id, lun,
hostdata->msgin[0], hostdata->msgin[1], hostdata->msgin[0], hostdata->msgin[1],
hostdata->msgin[2]); hostdata->msgin[2]);
printk(KERN_ERR " OUTSTANDING TAGS:");
while(s != NULL) {
if(s->cmnd->target == reselection_id &&
s->cmnd->lun == lun) {
printk("%d ", s->tag);
if(s->tag == hostdata->msgin[2]) {
printk(" ***FOUND*** \n");
slot = s;
goto retry;
}
}
s = s->ITL_back;
}
printk("\n");
} else { } else {
if(hostdata->state != NCR_700_HOST_BUSY) if(hostdata->state != NCR_700_HOST_BUSY)
printk(KERN_ERR "scsi%d: FATAL, host not busy during valid reselection!\n", printk(KERN_ERR "scsi%d: FATAL, host not busy during valid reselection!\n",
...@@ -1473,9 +1403,8 @@ NCR_700_start_command(Scsi_Cmnd *SCp) ...@@ -1473,9 +1403,8 @@ NCR_700_start_command(Scsi_Cmnd *SCp)
* will refuse all tags, so send the request sense as untagged * will refuse all tags, so send the request sense as untagged
* */ * */
if((hostdata->tag_negotiated & (1<<SCp->target)) if((hostdata->tag_negotiated & (1<<SCp->target))
&& (slot->tag != NCR_700_NO_TAG && SCp->cmnd[0] != REQUEST_SENSE)) { && (slot->tag != SCSI_NO_TAG && SCp->cmnd[0] != REQUEST_SENSE)) {
hostdata->msgout[count++] = A_SIMPLE_TAG_MSG; count += scsi_populate_tag_msg(SCp, &hostdata->msgout[count]);
hostdata->msgout[count++] = slot->tag;
} }
if(hostdata->fast && if(hostdata->fast &&
...@@ -1835,7 +1764,6 @@ NCR_700_queuecommand(Scsi_Cmnd *SCp, void (*done)(Scsi_Cmnd *)) ...@@ -1835,7 +1764,6 @@ NCR_700_queuecommand(Scsi_Cmnd *SCp, void (*done)(Scsi_Cmnd *))
__u32 move_ins; __u32 move_ins;
int pci_direction; int pci_direction;
struct NCR_700_command_slot *slot; struct NCR_700_command_slot *slot;
int hash;
if(hostdata->command_slot_count >= NCR_700_COMMAND_SLOTS_PER_HOST) { if(hostdata->command_slot_count >= NCR_700_COMMAND_SLOTS_PER_HOST) {
/* We're over our allocation, this should never happen /* We're over our allocation, this should never happen
...@@ -1843,7 +1771,15 @@ NCR_700_queuecommand(Scsi_Cmnd *SCp, void (*done)(Scsi_Cmnd *)) ...@@ -1843,7 +1771,15 @@ NCR_700_queuecommand(Scsi_Cmnd *SCp, void (*done)(Scsi_Cmnd *))
printk(KERN_WARNING "scsi%d: Command depth has gone over queue depth\n", SCp->host->host_no); printk(KERN_WARNING "scsi%d: Command depth has gone over queue depth\n", SCp->host->host_no);
return 1; return 1;
} }
if(NCR_700_get_depth(SCp->device) != 0 && !(hostdata->tag_negotiated & (1<<SCp->target))) { /* check for untagged commands. We cannot have any outstanding
* commands if we accept them. Commands could be untagged because:
*
* - The tag negotiated bitmap is clear
* - The blk layer sent and untagged command
*/
if(NCR_700_get_depth(SCp->device) != 0
&& (!(hostdata->tag_negotiated & (1<<SCp->target))
|| !blk_rq_tagged(SCp->request))) {
DEBUG((KERN_ERR "scsi%d (%d:%d) has non zero depth %d\n", DEBUG((KERN_ERR "scsi%d (%d:%d) has non zero depth %d\n",
SCp->host->host_no, SCp->target, SCp->lun, SCp->host->host_no, SCp->target, SCp->lun,
NCR_700_get_depth(SCp->device))); NCR_700_get_depth(SCp->device)));
...@@ -1882,84 +1818,40 @@ NCR_700_queuecommand(Scsi_Cmnd *SCp, void (*done)(Scsi_Cmnd *)) ...@@ -1882,84 +1818,40 @@ NCR_700_queuecommand(Scsi_Cmnd *SCp, void (*done)(Scsi_Cmnd *))
* NOTE: There is a danger here: the mid layer supports * NOTE: There is a danger here: the mid layer supports
* tag queuing per LUN. We only support it per PUN because * tag queuing per LUN. We only support it per PUN because
* of potential reselection issues */ * of potential reselection issues */
printk(KERN_NOTICE "scsi%d: (%d:%d) beginning blk layer TCQ\n",
SCp->device->host->host_no, SCp->target, SCp->lun);
scsi_activate_tcq(SCp->device, NCR_700_MAX_TAGS);
}
if(blk_rq_tagged(SCp->request)
&& (hostdata->tag_negotiated &(1<<SCp->target)) == 0) {
printk(KERN_INFO "scsi%d: (%d:%d) Enabling Tag Command Queuing\n", SCp->device->host->host_no, SCp->target, SCp->lun); printk(KERN_INFO "scsi%d: (%d:%d) Enabling Tag Command Queuing\n", SCp->device->host->host_no, SCp->target, SCp->lun);
hostdata->tag_negotiated |= (1<<SCp->target); hostdata->tag_negotiated |= (1<<SCp->target);
NCR_700_set_flag(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING); NCR_700_set_flag(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING);
SCp->device->tagged_queue = 1;
} }
if(hostdata->tag_negotiated &(1<<SCp->target)) { /* here we may have to process an untagged command. The gate
* above ensures that this will be the only one outstanding,
* so clear the tag negotiated bit.
*
* FIXME: This will royally screw up on multiple LUN devices
* */
if(!blk_rq_tagged(SCp->request)
&& (hostdata->tag_negotiated &(1<<SCp->target))) {
printk(KERN_INFO "scsi%d: (%d:%d) Disabling Tag Command Queuing\n", SCp->device->host->host_no, SCp->target, SCp->lun);
hostdata->tag_negotiated &= ~(1<<SCp->target);
}
struct NCR_700_command_slot *old = if((hostdata->tag_negotiated &(1<<SCp->target))) {
find_ITL_Nexus(hostdata, SCp->target, SCp->lun); slot->tag = SCp->request->tag;
#ifdef NCR_700_TAG_DEBUG DEBUG(("53c700 %d:%d:%d, sending out tag %d, slot %p\n",
struct NCR_700_command_slot *found; SCp->host->host_no, SCp->target, SCp->lun, slot->tag,
#endif slot));
if(old != NULL && old->tag == SCp->device->current_tag) {
/* On some badly starving drives, this can be
* a frequent occurance, so print the message
* only once */
if(NCR_700_is_flag_clear(SCp->device, NCR_700_DEV_TAG_STARVATION_WARNED)) {
printk(KERN_WARNING "scsi%d (%d:%d) Target is suffering from tag starvation.\n", SCp->host->host_no, SCp->target, SCp->lun);
NCR_700_set_flag(SCp->device, NCR_700_DEV_TAG_STARVATION_WARNED);
}
/* Release the slot and ajust the depth before refusing
* the command */
free_slot(slot, hostdata);
NCR_700_set_depth(SCp->device, NCR_700_get_depth(SCp->device) - 1);
return 1;
}
slot->tag = SCp->device->current_tag++;
#ifdef NCR_700_TAG_DEBUG
while((found = find_ITLQ_Nexus(hostdata, SCp->target, SCp->lun, slot->tag)) != NULL) {
printk("\n\n**ERROR** already using tag %d, but oldest is %d\n", slot->tag, (old == NULL) ? -1 : old->tag);
printk(" FOUND = %p, tag = %d, pun = %d, lun = %d\n",
found, found->tag, found->cmnd->target, found->cmnd->lun);
slot->tag = SCp->device->current_tag++;
printk(" Tag list is: ");
while(old != NULL) {
if(old->cmnd->target == SCp->target &&
old->cmnd->lun == SCp->lun)
printk("%d ", old->tag);
old = old->ITL_back;
}
printk("\n\n");
}
#endif
hash = hash_ITLQ(SCp->target, SCp->lun, slot->tag);
/* link into the ITLQ hash queues */
slot->ITLQ_forw = hostdata->ITLQ_Hash_forw[hash];
hostdata->ITLQ_Hash_forw[hash] = slot;
#ifdef NCR_700_TAG_DEBUG
if(slot->ITLQ_forw != NULL && slot->ITLQ_forw->ITLQ_back != NULL) {
printk(KERN_ERR "scsi%d (%d:%d) ITLQ_back is not NULL!!!!\n", SCp->host->host_no, SCp->target, SCp->lun);
}
#endif
if(slot->ITLQ_forw != NULL)
slot->ITLQ_forw->ITLQ_back = slot;
else
hostdata->ITLQ_Hash_back[hash] = slot;
slot->ITLQ_back = NULL;
} else { } else {
slot->tag = NCR_700_NO_TAG; slot->tag = SCSI_NO_TAG;
/* must populate current_cmnd for scsi_find_tag to work */
SCp->device->current_cmnd = SCp;
} }
/* link into the ITL hash queues */
hash = hash_ITL(SCp->target, SCp->lun);
slot->ITL_forw = hostdata->ITL_Hash_forw[hash];
hostdata->ITL_Hash_forw[hash] = slot;
#ifdef NCR_700_TAG_DEBUG
if(slot->ITL_forw != NULL && slot->ITL_forw->ITL_back != NULL) {
printk(KERN_ERR "scsi%d (%d:%d) ITL_back is not NULL!!!!\n",
SCp->host->host_no, SCp->target, SCp->lun);
}
#endif
if(slot->ITL_forw != NULL)
slot->ITL_forw->ITL_back = slot;
else
hostdata->ITL_Hash_back[hash] = slot;
slot->ITL_back = NULL;
/* sanity check: some of the commands generated by the mid-layer /* sanity check: some of the commands generated by the mid-layer
* have an eccentric idea of their sc_data_direction */ * have an eccentric idea of their sc_data_direction */
if(!SCp->use_sg && !SCp->request_bufflen if(!SCp->use_sg && !SCp->request_bufflen
...@@ -2053,16 +1945,12 @@ STATIC int ...@@ -2053,16 +1945,12 @@ STATIC int
NCR_700_abort(Scsi_Cmnd * SCp) NCR_700_abort(Scsi_Cmnd * SCp)
{ {
struct NCR_700_command_slot *slot; struct NCR_700_command_slot *slot;
struct NCR_700_Host_Parameters *hostdata =
(struct NCR_700_Host_Parameters *)SCp->host->hostdata[0];
printk(KERN_INFO "scsi%d (%d:%d) New error handler wants to abort command\n\t", printk(KERN_INFO "scsi%d (%d:%d) New error handler wants to abort command\n\t",
SCp->host->host_no, SCp->target, SCp->lun); SCp->host->host_no, SCp->target, SCp->lun);
print_command(SCp->cmnd); print_command(SCp->cmnd);
slot = find_ITL_Nexus(hostdata, SCp->target, SCp->lun); slot = (struct NCR_700_command_slot *)SCp->host_scribble;
while(slot != NULL && slot->cmnd != SCp)
slot = slot->ITL_back;
if(slot == NULL) if(slot == NULL)
/* no outstanding command to abort */ /* no outstanding command to abort */
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
#define _53C700_H #define _53C700_H
/* Turn on for general debugging---too verbose for normal use */ /* Turn on for general debugging---too verbose for normal use */
#undef NCR_700_DEBUG #undef NCR_700_DEBUG
/* Debug the tag queues, checking hash queue allocation and deallocation /* Debug the tag queues, checking hash queue allocation and deallocation
* and search for duplicate tags */ * and search for duplicate tags */
#undef NCR_700_TAG_DEBUG #undef NCR_700_TAG_DEBUG
...@@ -189,8 +189,7 @@ struct NCR_700_command_slot { ...@@ -189,8 +189,7 @@ struct NCR_700_command_slot {
#define NCR_700_SLOT_BUSY (1|NCR_700_SLOT_MAGIC) /* slot has command active on HA */ #define NCR_700_SLOT_BUSY (1|NCR_700_SLOT_MAGIC) /* slot has command active on HA */
#define NCR_700_SLOT_QUEUED (2|NCR_700_SLOT_MAGIC) /* slot has command to be made active on HA */ #define NCR_700_SLOT_QUEUED (2|NCR_700_SLOT_MAGIC) /* slot has command to be made active on HA */
__u8 state; __u8 state;
#define NCR_700_NO_TAG 0xdead int tag;
__u16 tag;
__u32 resume_offset; __u32 resume_offset;
Scsi_Cmnd *cmnd; Scsi_Cmnd *cmnd;
/* The pci_mapped address of the actual command in cmnd */ /* The pci_mapped address of the actual command in cmnd */
......
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