diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1998-08-25 09:12:35 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1998-08-25 09:12:35 +0000 |
commit | c7fc24dc4420057f103afe8fc64524ebc25c5d37 (patch) | |
tree | 3682407a599b8f9f03fc096298134cafba1c9b2f /drivers/scsi/scsi.c | |
parent | 1d793fade8b063fde3cf275bf1a5c2d381292cd9 (diff) |
o Merge with Linux 2.1.116.
o New Newport console code.
o New G364 console code.
Diffstat (limited to 'drivers/scsi/scsi.c')
-rw-r--r-- | drivers/scsi/scsi.c | 116 |
1 files changed, 68 insertions, 48 deletions
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 469de6d25..8bdef9d14 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -127,7 +127,6 @@ const unsigned char scsi_command_size[8] = { 6, 10, 10, 12, static unsigned long serial_number = 0; static Scsi_Cmnd * scsi_bh_queue_head = NULL; static Scsi_Cmnd * scsi_bh_queue_tail = NULL; -static spinlock_t scsi_bh_queue_spin = SPIN_LOCK_UNLOCKED; static FreeSectorBitmap * dma_malloc_freelist = NULL; static int need_isa_bounce_buffers; static unsigned int dma_sectors = 0; @@ -275,6 +274,8 @@ static struct dev_info device_list[] = {"NRC","MBR-7","*", BLIST_FORCELUN | BLIST_SINGLELUN}, {"NRC","MBR-7.4","*", BLIST_FORCELUN | BLIST_SINGLELUN}, {"NAKAMICH","MJ-4.8S","*", BLIST_FORCELUN | BLIST_SINGLELUN}, +{"NAKAMICH","MJ-5.16S","*", BLIST_FORCELUN | BLIST_SINGLELUN}, +{"PIONEER","CD-ROM DRM-600","*", BLIST_FORCELUN | BLIST_SINGLELUN}, {"PIONEER","CD-ROM DRM-602X","*", BLIST_FORCELUN | BLIST_SINGLELUN}, {"PIONEER","CD-ROM DRM-604X","*", BLIST_FORCELUN | BLIST_SINGLELUN}, {"EMULEX","MD21/S2 ESDI","*", BLIST_SINGLELUN}, @@ -397,7 +398,7 @@ static void scan_scsis_done (Scsi_Cmnd * SCpnt) up(SCpnt->request.sem); } -void scsi_logging_setup(char *str, int *ints) +__initfunc(void scsi_logging_setup(char *str, int *ints)) { if (ints[0] != 1) { printk("scsi_logging_setup : usage scsi_logging_level=n " @@ -413,7 +414,7 @@ static int max_scsi_luns = 8; static int max_scsi_luns = 1; #endif -void scsi_luns_setup(char *str, int *ints) +__initfunc(void scsi_luns_setup(char *str, int *ints)) { if (ints[0] != 1) printk("scsi_luns_setup : usage max_scsi_luns=n (n should be between 1 and 8)\n"); @@ -754,6 +755,7 @@ int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun, case TYPE_MOD: case TYPE_PROCESSOR: case TYPE_SCANNER: + case TYPE_MEDIUM_CHANGER: SDpnt->writeable = 1; break; case TYPE_WORM: @@ -1264,7 +1266,7 @@ scsi_release_command(Scsi_Cmnd * SCpnt) */ if( SCpnt->host->in_recovery && !SCpnt->host->eh_active - && atomic_read(&SCpnt->host->host_active) == SCpnt->host->host_failed ) + && SCpnt->host->host_busy == SCpnt->host->host_failed ) { SCSI_LOG_ERROR_RECOVERY(5, printk("Waking error handler thread (%d)\n", atomic_read(&SCpnt->host->eh_wait->count))); @@ -1318,7 +1320,7 @@ inline int internal_cmnd (Scsi_Cmnd * SCpnt) * host). */ spin_unlock_irq(&io_request_lock); - while (--ticks_remaining >= 0) udelay(1000000/HZ); + while (--ticks_remaining >= 0) mdelay(1+999/HZ); host->last_reset = jiffies - MIN_RESET_DELAY; spin_lock_irq(&io_request_lock); } @@ -1461,6 +1463,7 @@ SCSI_LOG_MLQUEUE(4, memcpy ((void *) SCpnt->data_cmnd , (const void *) cmnd, 12); SCpnt->reset_chain = NULL; SCpnt->serial_number = 0; + SCpnt->serial_number_at_timeout = 0; SCpnt->bufflen = bufflen; SCpnt->buffer = buffer; SCpnt->flags = 0; @@ -1513,16 +1516,22 @@ SCSI_LOG_MLQUEUE(4, void scsi_done (Scsi_Cmnd * SCpnt) { - unsigned long flags; /* * We don't have to worry about this one timing out any more. */ scsi_delete_timer(SCpnt); + /* Set the serial numbers back to zero */ + SCpnt->serial_number = 0; + /* * First, see whether this command already timed out. If so, we ignore * the response. We treat it as if the command never finished. + * + * Since serial_number is now 0, the error handler cound detect this + * situation and avoid to call the the low level driver abort routine. + * (DB) */ if( SCpnt->state == SCSI_STATE_TIMEOUT ) { @@ -1530,23 +1539,22 @@ scsi_done (Scsi_Cmnd * SCpnt) return; } + SCpnt->serial_number_at_timeout = 0; SCpnt->state = SCSI_STATE_BHQUEUE; SCpnt->owner = SCSI_OWNER_BH_HANDLER; SCpnt->bh_next = NULL; /* - * Next, put this command in the BH queue. All processing of the command - * past this point will take place with interrupts turned on. - * We start by atomicly swapping the pointer into the queue head slot. - * If it was NULL before, then everything is fine, and we are done - * (this is the normal case). If it was not NULL, then we block interrupts, - * and link them together. + * Next, put this command in the BH queue. + * * We need a spinlock here, or compare and exchange if we can reorder incoming * Scsi_Cmnds, as it happens pretty often scsi_done is called multiple times * before bh is serviced. -jj + * + * We already have the io_request_lock here, since we are called from the + * interrupt handler or the error handler. (DB) + * */ - - spin_lock_irqsave(&scsi_bh_queue_spin, flags); if (!scsi_bh_queue_head) { scsi_bh_queue_head = SCpnt; scsi_bh_queue_tail = SCpnt; @@ -1554,7 +1562,6 @@ scsi_done (Scsi_Cmnd * SCpnt) scsi_bh_queue_tail->bh_next = SCpnt; scsi_bh_queue_tail = SCpnt; } - spin_unlock_irqrestore(&scsi_bh_queue_spin, flags); /* * Mark the bottom half handler to be run. @@ -1572,45 +1579,29 @@ scsi_done (Scsi_Cmnd * SCpnt) * Notes: This is called with all interrupts enabled. This should reduce * interrupt latency, stack depth, and reentrancy of the low-level * drivers. + * + * The io_request_lock is required in all the routine. There was a subtle + * race condition when scsi_done is called after a command has already + * timed out but before the time out is processed by the error handler. + * (DB) */ void scsi_bottom_half_handler(void) { Scsi_Cmnd * SCpnt; Scsi_Cmnd * SCnext; - static atomic_t recursion_depth; unsigned long flags; + spin_lock_irqsave(&io_request_lock, flags); + while(1==1) { - /* - * If the counter is > 0, that means that there is another interrupt handler - * out there somewhere processing commands. We don't want to get these guys - * nested as this can lead to stack overflow problems, and there isn't any - * real sense in it anyways. - */ - if( atomic_read(&recursion_depth) > 0 ) - { - printk("SCSI bottom half recursion depth = %d \n", atomic_read(&recursion_depth)); - SCSI_LOG_MLCOMPLETE(1,printk("SCSI bottom half recursion depth = %d \n", - atomic_read(&recursion_depth))); - break; - } - - /* - * We need to hold the spinlock, so that nobody is tampering with the queue. -jj - * We will process everything we find in the list here. - */ - - spin_lock_irqsave(&scsi_bh_queue_spin, flags); SCpnt = scsi_bh_queue_head; scsi_bh_queue_head = NULL; - spin_unlock_irqrestore(&scsi_bh_queue_spin, flags); - if( SCpnt == NULL ) + if( SCpnt == NULL ) { + spin_unlock_irqrestore(&io_request_lock, flags); return; - - spin_lock_irqsave(&io_request_lock, flags); - atomic_inc(&recursion_depth); + } SCnext = SCpnt->bh_next; @@ -1683,7 +1674,7 @@ void scsi_bottom_half_handler(void) * If the host is having troubles, then look to see if this was the last * command that might have failed. If so, wake up the error handler. */ - if( atomic_read(&SCpnt->host->host_active) == SCpnt->host->host_failed ) + if( SCpnt->host->host_busy == SCpnt->host->host_failed ) { SCSI_LOG_ERROR_RECOVERY(5, printk("Waking error handler thread (%d)\n", atomic_read(&SCpnt->host->eh_wait->count))); @@ -1700,11 +1691,10 @@ void scsi_bottom_half_handler(void) } } /* for(; SCpnt...) */ - atomic_dec(&recursion_depth); - spin_unlock_irqrestore(&io_request_lock, flags); - } /* while(1==1) */ + spin_unlock_irqrestore(&io_request_lock, flags); + } /* @@ -1789,6 +1779,10 @@ scsi_finish_command(Scsi_Cmnd * SCpnt) SCpnt->owner = SCSI_OWNER_HIGHLEVEL; SCpnt->state = SCSI_STATE_FINISHED; + + /* We can get here with use_sg=0, causing a panic in the upper level (DB) */ + SCpnt->use_sg = SCpnt->old_use_sg; + SCpnt->done (SCpnt); } @@ -2304,6 +2298,13 @@ int scsi_proc_info(char *buffer, char **start, off_t offset, int length, return(-ENOSYS); /* We do not yet support unplugging */ scan_scsis (HBA_ptr, 1, channel, id, lun); + + /* FIXME (DB) This assumes that the queue_depth routines can be used + in this context as well, while they were all designed to be + called only once after the detect routine. (DB) */ + if (HBA_ptr->select_queue_depths != NULL) + (HBA_ptr->select_queue_depths)(HBA_ptr, HBA_ptr->host_queue); + return(length); } @@ -2563,12 +2564,30 @@ static int scsi_register_host(Scsi_Host_Template * tpnt) Scsi_Device * SDpnt; struct Scsi_Device_Template * sdtpnt; const char * name; + unsigned long flags; if (tpnt->next || !tpnt->detect) return 1;/* Must be already loaded, or * no detect routine available */ pcount = next_scsi_host; - if ((tpnt->present = tpnt->detect(tpnt))) + + /* The detect routine must carefully spinunlock/spinlock if + it enables interrupts, since all interrupt handlers do + spinlock as well. + All lame drivers are going to fail due to the following + spinlock. For the time beeing let's use it only for drivers + using the new scsi code. NOTE: the detect routine could + redefine the value tpnt->use_new_eh_code. (DB, 13 May 1998) */ + + if (tpnt->use_new_eh_code) { + spin_lock_irqsave(&io_request_lock, flags); + tpnt->present = tpnt->detect(tpnt); + spin_unlock_irqrestore(&io_request_lock, flags); + } + else + tpnt->present = tpnt->detect(tpnt); + + if (tpnt->present) { if(pcount == next_scsi_host) { @@ -2781,8 +2800,9 @@ static void scsi_unregister_host(Scsi_Host_Template * tpnt) SDpnt->online = FALSE; if(SCpnt->request.rq_status != RQ_INACTIVE) { - printk("SCSI device not inactive - state=%d, id=%d\n", - SCpnt->request.rq_status, SCpnt->target); + printk("SCSI device not inactive - rq_status=%d, target=%d, pid=%ld, state=%d, owner=%d.\n", + SCpnt->request.rq_status, SCpnt->target, SCpnt->pid, + SCpnt->state, SCpnt->owner); for(SDpnt1 = shpnt->host_queue; SDpnt1; SDpnt1 = SDpnt1->next) { |