diff options
42 files changed, 1373 insertions, 535 deletions
diff --git a/Documentation/swsusp.txt b/Documentation/swsusp.txt index 7c7373ae8f30..88bcefb64403 100644 --- a/Documentation/swsusp.txt +++ b/Documentation/swsusp.txt @@ -122,11 +122,9 @@ Things to implement interrupts AFAIK.. - We should only make a copy of data related to kernel segment, since any process data won't be changed. -- By copying pages back to their original position, copy_page caused General - Protection Fault. Why? - Hardware state restoring. Now there's support for notifying via the notify chain, event handlers are welcome. Some devices may have microcodes loaded - into them. We should have event handlers for them aswell. + into them. We should have event handlers for them as well. - We should support other architectures (There are really only some arch related functions..) - We should also restore original state of swaps if the ``noresume'' kernel @@ -149,6 +147,15 @@ Not so important ideas for implementing - If X is active while suspending then by resuming calling svgatextmode corrupts the virtual console of X.. (Maybe this has been fixed AFAIK). +Drivers we support +- IDE disks are okay +- vesafb + +Drivers that need support +- pc_keyb -- perhaps we can wait for vojtech's input patches +- do IDE cdroms need some kind of support? +- IDE CD-RW -- how to deal with that? + Any other idea you might have tell me! Contacting the author diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c index d6814ebef9a4..d19bce8ee5f7 100644 --- a/arch/i386/kernel/apm.c +++ b/arch/i386/kernel/apm.c @@ -814,16 +814,16 @@ recalc: if (jiffies_since_last_check > IDLE_CALC_LIMIT) { use_apm_idle = 0; last_jiffies = jiffies; - last_stime = current->times.tms_stime; + last_stime = current->stime; } else if (jiffies_since_last_check > idle_period) { unsigned int idle_percentage; - idle_percentage = current->times.tms_stime - last_stime; + idle_percentage = current->stime - last_stime; idle_percentage *= 100; idle_percentage /= jiffies_since_last_check; use_apm_idle = (idle_percentage > idle_threshold); last_jiffies = jiffies; - last_stime = current->times.tms_stime; + last_stime = current->stime; } bucket = IDLE_LEAKY_MAX; diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index fc2fa884e1ed..5092049cdb57 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -431,6 +431,11 @@ int unregister_cdrom(struct cdrom_device_info *unreg) topCdromPtr = cdi->next; cdi->ops->n_minors--; devfs_unregister (cdi->de); + if (atomic_read (&cdi->cdrom_driverfs_dev.refcount)) { + device_remove_file (&cdi->cdrom_driverfs_dev, "name"); + device_remove_file (&cdi->cdrom_driverfs_dev, "kdev"); + put_device (&cdi->cdrom_driverfs_dev); + } devfs_dealloc_unique_number (&cdrom_numspace, cdi->number); cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" unregistered\n", cdi->name); return 0; diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c index ca975028da19..1e10ccc11e0f 100644 --- a/drivers/scsi/53c700.c +++ b/drivers/scsi/53c700.c @@ -283,6 +283,7 @@ NCR_700_detect(Scsi_Host_Template *tpnt, tpnt->cmd_per_lun = NCR_700_MAX_TAGS; tpnt->use_clustering = DISABLE_CLUSTERING; tpnt->proc_info = NCR_700_proc_directory_info; + tpnt->use_blk_tcq = 1; if(tpnt->name == NULL) tpnt->name = "53c700"; @@ -498,46 +499,12 @@ STATIC void free_slot(struct NCR_700_command_slot *slot, 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) { printk(KERN_ERR "53c700: SLOT %p is not MAGIC!!!\n", slot); } if(slot->state == NCR_700_SLOT_FREE) { 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->cmnd = NULL; @@ -565,48 +532,6 @@ save_for_reselection(struct NCR_700_Host_Parameters *hostdata, 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 * which can be loaded into the SXFER_REG. * @@ -696,7 +621,6 @@ NCR_700_scsi_done(struct NCR_700_Host_Parameters *hostdata, SCp->underflow = SCp->old_underflow; } - free_slot(slot, hostdata); #ifdef NCR_700_DEBUG if(NCR_700_get_depth(SCp->device) == 0 || @@ -1147,6 +1071,7 @@ process_script_interrupt(__u32 dsps, __u32 dsp, Scsi_Cmnd *SCp, __u8 lun; struct NCR_700_command_slot *slot; __u8 reselection_id = hostdata->reselection_id; + Scsi_Device *SDp; lun = hostdata->msgin[0] & 0x1f; @@ -1154,34 +1079,39 @@ process_script_interrupt(__u32 dsps, __u32 dsp, Scsi_Cmnd *SCp, DEBUG(("scsi%d: (%d:%d) RESELECTED!\n", host->host_no, reselection_id, lun)); /* 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) { - slot = find_ITLQ_Nexus(hostdata, reselection_id, - lun, hostdata->msgin[2]); + Scsi_Cmnd *SCp = scsi_find_tag(SDp, 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 { - 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) { - 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", host->host_no, reselection_id, lun, hostdata->msgin[0], hostdata->msgin[1], 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 { if(hostdata->state != NCR_700_HOST_BUSY) printk(KERN_ERR "scsi%d: FATAL, host not busy during valid reselection!\n", @@ -1473,9 +1403,8 @@ NCR_700_start_command(Scsi_Cmnd *SCp) * will refuse all tags, so send the request sense as untagged * */ if((hostdata->tag_negotiated & (1<<SCp->target)) - && (slot->tag != NCR_700_NO_TAG && SCp->cmnd[0] != REQUEST_SENSE)) { - hostdata->msgout[count++] = A_SIMPLE_TAG_MSG; - hostdata->msgout[count++] = slot->tag; + && (slot->tag != SCSI_NO_TAG && SCp->cmnd[0] != REQUEST_SENSE)) { + count += scsi_populate_tag_msg(SCp, &hostdata->msgout[count]); } if(hostdata->fast && @@ -1835,7 +1764,6 @@ NCR_700_queuecommand(Scsi_Cmnd *SCp, void (*done)(Scsi_Cmnd *)) __u32 move_ins; int pci_direction; struct NCR_700_command_slot *slot; - int hash; if(hostdata->command_slot_count >= NCR_700_COMMAND_SLOTS_PER_HOST) { /* We're over our allocation, this should never happen @@ -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); 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", SCp->host->host_no, SCp->target, SCp->lun, NCR_700_get_depth(SCp->device))); @@ -1882,84 +1818,40 @@ NCR_700_queuecommand(Scsi_Cmnd *SCp, void (*done)(Scsi_Cmnd *)) * NOTE: There is a danger here: the mid layer supports * tag queuing per LUN. We only support it per PUN because * 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); hostdata->tag_negotiated |= (1<<SCp->target); 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 = - find_ITL_Nexus(hostdata, SCp->target, SCp->lun); -#ifdef NCR_700_TAG_DEBUG - struct NCR_700_command_slot *found; -#endif - - 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; + if((hostdata->tag_negotiated &(1<<SCp->target))) { + slot->tag = SCp->request->tag; + DEBUG(("53c700 %d:%d:%d, sending out tag %d, slot %p\n", + SCp->host->host_no, SCp->target, SCp->lun, slot->tag, + slot)); } 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 * have an eccentric idea of their sc_data_direction */ if(!SCp->use_sg && !SCp->request_bufflen @@ -2053,16 +1945,12 @@ STATIC int NCR_700_abort(Scsi_Cmnd * SCp) { 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", SCp->host->host_no, SCp->target, SCp->lun); print_command(SCp->cmnd); - slot = find_ITL_Nexus(hostdata, SCp->target, SCp->lun); - while(slot != NULL && slot->cmnd != SCp) - slot = slot->ITL_back; + slot = (struct NCR_700_command_slot *)SCp->host_scribble; if(slot == NULL) /* no outstanding command to abort */ diff --git a/drivers/scsi/53c700.h b/drivers/scsi/53c700.h index c106937d2037..ccb675372935 100644 --- a/drivers/scsi/53c700.h +++ b/drivers/scsi/53c700.h @@ -9,7 +9,7 @@ #define _53C700_H /* 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 * and search for duplicate tags */ #undef NCR_700_TAG_DEBUG @@ -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_QUEUED (2|NCR_700_SLOT_MAGIC) /* slot has command to be made active on HA */ __u8 state; - #define NCR_700_NO_TAG 0xdead - __u16 tag; + int tag; __u32 resume_offset; Scsi_Cmnd *cmnd; /* The pci_mapped address of the actual command in cmnd */ diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c index 865a02c08711..ad1af6379ffb 100644 --- a/drivers/scsi/aha1542.c +++ b/drivers/scsi/aha1542.c @@ -1635,14 +1635,14 @@ static int aha1542_old_abort(Scsi_Cmnd * SCpnt) if (HOSTDATA(SCpnt->host)->SCint[i]) { if (HOSTDATA(SCpnt->host)->SCint[i] == SCpnt) { printk(KERN_ERR "Timed out command pending for %s\n", - kdevname(SCpnt->request.rq_dev)); + kdevname(SCpnt->request->rq_dev)); if (HOSTDATA(SCpnt->host)->mb[i].status) { printk(KERN_ERR "OGMB still full - restarting\n"); aha1542_out(SCpnt->host->io_port, &ahacmd, 1); }; } else printk(KERN_ERR "Other pending command %s\n", - kdevname(SCpnt->request.rq_dev)); + kdevname(SCpnt->request->rq_dev)); } #endif diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c index 57d3f82b80c4..530247392207 100644 --- a/drivers/scsi/constants.c +++ b/drivers/scsi/constants.c @@ -1006,13 +1006,13 @@ print_sense_internal(const char * devclass, void print_sense(const char * devclass, Scsi_Cmnd * SCpnt) { print_sense_internal(devclass, SCpnt->sense_buffer, - SCpnt->request.rq_dev); + SCpnt->request->rq_dev); } void print_req_sense(const char * devclass, Scsi_Request * SRpnt) { print_sense_internal(devclass, SRpnt->sr_sense_buffer, - SRpnt->sr_request.rq_dev); + SRpnt->sr_request->rq_dev); } #if (CONSTANTS & CONST_MSG) diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c index 5a84221d5d5c..cc73354accc6 100644 --- a/drivers/scsi/eata.c +++ b/drivers/scsi/eata.c @@ -1563,7 +1563,7 @@ static inline int do_qcomm(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) { if (linked_comm && SCpnt->device->queue_depth > 2 && TLDEV(SCpnt->device->type)) { HD(j)->cp_stat[i] = READY; - flush_dev(SCpnt->device, SCpnt->request.sector, j, FALSE); + flush_dev(SCpnt->device, SCpnt->request->sector, j, FALSE); return 0; } @@ -1875,11 +1875,11 @@ static inline int reorder(unsigned int j, unsigned long cursec, if (!cpp->din) input_only = FALSE; - if (SCpnt->request.sector < minsec) minsec = SCpnt->request.sector; - if (SCpnt->request.sector > maxsec) maxsec = SCpnt->request.sector; + if (SCpnt->request->sector < minsec) minsec = SCpnt->request->sector; + if (SCpnt->request->sector > maxsec) maxsec = SCpnt->request->sector; - sl[n] = SCpnt->request.sector; - ioseek += SCpnt->request.nr_sectors; + sl[n] = SCpnt->request->sector; + ioseek += SCpnt->request->nr_sectors; if (!n) continue; @@ -1907,7 +1907,7 @@ static inline int reorder(unsigned int j, unsigned long cursec, if (!input_only) for (n = 0; n < n_ready; n++) { k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt; - ll[n] = SCpnt->request.nr_sectors; pl[n] = SCpnt->pid; + ll[n] = SCpnt->request->nr_sectors; pl[n] = SCpnt->pid; if (!n) continue; @@ -1935,7 +1935,7 @@ static inline int reorder(unsigned int j, unsigned long cursec, " cur %ld s:%c r:%c rev:%c in:%c ov:%c xd %d.\n", (ihdlr ? "ihdlr" : "qcomm"), SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid, k, flushcount, n_ready, - SCpnt->request.sector, SCpnt->request.nr_sectors, cursec, + SCpnt->request->sector, SCpnt->request->nr_sectors, cursec, YESNO(s), YESNO(r), YESNO(rev), YESNO(input_only), YESNO(overlap), cpp->din); } @@ -2073,7 +2073,7 @@ static inline void ihdlr(int irq, unsigned int j) { if (linked_comm && SCpnt->device->queue_depth > 2 && TLDEV(SCpnt->device->type)) - flush_dev(SCpnt->device, SCpnt->request.sector, j, TRUE); + flush_dev(SCpnt->device, SCpnt->request->sector, j, TRUE); tstatus = status_byte(spp->target_status); diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index e276376771ae..2b0ab4e4e0b4 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -230,6 +230,7 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template * tpnt, int j) retval->select_queue_depths = tpnt->select_queue_depths; retval->max_sectors = tpnt->max_sectors; + retval->use_blk_tcq = tpnt->use_blk_tcq; if(!scsi_hostlist) scsi_hostlist = retval; diff --git a/drivers/scsi/hosts.h b/drivers/scsi/hosts.h index 8604eb35140a..f338366ff443 100644 --- a/drivers/scsi/hosts.h +++ b/drivers/scsi/hosts.h @@ -286,6 +286,12 @@ typedef struct SHT unsigned highmem_io:1; + /* + * True if the driver wishes to use the generic block layer + * tag queueing functions + */ + unsigned use_blk_tcq:1; + /* * Name of proc directory */ @@ -386,6 +392,7 @@ struct Scsi_Host unsigned unchecked_isa_dma:1; unsigned use_clustering:1; unsigned highmem_io:1; + unsigned use_blk_tcq:1; /* * Host has rejected a command because it was busy. @@ -418,6 +425,11 @@ struct Scsi_Host */ struct pci_dev *pci_dev; + /* + * Support for driverfs filesystem + */ + struct device host_driverfs_dev; + /* * We should ensure that this is aligned, both for better performance * and also because some compilers (m68k) don't automatically force @@ -478,6 +490,7 @@ static inline void scsi_set_pci_device(struct Scsi_Host *SHpnt, struct pci_dev *pdev) { SHpnt->pci_dev = pdev; + SHpnt->host_driverfs_dev.parent=&pdev->dev; } @@ -516,6 +529,7 @@ struct Scsi_Device_Template void (*detach)(Scsi_Device *); int (*init_command)(Scsi_Cmnd *); /* Used by new queueing code. Selects command for blkdevs */ + struct device_driver scsi_driverfs_driver; }; void scsi_initialize_queue(Scsi_Device * SDpnt, struct Scsi_Host * SHpnt); @@ -555,6 +569,26 @@ extern int scsi_unregister_host(Scsi_Host_Template *); #define SD_EXTRA_DEVS CONFIG_SD_EXTRA_DEVS #define SR_EXTRA_DEVS CONFIG_SR_EXTRA_DEVS + +/** + * scsi_find_device - find a device given the host + * @channel: SCSI channel (zero if only one channel) + * @pun: SCSI target number (physical unit number) + * @lun: SCSI Logical Unit Number + **/ +static inline Scsi_Device *scsi_find_device(struct Scsi_Host *host, + int channel, int pun, int lun) { + Scsi_Device *SDpnt; + + for(SDpnt = host->host_queue; + SDpnt != NULL; + SDpnt = SDpnt->next) + if(SDpnt->channel == channel && SDpnt->id == pun + && SDpnt->lun ==lun) + break; + return SDpnt; +} + #endif /* * Overrides for Emacs so that we follow Linus's tabbing style. diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c index 9652a0f71616..14960822b3e6 100644 --- a/drivers/scsi/ide-scsi.c +++ b/drivers/scsi/ide-scsi.c @@ -668,7 +668,7 @@ static inline int should_transform(struct ata_device *drive, Scsi_Cmnd *cmd) struct Scsi_Host *host = drive->driver_data; idescsi_scsi_t *scsi = idescsi_private(host); - if (major(cmd->request.rq_dev) == SCSI_GENERIC_MAJOR) + if (major(cmd->request->rq_dev) == SCSI_GENERIC_MAJOR) return test_bit(IDESCSI_SG_TRANSFORM, &scsi->transform); return test_bit(IDESCSI_TRANSFORM, &scsi->transform); } diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c index 8c91af6f7900..9ea4f1b68ca7 100644 --- a/drivers/scsi/osst.c +++ b/drivers/scsi/osst.c @@ -270,7 +270,7 @@ static int osst_chk_result(OS_Scsi_Tape * STp, Scsi_Request * SRpnt) /* Wakeup from interrupt */ static void osst_sleep_done (Scsi_Cmnd * SCpnt) { - unsigned int dev = TAPE_NR(SCpnt->request.rq_dev); + unsigned int dev = TAPE_NR(SCpnt->request->rq_dev); OS_Scsi_Tape * STp; if (os_scsi_tapes && (STp = os_scsi_tapes[dev])) { @@ -285,13 +285,13 @@ static void osst_sleep_done (Scsi_Cmnd * SCpnt) } else (STp->buffer)->midlevel_result = SCpnt->result; - SCpnt->request.rq_status = RQ_SCSI_DONE; + SCpnt->request->rq_status = RQ_SCSI_DONE; (STp->buffer)->last_SRpnt = SCpnt->sc_request; #if DEBUG STp->write_pending = 0; #endif - complete(SCpnt->request.waiting); + complete(SCpnt->request->waiting); } #if DEBUG else if (debugging) @@ -313,7 +313,7 @@ static Scsi_Request * osst_do_scsi(Scsi_Request *SRpnt, OS_Scsi_Tape *STp, #endif if (SRpnt == NULL) { if ((SRpnt = scsi_allocate_request(STp->device)) == NULL) { - printk(KERN_ERR "osst%d:E: Can't get SCSI request.\n", TAPE_NR(STp->devt)); + printk(KERN_ERR "osst%d:E: Can't get SCSI request->\n", TAPE_NR(STp->devt)); if (signal_pending(current)) (STp->buffer)->syscall_result = (-EINTR); else @@ -336,15 +336,15 @@ static Scsi_Request * osst_do_scsi(Scsi_Request *SRpnt, OS_Scsi_Tape *STp, bp = (STp->buffer)->b_data; SRpnt->sr_data_direction = direction; SRpnt->sr_cmd_len = 0; - SRpnt->sr_request.waiting = &(STp->wait); - SRpnt->sr_request.rq_status = RQ_SCSI_BUSY; - SRpnt->sr_request.rq_dev = STp->devt; + SRpnt->sr_request->waiting = &(STp->wait); + SRpnt->sr_request->rq_status = RQ_SCSI_BUSY; + SRpnt->sr_request->rq_dev = STp->devt; scsi_do_req(SRpnt, (void *)cmd, bp, bytes, osst_sleep_done, timeout, retries); if (do_wait) { - wait_for_completion(SRpnt->sr_request.waiting); - SRpnt->sr_request.waiting = NULL; + wait_for_completion(SRpnt->sr_request->waiting); + SRpnt->sr_request->waiting = NULL; STp->buffer->syscall_result = osst_chk_result(STp, SRpnt); #ifdef OSST_INJECT_ERRORS if (STp->buffer->syscall_result == 0 && @@ -377,7 +377,7 @@ static void osst_write_behind_check(OS_Scsi_Tape *STp) STp->nbr_finished++; #endif wait_for_completion(&(STp->wait)); - (STp->buffer)->last_SRpnt->sr_request.waiting = NULL; + (STp->buffer)->last_SRpnt->sr_request->waiting = NULL; STp->buffer->syscall_result = osst_chk_result(STp, STp->buffer->last_SRpnt); diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index a008f3dd87b0..9debb242fe73 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -4236,7 +4236,7 @@ qla1280_32bit_start_scsi(struct scsi_qla_host *ha, srb_t * sp) /* Set transfer direction (READ and WRITE) */ /* Linux doesn't tell us */ /* - * For block devices, cmd->request.cmd has the operation + * For block devices, cmd->request->cmd has the operation * For character devices, this isn't always set properly, so * we need to check data_cmnd[0]. This catches the conditions * for st.c, but not sg. Generic commands are pass down to us. @@ -6241,7 +6241,7 @@ qla1280_print_scsi_cmd(Scsi_Cmnd * cmd) cmd->tag, cmd->flags, cmd->transfersize); printk(" Pid=%li, SP=0x%p\n", cmd->pid, CMD_SP(cmd)); printk(" underflow size = 0x%x, direction=0x%x, req.cmd=0x%x \n", - cmd->underflow, sp->dir, cmd->request.cmd); + cmd->underflow, sp->dir, cmd->request->cmd); } /************************************************************************** diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 0215c45cbd37..26b9a49cd49a 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -130,8 +130,13 @@ const unsigned char scsi_command_size[8] = 16, 12, 10, 10 }; static unsigned long serial_number; -static Scsi_Cmnd *scsi_bh_queue_head; -static Scsi_Cmnd *scsi_bh_queue_tail; + +struct softscsi_data { + Scsi_Cmnd *head; + Scsi_Cmnd *tail; +}; + +static struct softscsi_data softscsi_data[NR_CPUS] __cacheline_aligned; /* * Note - the initial logging level can be set here to log events at boot time. @@ -253,11 +258,20 @@ __setup("scsi_logging=", scsi_logging_setup); static void scsi_wait_done(Scsi_Cmnd * SCpnt) { - struct request *req; + struct request *req = SCpnt->request; + struct request_queue *q = &SCpnt->device->request_queue; + unsigned long flags; - req = &SCpnt->request; + ASSERT_LOCK(q->queue_lock, 0); req->rq_status = RQ_SCSI_DONE; /* Busy, but indicate request done */ + spin_lock_irqsave(q->queue_lock, flags); + + if(blk_rq_tagged(req)) + blk_queue_end_tag(q, req); + + spin_unlock_irqrestore(q->queue_lock, flags); + if (req->waiting) complete(req->waiting); } @@ -271,12 +285,6 @@ static void scsi_wait_done(Scsi_Cmnd * SCpnt) static spinlock_t device_request_lock = SPIN_LOCK_UNLOCKED; /* - * Used to protect insertion into and removal from the queue of - * commands to be processed by the bottom half handler. - */ -static spinlock_t scsi_bhqueue_lock = SPIN_LOCK_UNLOCKED; - -/* * Function: scsi_allocate_request * * Purpose: Allocate a request descriptor. @@ -296,17 +304,19 @@ static spinlock_t scsi_bhqueue_lock = SPIN_LOCK_UNLOCKED; Scsi_Request *scsi_allocate_request(Scsi_Device * device) { Scsi_Request *SRpnt = NULL; + const int offset = ALIGN(sizeof(Scsi_Request), 4); + const int size = offset + sizeof(struct request); if (!device) panic("No device passed to scsi_allocate_request().\n"); - SRpnt = (Scsi_Request *) kmalloc(sizeof(Scsi_Request), GFP_ATOMIC); + SRpnt = (Scsi_Request *) kmalloc(size, GFP_ATOMIC); if( SRpnt == NULL ) { return NULL; } - - memset(SRpnt, 0, sizeof(Scsi_Request)); + memset(SRpnt, 0, size); + SRpnt->sr_request = (struct request *)(((char *)SRpnt) + offset); SRpnt->sr_device = device; SRpnt->sr_host = device->host; SRpnt->sr_magic = SCSI_REQ_MAGIC; @@ -434,7 +444,7 @@ Scsi_Cmnd *scsi_allocate_device(Scsi_Device * device, int wait, * Now we can check for a free command block for this device. */ for (SCpnt = device->device_queue; SCpnt; SCpnt = SCpnt->next) { - if (SCpnt->request.rq_status == RQ_INACTIVE) + if (SCpnt->request == NULL) break; } } @@ -503,9 +513,7 @@ Scsi_Cmnd *scsi_allocate_device(Scsi_Device * device, int wait, } } - SCpnt->request.rq_status = RQ_SCSI_BUSY; - SCpnt->request.waiting = NULL; /* And no one is waiting for this - * to complete */ + SCpnt->request = NULL; atomic_inc(&SCpnt->host->host_active); atomic_inc(&SCpnt->device->device_active); @@ -548,7 +556,7 @@ inline void __scsi_release_command(Scsi_Cmnd * SCpnt) SDpnt = SCpnt->device; - SCpnt->request.rq_status = RQ_INACTIVE; + SCpnt->request = NULL; SCpnt->state = SCSI_STATE_UNUSED; SCpnt->owner = SCSI_OWNER_NOBODY; atomic_dec(&SCpnt->host->host_active); @@ -771,13 +779,13 @@ void scsi_wait_req (Scsi_Request * SRpnt, const void *cmnd , DECLARE_COMPLETION(wait); request_queue_t *q = &SRpnt->sr_device->request_queue; - SRpnt->sr_request.waiting = &wait; - SRpnt->sr_request.rq_status = RQ_SCSI_BUSY; + SRpnt->sr_request->waiting = &wait; + SRpnt->sr_request->rq_status = RQ_SCSI_BUSY; scsi_do_req (SRpnt, (void *) cmnd, buffer, bufflen, scsi_wait_done, timeout, retries); generic_unplug_device(q); wait_for_completion(&wait); - SRpnt->sr_request.waiting = NULL; + SRpnt->sr_request->waiting = NULL; if( SRpnt->sr_command != NULL ) { scsi_release_command(SRpnt->sr_command); @@ -928,8 +936,7 @@ void scsi_init_cmd_from_req(Scsi_Cmnd * SCpnt, Scsi_Request * SRpnt) SCpnt->cmd_len = SRpnt->sr_cmd_len; SCpnt->use_sg = SRpnt->sr_use_sg; - memcpy((void *) &SCpnt->request, (const void *) &SRpnt->sr_request, - sizeof(SRpnt->sr_request)); + SCpnt->request = SRpnt->sr_request; memcpy((void *) SCpnt->data_cmnd, (const void *) SRpnt->sr_cmnd, sizeof(SCpnt->data_cmnd)); SCpnt->reset_chain = NULL; @@ -1089,37 +1096,29 @@ void scsi_do_cmd(Scsi_Cmnd * SCpnt, const void *cmnd, SCSI_LOG_MLQUEUE(3, printk("Leaving scsi_do_cmd()\n")); } -void scsi_tasklet_func(unsigned long); -static DECLARE_TASKLET(scsi_tasklet, scsi_tasklet_func, 0); - -/* +/** + * scsi_done - Mark this command as done + * @SCpnt: The SCSI Command which we think we've completed. + * * This function is the mid-level interrupt routine, which decides how - * to handle error conditions. Each invocation of this function must - * do one and *only* one of the following: + * to handle error conditions. Each invocation of this function must + * do one and *only* one of the following: * * 1) Insert command in BH queue. * 2) Activate error handler for host. * - * FIXME(eric) - I am concerned about stack overflow (still). An - * interrupt could come while we are processing the bottom queue, - * which would cause another command to be stuffed onto the bottom - * queue, and it would in turn be processed as that interrupt handler - * is returning. Given a sufficiently steady rate of returning - * commands, this could cause the stack to overflow. I am not sure - * what is the most appropriate solution here - we should probably - * keep a depth count, and not process any commands while we still - * have a bottom handler active higher in the stack. - * - * There is currently code in the bottom half handler to monitor - * recursion in the bottom handler and report if it ever happens. If - * this becomes a problem, it won't be hard to engineer something to - * deal with it so that only the outer layer ever does any real - * processing. + * There is no longer a problem with stack overflow. Interrupts queue + * Scsi_Cmnd on a per-CPU queue and the softirq handler removes them + * from the queue one at a time. + * + * This function is sometimes called from interrupt context, but sometimes + * from task context. */ void scsi_done(Scsi_Cmnd * SCpnt) { unsigned long flags; - int tstatus; + int cpu, tstatus; + struct softscsi_data *queue; /* * We don't have to worry about this one timing out any more. @@ -1155,7 +1154,6 @@ void scsi_done(Scsi_Cmnd * SCpnt) SCSI_LOG_MLCOMPLETE(1, printk("Ignoring completion of %p due to timeout status", SCpnt)); return; } - spin_lock_irqsave(&scsi_bhqueue_lock, flags); SCpnt->serial_number_at_timeout = 0; SCpnt->state = SCSI_STATE_BHQUEUE; @@ -1163,75 +1161,49 @@ void scsi_done(Scsi_Cmnd * SCpnt) SCpnt->bh_next = NULL; /* - * 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) + * Next, put this command in the softirq queue. * - * This may be true at the moment, but I would like to wean all of the low - * level drivers away from using io_request_lock. Technically they should - * all use their own locking. I am adding a small spinlock to protect - * this datastructure to make it safe for that day. (ERY) + * This is a per-CPU queue, so we just disable local interrupts + * and need no spinlock. */ - if (!scsi_bh_queue_head) { - scsi_bh_queue_head = SCpnt; - scsi_bh_queue_tail = SCpnt; + + local_irq_save(flags); + + cpu = smp_processor_id(); + queue = &softscsi_data[cpu]; + + if (!queue->head) { + queue->head = SCpnt; + queue->tail = SCpnt; } else { - scsi_bh_queue_tail->bh_next = SCpnt; - scsi_bh_queue_tail = SCpnt; + queue->tail->bh_next = SCpnt; + queue->tail = SCpnt; } - spin_unlock_irqrestore(&scsi_bhqueue_lock, flags); - /* - * Mark the bottom half handler to be run. - */ - tasklet_hi_schedule(&scsi_tasklet); + cpu_raise_softirq(cpu, SCSI_SOFTIRQ); + + local_irq_restore(flags); } -/* - * Procedure: scsi_bottom_half_handler - * - * Purpose: Called after we have finished processing interrupts, it - * performs post-interrupt handling for commands that may - * have completed. - * - * 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) - * - * I believe I have corrected this. We simply monitor the return status of - * del_timer() - if this comes back as 0, it means that the timer has fired - * and that a timeout is in progress. I have modified scsi_done() such - * that in this instance the command is never inserted in the bottom - * half queue. Thus the only time we hold the lock here is when - * we wish to atomically remove the contents of the queue. +/** + * scsi_softirq - Perform post-interrupt handling for completed commands + * + * This is called with all interrupts enabled. This should reduce + * interrupt latency, stack depth, and reentrancy of the low-level + * drivers. */ -void scsi_tasklet_func(unsigned long ignore) +static void scsi_softirq(struct softirq_action *h) { - Scsi_Cmnd *SCpnt; - Scsi_Cmnd *SCnext; - unsigned long flags; + int cpu = smp_processor_id(); + struct softscsi_data *queue = &softscsi_data[cpu]; + while (queue->head) { + Scsi_Cmnd *SCpnt, *SCnext; - while (1 == 1) { - spin_lock_irqsave(&scsi_bhqueue_lock, flags); - SCpnt = scsi_bh_queue_head; - scsi_bh_queue_head = NULL; - spin_unlock_irqrestore(&scsi_bhqueue_lock, flags); - - if (SCpnt == NULL) { - return; - } - SCnext = SCpnt->bh_next; + local_irq_disable(); + SCpnt = queue->head; + queue->head = NULL; + local_irq_enable(); for (; SCpnt; SCpnt = SCnext) { SCnext = SCpnt->bh_next; @@ -1249,10 +1221,11 @@ void scsi_tasklet_func(unsigned long ignore) break; case NEEDS_RETRY: /* - * We only come in here if we want to retry a command. The - * test to see whether the command should be retried should be - * keeping track of the number of tries, so we don't end up looping, - * of course. + * We only come in here if we want to retry a + * command. The test to see whether the + * command should be retried should be keeping + * track of the number of tries, so we don't + * end up looping, of course. */ SCSI_LOG_MLCOMPLETE(3, printk("Command needs retry %d %d 0x%x\n", SCpnt->host->host_busy, SCpnt->host->host_failed, SCpnt->result)); @@ -1261,12 +1234,14 @@ void scsi_tasklet_func(unsigned long ignore) break; case ADD_TO_MLQUEUE: /* - * This typically happens for a QUEUE_FULL message - - * typically only when the queue depth is only - * approximate for a given device. Adding a command - * to the queue for the device will prevent further commands - * from being sent to the device, so we shouldn't end up - * with tons of things being sent down that shouldn't be. + * This typically happens for a QUEUE_FULL + * message - typically only when the queue + * depth is only approximate for a given + * device. Adding a command to the queue for + * the device will prevent further commands + * 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)); @@ -1274,8 +1249,8 @@ void scsi_tasklet_func(unsigned long ignore) break; default: /* - * Here we have a fatal error of some sort. Turn it over to - * the error handler. + * Here we have a fatal error of some sort. + * Turn it over to the error handler. */ SCSI_LOG_MLCOMPLETE(3, printk("Command failed %p %x active=%d busy=%d failed=%d\n", SCpnt, SCpnt->result, @@ -1295,8 +1270,10 @@ void scsi_tasklet_func(unsigned long ignore) SCpnt->state = SCSI_STATE_FAILED; SCpnt->host->in_recovery = 1; /* - * 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 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 (SCpnt->host->host_busy == SCpnt->host->host_failed) { SCSI_LOG_ERROR_RECOVERY(5, printk("Waking error handler thread (%d)\n", @@ -1305,15 +1282,14 @@ void scsi_tasklet_func(unsigned long ignore) } } else { /* - * We only get here if the error recovery thread has died. + * We only get here if the error + * recovery thread has died. */ scsi_finish_command(SCpnt); } - } + } /* switch */ } /* for(; SCpnt...) */ - - } /* while(1==1) */ - + } /* while(queue->head) */ } /* @@ -1490,7 +1466,7 @@ void scsi_build_commandblocks(Scsi_Device * SDpnt) SCpnt->target = SDpnt->id; SCpnt->lun = SDpnt->lun; SCpnt->channel = SDpnt->channel; - SCpnt->request.rq_status = RQ_INACTIVE; + SCpnt->request = NULL; SCpnt->use_sg = 0; SCpnt->old_use_sg = 0; SCpnt->old_cmd_len = 0; @@ -1942,6 +1918,11 @@ int scsi_register_host(Scsi_Host_Template * tpnt) } printk(KERN_INFO "scsi%d : %s\n", /* And print a little message */ shpnt->host_no, name); + strncpy(shpnt->host_driverfs_dev.name,name, + DEVICE_NAME_SIZE-1); + sprintf(shpnt->host_driverfs_dev.bus_id, + "scsi%d", + shpnt->host_no); } } @@ -1950,6 +1931,8 @@ int scsi_register_host(Scsi_Host_Template * tpnt) */ for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) { if (shpnt->hostt == tpnt) { + /* first register parent with driverfs */ + device_register(&shpnt->host_driverfs_dev); scan_scsis(shpnt, 0, 0, 0, 0); if (shpnt->select_queue_depths != NULL) { (shpnt->select_queue_depths) (shpnt, shpnt->host_queue); @@ -2062,16 +2045,16 @@ int scsi_unregister_host(Scsi_Host_Template * tpnt) SCpnt = SCpnt->next) { online_status = SDpnt->online; SDpnt->online = FALSE; - if (SCpnt->request.rq_status != RQ_INACTIVE) { + if (SCpnt->request && SCpnt->request->rq_status != RQ_INACTIVE) { printk(KERN_ERR "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->request->rq_status, SCpnt->target, SCpnt->pid, SCpnt->state, SCpnt->owner); for (SDpnt1 = shpnt->host_queue; SDpnt1; SDpnt1 = SDpnt1->next) { for (SCpnt = SDpnt1->device_queue; SCpnt; SCpnt = SCpnt->next) - if (SCpnt->request.rq_status == RQ_SCSI_DISCONNECTING) - SCpnt->request.rq_status = RQ_INACTIVE; + if (SCpnt->request->rq_status == RQ_SCSI_DISCONNECTING) + SCpnt->request->rq_status = RQ_INACTIVE; } SDpnt->online = online_status; printk(KERN_ERR "Device busy???\n"); @@ -2082,7 +2065,8 @@ int scsi_unregister_host(Scsi_Host_Template * tpnt) * continue on. */ SCpnt->state = SCSI_STATE_DISCONNECTING; - SCpnt->request.rq_status = RQ_SCSI_DISCONNECTING; /* Mark as busy */ + if(SCpnt->request) + SCpnt->request->rq_status = RQ_SCSI_DISCONNECTING; /* Mark as busy */ } } } @@ -2104,6 +2088,7 @@ int scsi_unregister_host(Scsi_Host_Template * tpnt) goto err_out; } devfs_unregister (SDpnt->de); + put_device(&SDpnt->sdev_driverfs_dev); } } @@ -2154,6 +2139,7 @@ int scsi_unregister_host(Scsi_Host_Template * tpnt) /* Remove the /proc/scsi directory entry */ sprintf(name,"%d",shpnt->host_no); remove_proc_entry(name, tpnt->proc_dir); + put_device(&shpnt->host_driverfs_dev); if (tpnt->release) (*tpnt->release) (shpnt); else { @@ -2392,11 +2378,11 @@ static void scsi_dump_status(int level) SCpnt->target, SCpnt->lun, - kdevname(SCpnt->request.rq_dev), - SCpnt->request.sector, - SCpnt->request.nr_sectors, - (long)SCpnt->request.current_nr_sectors, - SCpnt->request.rq_status, + kdevname(SCpnt->request->rq_dev), + SCpnt->request->sector, + SCpnt->request->nr_sectors, + (long)SCpnt->request->current_nr_sectors, + SCpnt->request->rq_status, SCpnt->use_sg, SCpnt->retries, @@ -2502,6 +2488,34 @@ void scsi_free_sgtable(struct scatterlist *sgl, int index) mempool_free(sgl, sgp->pool); } +static int scsi_bus_match(struct device *scsi_driverfs_dev, + struct device_driver *scsi_driverfs_drv) +{ + char *p=0; + + if (!strcmp("sd", scsi_driverfs_drv->name)) { + if ((p = strstr(scsi_driverfs_dev->bus_id, ":disc")) || + (p = strstr(scsi_driverfs_dev->bus_id, ":p"))) { + return 1; + } + } else if (!strcmp("sg", scsi_driverfs_drv->name)) { + if (strstr(scsi_driverfs_dev->bus_id, ":gen")) + return 1; + } else if (!strcmp("sr",scsi_driverfs_drv->name)) { + if (strstr(scsi_driverfs_dev->bus_id,":cd")) + return 1; + } else if (!strcmp("st",scsi_driverfs_drv->name)) { + if (strstr(scsi_driverfs_dev->bus_id,":mt")) + return 1; + } + return 0; +} + +struct bus_type scsi_driverfs_bus_type = { + name: "scsi", + match: scsi_bus_match, +}; + static int __init init_scsi(void) { struct proc_dir_entry *generic; @@ -2548,6 +2562,11 @@ static int __init init_scsi(void) printk(KERN_INFO "scsi: host order: %s\n", scsihosts); scsi_host_no_init (scsihosts); + bus_register(&scsi_driverfs_bus_type); + + /* Where we handle work queued by scsi_done */ + open_softirq(SCSI_SOFTIRQ, scsi_softirq, NULL); + return 0; } @@ -2556,8 +2575,6 @@ static void __exit exit_scsi(void) Scsi_Host_Name *shn, *shn2 = NULL; int i; - tasklet_kill(&scsi_tasklet); - devfs_unregister (scsi_devfs_handle); for (shn = scsi_host_no_list;shn;shn = shn->next) { if (shn->name) @@ -2708,16 +2725,18 @@ int scsi_reset_provider(Scsi_Device *dev, int flag) { Scsi_Cmnd SC, *SCpnt = &SC; + struct request req; int rtn; + SCpnt->request = &req; memset(&SCpnt->eh_timeout, 0, sizeof(SCpnt->eh_timeout)); SCpnt->host = dev->host; SCpnt->device = dev; SCpnt->target = dev->id; SCpnt->lun = dev->lun; SCpnt->channel = dev->channel; - SCpnt->request.rq_status = RQ_SCSI_BUSY; - SCpnt->request.waiting = NULL; + SCpnt->request->rq_status = RQ_SCSI_BUSY; + SCpnt->request->waiting = NULL; SCpnt->use_sg = 0; SCpnt->old_use_sg = 0; SCpnt->old_cmd_len = 0; diff --git a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h index cd1df44e19a6..6170d763e2aa 100644 --- a/drivers/scsi/scsi.h +++ b/drivers/scsi/scsi.h @@ -417,6 +417,8 @@ extern unsigned int scsi_need_isa_buffer; /* True if some devices need indirecti extern volatile int in_scan_scsis; extern const unsigned char scsi_command_size[8]; +extern struct bus_type scsi_driverfs_bus_type; + /* * These are the error handling functions defined in scsi_error.c @@ -566,6 +568,7 @@ struct scsi_device { atomic_t device_active; /* commands checked out for device */ volatile unsigned short device_busy; /* commands actually active on low-level */ Scsi_Cmnd *device_queue; /* queue of SCSI Command structures */ + Scsi_Cmnd *current_cmnd; /* currently active command */ unsigned int id, lun, channel; @@ -622,6 +625,7 @@ struct scsi_device { // Flag to allow revalidate to succeed in sd_open int allow_revalidate; + struct device sdev_driverfs_dev; }; @@ -662,7 +666,7 @@ struct scsi_request { struct Scsi_Host *sr_host; Scsi_Device *sr_device; Scsi_Cmnd *sr_command; - struct request sr_request; /* A copy of the command we are + struct request *sr_request; /* A copy of the command we are working on */ unsigned sr_bufflen; /* Size of data buffer */ void *sr_buffer; /* Data buffer */ @@ -773,8 +777,8 @@ struct scsi_cmnd { transferred less actual number transferred (0 if not supported) */ - struct request request; /* A copy of the command we are - working on */ + struct request *request; /* The command we are + working on */ unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE]; /* obtained by REQUEST SENSE * when CHECK CONDITION is @@ -856,4 +860,87 @@ struct scsi_cmnd { extern int scsi_reset_provider(Scsi_Device *, int); +/** + * scsi_activate_tcq - turn on tag command queueing + * @SDpnt: device to turn on TCQ for + * @depth: queue depth + * + * Notes: + * Eventually, I hope depth would be the maximum depth + * the device could cope with and the real queue depth + * would be adjustable from 0 to depth. + **/ +static inline void scsi_activate_tcq(Scsi_Device *SDpnt, int depth) { + request_queue_t *q = &SDpnt->request_queue; + + if(SDpnt->tagged_supported && !blk_queue_tagged(q)) { + blk_queue_init_tags(q, depth); + SDpnt->tagged_queue = 1; + } +} + +/** + * scsi_deactivate_tcq - turn off tag command queueing + * @SDpnt: device to turn off TCQ for + **/ +static inline void scsi_deactivate_tcq(Scsi_Device *SDpnt) { + blk_queue_free_tags(&SDpnt->request_queue); + SDpnt->tagged_queue = 0; +} +#define MSG_SIMPLE_TAG 0x20 +#define MSG_HEAD_TAG 0x21 +#define MSG_ORDERED_TAG 0x22 + +#define SCSI_NO_TAG (-1) /* identify no tag in use */ + +/** + * scsi_populate_tag_msg - place a tag message in a buffer + * @SCpnt: pointer to the Scsi_Cmnd for the tag + * @msg: pointer to the area to place the tag + * + * Notes: + * designed to create the correct type of tag message for the + * particular request. Returns the size of the tag message. + * May return 0 if TCQ is disabled for this device. + **/ +static inline int scsi_populate_tag_msg(Scsi_Cmnd *SCpnt, char *msg) { + struct request *req = SCpnt->request; + + if(!blk_rq_tagged(req)) + return 0; + + if(req->flags & REQ_BARRIER) + *msg++ = MSG_ORDERED_TAG; + else + *msg++ = MSG_SIMPLE_TAG; + + *msg++ = SCpnt->request->tag; + + return 2; +} + +/** + * scsi_find_tag - find a tagged command by device + * @SDpnt: pointer to the ScSI device + * @tag: the tag number + * + * Notes: + * Only works with tags allocated by the generic blk layer. + **/ +static inline Scsi_Cmnd *scsi_find_tag(Scsi_Device *SDpnt, int tag) { + + struct request *req; + + if(tag == SCSI_NO_TAG) + /* single command, look in space */ + return SDpnt->current_cmnd; + + req = blk_queue_find_tag(&SDpnt->request_queue, tag); + + if(req == NULL) + return NULL; + + return (Scsi_Cmnd *)req->special; +} + #endif diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 328875a71815..058688349f5d 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -694,7 +694,7 @@ static int scsi_debug_read(Scsi_Cmnd * SCpnt, int upper_blk, int block, { int delay = SCSI_SETUP_LATENCY; - delay += SCpnt->request.nr_sectors * SCSI_DATARATE; + delay += SCpnt->request->nr_sectors * SCSI_DATARATE; if (delay) usleep(delay); } diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 311f4a6fd149..11d9307d20f0 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -319,7 +319,7 @@ void scsi_eh_done(Scsi_Cmnd * SCpnt) return; } - SCpnt->request.rq_status = RQ_SCSI_DONE; + SCpnt->request->rq_status = RQ_SCSI_DONE; SCpnt->owner = SCSI_OWNER_ERROR_HANDLER; SCpnt->eh_state = SUCCESS; @@ -346,7 +346,7 @@ void scsi_eh_done(Scsi_Cmnd * SCpnt) STATIC void scsi_eh_action_done(Scsi_Cmnd * SCpnt, int answer) { - SCpnt->request.rq_status = RQ_SCSI_DONE; + SCpnt->request->rq_status = RQ_SCSI_DONE; SCpnt->owner = SCSI_OWNER_ERROR_HANDLER; SCpnt->eh_state = (answer ? SUCCESS : FAILED); @@ -601,7 +601,7 @@ retry: * Set up the semaphore so we wait for the command to complete. */ SCpnt->host->eh_action = &sem; - SCpnt->request.rq_status = RQ_SCSI_BUSY; + SCpnt->request->rq_status = RQ_SCSI_BUSY; spin_lock_irqsave(SCpnt->host->host_lock, flags); host->hostt->queuecommand(SCpnt, scsi_eh_done); @@ -633,7 +633,7 @@ retry: SCpnt->host->hostt->eh_abort_handler(SCpnt); spin_unlock_irqrestore(SCpnt->host->host_lock, flags); - SCpnt->request.rq_status = RQ_SCSI_DONE; + SCpnt->request->rq_status = RQ_SCSI_DONE; SCpnt->owner = SCSI_OWNER_ERROR_HANDLER; SCpnt->eh_state = FAILED; diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index bede96547efb..5fbe664e65ea 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -76,12 +76,10 @@ static void __scsi_insert_special(request_queue_t *q, struct request *rq, * must not attempt merges on this) and that it acts as a soft * barrier */ - rq->flags = REQ_SPECIAL | REQ_BARRIER; + rq->flags &= REQ_QUEUED; + rq->flags |= REQ_SPECIAL | REQ_BARRIER; rq->special = data; - rq->q = NULL; - rq->bio = rq->biotail = NULL; - rq->nr_phys_segments = 0; /* * We have the option of inserting the head or the tail of the queue. @@ -90,6 +88,9 @@ static void __scsi_insert_special(request_queue_t *q, struct request *rq, * device, or a host that is unable to accept a particular command. */ spin_lock_irqsave(q->queue_lock, flags); + /* If command is tagged, release the tag */ + if(blk_rq_tagged(rq)) + blk_queue_end_tag(q, rq); _elv_add_request(q, rq, !at_head, 0); q->request_fn(q); spin_unlock_irqrestore(q->queue_lock, flags); @@ -120,7 +121,7 @@ int scsi_insert_special_cmd(Scsi_Cmnd * SCpnt, int at_head) { request_queue_t *q = &SCpnt->device->request_queue; - __scsi_insert_special(q, &SCpnt->request, SCpnt, at_head); + __scsi_insert_special(q, SCpnt->request, SCpnt, at_head); return 0; } @@ -148,7 +149,7 @@ int scsi_insert_special_req(Scsi_Request * SRpnt, int at_head) { request_queue_t *q = &SRpnt->sr_device->request_queue; - __scsi_insert_special(q, &SRpnt->sr_request, SRpnt, at_head); + __scsi_insert_special(q, SRpnt->sr_request, SRpnt, at_head); return 0; } @@ -259,8 +260,10 @@ void scsi_queue_next_request(request_queue_t * q, Scsi_Cmnd * SCpnt) * in which case we need to request the blocks that come after * the bad sector. */ - SCpnt->request.special = (void *) SCpnt; - _elv_add_request(q, &SCpnt->request, 0, 0); + SCpnt->request->special = (void *) SCpnt; + if(blk_rq_tagged(SCpnt->request)) + blk_queue_end_tag(q, SCpnt->request); + _elv_add_request(q, SCpnt->request, 0, 0); } /* @@ -356,15 +359,18 @@ static Scsi_Cmnd *__scsi_end_request(Scsi_Cmnd * SCpnt, int frequeue) { request_queue_t *q = &SCpnt->device->request_queue; - struct request *req = &SCpnt->request; + struct request *req = SCpnt->request; + int flags; ASSERT_LOCK(q->queue_lock, 0); + spin_lock_irqsave(q->queue_lock, flags); /* * If there are blocks left over at the end, set up the command * to queue the remainder of them. */ if (end_that_request_first(req, uptodate, sectors)) { + spin_unlock_irqrestore(q->queue_lock, flags); if (!requeue) return SCpnt; @@ -376,15 +382,15 @@ static Scsi_Cmnd *__scsi_end_request(Scsi_Cmnd * SCpnt, return SCpnt; } - /* - * This request is done. If there is someone blocked waiting for this - * request, wake them up. - */ - if (req->waiting) - complete(req->waiting); - add_blkdev_randomness(major(req->rq_dev)); + if(blk_rq_tagged(req)) + blk_queue_end_tag(q, req); + + end_that_request_last(req); + + spin_unlock_irqrestore(q->queue_lock, flags); + /* * This will goose the queue request function at the end, so we don't * need to worry about launching another command. @@ -441,7 +447,7 @@ Scsi_Cmnd *scsi_end_request(Scsi_Cmnd * SCpnt, int uptodate, int sectors) */ static void scsi_release_buffers(Scsi_Cmnd * SCpnt) { - struct request *req = &SCpnt->request; + struct request *req = SCpnt->request; ASSERT_LOCK(SCpnt->host->host_lock, 0); @@ -491,7 +497,7 @@ void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors, int result = SCpnt->result; int this_count = SCpnt->bufflen >> 9; request_queue_t *q = &SCpnt->device->request_queue; - struct request *req = &SCpnt->request; + struct request *req = SCpnt->request; /* * We must do one of several things here: @@ -675,7 +681,7 @@ void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors, if (result) { struct Scsi_Device_Template *STpnt; - STpnt = scsi_get_request_dev(&SCpnt->request); + STpnt = scsi_get_request_dev(SCpnt->request); printk("SCSI %s error : host %d channel %d id %d lun %d return code = %x\n", (STpnt ? STpnt->name : "device"), SCpnt->device->host->host_no, @@ -868,7 +874,7 @@ void scsi_request_fn(request_queue_t * q) * the remainder of a partially fulfilled request that can * come up when there is a medium error. We have to treat * these two cases differently. We differentiate by looking - * at request.cmd, as this tells us the real story. + * at request->cmd, as this tells us the real story. */ if (req->flags & REQ_SPECIAL) { STpnt = NULL; @@ -904,6 +910,9 @@ void scsi_request_fn(request_queue_t * q) */ if (!SCpnt) break; + + /* pull a tag out of the request if we have one */ + SCpnt->tag = req->tag; } else { blk_dump_rq_flags(req, "SCSI bad req"); break; @@ -924,18 +933,15 @@ void scsi_request_fn(request_queue_t * q) * reason to search the list, because all of the commands * in this queue are for the same device. */ - blkdev_dequeue_request(req); + if(!(blk_queue_tagged(q) && (blk_queue_start_tag(q, req) == 0))) + blkdev_dequeue_request(req); - if (req != &SCpnt->request && req != &SRpnt->sr_request ) { - memcpy(&SCpnt->request, req, sizeof(struct request)); + /* note the overloading of req->special. When the tag + * is active it always means SCpnt. If the tag goes + * back for re-queueing, it may be reset */ + req->special = SCpnt; + SCpnt->request = req; - /* - * We have copied the data out of the request block - - * it is now in a field in SCpnt. Release the request - * block. - */ - blkdev_release_request(req); - } /* * Now it is finally safe to release the lock. We are * not going to noodle the request list until this @@ -945,7 +951,7 @@ void scsi_request_fn(request_queue_t * q) req = NULL; spin_unlock_irq(q->queue_lock); - if (SCpnt->request.flags & REQ_CMD) { + if (SCpnt->request->flags & REQ_CMD) { /* * This will do a couple of things: * 1) Fill in the actual SCSI command. @@ -959,7 +965,7 @@ void scsi_request_fn(request_queue_t * q) * request to be rejected immediately. */ if (STpnt == NULL) - STpnt = scsi_get_request_dev(&SCpnt->request); + STpnt = scsi_get_request_dev(SCpnt->request); /* * This sets up the scatter-gather table (allocating if @@ -973,9 +979,11 @@ void scsi_request_fn(request_queue_t * q) SDpnt->starved = 1; SHpnt->some_device_starved = 1; } - SCpnt->request.special = SCpnt; - SCpnt->request.flags |= REQ_SPECIAL; - _elv_add_request(q, &SCpnt->request, 0, 0); + SCpnt->request->special = SCpnt; + SCpnt->request->flags |= REQ_SPECIAL; + if(blk_rq_tagged(SCpnt->request)) + blk_queue_end_tag(q, SCpnt->request); + _elv_add_request(q, SCpnt->request, 0, 0); break; } @@ -985,7 +993,7 @@ void scsi_request_fn(request_queue_t * q) if (!STpnt->init_command(SCpnt)) { scsi_release_buffers(SCpnt); SCpnt = __scsi_end_request(SCpnt, 0, - SCpnt->request.nr_sectors, 0, 0); + SCpnt->request->nr_sectors, 0, 0); if( SCpnt != NULL ) { panic("Should not have leftover blocks\n"); diff --git a/drivers/scsi/scsi_merge.c b/drivers/scsi/scsi_merge.c index 82c3a17235bc..b29b763bd38a 100644 --- a/drivers/scsi/scsi_merge.c +++ b/drivers/scsi/scsi_merge.c @@ -57,7 +57,7 @@ */ int scsi_init_io(Scsi_Cmnd *SCpnt) { - struct request *req = &SCpnt->request; + struct request *req = SCpnt->request; struct scatterlist *sgpnt; int count, gfp_mask; diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index bf046d01f433..3a2b1fcbf760 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -54,6 +54,7 @@ static void scan_scsis_target(unsigned int channel, unsigned int dev, char *scsi_result); static int find_lun0_scsi_level(unsigned int channel, unsigned int dev, struct Scsi_Host *shpnt); +static void scsi_load_identifier(Scsi_Device *SDpnt, Scsi_Request * SRpnt); struct dev_info { const char *vendor; @@ -288,6 +289,31 @@ static int scsilun_to_int(ScsiLun *scsilun_pnt) } #endif +/* Driverfs file content handlers */ +static ssize_t scsi_device_type_read(struct device *driverfs_dev, char *page, + size_t count, loff_t off) +{ + struct scsi_device *SDpnt = list_entry(driverfs_dev, + struct scsi_device, sdev_driverfs_dev); + + if ((SDpnt->type <= MAX_SCSI_DEVICE_CODE) && + (scsi_device_types[(int)SDpnt->type] != NULL)) + return off ? 0 : + sprintf(page, "%s\n", + scsi_device_types[(int)SDpnt->type]); + else + return off ? 0 : sprintf(page, "UNKNOWN\n"); + + return 0; +} + +static struct driver_file_entry scsi_device_type_file = { + name: "type", + mode: S_IRUGO, + show: scsi_device_type_read, +}; +/* end content handlers */ + static void print_inquiry(unsigned char *data) { int i; @@ -786,6 +812,22 @@ static int scan_scsis_single(unsigned int channel, unsigned int dev, print_inquiry(scsi_result); + /* interrogate scsi target to provide device identifier */ + scsi_load_identifier(SDpnt, SRpnt); + + /* create driverfs files */ + sprintf(SDpnt->sdev_driverfs_dev.bus_id,"%d:%d:%d:%d", + SDpnt->host->host_no, SDpnt->channel, SDpnt->id, SDpnt->lun); + + SDpnt->sdev_driverfs_dev.parent = &SDpnt->host->host_driverfs_dev; + SDpnt->sdev_driverfs_dev.bus = &scsi_driverfs_bus_type; + + device_register(&SDpnt->sdev_driverfs_dev); + + /* Create driverfs file entries */ + device_create_file(&SDpnt->sdev_driverfs_dev, + &scsi_device_type_file); + sprintf (devname, "host%d/bus%d/target%d/lun%d", SDpnt->host->host_no, SDpnt->channel, SDpnt->id, SDpnt->lun); if (SDpnt->de) printk ("DEBUG: dir: \"%s\" already exists\n", devname); @@ -1306,3 +1348,374 @@ static int find_lun0_scsi_level(unsigned int channel, unsigned int dev, /* haven't found lun0, should send INQUIRY but take easy route */ return res; } + +#define SCSI_UID_DEV_ID 'U' +#define SCSI_UID_SER_NUM 'S' +#define SCSI_UID_UNKNOWN 'Z' + +unsigned char *scsi_get_evpd_page(Scsi_Device *SDpnt, Scsi_Request * SRpnt) +{ + unsigned char *evpd_page = NULL; + unsigned char *scsi_cmd = NULL; + int lun = SDpnt->lun; + int scsi_level = SDpnt->scsi_level; + + evpd_page = kmalloc(255, + (SDpnt->host->unchecked_isa_dma ? GFP_DMA : GFP_ATOMIC)); + if (!evpd_page) + return NULL; + + scsi_cmd = kmalloc(MAX_COMMAND_SIZE, GFP_ATOMIC); + if (!scsi_cmd) { + kfree(evpd_page); + return NULL; + } + + /* Use vital product pages to determine serial number */ + /* Try Supported vital product data pages 0x00 first */ + scsi_cmd[0] = INQUIRY; + if ((lun > 0) && (scsi_level <= SCSI_2)) + scsi_cmd[1] = ((lun << 5) & 0xe0) | 0x01; + else + scsi_cmd[1] = 0x01; /* SCSI_3 and higher, don't touch */ + scsi_cmd[2] = 0x00; + scsi_cmd[3] = 0; + scsi_cmd[4] = 255; + scsi_cmd[5] = 0; + SRpnt->sr_cmd_len = 0; + SRpnt->sr_sense_buffer[0] = 0; + SRpnt->sr_sense_buffer[2] = 0; + SRpnt->sr_data_direction = SCSI_DATA_READ; + scsi_wait_req(SRpnt, (void *) scsi_cmd, (void *) evpd_page, + 255, SCSI_TIMEOUT+4*HZ, 3); + + if (SRpnt->sr_result) { + kfree(scsi_cmd); + kfree(evpd_page); + return NULL; + } + + /* check to see if response was truncated */ + if (evpd_page[3] > 255) { + int max_lgth = evpd_page[3] + 4; + + kfree(evpd_page); + evpd_page = kmalloc(max_lgth, (SDpnt->host->unchecked_isa_dma ? + GFP_DMA : GFP_ATOMIC)); + if (!evpd_page) { + kfree(scsi_cmd); + return NULL; + } + memset(scsi_cmd, 0, MAX_COMMAND_SIZE); + scsi_cmd[0] = INQUIRY; + if ((lun > 0) && (scsi_level <= SCSI_2)) + scsi_cmd[1] = ((lun << 5) & 0xe0) | 0x01; + else + scsi_cmd[1] = 0x01; /* SCSI_3 and higher, don't touch */ + scsi_cmd[2] = 0x00; + scsi_cmd[3] = 0; + scsi_cmd[4] = max_lgth; + scsi_cmd[5] = 0; + SRpnt->sr_cmd_len = 0; + SRpnt->sr_sense_buffer[0] = 0; + SRpnt->sr_sense_buffer[2] = 0; + SRpnt->sr_data_direction = SCSI_DATA_READ; + scsi_wait_req(SRpnt, (void *) scsi_cmd, (void *) evpd_page, + max_lgth, SCSI_TIMEOUT+4*HZ, 3); + if (SRpnt->sr_result) { + kfree(scsi_cmd); + kfree(evpd_page); + return NULL; + } + } + kfree(scsi_cmd); + /* some ill behaved devices return the std inquiry here rather than + the evpd data. snoop the data to verify */ + if (evpd_page[3] > 16) { + /* if vend id appears in the evpd page assume evpd is invalid */ + if (!strncmp(&evpd_page[8], SDpnt->vendor, 8)) { + kfree(evpd_page); + return NULL; + } + } + return evpd_page; +} + +int scsi_get_deviceid(Scsi_Device *SDpnt,Scsi_Request * SRpnt) +{ + unsigned char *id_page = NULL; + unsigned char *scsi_cmd = NULL; + int scnt, i, j, idtype; + char * id = SDpnt->sdev_driverfs_dev.name; + int lun = SDpnt->lun; + int scsi_level = SDpnt->scsi_level; + + id_page = kmalloc(255, + (SDpnt->host->unchecked_isa_dma ? GFP_DMA : GFP_ATOMIC)); + if (!id_page) + return 0; + + scsi_cmd = kmalloc(MAX_COMMAND_SIZE, GFP_ATOMIC); + if (!scsi_cmd) + goto leave; + + /* Use vital product pages to determine serial number */ + /* Try Supported vital product data pages 0x00 first */ + scsi_cmd[0] = INQUIRY; + if ((lun > 0) && (scsi_level <= SCSI_2)) + scsi_cmd[1] = ((lun << 5) & 0xe0) | 0x01; + else + scsi_cmd[1] = 0x01; /* SCSI_3 and higher, don't touch */ + scsi_cmd[2] = 0x83; + scsi_cmd[3] = 0; + scsi_cmd[4] = 255; + scsi_cmd[5] = 0; + SRpnt->sr_cmd_len = 0; + SRpnt->sr_sense_buffer[0] = 0; + SRpnt->sr_sense_buffer[2] = 0; + SRpnt->sr_data_direction = SCSI_DATA_READ; + scsi_wait_req(SRpnt, (void *) scsi_cmd, (void *) id_page, + 255, SCSI_TIMEOUT+4*HZ, 3); + if (SRpnt->sr_result) { + kfree(scsi_cmd); + goto leave; + } + + /* check to see if response was truncated */ + if (id_page[3] > 255) { + int max_lgth = id_page[3] + 4; + + kfree(id_page); + id_page = kmalloc(max_lgth, + (SDpnt->host->unchecked_isa_dma ? + GFP_DMA : GFP_ATOMIC)); + if (!id_page) { + kfree(scsi_cmd); + return 0; + } + memset(scsi_cmd, 0, MAX_COMMAND_SIZE); + scsi_cmd[0] = INQUIRY; + if ((lun > 0) && (scsi_level <= SCSI_2)) + scsi_cmd[1] = ((lun << 5) & 0xe0) | 0x01; + else + scsi_cmd[1] = 0x01; /* SCSI_3 and higher, don't touch */ + scsi_cmd[2] = 0x83; + scsi_cmd[3] = 0; + scsi_cmd[4] = max_lgth; + scsi_cmd[5] = 0; + SRpnt->sr_cmd_len = 0; + SRpnt->sr_sense_buffer[0] = 0; + SRpnt->sr_sense_buffer[2] = 0; + SRpnt->sr_data_direction = SCSI_DATA_READ; + scsi_wait_req(SRpnt, (void *) scsi_cmd, (void *) id_page, + max_lgth, SCSI_TIMEOUT+4*HZ, 3); + if (SRpnt->sr_result) { + kfree(scsi_cmd); + goto leave; + } + } + kfree(scsi_cmd); + + idtype = 3; + while (idtype > 0) { + for(scnt = 4; scnt <= id_page[3] + 3; + scnt += id_page[scnt + 3] + 4) { + if ((id_page[scnt + 1] & 0x0f) != idtype) { + continue; + } + if ((id_page[scnt] & 0x0f) == 2) { + for(i = scnt + 4, j = 1; + i < scnt + 4 + id_page[scnt + 3]; + i++) { + if (id_page[i] > 0x20) { + if (j == DEVICE_NAME_SIZE) { + memset(id, 0, + DEVICE_NAME_SIZE); + break; + } + id[j++] = id_page[i]; + } + } + } else if ((id_page[scnt] & 0x0f) == 1) { + static const char hex_str[]="0123456789abcdef"; + for(i = scnt + 4, j = 1; + i < scnt + 4 + id_page[scnt + 3]; + i++) { + if ((j + 1) == DEVICE_NAME_SIZE) { + memset(id, 0, DEVICE_NAME_SIZE); + break; + } + id[j++] = hex_str[(id_page[i] & 0xf0) >> + 4]; + id[j++] = hex_str[id_page[i] & 0x0f]; + } + } + if (id[1] != 0) goto leave; + } + idtype--; + } + leave: + kfree(id_page); + if (id[1] != 0) { + id[0] = SCSI_UID_DEV_ID; + return 1; + } + return 0; +} + +int scsi_get_serialnumber(Scsi_Device *SDpnt, Scsi_Request * SRpnt) +{ + unsigned char *serialnumber_page = NULL; + unsigned char *scsi_cmd = NULL; + int lun = SDpnt->lun; + int scsi_level = SDpnt->scsi_level; + int i, j; + + serialnumber_page = kmalloc(255, (SDpnt->host->unchecked_isa_dma ? + GFP_DMA : GFP_ATOMIC)); + if (!serialnumber_page) + return 0; + + scsi_cmd = kmalloc(MAX_COMMAND_SIZE, GFP_ATOMIC); + if (!scsi_cmd) + goto leave; + + /* Use vital product pages to determine serial number */ + /* Try Supported vital product data pages 0x00 first */ + scsi_cmd[0] = INQUIRY; + if ((lun > 0) && (scsi_level <= SCSI_2)) + scsi_cmd[1] = ((lun << 5) & 0xe0) | 0x01; + else + scsi_cmd[1] = 0x01; /* SCSI_3 and higher, don't touch */ + scsi_cmd[2] = 0x80; + scsi_cmd[3] = 0; + scsi_cmd[4] = 255; + scsi_cmd[5] = 0; + SRpnt->sr_cmd_len = 0; + SRpnt->sr_sense_buffer[0] = 0; + SRpnt->sr_sense_buffer[2] = 0; + SRpnt->sr_data_direction = SCSI_DATA_READ; + scsi_wait_req(SRpnt, (void *) scsi_cmd, (void *) serialnumber_page, + 255, SCSI_TIMEOUT+4*HZ, 3); + + if (SRpnt->sr_result) { + kfree(scsi_cmd); + goto leave; + } + /* check to see if response was truncated */ + if (serialnumber_page[3] > 255) { + int max_lgth = serialnumber_page[3] + 4; + + kfree(serialnumber_page); + serialnumber_page = kmalloc(max_lgth, + (SDpnt->host->unchecked_isa_dma ? + GFP_DMA : GFP_ATOMIC)); + if (!serialnumber_page) { + kfree(scsi_cmd); + return 0; + } + memset(scsi_cmd, 0, MAX_COMMAND_SIZE); + scsi_cmd[0] = INQUIRY; + if ((lun > 0) && (scsi_level <= SCSI_2)) + scsi_cmd[1] = ((lun << 5) & 0xe0) | 0x01; + else + scsi_cmd[1] = 0x01; /* SCSI_3 and higher, don't touch */ + scsi_cmd[2] = 0x80; + scsi_cmd[3] = 0; + scsi_cmd[4] = max_lgth; + scsi_cmd[5] = 0; + SRpnt->sr_cmd_len = 0; + SRpnt->sr_sense_buffer[0] = 0; + SRpnt->sr_sense_buffer[2] = 0; + SRpnt->sr_data_direction = SCSI_DATA_READ; + scsi_wait_req(SRpnt, (void *) scsi_cmd, + (void *) serialnumber_page, + max_lgth, SCSI_TIMEOUT+4*HZ, 3); + if (SRpnt->sr_result) { + kfree(scsi_cmd); + goto leave; + } + } + kfree(scsi_cmd); + + SDpnt->sdev_driverfs_dev.name[0] = SCSI_UID_SER_NUM; + for(i = 0, j = 1; i < serialnumber_page[3]; i++) { + if (serialnumber_page[4 + i] > 0x20) + SDpnt->sdev_driverfs_dev.name[j++] = + serialnumber_page[4 + i]; + } + for(i = 0, j = strlen(SDpnt->sdev_driverfs_dev.name); i < 8; i++) { + if (SDpnt->vendor[i] > 0x20) { + SDpnt->sdev_driverfs_dev.name[j++] = SDpnt->vendor[i]; + } + } + kfree(serialnumber_page); + return 1; + leave: + memset(SDpnt->sdev_driverfs_dev.name, 0, DEVICE_NAME_SIZE); + kfree(serialnumber_page); + return 0; +} + +int scsi_get_default_name(Scsi_Device *SDpnt) +{ + int i, j; + + SDpnt->sdev_driverfs_dev.name[0] = SCSI_UID_UNKNOWN; + for(i = 0, j = 1; i < 8; i++) { + if (SDpnt->vendor[i] > 0x20) { + SDpnt->sdev_driverfs_dev.name[j++] = + SDpnt->vendor[i]; + } + } + for(i = 0, j = strlen(SDpnt->sdev_driverfs_dev.name); + i < 16; i++) { + if (SDpnt->model[i] > 0x20) { + SDpnt->sdev_driverfs_dev.name[j++] = + SDpnt->model[i]; + } + } + for(i = 0, j = strlen(SDpnt->sdev_driverfs_dev.name); i < 4; i++) { + if (SDpnt->rev[i] > 0x20) { + SDpnt->sdev_driverfs_dev.name[j++] = SDpnt->rev[i]; + } + } + return 1; +} + + +static void scsi_load_identifier(Scsi_Device *SDpnt, Scsi_Request * SRpnt) +{ + unsigned char *evpd_page = NULL; + int cnt; + + memset(SDpnt->sdev_driverfs_dev.name, 0, DEVICE_NAME_SIZE); + evpd_page = scsi_get_evpd_page(SDpnt, SRpnt); + if (!evpd_page) { + /* try to obtain serial number anyway */ + if (!scsi_get_serialnumber(SDpnt, SRpnt)) + goto leave; + goto leave; + } + + for(cnt = 4; cnt <= evpd_page[3] + 3; cnt++) { + if (evpd_page[cnt] == 0x83) { + if (scsi_get_deviceid(SDpnt, SRpnt)) + goto leave; + } + } + + for(cnt = 4; cnt <= evpd_page[3] + 3; cnt++) { + if (evpd_page[cnt] == 0x80) { + if (scsi_get_serialnumber(SDpnt, SRpnt)) + goto leave; + } + } + +leave: + if (SDpnt->sdev_driverfs_dev.name[0] == 0) + scsi_get_default_name(SDpnt); + + if (evpd_page) kfree(evpd_page); + return; +} diff --git a/drivers/scsi/scsi_syms.c b/drivers/scsi/scsi_syms.c index fcc1dd92512c..20a06b1be288 100644 --- a/drivers/scsi/scsi_syms.c +++ b/drivers/scsi/scsi_syms.c @@ -101,3 +101,8 @@ extern void scsi_add_timer(Scsi_Cmnd *, int, void ((*) (Scsi_Cmnd *))); extern int scsi_delete_timer(Scsi_Cmnd *); EXPORT_SYMBOL(scsi_add_timer); EXPORT_SYMBOL(scsi_delete_timer); + +/* + * driverfs support for determining driver types + */ +EXPORT_SYMBOL(scsi_driverfs_bus_type); diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 63fe305e4342..fd92ed1924f1 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -129,6 +129,7 @@ static void sd_rw_intr(Scsi_Cmnd * SCpnt); static Scsi_Disk * sd_get_sdisk(int index); +extern void driverfs_remove_partitions(struct gendisk *hd, int minor); #if defined(CONFIG_PPC32) /** @@ -327,13 +328,13 @@ static int sd_init_command(Scsi_Cmnd * SCpnt) /* * don't support specials for nwo */ - if (!(SCpnt->request.flags & REQ_CMD)) + if (!(SCpnt->request->flags & REQ_CMD)) return 0; - part_nr = SD_PARTITION(SCpnt->request.rq_dev); - dsk_nr = DEVICE_NR(SCpnt->request.rq_dev); + part_nr = SD_PARTITION(SCpnt->request->rq_dev); + dsk_nr = DEVICE_NR(SCpnt->request->rq_dev); - block = SCpnt->request.sector; + block = SCpnt->request->sector; this_count = SCpnt->request_bufflen >> 9; SCSI_LOG_HLQUEUE(1, printk("sd_command_init: dsk_nr=%d, block=%d, " @@ -344,9 +345,9 @@ static int sd_init_command(Scsi_Cmnd * SCpnt) /* >>>>> this change is not in the lk 2.5 series */ if (part_nr >= (sd_template.dev_max << 4) || (part_nr & 0xf) || !sdp || !sdp->online || - block + SCpnt->request.nr_sectors > sd[part_nr].nr_sects) { + block + SCpnt->request->nr_sectors > sd[part_nr].nr_sects) { SCSI_LOG_HLQUEUE(2, printk("Finishing %ld sectors\n", - SCpnt->request.nr_sectors)); + SCpnt->request->nr_sectors)); SCSI_LOG_HLQUEUE(2, printk("Retry with 0x%p\n", SCpnt)); return 0; } @@ -375,7 +376,7 @@ static int sd_init_command(Scsi_Cmnd * SCpnt) * for this. */ if (sdp->sector_size == 1024) { - if ((block & 1) || (SCpnt->request.nr_sectors & 1)) { + if ((block & 1) || (SCpnt->request->nr_sectors & 1)) { printk(KERN_ERR "sd: Bad block number requested"); return 0; } else { @@ -384,7 +385,7 @@ static int sd_init_command(Scsi_Cmnd * SCpnt) } } if (sdp->sector_size == 2048) { - if ((block & 3) || (SCpnt->request.nr_sectors & 3)) { + if ((block & 3) || (SCpnt->request->nr_sectors & 3)) { printk(KERN_ERR "sd: Bad block number requested"); return 0; } else { @@ -393,7 +394,7 @@ static int sd_init_command(Scsi_Cmnd * SCpnt) } } if (sdp->sector_size == 4096) { - if ((block & 7) || (SCpnt->request.nr_sectors & 7)) { + if ((block & 7) || (SCpnt->request->nr_sectors & 7)) { printk(KERN_ERR "sd: Bad block number requested"); return 0; } else { @@ -401,25 +402,25 @@ static int sd_init_command(Scsi_Cmnd * SCpnt) this_count = this_count >> 3; } } - if (rq_data_dir(&SCpnt->request) == WRITE) { + if (rq_data_dir(SCpnt->request) == WRITE) { if (!sdp->writeable) { return 0; } SCpnt->cmnd[0] = WRITE_6; SCpnt->sc_data_direction = SCSI_DATA_WRITE; - } else if (rq_data_dir(&SCpnt->request) == READ) { + } else if (rq_data_dir(SCpnt->request) == READ) { SCpnt->cmnd[0] = READ_6; SCpnt->sc_data_direction = SCSI_DATA_READ; } else { printk(KERN_ERR "sd: Unknown command %lx\n", - SCpnt->request.flags); -/* overkill panic("Unknown sd command %lx\n", SCpnt->request.flags); */ + SCpnt->request->flags); +/* overkill panic("Unknown sd command %lx\n", SCpnt->request->flags); */ return 0; } SCSI_LOG_HLQUEUE(2, printk("%s : %s %d/%ld 512 byte blocks.\n", - nbuff, (rq_data_dir(&SCpnt->request) == WRITE) ? - "writing" : "reading", this_count, SCpnt->request.nr_sectors)); + nbuff, (rq_data_dir(SCpnt->request) == WRITE) ? + "writing" : "reading", this_count, SCpnt->request->nr_sectors)); SCpnt->cmnd[1] = (SCpnt->device->scsi_level <= SCSI_2) ? ((SCpnt->lun << 5) & 0xe0) : 0; @@ -664,7 +665,7 @@ static void sd_rw_intr(Scsi_Cmnd * SCpnt) #if CONFIG_SCSI_LOGGING char nbuff[6]; - SCSI_LOG_HLCOMPLETE(1, sd_dskname(DEVICE_NR(SCpnt->request.rq_dev), + SCSI_LOG_HLCOMPLETE(1, sd_dskname(DEVICE_NR(SCpnt->request->rq_dev), nbuff)); SCSI_LOG_HLCOMPLETE(1, printk("sd_rw_intr: %s: res=0x%x\n", nbuff, result)); @@ -690,8 +691,8 @@ static void sd_rw_intr(Scsi_Cmnd * SCpnt) (SCpnt->sense_buffer[4] << 16) | (SCpnt->sense_buffer[5] << 8) | SCpnt->sense_buffer[6]; - if (SCpnt->request.bio != NULL) - block_sectors = bio_sectors(SCpnt->request.bio); + if (SCpnt->request->bio != NULL) + block_sectors = bio_sectors(SCpnt->request->bio); switch (SCpnt->device->sector_size) { case 1024: error_sector <<= 1; @@ -716,7 +717,7 @@ static void sd_rw_intr(Scsi_Cmnd * SCpnt) } error_sector &= ~(block_sectors - 1); - good_sectors = error_sector - SCpnt->request.sector; + good_sectors = error_sector - SCpnt->request->sector; if (good_sectors < 0 || good_sectors >= this_count) good_sectors = 0; break; @@ -1277,12 +1278,15 @@ static int sd_init() init_mem_lth(sd_gendisks[k].de_arr, N); init_mem_lth(sd_gendisks[k].flags, N); + init_mem_lth(sd_gendisks[k].driverfs_dev_arr, N); - if (!sd_gendisks[k].de_arr || !sd_gendisks[k].flags) + if (!sd_gendisks[k].de_arr || !sd_gendisks[k].flags || + !sd_gendisks[k].driverfs_dev_arr) goto cleanup_gendisks; zero_mem_lth(sd_gendisks[k].de_arr, N); zero_mem_lth(sd_gendisks[k].flags, N); + zero_mem_lth(sd_gendisks[k].driverfs_dev_arr, N); sd_gendisks[k].major = SD_MAJOR(k); sd_gendisks[k].major_name = "sd"; @@ -1291,7 +1295,6 @@ static int sd_init() sd_gendisks[k].sizes = sd_sizes + k * (N << 4); sd_gendisks[k].nr_real = 0; } - return 0; #undef init_mem_lth @@ -1302,6 +1305,7 @@ cleanup_gendisks: for (k = 0; k < N_USED_SD_MAJORS; k++) { vfree(sd_gendisks[k].de_arr); vfree(sd_gendisks[k].flags); + vfree(sd_gendisks[k].driverfs_dev_arr); } cleanup_mem: vfree(sd_gendisks); @@ -1436,6 +1440,8 @@ static int sd_attach(Scsi_Device * sdp) SD_GENDISK(dsk_nr).nr_real++; devnum = dsk_nr % SCSI_DISKS_PER_MAJOR; SD_GENDISK(dsk_nr).de_arr[devnum] = sdp->de; + SD_GENDISK(dsk_nr).driverfs_dev_arr[devnum] = + &sdp->sdev_driverfs_dev; if (sdp->removable) SD_GENDISK(dsk_nr).flags[devnum] |= GENHD_FL_REMOVABLE; sd_dskname(dsk_nr, diskname); @@ -1535,6 +1541,8 @@ static void sd_detach(Scsi_Device * sdp) max_p = 1 << sd_gendisk.minor_shift; start = dsk_nr << sd_gendisk.minor_shift; dev = MKDEV_SD_PARTITION(start); + driverfs_remove_partitions(&SD_GENDISK (dsk_nr), + SD_MINOR_NUMBER (start)); wipe_partitions(dev); for (j = max_p - 1; j >= 0; j--) sd_sizes[start + j] = 0; @@ -1556,9 +1564,16 @@ static void sd_detach(Scsi_Device * sdp) **/ static int __init init_sd(void) { + int rc; SCSI_LOG_HLQUEUE(3, printk("init_sd: sd driver entry point\n")); sd_template.module = THIS_MODULE; - return scsi_register_device(&sd_template); + rc = scsi_register_device(&sd_template); + if (!rc) { + sd_template.scsi_driverfs_driver.name = (char *)sd_template.tag; + sd_template.scsi_driverfs_driver.bus = &scsi_driverfs_bus_type; + driver_register(&sd_template.scsi_driverfs_driver); + } + return rc; } /** @@ -1591,6 +1606,7 @@ static void __exit exit_sd(void) sd_template.dev_max = 0; if (sd_gendisks != &sd_gendisk) vfree(sd_gendisks); + remove_driver(&sd_template.scsi_driverfs_driver); } static Scsi_Disk * sd_get_sdisk(int index) diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 9b5e51229c09..c84271223ce6 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -194,6 +194,7 @@ typedef struct sg_device /* holds the state of each scsi generic device */ volatile char detached; /* 0->attached, 1->detached pending removal */ volatile char exclude; /* opened for exclusive access */ char sgdebug; /* 0->off, 1->sense, 9->dump dev, 10-> all devs */ + struct device sg_driverfs_dev; } Sg_device; /* 36 bytes long on i386 */ @@ -695,7 +696,7 @@ static int sg_common_write(Sg_fd * sfp, Sg_request * srp, srp->my_cmdp = SRpnt; q = &SRpnt->sr_device->request_queue; - SRpnt->sr_request.rq_dev = sdp->i_rdev; + SRpnt->sr_request->rq_dev = sdp->i_rdev; SRpnt->sr_sense_buffer[0] = 0; SRpnt->sr_cmd_len = hp->cmd_len; if (! (hp->flags & SG_FLAG_LUN_INHIBIT)) { @@ -1222,7 +1223,7 @@ static void sg_cmd_done_bh(Scsi_Cmnd * SCpnt) SRpnt->sr_bufflen = 0; SRpnt->sr_buffer = NULL; SRpnt->sr_underflow = 0; - SRpnt->sr_request.rq_dev = mk_kdev(0, 0); /* "sg" _disowns_ request blk */ + SRpnt->sr_request->rq_dev = mk_kdev(0, 0); /* "sg" _disowns_ request blk */ srp->my_cmdp = NULL; srp->done = 1; @@ -1370,6 +1371,29 @@ static int __init sg_def_reserved_size_setup(char *str) __setup("sg_def_reserved_size=", sg_def_reserved_size_setup); #endif +/* Driverfs file support */ +static ssize_t sg_device_kdev_read(struct device *driverfs_dev, char *page, + size_t count, loff_t off) +{ + Sg_device * sdp=list_entry(driverfs_dev, Sg_device, sg_driverfs_dev); + return off ? 0 : sprintf(page, "%x\n",sdp->i_rdev.value); +} +static struct driver_file_entry sg_device_kdev_file = { + name: "kdev", + mode: S_IRUGO, + show: sg_device_kdev_read, +}; + +static ssize_t sg_device_type_read(struct device *driverfs_dev, char *page, + size_t count, loff_t off) +{ + return off ? 0 : sprintf (page, "CHR\n"); +} +static struct driver_file_entry sg_device_type_file = { + name: "type", + mode: S_IRUGO, + show: sg_device_type_read, +}; static int sg_attach(Scsi_Device * scsidp) { @@ -1428,6 +1452,18 @@ static int sg_attach(Scsi_Device * scsidp) sdp->detached = 0; sdp->sg_tablesize = scsidp->host ? scsidp->host->sg_tablesize : 0; sdp->i_rdev = mk_kdev(SCSI_GENERIC_MAJOR, k); + + memset(&sdp->sg_driverfs_dev, 0, sizeof(struct device)); + sprintf(sdp->sg_driverfs_dev.bus_id, "%s:gen", + scsidp->sdev_driverfs_dev.bus_id); + sprintf(sdp->sg_driverfs_dev.name, "%sgeneric", + scsidp->sdev_driverfs_dev.name); + sdp->sg_driverfs_dev.parent = &scsidp->sdev_driverfs_dev; + sdp->sg_driverfs_dev.bus = &scsi_driverfs_bus_type; + device_register(&sdp->sg_driverfs_dev); + device_create_file(&sdp->sg_driverfs_dev, &sg_device_type_file); + device_create_file(&sdp->sg_driverfs_dev, &sg_device_kdev_file); + sdp->de = devfs_register (scsidp->de, "generic", DEVFS_FL_DEFAULT, SCSI_GENERIC_MAJOR, k, S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, @@ -1496,6 +1532,9 @@ static void sg_detach(Scsi_Device * scsidp) } SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d, dirty\n", k)); devfs_unregister (sdp->de); + device_remove_file(&sdp->sg_driverfs_dev,sg_device_type_file.name); + device_remove_file(&sdp->sg_driverfs_dev,sg_device_kdev_file.name); + put_device(&sdp->sg_driverfs_dev); sdp->de = NULL; if (NULL == sdp->headfp) { kfree((char *)sdp); @@ -1505,6 +1544,7 @@ static void sg_detach(Scsi_Device * scsidp) else { /* nothing active, simple case */ SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d\n", k)); devfs_unregister (sdp->de); + put_device(&sdp->sg_driverfs_dev); kfree((char *)sdp); sg_dev_arr[k] = NULL; } @@ -1529,9 +1569,16 @@ MODULE_PARM(def_reserved_size, "i"); MODULE_PARM_DESC(def_reserved_size, "size of buffer reserved for each fd"); static int __init init_sg(void) { + int rc; if (def_reserved_size >= 0) sg_big_buff = def_reserved_size; - return scsi_register_device(&sg_template); + rc = scsi_register_device(&sg_template); + if (!rc) { + sg_template.scsi_driverfs_driver.name = (char *)sg_template.tag; + sg_template.scsi_driverfs_driver.bus = &scsi_driverfs_bus_type; + driver_register(&sg_template.scsi_driverfs_driver); + } + return rc; } static void __exit exit_sg( void) @@ -1546,6 +1593,7 @@ static void __exit exit_sg( void) sg_dev_arr = NULL; } sg_template.dev_max = 0; + remove_driver(&sg_template.scsi_driverfs_driver); } diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index 0e28dc69652b..7ed4d818f3e6 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -197,11 +197,11 @@ static void rw_intr(Scsi_Cmnd * SCpnt) int this_count = SCpnt->bufflen >> 9; int good_sectors = (result == 0 ? this_count : 0); int block_sectors = 0; - int device_nr = DEVICE_NR(SCpnt->request.rq_dev); + int device_nr = DEVICE_NR(SCpnt->request->rq_dev); Scsi_CD *SCp = &scsi_CDs[device_nr]; #ifdef DEBUG - printk("sr.c done: %x %p\n", result, SCpnt->request.bh->b_data); + printk("sr.c done: %x %p\n", result, SCpnt->request->bh->b_data); #endif /* Handle MEDIUM ERRORs or VOLUME OVERFLOWs that indicate partial success. @@ -219,14 +219,14 @@ static void rw_intr(Scsi_Cmnd * SCpnt) (SCpnt->sense_buffer[4] << 16) | (SCpnt->sense_buffer[5] << 8) | SCpnt->sense_buffer[6]; - if (SCpnt->request.bio != NULL) - block_sectors = bio_sectors(SCpnt->request.bio); + if (SCpnt->request->bio != NULL) + block_sectors = bio_sectors(SCpnt->request->bio); if (block_sectors < 4) block_sectors = 4; if (SCp->device->sector_size == 2048) error_sector <<= 2; error_sector &= ~(block_sectors - 1); - good_sectors = error_sector - SCpnt->request.sector; + good_sectors = error_sector - SCpnt->request->sector; if (good_sectors < 0 || good_sectors >= this_count) good_sectors = 0; /* @@ -266,14 +266,14 @@ static int sr_init_command(Scsi_Cmnd * SCpnt) int dev, devm, block=0, this_count, s_size; Scsi_CD *SCp; - devm = minor(SCpnt->request.rq_dev); - dev = DEVICE_NR(SCpnt->request.rq_dev); + devm = minor(SCpnt->request->rq_dev); + dev = DEVICE_NR(SCpnt->request->rq_dev); SCp = &scsi_CDs[dev]; SCSI_LOG_HLQUEUE(1, printk("Doing sr request, dev = %d, block = %d\n", devm, block)); if (dev >= sr_template.nr_dev || !SCp->device || !SCp->device->online) { - SCSI_LOG_HLQUEUE(2, printk("Finishing %ld sectors\n", SCpnt->request.nr_sectors)); + SCSI_LOG_HLQUEUE(2, printk("Finishing %ld sectors\n", SCpnt->request->nr_sectors)); SCSI_LOG_HLQUEUE(2, printk("Retry with 0x%p\n", SCpnt)); return 0; } @@ -286,8 +286,8 @@ static int sr_init_command(Scsi_Cmnd * SCpnt) return 0; } - if (!(SCpnt->request.flags & REQ_CMD)) { - blk_dump_rq_flags(&SCpnt->request, "sr unsup command"); + if (!(SCpnt->request->flags & REQ_CMD)) { + blk_dump_rq_flags(SCpnt->request, "sr unsup command"); return 0; } @@ -308,23 +308,23 @@ static int sr_init_command(Scsi_Cmnd * SCpnt) return 0; } - if (rq_data_dir(&SCpnt->request) == WRITE) { + if (rq_data_dir(SCpnt->request) == WRITE) { if (!SCp->device->writeable) return 0; SCpnt->cmnd[0] = WRITE_10; SCpnt->sc_data_direction = SCSI_DATA_WRITE; - } else if (rq_data_dir(&SCpnt->request) == READ) { + } else if (rq_data_dir(SCpnt->request) == READ) { SCpnt->cmnd[0] = READ_10; SCpnt->sc_data_direction = SCSI_DATA_READ; } else { - blk_dump_rq_flags(&SCpnt->request, "Unknown sr command"); + blk_dump_rq_flags(SCpnt->request, "Unknown sr command"); return 0; } /* * request doesn't start on hw block boundary, add scatter pads */ - if ((SCpnt->request.sector % (s_size >> 9)) || (SCpnt->request_bufflen % s_size)) { + if ((SCpnt->request->sector % (s_size >> 9)) || (SCpnt->request_bufflen % s_size)) { printk("sr: unaligned transfer\n"); return 0; } @@ -334,13 +334,13 @@ static int sr_init_command(Scsi_Cmnd * SCpnt) SCSI_LOG_HLQUEUE(2, printk("sr%d : %s %d/%ld 512 byte blocks.\n", devm, - (rq_data_dir(&SCpnt->request) == WRITE) ? "writing" : "reading", - this_count, SCpnt->request.nr_sectors)); + (rq_data_dir(SCpnt->request) == WRITE) ? "writing" : "reading", + this_count, SCpnt->request->nr_sectors)); SCpnt->cmnd[1] = (SCpnt->device->scsi_level <= SCSI_2) ? ((SCpnt->lun << 5) & 0xe0) : 0; - block = SCpnt->request.sector / (s_size >> 9); + block = SCpnt->request->sector / (s_size >> 9); if (this_count > 0xffff) this_count = 0xffff; @@ -496,7 +496,7 @@ void get_sectorsize(int i) cmd[1] = (SCp->device->scsi_level <= SCSI_2) ? ((SCp->device->lun << 5) & 0xe0) : 0; memset((void *) &cmd[2], 0, 8); - SRpnt->sr_request.rq_status = RQ_SCSI_BUSY; /* Mark as really busy */ + SRpnt->sr_request->rq_status = RQ_SCSI_BUSY; /* Mark as really busy */ SRpnt->sr_cmd_len = 0; memset(buffer, 0, 8); @@ -731,6 +731,32 @@ cleanup_devfs: return 1; } +/* Driverfs file support */ +static ssize_t sr_device_kdev_read(struct device *driverfs_dev, + char *page, size_t count, loff_t off) +{ + kdev_t kdev; + kdev.value=(int)driverfs_dev->driver_data; + return off ? 0 : sprintf(page, "%x\n",kdev.value); +} +static struct driver_file_entry sr_device_kdev_file = { + name: "kdev", + mode: S_IRUGO, + show: sr_device_kdev_read, +}; + +static ssize_t sr_device_type_read(struct device *driverfs_dev, + char *page, size_t count, loff_t off) +{ + return off ? 0 : sprintf (page, "CHR\n"); +} +static struct driver_file_entry sr_device_type_file = { + name: "type", + mode: S_IRUGO, + show: sr_device_type_read, +}; + + void sr_finish() { int i; @@ -776,6 +802,20 @@ void sr_finish() sprintf(name, "sr%d", i); strcpy(SCp->cdi.name, name); + sprintf(SCp->cdi.cdrom_driverfs_dev.bus_id, "%s:cd", + SCp->device->sdev_driverfs_dev.bus_id); + sprintf(SCp->cdi.cdrom_driverfs_dev.name, "%scdrom", + SCp->device->sdev_driverfs_dev.name); + SCp->cdi.cdrom_driverfs_dev.parent = + &SCp->device->sdev_driverfs_dev; + SCp->cdi.cdrom_driverfs_dev.bus = &scsi_driverfs_bus_type; + SCp->cdi.cdrom_driverfs_dev.driver_data = + (void *)__mkdev(MAJOR_NR, i); + device_register(&SCp->cdi.cdrom_driverfs_dev); + device_create_file(&SCp->cdi.cdrom_driverfs_dev, + &sr_device_type_file); + device_create_file(&SCp->cdi.cdrom_driverfs_dev, + &sr_device_kdev_file); SCp->cdi.de = devfs_register(SCp->device->de, "cd", DEVFS_FL_DEFAULT, MAJOR_NR, i, S_IFBLK | S_IRUGO | S_IWUGO, @@ -816,7 +856,14 @@ static void sr_detach(Scsi_Device * SDp) static int __init init_sr(void) { - return scsi_register_device(&sr_template); + int rc; + rc = scsi_register_device(&sr_template); + if (!rc) { + sr_template.scsi_driverfs_driver.name = (char *)sr_template.tag; + sr_template.scsi_driverfs_driver.bus = &scsi_driverfs_bus_type; + driver_register(&sr_template.scsi_driverfs_driver); + } + return rc; } static void __exit exit_sr(void) @@ -833,6 +880,7 @@ static void __exit exit_sr(void) blk_clear(MAJOR_NR); sr_template.dev_max = 0; + remove_driver(&sr_template.scsi_driverfs_driver); } module_init(init_sr); diff --git a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c index ebf2474d7067..85ba7a66a237 100644 --- a/drivers/scsi/sr_ioctl.c +++ b/drivers/scsi/sr_ioctl.c @@ -93,7 +93,7 @@ int sr_do_ioctl(int target, unsigned char *sr_cmd, void *buffer, unsigned buflen SRpnt->sr_data_direction = readwrite; /* use ISA DMA buffer if necessary */ - SRpnt->sr_request.buffer = buffer; + SRpnt->sr_request->buffer = buffer; if (buffer && SRpnt->sr_host->unchecked_isa_dma && (virt_to_phys(buffer) + buflength - 1 > ISA_DMA_THRESHOLD)) { bounce_buffer = (char *) kmalloc(buflength, GFP_DMA); @@ -112,7 +112,7 @@ int sr_do_ioctl(int target, unsigned char *sr_cmd, void *buffer, unsigned buflen scsi_wait_req(SRpnt, (void *) sr_cmd, (void *) buffer, buflength, IOCTL_TIMEOUT, IOCTL_RETRIES); - req = &SRpnt->sr_request; + req = SRpnt->sr_request; if (SRpnt->sr_buffer && req->buffer && SRpnt->sr_buffer != req->buffer) { memcpy(req->buffer, SRpnt->sr_buffer, SRpnt->sr_bufflen); kfree(SRpnt->sr_buffer); diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 7342c3e661f3..6310d0f1b182 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -229,7 +229,7 @@ static int st_chk_result(Scsi_Tape *STp, Scsi_Request * SRpnt) scode = 0; } - dev = TAPE_NR(SRpnt->sr_request.rq_dev); + dev = TAPE_NR(SRpnt->sr_request->rq_dev); DEB( if (debugging) { printk(ST_DEB_MSG "st%d: Error: %x, cmd: %x %x %x %x %x %x Len: %d\n", @@ -306,7 +306,7 @@ static void st_sleep_done(Scsi_Cmnd * SCpnt) int remainder; Scsi_Tape *STp; - st_nbr = TAPE_NR(SCpnt->request.rq_dev); + st_nbr = TAPE_NR(SCpnt->request->rq_dev); read_lock(&st_dev_arr_lock); STp = scsi_tapes[st_nbr]; read_unlock(&st_dev_arr_lock); @@ -328,11 +328,11 @@ static void st_sleep_done(Scsi_Cmnd * SCpnt) (STp->buffer)->midlevel_result = INT_MAX; /* OK */ } else (STp->buffer)->midlevel_result = SCpnt->result; - SCpnt->request.rq_status = RQ_SCSI_DONE; + SCpnt->request->rq_status = RQ_SCSI_DONE; (STp->buffer)->last_SRpnt = SCpnt->sc_request; DEB( STp->write_pending = 0; ) - complete(SCpnt->request.waiting); + complete(SCpnt->request->waiting); } @@ -371,16 +371,16 @@ static Scsi_Request * bp = (STp->buffer)->b_data; SRpnt->sr_data_direction = direction; SRpnt->sr_cmd_len = 0; - SRpnt->sr_request.waiting = &(STp->wait); - SRpnt->sr_request.rq_status = RQ_SCSI_BUSY; - SRpnt->sr_request.rq_dev = STp->devt; + SRpnt->sr_request->waiting = &(STp->wait); + SRpnt->sr_request->rq_status = RQ_SCSI_BUSY; + SRpnt->sr_request->rq_dev = STp->devt; scsi_do_req(SRpnt, (void *) cmd, bp, bytes, st_sleep_done, timeout, retries); if (do_wait) { - wait_for_completion(SRpnt->sr_request.waiting); - SRpnt->sr_request.waiting = NULL; + wait_for_completion(SRpnt->sr_request->waiting); + SRpnt->sr_request->waiting = NULL; (STp->buffer)->syscall_result = st_chk_result(STp, SRpnt); } return SRpnt; @@ -403,7 +403,7 @@ static void write_behind_check(Scsi_Tape * STp) ) /* end DEB */ wait_for_completion(&(STp->wait)); - (STp->buffer)->last_SRpnt->sr_request.waiting = NULL; + (STp->buffer)->last_SRpnt->sr_request->waiting = NULL; (STp->buffer)->syscall_result = st_chk_result(STp, (STp->buffer)->last_SRpnt); scsi_release_request((STp->buffer)->last_SRpnt); @@ -3531,6 +3531,31 @@ __setup("st=", st_setup); #endif +/* Driverfs file support */ +static ssize_t st_device_kdev_read(struct device *driverfs_dev, + char *page, size_t count, loff_t off) +{ + kdev_t kdev; + kdev.value=(int)driverfs_dev->driver_data; + return off ? 0 : sprintf(page, "%x\n",kdev.value); +} +static struct driver_file_entry st_device_kdev_file = { + name: "kdev", + mode: S_IRUGO, + show: st_device_kdev_read, +}; + +static ssize_t st_device_type_read(struct device *driverfs_dev, + char *page, size_t count, loff_t off) +{ + return off ? 0 : sprintf (page, "CHR\n"); +} +static struct driver_file_entry st_device_type_file = { + name: "type", + mode: S_IRUGO, + show: st_device_type_read, +}; + static struct file_operations st_fops = { @@ -3632,6 +3657,18 @@ static int st_attach(Scsi_Device * SDp) /* Rewind entry */ sprintf (name, "mt%s", formats[mode]); + sprintf(tpnt->driverfs_dev_r[mode].bus_id, "%s:%s", + SDp->sdev_driverfs_dev.name, name); + sprintf(tpnt->driverfs_dev_r[mode].name, "%s%s", + SDp->sdev_driverfs_dev.name, name); + tpnt->driverfs_dev_r[mode].parent = &SDp->sdev_driverfs_dev; + tpnt->driverfs_dev_r[mode].bus = &scsi_driverfs_bus_type; + tpnt->driverfs_dev_r[mode].driver_data = + (void *)__mkdev(MAJOR_NR, i + (mode << 5)); + device_register(&tpnt->driverfs_dev_r[mode]); + device_create_file(&tpnt->driverfs_dev_r[mode], + &st_device_type_file); + device_create_file(&tpnt->driverfs_dev_r[mode], &st_device_kdev_file); tpnt->de_r[mode] = devfs_register (SDp->de, name, DEVFS_FL_DEFAULT, MAJOR_NR, i + (mode << 5), @@ -3639,6 +3676,19 @@ static int st_attach(Scsi_Device * SDp) &st_fops, NULL); /* No-rewind entry */ sprintf (name, "mt%sn", formats[mode]); + sprintf(tpnt->driverfs_dev_n[mode].bus_id, "%s:%s", + SDp->sdev_driverfs_dev.name, name); + sprintf(tpnt->driverfs_dev_n[mode].name, "%s%s", + SDp->sdev_driverfs_dev.name, name); + tpnt->driverfs_dev_n[mode].parent= &SDp->sdev_driverfs_dev; + tpnt->driverfs_dev_n[mode].bus = &scsi_driverfs_bus_type; + tpnt->driverfs_dev_n[mode].driver_data = + (void *)__mkdev(MAJOR_NR, i + (mode << 5) + 128); + device_register(&tpnt->driverfs_dev_n[mode]); + device_create_file(&tpnt->driverfs_dev_n[mode], + &st_device_type_file); + device_create_file(&tpnt->driverfs_dev_n[mode], + &st_device_kdev_file); tpnt->de_n[mode] = devfs_register (SDp->de, name, DEVFS_FL_DEFAULT, MAJOR_NR, i + (mode << 5) + 128, @@ -3738,8 +3788,18 @@ static void st_detach(Scsi_Device * SDp) for (mode = 0; mode < ST_NBR_MODES; ++mode) { devfs_unregister (tpnt->de_r[mode]); tpnt->de_r[mode] = NULL; + device_remove_file(&tpnt->driverfs_dev_r[mode], + st_device_type_file.name); + device_remove_file(&tpnt->driverfs_dev_r[mode], + st_device_kdev_file.name); + put_device(&tpnt->driverfs_dev_r[mode]); devfs_unregister (tpnt->de_n[mode]); tpnt->de_n[mode] = NULL; + device_remove_file(&tpnt->driverfs_dev_n[mode], + st_device_type_file.name); + device_remove_file(&tpnt->driverfs_dev_n[mode], + st_device_kdev_file.name); + put_device(&tpnt->driverfs_dev_n[mode]); } if (tpnt->buffer) { tpnt->buffer->orig_sg_segs = 0; @@ -3770,8 +3830,16 @@ static int __init init_st(void) verstr, st_fixed_buffer_size, st_write_threshold, st_max_sg_segs); - if (devfs_register_chrdev(SCSI_TAPE_MAJOR, "st", &st_fops) >= 0) - return scsi_register_device(&st_template); + if (devfs_register_chrdev(SCSI_TAPE_MAJOR, "st", &st_fops) >= 0) { + if (scsi_register_device(&st_template) == 0) { + st_template.scsi_driverfs_driver.name = + (char *)st_template.tag; + st_template.scsi_driverfs_driver.bus = + &scsi_driverfs_bus_type; + driver_register(&st_template.scsi_driverfs_driver); + return 0; + } + } printk(KERN_ERR "Unable to get major %d for SCSI tapes\n", MAJOR_NR); return 1; @@ -3790,6 +3858,7 @@ static void __exit exit_st(void) kfree(scsi_tapes); } st_template.dev_max = 0; + remove_driver(&st_template.scsi_driverfs_driver); printk(KERN_INFO "st: Unloaded.\n"); } diff --git a/drivers/scsi/st.h b/drivers/scsi/st.h index 7fcd055b5981..b5fcd14b9cfb 100644 --- a/drivers/scsi/st.h +++ b/drivers/scsi/st.h @@ -94,6 +94,8 @@ typedef struct { int current_mode; devfs_handle_t de_r[ST_NBR_MODES]; /* Rewind entries */ devfs_handle_t de_n[ST_NBR_MODES]; /* No-rewind entries */ + struct device driverfs_dev_r[ST_NBR_MODES]; + struct device driverfs_dev_n[ST_NBR_MODES]; /* Status variables */ int partition; diff --git a/drivers/scsi/sun3_NCR5380.c b/drivers/scsi/sun3_NCR5380.c index 88ecf5d92a56..b4d0903a79a9 100644 --- a/drivers/scsi/sun3_NCR5380.c +++ b/drivers/scsi/sun3_NCR5380.c @@ -1217,7 +1217,7 @@ static void NCR5380_dma_complete( struct Scsi_Host *instance ) HOSTNO, NCR5380_read(BUS_AND_STATUS_REG), NCR5380_read(STATUS_REG)); - if((sun3scsi_dma_finish(hostdata->connected->request.cmd))) { + if((sun3scsi_dma_finish(hostdata->connected->request->cmd))) { printk("scsi%d: overrun in UDC counter -- not prepared to deal with this!\n", HOSTNO); printk("please e-mail sammy@oh.verio.com with a description of how this\n"); printk("error was produced.\n"); @@ -2016,9 +2016,9 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) if((count > SUN3_DMA_MINSIZE) && (sun3_dma_setup_done != cmd)) { - if((cmd->request.cmd == 0) || (cmd->request.cmd == 1)) { + if((cmd->request->cmd == 0) || (cmd->request->cmd == 1)) { sun3scsi_dma_setup(d, count, - cmd->request.cmd); + cmd->request->cmd); sun3_dma_setup_done = cmd; } } @@ -2628,7 +2628,7 @@ static void NCR5380_reselect (struct Scsi_Host *instance) != tmp)) { sun3scsi_dma_setup(d, count, - tmp->request.cmd); + tmp->request->cmd); sun3_dma_setup_done = tmp; } #endif diff --git a/drivers/scsi/sun3_scsi.c b/drivers/scsi/sun3_scsi.c index 3eae7cee2490..457a5518b34e 100644 --- a/drivers/scsi/sun3_scsi.c +++ b/drivers/scsi/sun3_scsi.c @@ -518,7 +518,7 @@ static inline unsigned long sun3scsi_dma_residual(struct Scsi_Host *instance) static inline unsigned long sun3scsi_dma_xfer_len(unsigned long wanted, Scsi_Cmnd *cmd, int write_flag) { - if((cmd->request.cmd == 0) || (cmd->request.cmd == 1)) + if((cmd->request->cmd == 0) || (cmd->request->cmd == 1)) return wanted; else return 0; diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c index 5ae088c86547..6de097b8368b 100644 --- a/drivers/scsi/u14-34f.c +++ b/drivers/scsi/u14-34f.c @@ -1206,7 +1206,7 @@ static inline int do_qcomm(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) { if (linked_comm && SCpnt->device->queue_depth > 2 && TLDEV(SCpnt->device->type)) { HD(j)->cp_stat[i] = READY; - flush_dev(SCpnt->device, SCpnt->request.sector, j, FALSE); + flush_dev(SCpnt->device, SCpnt->request->sector, j, FALSE); return 0; } @@ -1529,11 +1529,11 @@ static inline int reorder(unsigned int j, unsigned long cursec, if (!(cpp->xdir == DTD_IN)) input_only = FALSE; - if (SCpnt->request.sector < minsec) minsec = SCpnt->request.sector; - if (SCpnt->request.sector > maxsec) maxsec = SCpnt->request.sector; + if (SCpnt->request->sector < minsec) minsec = SCpnt->request->sector; + if (SCpnt->request->sector > maxsec) maxsec = SCpnt->request->sector; - sl[n] = SCpnt->request.sector; - ioseek += SCpnt->request.nr_sectors; + sl[n] = SCpnt->request->sector; + ioseek += SCpnt->request->nr_sectors; if (!n) continue; @@ -1561,7 +1561,7 @@ static inline int reorder(unsigned int j, unsigned long cursec, if (!input_only) for (n = 0; n < n_ready; n++) { k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt; - ll[n] = SCpnt->request.nr_sectors; pl[n] = SCpnt->pid; + ll[n] = SCpnt->request->nr_sectors; pl[n] = SCpnt->pid; if (!n) continue; @@ -1589,7 +1589,7 @@ static inline int reorder(unsigned int j, unsigned long cursec, " cur %ld s:%c r:%c rev:%c in:%c ov:%c xd %d.\n", (ihdlr ? "ihdlr" : "qcomm"), SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid, k, flushcount, n_ready, - SCpnt->request.sector, SCpnt->request.nr_sectors, cursec, + SCpnt->request->sector, SCpnt->request->nr_sectors, cursec, YESNO(s), YESNO(r), YESNO(rev), YESNO(input_only), YESNO(overlap), cpp->xdir); } @@ -1718,7 +1718,7 @@ static inline void ihdlr(int irq, unsigned int j) { if (linked_comm && SCpnt->device->queue_depth > 2 && TLDEV(SCpnt->device->type)) - flush_dev(SCpnt->device, SCpnt->request.sector, j, TRUE); + flush_dev(SCpnt->device, SCpnt->request->sector, j, TRUE); tstatus = status_byte(spp->target_status); diff --git a/fs/driverfs/inode.c b/fs/driverfs/inode.c index 73ad5c1f6adb..2fd9126199b2 100644 --- a/fs/driverfs/inode.c +++ b/fs/driverfs/inode.c @@ -149,6 +149,10 @@ static int driverfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) lock_kernel(); dentry->d_op = &driverfs_dentry_dir_ops; res = driverfs_mknod(dir, dentry, mode | S_IFDIR, 0); + if (!res) { + dir->i_nlink++; + dentry->d_inode->i_nlink++; + } unlock_kernel(); return res; } @@ -206,22 +210,28 @@ static int driverfs_empty(struct dentry *dentry) static int driverfs_unlink(struct inode *dir, struct dentry *dentry) { + struct inode *inode = dentry->d_inode; + + lock_kernel(); + inode->i_nlink--; + unlock_kernel(); + dput(dentry); + return 0; +} + +static int driverfs_rmdir(struct inode *dir, struct dentry *dentry) +{ int error = -ENOTEMPTY; if (driverfs_empty(dentry)) { - struct inode *inode = dentry->d_inode; - - lock_kernel(); - inode->i_nlink--; - unlock_kernel(); - dput(dentry); + dentry->d_inode->i_nlink--; + driverfs_unlink(dir, dentry); + dir->i_nlink--; error = 0; } return error; } -#define driverfs_rmdir driverfs_unlink - /** * driverfs_read_file - "read" data from a file. * @file: file pointer diff --git a/fs/libfs.c b/fs/libfs.c index f4b12699b37a..be9a8f7963e8 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -83,6 +83,12 @@ loff_t dcache_dir_lseek(struct file *file, loff_t offset, int origin) return offset; } +/* Relationship between i_mode and the DT_xxx types */ +static inline unsigned char dt_type(struct inode *inode) +{ + return (inode->i_mode >> 12) & 15; +} + /* * Directory is locked and all positive dentries in it are safe, since * for ramfs-type trees they can't go away without unlink() or rmdir(), @@ -125,7 +131,7 @@ int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir) continue; spin_unlock(&dcache_lock); - if (filldir(dirent, next->d_name.name, next->d_name.len, filp->f_pos, next->d_inode->i_ino, DT_UNKNOWN) < 0) + if (filldir(dirent, next->d_name.name, next->d_name.len, filp->f_pos, next->d_inode->i_ino, dt_type(next->d_inode)) < 0) return 0; spin_lock(&dcache_lock); /* next is still alive */ diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 3137aa78fea6..36fc86dcff3e 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c @@ -22,6 +22,7 @@ #include <linux/init.h> #include <linux/raid/md.h> #include <linux/buffer_head.h> /* for invalidate_bdev() */ +#include <linux/kmod.h> #include "check.h" @@ -225,6 +226,136 @@ void add_gd_partition(struct gendisk *hd, int minor, int start, int size) #endif } +/* Driverfs file support */ +static ssize_t partition_device_kdev_read(struct device *driverfs_dev, + char *page, size_t count, loff_t off) +{ + kdev_t kdev; + kdev.value=(int)driverfs_dev->driver_data; + return off ? 0 : sprintf (page, "%x\n",kdev.value); +} +static struct driver_file_entry partition_device_kdev_file = { + name: "kdev", + mode: S_IRUGO, + show: partition_device_kdev_read, +}; + +static ssize_t partition_device_type_read(struct device *driverfs_dev, + char *page, size_t count, loff_t off) +{ + return off ? 0 : sprintf (page, "BLK\n"); +} +static struct driver_file_entry partition_device_type_file = { + name: "type", + mode: S_IRUGO, + show: partition_device_type_read, +}; + +void driverfs_create_partitions(struct gendisk *hd, int minor) +{ + int pos = -1; + int devnum = minor >> hd->minor_shift; + char dirname[256]; + struct device *parent = 0; + int max_p; + int part; + devfs_handle_t dir = 0; + + /* get parent driverfs device structure */ + if (hd->driverfs_dev_arr) + parent = hd->driverfs_dev_arr[devnum]; + else /* if driverfs not supported by subsystem, skip partitions */ + return; + + /* get parent device node directory name */ + if (hd->de_arr) { + dir = hd->de_arr[devnum]; + if (dir) + pos = devfs_generate_path (dir, dirname, + sizeof dirname); + } + + if (pos < 0) { + disk_name(hd, minor, dirname); + pos = 0; + } + + max_p = (1 << hd->minor_shift); + + /* for all partitions setup parents and device node names */ + for(part=0; part < max_p; part++) { + if ((part == 0) || (hd->part[minor + part].nr_sects >= 1)) { + struct device * current_driverfs_dev = + &hd->part[minor+part].hd_driverfs_dev; + current_driverfs_dev->parent = parent; + /* handle disc case */ + current_driverfs_dev->driver_data = + (void *)__mkdev(hd->major, minor+part); + if (part == 0) { + if (parent) { + sprintf(current_driverfs_dev->name, + "%sdisc", parent->name); + sprintf(current_driverfs_dev->bus_id, + "%s:disc", parent->bus_id); + } else { + sprintf(current_driverfs_dev->name, + "disc"); + sprintf(current_driverfs_dev->bus_id, + "disc"); + } + } else { /* this is a partition */ + if (parent) { + sprintf(current_driverfs_dev->name, + "%spart%d", parent->name, part); + sprintf(current_driverfs_dev->bus_id, + "%s:p%d", parent->bus_id, part); + } else { + sprintf(current_driverfs_dev->name, + "part%d", part); + sprintf(current_driverfs_dev->bus_id, + "p%d" ,part); + } + } + if (parent) current_driverfs_dev->bus = parent->bus; + device_register(current_driverfs_dev); + device_create_file(current_driverfs_dev, + &partition_device_type_file); + device_create_file(current_driverfs_dev, + &partition_device_kdev_file); + } + } + return; +} + +void driverfs_remove_partitions(struct gendisk *hd, int minor) +{ + int max_p; + int part; + struct device * current_driverfs_dev; + + max_p=(1 << hd->minor_shift); + + /* for all parts setup parent relationships and device node names */ + for(part=1; part < max_p; part++) { + if ((hd->part[minor + part].nr_sects >= 1)) { + current_driverfs_dev = + &hd->part[minor + part].hd_driverfs_dev; + device_remove_file(current_driverfs_dev, + partition_device_type_file.name); + device_remove_file(current_driverfs_dev, + partition_device_kdev_file.name); + put_device(current_driverfs_dev); + } + } + current_driverfs_dev = &hd->part[minor].hd_driverfs_dev; + device_remove_file(current_driverfs_dev, + partition_device_type_file.name); + device_remove_file(current_driverfs_dev, + partition_device_kdev_file.name); + put_device(current_driverfs_dev); + return; +} + static void check_partition(struct gendisk *hd, kdev_t dev, int first_part_minor) { devfs_handle_t de = NULL; @@ -285,6 +416,13 @@ setup_devfs: truncate_inode_pages(bdev->bd_inode->i_mapping, 0); bdput(bdev); i = first_part_minor - 1; + + /* Setup driverfs tree */ + if (hd->sizes) + driverfs_create_partitions(hd, i); + else + driverfs_remove_partitions(hd, i); + devfs_register_partitions (hd, i, hd->sizes ? 0 : 1); } diff --git a/fs/proc/array.c b/fs/proc/array.c index c688bd7997a7..200adb72d9ac 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -368,8 +368,8 @@ int proc_pid_stat(struct task_struct *task, char * buffer) priority, nice, 0UL /* removed */, - task->it_real_value, - task->start_time, + jiffies_to_clock_t(task->it_real_value), + jiffies_to_clock_t(task->start_time), vsize, mm ? mm->rss : 0, /* you might want to shift this left 3 */ task->rlim[RLIMIT_RSS].rlim_cur, @@ -693,15 +693,15 @@ int proc_pid_cpu(struct task_struct *task, char * buffer) len = sprintf(buffer, "cpu %lu %lu\n", - task->utime, - task->stime); + jiffies_to_clock_t(task->utime), + jiffies_to_clock_t(task->stime)); for (i = 0 ; i < NR_CPUS; i++) { if (cpu_online(i)) len += sprintf(buffer + len, "cpu%d %lu %lu\n", i, - task->per_cpu_utime[i], - task->per_cpu_stime[i]); + jiffies_to_clock_t(task->per_cpu_utime[i]), + jiffies_to_clock_t(task->per_cpu_stime[i])); } return len; diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index 30ca58f87a0a..686bf540ed9c 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c @@ -36,6 +36,7 @@ #include <linux/init.h> #include <linux/smp_lock.h> #include <linux/seq_file.h> +#include <linux/times.h> #include <asm/uaccess.h> #include <asm/pgtable.h> @@ -294,18 +295,21 @@ static int kstat_read_proc(char *page, char **start, off_t off, #endif } - len = sprintf(page, "cpu %u %u %u %lu\n", user, nice, system, - jif * num_online_cpus() - (user + nice + system)); + len = sprintf(page, "cpu %u %u %u %lu\n", + jiffies_to_clock_t(user), + jiffies_to_clock_t(nice), + jiffies_to_clock_t(system), + jiffies_to_clock_t(jif * num_online_cpus() - (user + nice + system))); for (i = 0 ; i < NR_CPUS; i++){ if (!cpu_online(i)) continue; len += sprintf(page + len, "cpu%d %u %u %u %lu\n", i, - kstat.per_cpu_user[i], - kstat.per_cpu_nice[i], - kstat.per_cpu_system[i], - jif - ( kstat.per_cpu_user[i] \ + jiffies_to_clock_t(kstat.per_cpu_user[i]), + jiffies_to_clock_t(kstat.per_cpu_nice[i]), + jiffies_to_clock_t(kstat.per_cpu_system[i]), + jiffies_to_clock_t(jif - ( kstat.per_cpu_user[i] \ + kstat.per_cpu_nice[i] \ - + kstat.per_cpu_system[i])); + + kstat.per_cpu_system[i]))); } len += sprintf(page + len, "page %u %u\n" diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c index d3edc3128ec0..7d41fc6389f2 100644 --- a/fs/ramfs/inode.c +++ b/fs/ramfs/inode.c @@ -130,7 +130,12 @@ static int ramfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int d static int ramfs_mkdir(struct inode * dir, struct dentry * dentry, int mode) { - return ramfs_mknod(dir, dentry, mode | S_IFDIR, 0); + int retval = ramfs_mknod(dir, dentry, mode | S_IFDIR, 0); + if (!retval) { + dir->i_nlink++; + dentry->d_inode->i_nlink++; + } + return retval; } static int ramfs_create(struct inode *dir, struct dentry *dentry, int mode) @@ -186,25 +191,30 @@ static int ramfs_empty(struct dentry *dentry) } /* - * This works for both directories and regular files. - * (non-directories will always have empty subdirs) + * Unlink a ramfs entry */ static int ramfs_unlink(struct inode * dir, struct dentry *dentry) { + struct inode *inode = dentry->d_inode; + + inode->i_nlink--; + dput(dentry); /* Undo the count from "create" - this does all the work */ + return 0; +} + +static int ramfs_rmdir(struct inode * dir, struct dentry *dentry) +{ int retval = -ENOTEMPTY; if (ramfs_empty(dentry)) { - struct inode *inode = dentry->d_inode; - - inode->i_nlink--; - dput(dentry); /* Undo the count from "create" - this does all the work */ + dentry->d_inode->i_nlink--; + ramfs_unlink(dir, dentry); + dir->i_nlink--; retval = 0; } return retval; } -#define ramfs_rmdir ramfs_unlink - /* * The VFS layer already does all the dentry stuff for rename, * we just have to decrement the usage count for the target if @@ -221,6 +231,10 @@ static int ramfs_rename(struct inode * old_dir, struct dentry *old_dentry, struc inode->i_nlink--; dput(new_dentry); } + if (S_ISDIR(old_dentry->d_inode->i_mode)) { + old_dir->i_nlink--; + new_dir->i_nlink++; + } error = 0; } return error; diff --git a/include/linux/cdrom.h b/include/linux/cdrom.h index b3a349fc341d..296ffe2cdfd4 100644 --- a/include/linux/cdrom.h +++ b/include/linux/cdrom.h @@ -716,6 +716,7 @@ struct request_sense { #ifdef __KERNEL__ #include <linux/devfs_fs_kernel.h> +#include <linux/device.h> struct cdrom_write_settings { unsigned char fpacket; /* fixed/variable packets */ @@ -730,6 +731,7 @@ struct cdrom_device_info { struct cdrom_device_info *next; /* next device_info for this major */ void *handle; /* driver-dependent data */ devfs_handle_t de; /* real driver should create this */ + struct device cdrom_driverfs_dev; /* driverfs implementation */ int number; /* generic driver updates this */ /* specifications */ kdev_t dev; /* device number */ diff --git a/include/linux/fs.h b/include/linux/fs.h index 322e644060cf..002e02289155 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -701,6 +701,9 @@ extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct de /* * File types + * + * NOTE! These match bits 12..15 of stat.st_mode + * (ie "(i_mode >> 12) & 15"). */ #define DT_UNKNOWN 0 #define DT_FIFO 1 diff --git a/include/linux/genhd.h b/include/linux/genhd.h index 18c981dafbf3..44a954b2c370 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -12,6 +12,7 @@ #include <linux/config.h> #include <linux/types.h> #include <linux/major.h> +#include <linux/device.h> enum { /* These three have identical behaviour; use the second one if DOS fdisk gets @@ -62,6 +63,7 @@ struct hd_struct { unsigned long nr_sects; devfs_handle_t de; /* primary (master) devfs entry */ int number; /* stupid old code wastes space */ + struct device hd_driverfs_dev; /* support driverfs hiearchy */ }; #define GENHD_FL_REMOVABLE 1 @@ -80,6 +82,7 @@ struct gendisk { struct block_device_operations *fops; devfs_handle_t *de_arr; /* one per physical disc */ + struct device **driverfs_dev_arr;/* support driverfs hierarchy */ char *flags; /* one per physical disc */ }; @@ -241,6 +244,7 @@ char *disk_name (struct gendisk *hd, int minor, char *buf); extern void devfs_register_partitions (struct gendisk *dev, int minor, int unregister); +extern void driverfs_remove_partitions (struct gendisk *hd, int minor); static inline unsigned int disk_index (kdev_t dev) { diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index fbc10eab16f4..3870d26066e9 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -57,6 +57,7 @@ enum HI_SOFTIRQ=0, NET_TX_SOFTIRQ, NET_RX_SOFTIRQ, + SCSI_SOFTIRQ, TASKLET_SOFTIRQ }; diff --git a/kernel/ksyms.c b/kernel/ksyms.c index cbf06ff3725b..62c20bcff150 100644 --- a/kernel/ksyms.c +++ b/kernel/ksyms.c @@ -334,6 +334,7 @@ EXPORT_SYMBOL(bdev_read_only); EXPORT_SYMBOL(set_device_ro); EXPORT_SYMBOL(bmap); EXPORT_SYMBOL(devfs_register_partitions); +EXPORT_SYMBOL(driverfs_remove_partitions); EXPORT_SYMBOL(blkdev_open); EXPORT_SYMBOL(blkdev_get); EXPORT_SYMBOL(blkdev_put); @@ -588,6 +589,7 @@ EXPORT_SYMBOL(tasklet_kill); EXPORT_SYMBOL(__run_task_queue); EXPORT_SYMBOL(do_softirq); EXPORT_SYMBOL(raise_softirq); +EXPORT_SYMBOL(open_softirq); EXPORT_SYMBOL(cpu_raise_softirq); EXPORT_SYMBOL(__tasklet_schedule); EXPORT_SYMBOL(__tasklet_hi_schedule); diff --git a/mm/mmap.c b/mm/mmap.c index c05c85452e76..7c1badcd5155 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -669,49 +669,53 @@ struct vm_area_struct * find_vma(struct mm_struct * mm, unsigned long addr) struct vm_area_struct * find_vma_prev(struct mm_struct * mm, unsigned long addr, struct vm_area_struct **pprev) { - if (mm) { - /* Go through the RB tree quickly. */ - struct vm_area_struct * vma; - rb_node_t * rb_node, * rb_last_right, * rb_prev; - - rb_node = mm->mm_rb.rb_node; - rb_last_right = rb_prev = NULL; - vma = NULL; - - while (rb_node) { - struct vm_area_struct * vma_tmp; - - vma_tmp = rb_entry(rb_node, struct vm_area_struct, vm_rb); - - if (vma_tmp->vm_end > addr) { - vma = vma_tmp; - rb_prev = rb_last_right; - if (vma_tmp->vm_start <= addr) - break; - rb_node = rb_node->rb_left; - } else { - rb_last_right = rb_node; - rb_node = rb_node->rb_right; - } - } - if (vma) { - if (vma->vm_rb.rb_left) { - rb_prev = vma->vm_rb.rb_left; - while (rb_prev->rb_right) - rb_prev = rb_prev->rb_right; - } - *pprev = NULL; - if (rb_prev) - *pprev = rb_entry(rb_prev, struct vm_area_struct, vm_rb); - if ((rb_prev ? (*pprev)->vm_next : mm->mmap) != vma) - BUG(); - return vma; + struct vm_area_struct *vma = NULL, *prev = NULL; + rb_node_t * rb_node; + if (!mm) + goto out; + + /* Guard against addr being lower than the first VMA */ + vma = mm->mmap; + + /* Go through the RB tree quickly. */ + rb_node = mm->mm_rb.rb_node; + + while (rb_node) { + struct vm_area_struct *vma_tmp; + vma_tmp = rb_entry(rb_node, struct vm_area_struct, vm_rb); + + if (addr < vma_tmp->vm_end) { + rb_node = rb_node->rb_left; + } else { + prev = vma_tmp; + if (!prev->vm_next || (addr < prev->vm_next->vm_end)) + break; + rb_node = rb_node->rb_right; } } - *pprev = NULL; - return NULL; + + out: + *pprev = prev; + return prev ? prev->vm_next : vma; } +#ifdef ARCH_STACK_GROWSUP +struct vm_area_struct * find_extend_vma(struct mm_struct * mm, unsigned long addr) +{ + struct vm_area_struct *vma, *prev; + + addr &= PAGE_MASK; + vma = find_vma_prev(mm, addr, &prev); + if (vma && (vma->vm_start <= addr)) + return vma; + if (!prev || expand_stack(prev, addr)) + return NULL; + if (prev->vm_flags & VM_LOCKED) { + make_pages_present(addr, prev->vm_end); + } + return prev; +} +#else struct vm_area_struct * find_extend_vma(struct mm_struct * mm, unsigned long addr) { struct vm_area_struct * vma; @@ -733,6 +737,7 @@ struct vm_area_struct * find_extend_vma(struct mm_struct * mm, unsigned long add } return vma; } +#endif /* * Try to free as many page directory entries as we can, |
