summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/swsusp.txt13
-rw-r--r--arch/i386/kernel/apm.c6
-rw-r--r--drivers/cdrom/cdrom.c5
-rw-r--r--drivers/scsi/53c700.c242
-rw-r--r--drivers/scsi/53c700.h5
-rw-r--r--drivers/scsi/aha1542.c4
-rw-r--r--drivers/scsi/constants.c4
-rw-r--r--drivers/scsi/eata.c16
-rw-r--r--drivers/scsi/hosts.c1
-rw-r--r--drivers/scsi/hosts.h34
-rw-r--r--drivers/scsi/ide-scsi.c2
-rw-r--r--drivers/scsi/osst.c20
-rw-r--r--drivers/scsi/qla1280.c4
-rw-r--r--drivers/scsi/scsi.c295
-rw-r--r--drivers/scsi/scsi.h93
-rw-r--r--drivers/scsi/scsi_debug.c2
-rw-r--r--drivers/scsi/scsi_error.c8
-rw-r--r--drivers/scsi/scsi_lib.c80
-rw-r--r--drivers/scsi/scsi_merge.c2
-rw-r--r--drivers/scsi/scsi_scan.c413
-rw-r--r--drivers/scsi/scsi_syms.c5
-rw-r--r--drivers/scsi/sd.c60
-rw-r--r--drivers/scsi/sg.c54
-rw-r--r--drivers/scsi/sr.c86
-rw-r--r--drivers/scsi/sr_ioctl.c4
-rw-r--r--drivers/scsi/st.c93
-rw-r--r--drivers/scsi/st.h2
-rw-r--r--drivers/scsi/sun3_NCR5380.c8
-rw-r--r--drivers/scsi/sun3_scsi.c2
-rw-r--r--drivers/scsi/u14-34f.c16
-rw-r--r--fs/driverfs/inode.c26
-rw-r--r--fs/libfs.c8
-rw-r--r--fs/partitions/check.c138
-rw-r--r--fs/proc/array.c12
-rw-r--r--fs/proc/proc_misc.c18
-rw-r--r--fs/ramfs/inode.c32
-rw-r--r--include/linux/cdrom.h2
-rw-r--r--include/linux/fs.h3
-rw-r--r--include/linux/genhd.h4
-rw-r--r--include/linux/interrupt.h1
-rw-r--r--kernel/ksyms.c2
-rw-r--r--mm/mmap.c83
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,