diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-02-05 06:47:02 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-02-05 06:47:02 +0000 |
commit | 99a7e12f34b3661a0d1354eef83a0eef4df5e34c (patch) | |
tree | 3560aca9ca86792f9ab7bd87861ea143a1b3c7a3 /drivers/scsi/scsi.c | |
parent | e73a04659c0b8cdee4dd40e58630e2cf63afb316 (diff) |
Merge with Linux 2.3.38.
Diffstat (limited to 'drivers/scsi/scsi.c')
-rw-r--r-- | drivers/scsi/scsi.c | 299 |
1 files changed, 237 insertions, 62 deletions
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index f4ccd6e52..18185133d 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -1,6 +1,6 @@ /* * scsi.c Copyright (C) 1992 Drew Eckhardt - * Copyright (C) 1993, 1994, 1995 Eric Youngdale + * Copyright (C) 1993, 1994, 1995, 1999 Eric Youngdale * * generic mid-level SCSI driver * Initial versions: Drew Eckhardt @@ -13,7 +13,7 @@ * Tommy Thorn <tthorn> * Thomas Wuensche <tw@fgb1.fgb.mw.tu-muenchen.de> * - * Modified by Eric Youngdale eric@andante.jic.com or ericy@gnu.ai.mit.edu to + * Modified by Eric Youngdale eric@andante.org or ericy@gnu.ai.mit.edu to * add scatter-gather, multiple outstanding request, and other * enhancements. * @@ -85,7 +85,6 @@ static void scsi_dump_status(int level); /* * Definitions and constants. */ -#define INTERNAL_ERROR (panic ("Internal error in file %s, line %d.\n", __FILE__, __LINE__)) /* * PAGE_SIZE must be a multiple of the sector size (512). True @@ -153,9 +152,6 @@ static unsigned char **dma_malloc_pages = NULL; */ unsigned int scsi_logging_level = 0; -volatile struct Scsi_Host *host_active = NULL; - - const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE] = { "Direct-Access ", @@ -193,14 +189,6 @@ static int scsi_unregister_device(struct Scsi_Device_Template *tpnt); extern void scsi_old_done(Scsi_Cmnd * SCpnt); extern void scsi_old_times_out(Scsi_Cmnd * SCpnt); -#define SCSI_BLOCK(DEVICE, HOST) \ - ((HOST->block && host_active && HOST != host_active) \ - || ((HOST)->can_queue && HOST->host_busy >= HOST->can_queue) \ - || ((HOST)->host_blocked) \ - || ((DEVICE) != NULL && (DEVICE)->device_blocked) ) - - - struct dev_info { const char *vendor; const char *model; @@ -265,6 +253,7 @@ static struct dev_info device_list[] = {"YAMAHA", "CDR102", "1.00", BLIST_NOLUN}, /* Locks up if polled for lun != 0 * extra reset */ {"RELISYS", "Scorpio", "*", BLIST_NOLUN}, /* responds to all LUN */ + {"MICROTEK", "ScanMaker II", "5.61", BLIST_NOLUN}, /* responds to all LUN */ /* * Other types of devices that have special flags. @@ -292,8 +281,8 @@ static struct dev_info device_list[] = {"MATSHITA","PD-2 LF-D100","*", BLIST_GHOST}, {"HITACHI", "GF-1050","*", BLIST_GHOST}, /* Hitachi SCSI DVD-RAM */ {"TOSHIBA","CDROM","*", BLIST_ISROM}, - {"Toshiba","DVD-RAM SD-W1101","*", BLIST_GHOST}, - {"Toshiba","DVD-RAM SD-W1111","*", BLIST_GHOST}, + {"TOSHIBA","DVD-RAM SD-W1101","*", BLIST_GHOST}, + {"TOSHIBA","DVD-RAM SD-W1111","*", BLIST_GHOST}, /* * Must be at end of list... @@ -470,7 +459,10 @@ static void scan_scsis(struct Scsi_Host *shpnt, initialize_merge_fn(SDpnt); - init_waitqueue_head(&SDpnt->device_wait); + /* + * Initialize the object that we will use to wait for command blocks. + */ + init_waitqueue_head(&SDpnt->scpnt_wait); /* * Next, hook the device to the host in question. @@ -493,6 +485,7 @@ static void scan_scsis(struct Scsi_Host *shpnt, * things are quiet. */ atomic_inc(&shpnt->host_active); + atomic_inc(&SDpnt->device_active); if (hardcoded == 1) { Scsi_Device *oldSDpnt = SDpnt; @@ -574,6 +567,7 @@ static void scan_scsis(struct Scsi_Host *shpnt, * so we know when everything is quiet. */ atomic_dec(&shpnt->host_active); + atomic_dec(&SDpnt->device_active); leave: @@ -901,7 +895,10 @@ int scan_scsis_single(int channel, int dev, int lun, int *max_dev_lun, SDpnt->device_queue = SCpnt; SDpnt->online = TRUE; - init_waitqueue_head(&SDpnt->device_wait); + /* + * Initialize the object that we will use to wait for command blocks. + */ + init_waitqueue_head(&SDpnt->scpnt_wait); /* * Since we just found one device, there had damn well better be one in the list @@ -984,24 +981,6 @@ int scan_scsis_single(int channel, int dev, int lun, int *max_dev_lun, #define IN_RESET3 8 -/* This function takes a quick look at a request, and decides if it - * can be queued now, or if there would be a stall while waiting for - * something else to finish. This routine assumes that interrupts are - * turned off when entering the routine. It is the responsibility - * of the calling code to ensure that this is the case. - */ - - -/* This function returns a structure pointer that will be valid for - * the device. The wait parameter tells us whether we should wait for - * the unit to become free or not. We are also able to tell this routine - * not to return a descriptor if the host is unable to accept any more - * commands for the time being. We need to keep in mind that there is no - * guarantee that the host remain not busy. Keep in mind the - * scsi_request_queueable function also knows the internal allocation scheme - * of the packets for each device - */ - /* * This lock protects the freelist for all devices on the system. * We could make this finer grained by having a single lock per @@ -1029,15 +1008,24 @@ static spinlock_t scsi_bhqueue_lock = SPIN_LOCK_UNLOCKED; * Arguments: device - device for which we want a command descriptor * wait - 1 if we should wait in the event that none * are available. + * interruptible - 1 if we should unblock and return NULL + * in the event that we must wait, and a signal + * arrives. * * Lock status: No locks assumed to be held. This function is SMP-safe. * * Returns: Pointer to command descriptor. * * Notes: Prior to the new queue code, this function was not SMP-safe. + * + * If the wait flag is true, and we are waiting for a free + * command block, this function will interrupt and return + * NULL in the event that a signal arrives that needs to + * be handled. */ -Scsi_Cmnd *scsi_allocate_device(Scsi_Device * device, int wait) +Scsi_Cmnd *scsi_allocate_device(Scsi_Device * device, int wait, + int interruptable) { struct Scsi_Host *host; Scsi_Cmnd *SCpnt = NULL; @@ -1081,16 +1069,10 @@ Scsi_Cmnd *scsi_allocate_device(Scsi_Device * device, int wait) || SDpnt == device) { continue; } - for (SCpnt = SDpnt->device_queue; - SCpnt; - SCpnt = SCpnt->next) { - if (SCpnt->request.rq_status != RQ_INACTIVE) { - break; - } - } - if (SCpnt) { - break; - } + if( atomic_read(&SDpnt->device_active) != 0) + { + break; + } } if (SDpnt) { /* @@ -1121,15 +1103,53 @@ Scsi_Cmnd *scsi_allocate_device(Scsi_Device * device, int wait) * If we have been asked to wait for a free block, then * wait here. */ - spin_unlock_irqrestore(&device_request_lock, flags); if (wait) { + DECLARE_WAITQUEUE(wait, current); + + /* + * We need to wait for a free commandblock. We need to + * insert ourselves into the list before we release the + * lock. This way if a block were released the same + * microsecond that we released the lock, the call + * to schedule() wouldn't block (well, it might switch, + * but the current task will still be schedulable. + */ + add_wait_queue(&device->scpnt_wait, &wait); + if( interruptable ) { + set_current_state(TASK_INTERRUPTIBLE); + } else { + set_current_state(TASK_UNINTERRUPTIBLE); + } + + spin_unlock_irqrestore(&device_request_lock, flags); + /* * This should block until a device command block * becomes available. */ - sleep_on(&device->device_wait); + schedule(); + spin_lock_irqsave(&device_request_lock, flags); + + remove_wait_queue(&device->scpnt_wait, &wait); + /* + * FIXME - Isn't this redundant?? Someone + * else will have forced the state back to running. + */ + set_current_state(TASK_RUNNING); + /* + * In the event that a signal has arrived that we need + * to consider, then simply return NULL. Everyone + * that calls us should be prepared for this + * possibility, and pass the appropriate code back + * to the user. + */ + if( interruptable ) { + if (signal_pending(current)) + return NULL; + } } else { + spin_unlock_irqrestore(&device_request_lock, flags); return NULL; } } @@ -1138,13 +1158,21 @@ Scsi_Cmnd *scsi_allocate_device(Scsi_Device * device, int wait) SCpnt->request.sem = NULL; /* And no one is waiting for this * to complete */ atomic_inc(&SCpnt->host->host_active); + atomic_inc(&SCpnt->device->device_active); + + SCpnt->buffer = NULL; + SCpnt->bufflen = 0; + SCpnt->request_buffer = NULL; + SCpnt->request_bufflen = 0; SCpnt->use_sg = 0; /* Reset the scatter-gather flag */ SCpnt->old_use_sg = 0; SCpnt->transfersize = 0; /* No default transfer size */ SCpnt->cmd_len = 0; + SCpnt->result = 0; SCpnt->underflow = 0; /* Do not flag underflow conditions */ + SCpnt->resid = 0; SCpnt->state = SCSI_STATE_INITIALIZING; SCpnt->owner = SCSI_OWNER_HIGHLEVEL; @@ -1166,17 +1194,31 @@ Scsi_Cmnd *scsi_allocate_device(Scsi_Device * device, int wait) * * Notes: The command block can no longer be used by the caller once * this funciton is called. This is in effect the inverse - * of scsi_allocate_device/scsi_request_queueable. + * of scsi_allocate_device. Note that we also must perform + * a couple of additional tasks. We must first wake up any + * processes that might have blocked waiting for a command + * block, and secondly we must hit the queue handler function + * to make sure that the device is busy. + * + * The idea is that a lot of the mid-level internals gunk + * gets hidden in this function. Upper level drivers don't + * have any chickens to wave in the air to get things to + * work reliably. */ void scsi_release_command(Scsi_Cmnd * SCpnt) { unsigned long flags; + Scsi_Device * SDpnt; + spin_lock_irqsave(&device_request_lock, flags); + SDpnt = SCpnt->device; + SCpnt->request.rq_status = RQ_INACTIVE; SCpnt->state = SCSI_STATE_UNUSED; SCpnt->owner = SCSI_OWNER_NOBODY; atomic_dec(&SCpnt->host->host_active); + atomic_dec(&SDpnt->device_active); SCSI_LOG_MLQUEUE(5, printk("Deactivating command for device %d (active=%d, failed=%d)\n", SCpnt->target, @@ -1198,13 +1240,39 @@ void scsi_release_command(Scsi_Cmnd * SCpnt) atomic_read(&SCpnt->host->eh_wait->count))); up(SCpnt->host->eh_wait); } + spin_unlock_irqrestore(&device_request_lock, flags); + + /* + * Wake up anyone waiting for this device. Do this after we + * have released the lock, as they will need it as soon as + * they wake up. + */ + wake_up(&SDpnt->scpnt_wait); + + /* + * Finally, hit the queue request function to make sure that + * the device is actually busy if there are requests present. + * This won't block - if the device cannot take any more, life + * will go on. + */ + { + request_queue_t *q; + + q = &SDpnt->request_queue; + scsi_queue_next_request(q, NULL); + } } /* - * This is inline because we have stack problemes if we recurse to deeply. + * Function: scsi_dispatch_command + * + * Purpose: Dispatch a command to the low-level driver. + * + * Arguments: SCpnt - command block we are dispatching. + * + * Notes: */ - int scsi_dispatch_cmd(Scsi_Cmnd * SCpnt) { #ifdef DEBUG_DELAY @@ -1287,6 +1355,7 @@ int scsi_dispatch_cmd(Scsi_Cmnd * SCpnt) if (rtn != 0) { scsi_delete_timer(SCpnt); scsi_mlqueue_insert(SCpnt, SCSI_MLQUEUE_HOST_BUSY); + SCSI_LOG_MLQUEUE(3, printk("queuecommand : request rejected\n")); } } else { spin_lock_irqsave(&io_request_lock, flags); @@ -1344,7 +1413,7 @@ int scsi_dispatch_cmd(Scsi_Cmnd * SCpnt) * need be held upon entry. The old queueing code the lock was * assumed to be held upon entry. * - * Returns: Pointer to command descriptor. + * Returns: Nothing. * * Notes: Prior to the new queue code, this function was not SMP-safe. * Also, this function is now only used for queueing requests @@ -1358,7 +1427,6 @@ void scsi_do_cmd(Scsi_Cmnd * SCpnt, const void *cmnd, int timeout, int retries) { struct Scsi_Host *host = SCpnt->host; - Scsi_Device *device = SCpnt->device; ASSERT_LOCK(&io_request_lock, 0); @@ -1390,9 +1458,6 @@ void scsi_do_cmd(Scsi_Cmnd * SCpnt, const void *cmnd, */ - host->host_busy++; - device->device_busy++; - /* * Our own function scsi_done (which marks the host as not busy, disables * the timeout counter, etc) will be called by us or by the @@ -1482,6 +1547,7 @@ void scsi_done(Scsi_Cmnd * SCpnt) * etc, etc. */ if (!tstatus) { + SCpnt->done_late = 1; return; } /* Set the serial numbers back to zero */ @@ -1494,6 +1560,9 @@ void scsi_done(Scsi_Cmnd * SCpnt) * 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) + * + * FIXME(eric) - I believe that this test is now redundant, due to + * the test of the return status of del_timer(). */ if (SCpnt->state == SCSI_STATE_TIMEOUT) { SCSI_LOG_MLCOMPLETE(1, printk("Ignoring completion of %p due to timeout status", SCpnt)); @@ -1612,6 +1681,8 @@ void scsi_bottom_half_handler(void) * from being sent to the device, so we shouldn't end up * with tons of things being sent down that shouldn't be. */ + SCSI_LOG_MLCOMPLETE(3, printk("Command rejected as device queue full, put on ml queue %p\n", + SCpnt)); scsi_mlqueue_insert(SCpnt, SCSI_MLQUEUE_DEVICE_BUSY); break; default: @@ -1676,6 +1747,13 @@ int scsi_retry_command(Scsi_Cmnd * SCpnt) SCpnt->request_bufflen = SCpnt->bufflen; SCpnt->use_sg = SCpnt->old_use_sg; SCpnt->cmd_len = SCpnt->old_cmd_len; + + /* + * Zero the sense information from the last time we tried + * this command. + */ + memset((void *) SCpnt->sense_buffer, 0, sizeof SCpnt->sense_buffer); + return scsi_dispatch_cmd(SCpnt); } @@ -1699,6 +1777,14 @@ void scsi_finish_command(Scsi_Cmnd * SCpnt) host->host_busy--; /* Indicate that we are free */ device->device_busy--; /* Decrement device usage counter. */ + /* + * Clear the flags which say that the device/host is no longer + * capable of accepting new commands. These are set in scsi_queue.c + * for both the queue full condition on a device, and for a + * host full condition on the host. + */ + host->host_blocked = FALSE; + device->device_blocked = FALSE; /* * If we have valid sense information, then some kind of recovery @@ -1914,8 +2000,6 @@ void scsi_build_commandblocks(Scsi_Device * SDpnt) SCpnt->lun = SDpnt->lun; SCpnt->channel = SDpnt->channel; SCpnt->request.rq_status = RQ_INACTIVE; - SCpnt->host_wait = FALSE; - SCpnt->device_wait = FALSE; SCpnt->use_sg = 0; SCpnt->old_use_sg = 0; SCpnt->old_cmd_len = 0; @@ -1941,7 +2025,7 @@ void scsi_build_commandblocks(Scsi_Device * SDpnt) spin_unlock_irqrestore(&device_request_lock, flags); } -static ssize_t proc_scsi_gen_write(struct file * file, const char * buf, +static int proc_scsi_gen_write(struct file * file, const char * buf, unsigned long length, void *data); #ifndef MODULE /* { */ @@ -2136,7 +2220,7 @@ stop_output: return (len); } -static ssize_t proc_scsi_gen_write(struct file * file, const char * buf, +static int proc_scsi_gen_write(struct file * file, const char * buf, unsigned long length, void *data) { Scsi_Cmnd *SCpnt; @@ -2878,7 +2962,7 @@ static void scsi_unregister_host(Scsi_Host_Template * tpnt) DECLARE_MUTEX_LOCKED(sem); shpnt->eh_notify = &sem; - send_sig(SIGKILL, shpnt->ehandler, 1); + send_sig(SIGHUP, shpnt->ehandler, 1); down(&sem); shpnt->eh_notify = NULL; } @@ -3350,6 +3434,97 @@ void cleanup_module(void) #endif /* MODULE */ /* + * Function: scsi_get_host_dev() + * + * Purpose: Create a Scsi_Device that points to the host adapter itself. + * + * Arguments: SHpnt - Host that needs a Scsi_Device + * + * Lock status: None assumed. + * + * Returns: Nothing + * + * Notes: + */ +Scsi_Device * scsi_get_host_dev(struct Scsi_Host * SHpnt) +{ + Scsi_Device * SDpnt; + Scsi_Cmnd * SCpnt; + /* + * Attach a single Scsi_Device to the Scsi_Host - this should + * be made to look like a "pseudo-device" that points to the + * HA itself. For the moment, we include it at the head of + * the host_queue itself - I don't think we want to show this + * to the HA in select_queue_depths(), as this would probably confuse + * matters. + * Note - this device is not accessible from any high-level + * drivers (including generics), which is probably not + * optimal. We can add hooks later to attach + */ + SDpnt = (Scsi_Device *) kmalloc(sizeof(Scsi_Device), + GFP_ATOMIC); + memset(SDpnt, 0, sizeof(Scsi_Device)); + + SDpnt->host = SHpnt; + SDpnt->id = SHpnt->this_id; + SDpnt->type = -1; + SDpnt->queue_depth = 1; + + SCpnt = kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC); + memset(SCpnt, 0, sizeof(Scsi_Cmnd)); + SCpnt->host = SHpnt; + SCpnt->device = SDpnt; + SCpnt->target = SDpnt->id; + SCpnt->state = SCSI_STATE_UNUSED; + SCpnt->owner = SCSI_OWNER_NOBODY; + SCpnt->request.rq_status = RQ_INACTIVE; + + SDpnt->device_queue = SCpnt; + + blk_init_queue(&SDpnt->request_queue, scsi_request_fn); + blk_queue_headactive(&SDpnt->request_queue, 0); + SDpnt->request_queue.queuedata = (void *) SDpnt; + + SDpnt->online = TRUE; + + /* + * Initialize the object that we will use to wait for command blocks. + */ + init_waitqueue_head(&SDpnt->scpnt_wait); + return SDpnt; +} + +/* + * Function: scsi_free_host_dev() + * + * Purpose: Create a Scsi_Device that points to the host adapter itself. + * + * Arguments: SHpnt - Host that needs a Scsi_Device + * + * Lock status: None assumed. + * + * Returns: Nothing + * + * Notes: + */ +void scsi_free_host_dev(Scsi_Device * SDpnt) +{ + if( SDpnt->id != SDpnt->host->this_id ) + { + panic("Attempt to delete wrong device\n"); + } + + blk_cleanup_queue(&SDpnt->request_queue); + + /* + * We only have a single SCpnt attached to this device. Free + * it now. + */ + kfree(SDpnt->device_queue); + kfree(SDpnt); +} + +/* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically * adjust the settings for this buffer only. This must remain at the end |