Commit 64ef3596 authored by David S. Miller's avatar David S. Miller

Merge nuts.ninka.net:/disk1/davem/BK/sparcwork-2.5

into nuts.ninka.net:/disk1/davem/BK/sparc-2.5
parents 34f369c1 da2ee261
...@@ -49,6 +49,8 @@ ...@@ -49,6 +49,8 @@
#include <asm/page.h> #include <asm/page.h>
#include "irq_vectors.h" #include "irq_vectors.h"
#define nr_syscalls ((syscall_table_size)/4)
EBX = 0x00 EBX = 0x00
ECX = 0x04 ECX = 0x04
EDX = 0x08 EDX = 0x08
...@@ -881,4 +883,4 @@ ENTRY(sys_call_table) ...@@ -881,4 +883,4 @@ ENTRY(sys_call_table)
.long sys_fadvise64_64 .long sys_fadvise64_64
.long sys_ni_syscall /* sys_vserver */ .long sys_ni_syscall /* sys_vserver */
nr_syscalls=(.-sys_call_table)/4 syscall_table_size=(.-sys_call_table)
...@@ -720,6 +720,9 @@ restore_sigcontext_ia32 (struct pt_regs *regs, struct sigcontext_ia32 *sc, int * ...@@ -720,6 +720,9 @@ restore_sigcontext_ia32 (struct pt_regs *regs, struct sigcontext_ia32 *sc, int *
{ {
unsigned int err = 0; unsigned int err = 0;
/* Always make any pending restarted system calls return -EINTR */
current_thread_info()->restart_block.fn = do_no_restart_syscall;
if (!access_ok(VERIFY_READ, sc, sizeof(*sc))) if (!access_ok(VERIFY_READ, sc, sizeof(*sc)))
return(-EFAULT); return(-EFAULT);
......
...@@ -77,7 +77,7 @@ void ...@@ -77,7 +77,7 @@ void
ia64_patch_imm60 (u64 insn_addr, u64 val) ia64_patch_imm60 (u64 insn_addr, u64 val)
{ {
ia64_patch(insn_addr, ia64_patch(insn_addr,
0x011ffffe000, ( ((val & 0x1000000000000000) >> 24) /* bit 60 -> 36 */ 0x011ffffe000, ( ((val & 0x0800000000000000) >> 23) /* bit 59 -> 36 */
| ((val & 0x00000000000fffff) << 13) /* bit 0 -> 13 */)); | ((val & 0x00000000000fffff) << 13) /* bit 0 -> 13 */));
ia64_patch(insn_addr - 1, 0x1fffffffffc, val >> 18); ia64_patch(insn_addr - 1, 0x1fffffffffc, val >> 18);
} }
......
...@@ -115,6 +115,9 @@ restore_sigcontext (struct sigcontext *sc, struct sigscratch *scr) ...@@ -115,6 +115,9 @@ restore_sigcontext (struct sigcontext *sc, struct sigscratch *scr)
unsigned long ip, flags, nat, um, cfm; unsigned long ip, flags, nat, um, cfm;
long err; long err;
/* Always make any pending restarted system calls return -EINTR */
current_thread_info()->restart_block.fn = do_no_restart_syscall;
/* restore scratch that always needs gets updated during signal delivery: */ /* restore scratch that always needs gets updated during signal delivery: */
err = __get_user(flags, &sc->sc_flags); err = __get_user(flags, &sc->sc_flags);
err |= __get_user(nat, &sc->sc_nat); err |= __get_user(nat, &sc->sc_nat);
...@@ -559,9 +562,6 @@ ia64_do_signal (sigset_t *oldset, struct sigscratch *scr, long in_syscall) ...@@ -559,9 +562,6 @@ ia64_do_signal (sigset_t *oldset, struct sigscratch *scr, long in_syscall)
ka = &current->sighand->action[signr - 1]; ka = &current->sighand->action[signr - 1];
/* Always make any pending restarted system calls return -EINTR */
current_thread_info()->restart_block.fn = do_no_restart_syscall;
if (restart) { if (restart) {
switch (errno) { switch (errno) {
case ERESTART_RESTARTBLOCK: case ERESTART_RESTARTBLOCK:
......
...@@ -219,16 +219,14 @@ ia64_bad_break (unsigned long break_num, struct pt_regs *regs) ...@@ -219,16 +219,14 @@ ia64_bad_break (unsigned long break_num, struct pt_regs *regs)
* Unimplemented system calls. This is called only for stuff that * Unimplemented system calls. This is called only for stuff that
* we're supposed to implement but haven't done so yet. Everything * we're supposed to implement but haven't done so yet. Everything
* else goes to sys_ni_syscall. * else goes to sys_ni_syscall.
*
* XXX Remove this for v2.6.1.
*/ */
asmlinkage long asmlinkage long
ia64_ni_syscall (unsigned long arg0, unsigned long arg1, unsigned long arg2, unsigned long arg3, ia64_ni_syscall (unsigned long arg0, unsigned long arg1, unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5, unsigned long arg6, unsigned long arg7, unsigned long arg4, unsigned long arg5, unsigned long arg6, unsigned long arg7,
unsigned long stack) unsigned long stack)
{ {
struct pt_regs *regs = (struct pt_regs *) &stack;
printk(KERN_DEBUG "%s(%d): <sc%ld(%lx,%lx,%lx,%lx)>\n", current->comm, current->pid,
regs->r15, arg0, arg1, arg2, arg3);
return -ENOSYS; return -ENOSYS;
} }
......
...@@ -991,7 +991,7 @@ static int sbp2_start_device(struct scsi_id_instance_data *scsi_id) ...@@ -991,7 +991,7 @@ static int sbp2_start_device(struct scsi_id_instance_data *scsi_id)
static void sbp2_remove_device(struct scsi_id_instance_data *scsi_id) static void sbp2_remove_device(struct scsi_id_instance_data *scsi_id)
{ {
struct sbp2scsi_host_info *hi = scsi_id->hi; struct sbp2scsi_host_info *hi = scsi_id->hi;
struct scsi_device *sdev = scsi_find_device(hi->scsi_host, 0, scsi_id->id, 0); struct scsi_device *sdev;
SBP2_DEBUG("sbp2_remove_device"); SBP2_DEBUG("sbp2_remove_device");
...@@ -999,8 +999,13 @@ static void sbp2_remove_device(struct scsi_id_instance_data *scsi_id) ...@@ -999,8 +999,13 @@ static void sbp2_remove_device(struct scsi_id_instance_data *scsi_id)
sbp2scsi_complete_all_commands(scsi_id, DID_NO_CONNECT); sbp2scsi_complete_all_commands(scsi_id, DID_NO_CONNECT);
/* Remove it from the scsi layer now */ /* Remove it from the scsi layer now */
if (sdev) /* XXX(hch): why can't we simply cache the scsi_device
in struct scsi_id_instance_data? */
sdev = scsi_device_lookup(hi->scsi_host, 0, scsi_id->id, 0);
if (sdev) {
scsi_remove_device(sdev); scsi_remove_device(sdev);
scsi_device_put(sdev);
}
sbp2util_remove_command_orb_pool(scsi_id); sbp2util_remove_command_orb_pool(scsi_id);
......
...@@ -1065,7 +1065,7 @@ process_script_interrupt(__u32 dsps, __u32 dsp, Scsi_Cmnd *SCp, ...@@ -1065,7 +1065,7 @@ process_script_interrupt(__u32 dsps, __u32 dsp, Scsi_Cmnd *SCp,
DEBUG(("scsi%d: (%d:%d) RESELECTED!\n", DEBUG(("scsi%d: (%d:%d) RESELECTED!\n",
host->host_no, reselection_id, lun)); host->host_no, reselection_id, lun));
/* clear the reselection indicator */ /* clear the reselection indicator */
SDp = scsi_find_device(host, 0, reselection_id, lun); SDp = __scsi_device_lookup(host, 0, reselection_id, lun);
if(unlikely(SDp == NULL)) { if(unlikely(SDp == NULL)) {
printk(KERN_ERR "scsi%d: (%d:%d) HAS NO device\n", printk(KERN_ERR "scsi%d: (%d:%d) HAS NO device\n",
host->host_no, reselection_id, lun); host->host_no, reselection_id, lun);
...@@ -1498,7 +1498,7 @@ NCR_700_intr(int irq, void *dev_id, struct pt_regs *regs) ...@@ -1498,7 +1498,7 @@ NCR_700_intr(int irq, void *dev_id, struct pt_regs *regs)
host->host_no, SCp, SCp == NULL ? NULL : SCp->host_scribble, dsp, dsp - hostdata->pScript); host->host_no, SCp, SCp == NULL ? NULL : SCp->host_scribble, dsp, dsp - hostdata->pScript);
/* clear all the negotiated parameters */ /* clear all the negotiated parameters */
list_for_each_entry(SDp, &host->my_devices, siblings) __shost_for_each_device(SDp, host)
SDp->hostdata = 0; SDp->hostdata = 0;
/* clear all the slots and their pending commands */ /* clear all the slots and their pending commands */
......
...@@ -815,6 +815,7 @@ static int copy_info(struct info_str *info, char *fmt, ...) ...@@ -815,6 +815,7 @@ static int copy_info(struct info_str *info, char *fmt, ...)
static int esp_host_info(struct NCR_ESP *esp, char *ptr, off_t offset, int len) static int esp_host_info(struct NCR_ESP *esp, char *ptr, off_t offset, int len)
{ {
struct scsi_device *sdev;
struct info_str info; struct info_str info;
int i; int i;
...@@ -867,23 +868,20 @@ static int esp_host_info(struct NCR_ESP *esp, char *ptr, off_t offset, int len) ...@@ -867,23 +868,20 @@ static int esp_host_info(struct NCR_ESP *esp, char *ptr, off_t offset, int len)
/* Now describe the state of each existing target. */ /* Now describe the state of each existing target. */
copy_info(&info, "Target #\tconfig3\t\tSync Capabilities\tDisconnect\n"); copy_info(&info, "Target #\tconfig3\t\tSync Capabilities\tDisconnect\n");
for(i = 0; i < 15; i++) {
if(esp->targets_present & (1 << i)) {
Scsi_Device *SDptr;
struct esp_device *esp_dev;
list_for_each_entry(SDptr, &esp->ehost->my_devices, shost_for_each_device(sdev, esp->ehost) {
siblings) struct esp_device *esp_dev = sdev->hostdata;
if(SDptr->id == i) uint id = sdev->id;
break;
esp_dev = SDptr->hostdata; if (!(esp->targets_present & (1 << id)))
copy_info(&info, "%d\t\t", i); continue;
copy_info(&info, "%08lx\t", esp->config3[i]);
copy_info(&info, "[%02lx,%02lx]\t\t\t", esp_dev->sync_max_offset, copy_info(&info, "%d\t\t", id);
esp_dev->sync_min_period); copy_info(&info, "%08lx\t", esp->config3[id]);
copy_info(&info, "%s\n", esp_dev->disconnect ? "yes" : "no"); copy_info(&info, "[%02lx,%02lx]\t\t\t",
} esp_dev->sync_max_offset,
esp_dev->sync_min_period);
copy_info(&info, "%s\n", esp_dev->disconnect ? "yes" : "no");
} }
return info.pos > info.offset? info.pos - info.offset : 0; return info.pos > info.offset? info.pos - info.offset : 0;
......
...@@ -2930,7 +2930,7 @@ int acornscsi_proc_info(struct Scsi_Host *instance, char *buffer, char **start, ...@@ -2930,7 +2930,7 @@ int acornscsi_proc_info(struct Scsi_Host *instance, char *buffer, char **start,
p += sprintf(p, "\nAttached devices:\n"); p += sprintf(p, "\nAttached devices:\n");
list_for_each_entry(scd, &instance->my_devices, siblings) { shost_for_each_device(scd, instance) {
p += sprintf(p, "Device/Lun TaggedQ Sync\n"); p += sprintf(p, "Device/Lun TaggedQ Sync\n");
p += sprintf(p, " %d/%d ", scd->id, scd->lun); p += sprintf(p, " %d/%d ", scd->id, scd->lun);
if (scd->tagged_supported) if (scd->tagged_supported)
...@@ -2953,8 +2953,10 @@ int acornscsi_proc_info(struct Scsi_Host *instance, char *buffer, char **start, ...@@ -2953,8 +2953,10 @@ int acornscsi_proc_info(struct Scsi_Host *instance, char *buffer, char **start,
p = buffer; p = buffer;
} }
pos = p - buffer; pos = p - buffer;
if (pos + begin > offset + length) if (pos + begin > offset + length) {
scsi_device_put(scd);
break; break;
}
} }
pos = p - buffer; pos = p - buffer;
......
...@@ -1309,6 +1309,7 @@ static int copy_info(struct info_str *info, char *fmt, ...) ...@@ -1309,6 +1309,7 @@ static int copy_info(struct info_str *info, char *fmt, ...)
static int esp_host_info(struct esp *esp, char *ptr, off_t offset, int len) static int esp_host_info(struct esp *esp, char *ptr, off_t offset, int len)
{ {
struct scsi_device *sdev;
struct info_str info; struct info_str info;
int i; int i;
...@@ -1384,25 +1385,23 @@ static int esp_host_info(struct esp *esp, char *ptr, off_t offset, int len) ...@@ -1384,25 +1385,23 @@ static int esp_host_info(struct esp *esp, char *ptr, off_t offset, int len)
/* Now describe the state of each existing target. */ /* Now describe the state of each existing target. */
copy_info(&info, "Target #\tconfig3\t\tSync Capabilities\tDisconnect\tWide\n"); copy_info(&info, "Target #\tconfig3\t\tSync Capabilities\tDisconnect\tWide\n");
for (i = 0; i < 15; i++) {
if (esp->targets_present & (1 << i)) { shost_for_each_device(sdev, esp->ehost) {
Scsi_Device *SDptr; struct esp_device *esp_dev = sdev->hostdata;
struct esp_device *esp_dev; uint id = sdev->id;
list_for_each_entry(SDptr, &esp->ehost->my_devices, if (!(esp->targets_present & (1 << id)))
siblings) continue;
if(SDptr->id == i)
break; copy_info(&info, "%d\t\t", id);
copy_info(&info, "%08lx\t", esp->config3[id]);
esp_dev = SDptr->hostdata; copy_info(&info, "[%02lx,%02lx]\t\t\t",
copy_info(&info, "%d\t\t", i); esp_dev->sync_max_offset,
copy_info(&info, "%08lx\t", esp->config3[i]); esp_dev->sync_min_period);
copy_info(&info, "[%02lx,%02lx]\t\t\t", esp_dev->sync_max_offset, copy_info(&info, "%s\t\t",
esp_dev->sync_min_period); esp_dev->disconnect ? "yes" : "no");
copy_info(&info, "%s\t\t", esp_dev->disconnect ? "yes" : "no"); copy_info(&info, "%s\n",
copy_info(&info, "%s\n", (esp->config3[id] & ESP_CONFIG3_EWIDE) ? "yes" : "no");
(esp->config3[i] & ESP_CONFIG3_EWIDE) ? "yes" : "no");
}
} }
return info.pos > info.offset? info.pos - info.offset : 0; return info.pos > info.offset? info.pos - info.offset : 0;
} }
......
...@@ -228,7 +228,7 @@ int fcal_proc_info (struct Scsi_Host *host, char *buffer, char **start, off_t of ...@@ -228,7 +228,7 @@ int fcal_proc_info (struct Scsi_Host *host, char *buffer, char **start, off_t of
#endif #endif
SPRINTF ("Initiator AL-PA: %02x\n", fc->sid); SPRINTF ("Initiator AL-PA: %02x\n", fc->sid);
SPRINTF ("\nAttached devices: %s\n", !list_empty(&host->my_devices) ? "" : "none"); SPRINTF ("\nAttached devices:\n");
for (i = 0; i < fc->posmap->len; i++) { for (i = 0; i < fc->posmap->len; i++) {
unsigned char alpa = fc->posmap->list[i]; unsigned char alpa = fc->posmap->list[i];
......
/* /*
* hosts.c Copyright (C) 1992 Drew Eckhardt * hosts.c Copyright (C) 1992 Drew Eckhardt
* Copyright (C) 1993, 1994, 1995 Eric Youngdale * Copyright (C) 1993, 1994, 1995 Eric Youngdale
* Copyright (C) 2002-2003 Christoph Hellwig
* *
* mid to lowlevel SCSI driver interface * mid to lowlevel SCSI driver interface
* Initial versions: Drew Eckhardt * Initial versions: Drew Eckhardt
...@@ -30,8 +31,8 @@ ...@@ -30,8 +31,8 @@
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/unistd.h> #include <linux/unistd.h>
#include <scsi/scsi_host.h>
#include "scsi.h" #include "scsi.h"
#include "hosts.h"
#include "scsi_priv.h" #include "scsi_priv.h"
#include "scsi_logging.h" #include "scsi_logging.h"
...@@ -50,6 +51,11 @@ static struct class shost_class = { ...@@ -50,6 +51,11 @@ static struct class shost_class = {
.release = scsi_host_cls_release, .release = scsi_host_cls_release,
}; };
static int scsi_device_cancel_cb(struct device *dev, void *data)
{
return scsi_device_cancel(to_scsi_device(dev), *(int *)data);
}
/** /**
* scsi_host_cancel - cancel outstanding IO to this host * scsi_host_cancel - cancel outstanding IO to this host
* @shost: pointer to struct Scsi_Host * @shost: pointer to struct Scsi_Host
...@@ -57,11 +63,7 @@ static struct class shost_class = { ...@@ -57,11 +63,7 @@ static struct class shost_class = {
**/ **/
void scsi_host_cancel(struct Scsi_Host *shost, int recovery) void scsi_host_cancel(struct Scsi_Host *shost, int recovery)
{ {
unsigned long flags;
spin_lock_irqsave(shost->host_lock, flags);
set_bit(SHOST_CANCEL, &shost->shost_state); set_bit(SHOST_CANCEL, &shost->shost_state);
spin_unlock_irqrestore(shost->host_lock, flags);
device_for_each_child(&shost->shost_gendev, &recovery, device_for_each_child(&shost->shost_gendev, &recovery,
scsi_device_cancel_cb); scsi_device_cancel_cb);
wait_event(shost->host_wait, (!test_bit(SHOST_RECOVERY, wait_event(shost->host_wait, (!test_bit(SHOST_RECOVERY,
...@@ -74,15 +76,11 @@ void scsi_host_cancel(struct Scsi_Host *shost, int recovery) ...@@ -74,15 +76,11 @@ void scsi_host_cancel(struct Scsi_Host *shost, int recovery)
**/ **/
void scsi_remove_host(struct Scsi_Host *shost) void scsi_remove_host(struct Scsi_Host *shost)
{ {
unsigned long flags;
scsi_host_cancel(shost, 0); scsi_host_cancel(shost, 0);
scsi_proc_host_rm(shost); scsi_proc_host_rm(shost);
scsi_forget_host(shost); scsi_forget_host(shost);
spin_lock_irqsave(shost->host_lock, flags);
set_bit(SHOST_DEL, &shost->shost_state); set_bit(SHOST_DEL, &shost->shost_state);
spin_unlock_irqrestore(shost->host_lock, flags);
class_device_unregister(&shost->shost_classdev); class_device_unregister(&shost->shost_classdev);
device_del(&shost->shost_gendev); device_del(&shost->shost_gendev);
...@@ -209,7 +207,7 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) ...@@ -209,7 +207,7 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
spin_lock_init(&shost->default_lock); spin_lock_init(&shost->default_lock);
scsi_assign_lock(shost, &shost->default_lock); scsi_assign_lock(shost, &shost->default_lock);
INIT_LIST_HEAD(&shost->my_devices); INIT_LIST_HEAD(&shost->__devices);
INIT_LIST_HEAD(&shost->eh_cmd_q); INIT_LIST_HEAD(&shost->eh_cmd_q);
INIT_LIST_HEAD(&shost->starved_list); INIT_LIST_HEAD(&shost->starved_list);
init_waitqueue_head(&shost->host_wait); init_waitqueue_head(&shost->host_wait);
...@@ -323,23 +321,20 @@ void scsi_unregister(struct Scsi_Host *shost) ...@@ -323,23 +321,20 @@ void scsi_unregister(struct Scsi_Host *shost)
**/ **/
struct Scsi_Host *scsi_host_lookup(unsigned short hostnum) struct Scsi_Host *scsi_host_lookup(unsigned short hostnum)
{ {
struct class *class = class_get(&shost_class); struct class *class = &shost_class;
struct class_device *cdev; struct class_device *cdev;
struct Scsi_Host *shost = ERR_PTR(-ENXIO), *p; struct Scsi_Host *shost = ERR_PTR(-ENXIO), *p;
if (class) { down_read(&class->subsys.rwsem);
down_read(&class->subsys.rwsem); list_for_each_entry(cdev, &class->children, node) {
list_for_each_entry(cdev, &class->children, node) { p = class_to_shost(cdev);
p = class_to_shost(cdev); if (p->host_no == hostnum) {
if (p->host_no == hostnum) { shost = scsi_host_get(p);
shost = scsi_host_get(p); break;
break;
}
} }
up_read(&class->subsys.rwsem);
} }
up_read(&class->subsys.rwsem);
class_put(&shost_class);
return shost; return shost;
} }
......
/* // #warning "This file is obsolete, please use <scsi/scsi_host.h> instead"
* hosts.h Copyright (C) 1992 Drew Eckhardt
* Copyright (C) 1993, 1994, 1995, 1998, 1999 Eric Youngdale
*
* mid to low-level SCSI driver interface header
* Initial versions: Drew Eckhardt
* Subsequent revisions: Eric Youngdale
*
* <drew@colorado.edu>
*
* Modified by Eric Youngdale eric@andante.org to
* add scatter-gather, multiple outstanding request, and other
* enhancements.
*
* Further modified by Eric Youngdale to support multiple host adapters
* of the same type.
*
* Jiffies wrap fixes (host->resetting), 3 Dec 1998 Andrea Arcangeli
*
* Restructured scsi_host lists and associated functions.
* September 04, 2002 Mike Anderson (andmike@us.ibm.com)
*/
#ifndef _HOSTS_H
#define _HOSTS_H
#include <linux/config.h>
#include <scsi/scsi_host.h> #include <scsi/scsi_host.h>
/**
* scsi_find_device - find a device given the host
* @shost: SCSI host pointer
* @channel: SCSI channel (zero if only one channel)
* @pun: SCSI target number (physical unit number)
* @lun: SCSI Logical Unit Number
**/
static inline struct scsi_device *scsi_find_device(struct Scsi_Host *shost,
int channel, int pun, int lun) {
struct scsi_device *sdev;
list_for_each_entry (sdev, &shost->my_devices, siblings)
if (sdev->channel == channel && sdev->id == pun
&& sdev->lun ==lun)
return sdev;
return NULL;
}
#endif
...@@ -69,8 +69,9 @@ static Scsi_Host_Template lasi700_template = { ...@@ -69,8 +69,9 @@ static Scsi_Host_Template lasi700_template = {
.name = "LASI SCSI 53c700", .name = "LASI SCSI 53c700",
.proc_name = "lasi700", .proc_name = "lasi700",
.this_id = 7, .this_id = 7,
.module = THIS_MODULE,
}; };
MODULE_DEVICE_TABLE(parisc, lasi700_scsi_tbl); MODULE_DEVICE_TABLE(parisc, lasi700_ids);
static int __init static int __init
lasi700_probe(struct parisc_device *dev) lasi700_probe(struct parisc_device *dev)
......
/* /*
* scsi.c Copyright (C) 1992 Drew Eckhardt * scsi.c Copyright (C) 1992 Drew Eckhardt
* Copyright (C) 1993, 1994, 1995, 1999 Eric Youngdale * Copyright (C) 1993, 1994, 1995, 1999 Eric Youngdale
* Copyright (C) 2002, 2003 Christoph Hellwig
* *
* generic mid-level SCSI driver * generic mid-level SCSI driver
* Initial versions: Drew Eckhardt * Initial versions: Drew Eckhardt
...@@ -36,7 +37,6 @@ ...@@ -36,7 +37,6 @@
* out_of_space hacks, D. Gilbert (dpg) 990608 * out_of_space hacks, D. Gilbert (dpg) 990608
*/ */
#include <linux/config.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -54,8 +54,8 @@ ...@@ -54,8 +54,8 @@
#include <linux/kmod.h> #include <linux/kmod.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <scsi/scsi_host.h>
#include "scsi.h" #include "scsi.h"
#include "hosts.h"
#include "scsi_priv.h" #include "scsi_priv.h"
#include "scsi_logging.h" #include "scsi_logging.h"
...@@ -883,49 +883,124 @@ int scsi_track_queue_full(struct scsi_device *sdev, int depth) ...@@ -883,49 +883,124 @@ int scsi_track_queue_full(struct scsi_device *sdev, int depth)
return depth; return depth;
} }
/**
* scsi_device_get - get an addition reference to a scsi_device
* @sdev: device to get a reference to
*
* Gets a reference to the scsi_device and increments the use count
* of the underlying LLDD module. You must hold host_lock of the
* parent Scsi_Host or already have a reference when calling this.
*/
int scsi_device_get(struct scsi_device *sdev) int scsi_device_get(struct scsi_device *sdev)
{ {
struct class *class = class_get(&sdev_class);
if (!class)
goto out;
if (test_bit(SDEV_DEL, &sdev->sdev_state)) if (test_bit(SDEV_DEL, &sdev->sdev_state))
goto out; return -ENXIO;
if (!try_module_get(sdev->host->hostt->module))
goto out;
if (!get_device(&sdev->sdev_gendev)) if (!get_device(&sdev->sdev_gendev))
goto out_put_module; return -ENXIO;
atomic_inc(&sdev->access_count); if (!try_module_get(sdev->host->hostt->module)) {
class_put(&sdev_class); put_device(&sdev->sdev_gendev);
return -ENXIO;
}
return 0; return 0;
}
EXPORT_SYMBOL(scsi_device_get);
out_put_module: /**
* scsi_device_put - release a reference to a scsi_device
* @sdev: device to release a reference on.
*
* Release a reference to the scsi_device and decrements the use count
* of the underlying LLDD module. The device is freed once the last
* user vanishes.
*/
void scsi_device_put(struct scsi_device *sdev)
{
module_put(sdev->host->hostt->module); module_put(sdev->host->hostt->module);
out: put_device(&sdev->sdev_gendev);
class_put(&sdev_class);
return -ENXIO;
} }
EXPORT_SYMBOL(scsi_device_put);
void scsi_device_put(struct scsi_device *sdev) /* helper for shost_for_each_device, thus not documented */
struct scsi_device *__scsi_iterate_devices(struct Scsi_Host *shost,
struct scsi_device *prev)
{ {
struct class *class = class_get(&sdev_class); struct list_head *list = (prev ? &prev->siblings : &shost->__devices);
struct scsi_device *next = NULL;
unsigned long flags;
if (!class) spin_lock_irqsave(shost->host_lock, flags);
return; while (list->next != &shost->__devices) {
next = list_entry(list->next, struct scsi_device, siblings);
/* skip devices that we can't get a reference to */
if (!scsi_device_get(next))
break;
list = list->next;
}
spin_unlock_irqrestore(shost->host_lock, flags);
module_put(sdev->host->hostt->module); if (prev)
atomic_dec(&sdev->access_count); scsi_device_put(prev);
put_device(&sdev->sdev_gendev); return next;
class_put(&sdev_class);
} }
EXPORT_SYMBOL(__scsi_iterate_devices);
int scsi_device_cancel_cb(struct device *dev, void *data) /**
* scsi_device_lookup - find a device given the host (UNLOCKED)
* @shost: SCSI host pointer
* @channel: SCSI channel (zero if only one channel)
* @pun: SCSI target number (physical unit number)
* @lun: SCSI Logical Unit Number
*
* Looks up the scsi_device with the specified @channel, @id, @lun for a
* give host. The returned scsi_device does not have an additional reference.
* You must hold the host's host_lock over this call and any access to the
* returned scsi_device.
*
* Note: The only reason why drivers would want to use this is because
* they're need to access the device list in irq context. Otherwise you
* really want to use scsi_device_lookup instead.
**/
struct scsi_device *__scsi_device_lookup(struct Scsi_Host *shost,
uint channel, uint id, uint lun)
{ {
struct scsi_device *sdev = to_scsi_device(dev); struct scsi_device *sdev;
int recovery = *(int *)data;
list_for_each_entry(sdev, &shost->__devices, siblings) {
if (sdev->channel == channel && sdev->id == id &&
sdev->lun ==lun)
return sdev;
}
return NULL;
}
EXPORT_SYMBOL(__scsi_device_lookup);
/**
* scsi_device_lookup - find a device given the host
* @shost: SCSI host pointer
* @channel: SCSI channel (zero if only one channel)
* @id: SCSI target number (physical unit number)
* @lun: SCSI Logical Unit Number
*
* Looks up the scsi_device with the specified @channel, @id, @lun for a
* give host. The returned scsi_device has an additional reference that
* needs to be release with scsi_host_put once you're done with it.
**/
struct scsi_device *scsi_device_lookup(struct Scsi_Host *shost,
uint channel, uint id, uint lun)
{
struct scsi_device *sdev;
unsigned long flags;
spin_lock_irqsave(shost->host_lock, flags);
sdev = __scsi_device_lookup(shost, channel, id, lun);
if (sdev && scsi_device_get(sdev))
sdev = NULL;
spin_unlock_irqrestore(shost->host_lock, flags);
return scsi_device_cancel(sdev, recovery); return sdev;
} }
EXPORT_SYMBOL(scsi_device_lookup);
/** /**
* scsi_device_cancel - cancel outstanding IO to this device * scsi_device_cancel - cancel outstanding IO to this device
......
...@@ -16,9 +16,9 @@ ...@@ -16,9 +16,9 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/pci.h> #include <linux/pci.h>
#include "scsi.h"
#include "hosts.h"
#include <scsi/scsi_driver.h> #include <scsi/scsi_driver.h>
#include <scsi/scsi_host.h>
#include "scsi.h"
#include "scsi_priv.h" #include "scsi_priv.h"
#include "scsi_logging.h" #include "scsi_logging.h"
...@@ -335,13 +335,14 @@ void scsi_device_unbusy(struct scsi_device *sdev) ...@@ -335,13 +335,14 @@ void scsi_device_unbusy(struct scsi_device *sdev)
*/ */
static void scsi_single_lun_run(struct scsi_device *current_sdev) static void scsi_single_lun_run(struct scsi_device *current_sdev)
{ {
struct scsi_device *sdev; struct Scsi_Host *shost = current_sdev->host;
struct scsi_device *sdev, *tmp;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(current_sdev->host->host_lock, flags); spin_lock_irqsave(shost->host_lock, flags);
WARN_ON(!current_sdev->sdev_target->starget_sdev_user); WARN_ON(!current_sdev->sdev_target->starget_sdev_user);
current_sdev->sdev_target->starget_sdev_user = NULL; current_sdev->sdev_target->starget_sdev_user = NULL;
spin_unlock_irqrestore(current_sdev->host->host_lock, flags); spin_unlock_irqrestore(shost->host_lock, flags);
/* /*
* Call blk_run_queue for all LUNs on the target, starting with * Call blk_run_queue for all LUNs on the target, starting with
...@@ -351,21 +352,26 @@ static void scsi_single_lun_run(struct scsi_device *current_sdev) ...@@ -351,21 +352,26 @@ static void scsi_single_lun_run(struct scsi_device *current_sdev)
*/ */
blk_run_queue(current_sdev->request_queue); blk_run_queue(current_sdev->request_queue);
spin_lock_irqsave(current_sdev->host->host_lock, flags); /*
if (current_sdev->sdev_target->starget_sdev_user) { * After unlock, this races with anyone clearing starget_sdev_user,
/* * but we always enter this function again, avoiding any problems.
* After unlock, this races with anyone clearing */
* starget_sdev_user, but we (should) always enter this spin_lock_irqsave(shost->host_lock, flags);
* function again, avoiding any problems. if (current_sdev->sdev_target->starget_sdev_user)
*/ goto out;
spin_unlock_irqrestore(current_sdev->host->host_lock, flags); list_for_each_entry_safe(sdev, tmp, &current_sdev->same_target_siblings,
return; same_target_siblings) {
} if (scsi_device_get(sdev))
spin_unlock_irqrestore(current_sdev->host->host_lock, flags); continue;
list_for_each_entry(sdev, &current_sdev->same_target_siblings, spin_unlock_irqrestore(shost->host_lock, flags);
same_target_siblings)
blk_run_queue(sdev->request_queue); blk_run_queue(sdev->request_queue);
spin_lock_irqsave(shost->host_lock, flags);
scsi_device_put(sdev);
}
out:
spin_unlock_irqrestore(shost->host_lock, flags);
} }
/* /*
......
...@@ -27,8 +27,8 @@ ...@@ -27,8 +27,8 @@
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <scsi/scsi_host.h>
#include "scsi.h" #include "scsi.h"
#include "hosts.h"
#include "scsi_priv.h" #include "scsi_priv.h"
#include "scsi_logging.h" #include "scsi_logging.h"
...@@ -212,15 +212,13 @@ static int scsi_remove_single_device(uint host, uint channel, uint id, uint lun) ...@@ -212,15 +212,13 @@ static int scsi_remove_single_device(uint host, uint channel, uint id, uint lun)
shost = scsi_host_lookup(host); shost = scsi_host_lookup(host);
if (IS_ERR(shost)) if (IS_ERR(shost))
return PTR_ERR(shost); return PTR_ERR(shost);
sdev = scsi_find_device(shost, channel, id, lun); sdev = scsi_device_lookup(shost, channel, id, lun);
if (!sdev) if (sdev) {
goto out; scsi_remove_device(sdev);
if (atomic_read(&sdev->access_count)) scsi_device_put(sdev);
goto out; error = 0;
}
scsi_remove_device(sdev);
error = 0;
out:
scsi_host_put(shost); scsi_host_put(shost);
return error; return error;
} }
......
...@@ -32,10 +32,10 @@ ...@@ -32,10 +32,10 @@
#include <linux/blkdev.h> #include <linux/blkdev.h>
#include <asm/semaphore.h> #include <asm/semaphore.h>
#include "scsi.h"
#include "hosts.h"
#include <scsi/scsi_driver.h> #include <scsi/scsi_driver.h>
#include <scsi/scsi_devinfo.h> #include <scsi/scsi_devinfo.h>
#include <scsi/scsi_host.h>
#include "scsi.h"
#include "scsi_priv.h" #include "scsi_priv.h"
#include "scsi_logging.h" #include "scsi_logging.h"
...@@ -190,13 +190,13 @@ static struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost, ...@@ -190,13 +190,13 @@ static struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost,
uint channel, uint id, uint lun) uint channel, uint id, uint lun)
{ {
struct scsi_device *sdev, *device; struct scsi_device *sdev, *device;
unsigned long flags;
sdev = kmalloc(sizeof(*sdev), GFP_ATOMIC); sdev = kmalloc(sizeof(*sdev), GFP_ATOMIC);
if (!sdev) if (!sdev)
goto out; goto out;
memset(sdev, 0, sizeof(*sdev)); memset(sdev, 0, sizeof(*sdev));
atomic_set(&sdev->access_count, 0);
sdev->vendor = scsi_null_device_strs; sdev->vendor = scsi_null_device_strs;
sdev->model = scsi_null_device_strs; sdev->model = scsi_null_device_strs;
sdev->rev = scsi_null_device_strs; sdev->rev = scsi_null_device_strs;
...@@ -240,7 +240,8 @@ static struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost, ...@@ -240,7 +240,8 @@ static struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost,
* If there are any same target siblings, add this to the * If there are any same target siblings, add this to the
* sibling list * sibling list
*/ */
list_for_each_entry(device, &shost->my_devices, siblings) { spin_lock_irqsave(shost->host_lock, flags);
list_for_each_entry(device, &shost->__devices, siblings) {
if (device->id == sdev->id && if (device->id == sdev->id &&
device->channel == sdev->channel) { device->channel == sdev->channel) {
list_add_tail(&sdev->same_target_siblings, list_add_tail(&sdev->same_target_siblings,
...@@ -258,10 +259,8 @@ static struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost, ...@@ -258,10 +259,8 @@ static struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost,
if (!sdev->scsi_level) if (!sdev->scsi_level)
sdev->scsi_level = SCSI_2; sdev->scsi_level = SCSI_2;
/* list_add_tail(&sdev->siblings, &shost->__devices);
* Add it to the end of the shost->my_devices list. spin_unlock_irqrestore(shost->host_lock, flags);
*/
list_add_tail(&sdev->siblings, &shost->my_devices);
return sdev; return sdev;
out_free_queue: out_free_queue:
...@@ -285,21 +284,21 @@ void scsi_free_sdev(struct scsi_device *sdev) ...@@ -285,21 +284,21 @@ void scsi_free_sdev(struct scsi_device *sdev)
{ {
unsigned long flags; unsigned long flags;
spin_lock_irqsave(sdev->host->host_lock, flags);
list_del(&sdev->siblings); list_del(&sdev->siblings);
list_del(&sdev->same_target_siblings); list_del(&sdev->same_target_siblings);
spin_unlock_irqrestore(sdev->host->host_lock, flags);
if (sdev->request_queue) if (sdev->request_queue)
scsi_free_queue(sdev->request_queue); scsi_free_queue(sdev->request_queue);
if (sdev->inquiry)
kfree(sdev->inquiry);
spin_lock_irqsave(sdev->host->host_lock, flags); spin_lock_irqsave(sdev->host->host_lock, flags);
list_del(&sdev->starved_entry); list_del(&sdev->starved_entry);
if (sdev->single_lun) { if (sdev->single_lun && --sdev->sdev_target->starget_refcnt == 0)
if (--sdev->sdev_target->starget_refcnt == 0) kfree(sdev->sdev_target);
kfree(sdev->sdev_target);
}
spin_unlock_irqrestore(sdev->host->host_lock, flags); spin_unlock_irqrestore(sdev->host->host_lock, flags);
kfree(sdev->inquiry);
kfree(sdev); kfree(sdev);
} }
...@@ -678,7 +677,7 @@ static int scsi_probe_and_add_lun(struct Scsi_Host *host, ...@@ -678,7 +677,7 @@ static int scsi_probe_and_add_lun(struct Scsi_Host *host,
* host adapter calls into here with rescan == 0. * host adapter calls into here with rescan == 0.
*/ */
if (rescan) { if (rescan) {
sdev = scsi_find_device(host, channel, id, lun); sdev = scsi_device_lookup(host, channel, id, lun);
if (sdev) { if (sdev) {
SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO
"scsi scan: device exists on <%d:%d:%d:%d>\n", "scsi scan: device exists on <%d:%d:%d:%d>\n",
...@@ -689,6 +688,8 @@ static int scsi_probe_and_add_lun(struct Scsi_Host *host, ...@@ -689,6 +688,8 @@ static int scsi_probe_and_add_lun(struct Scsi_Host *host,
*bflagsp = scsi_get_device_flags(sdev, *bflagsp = scsi_get_device_flags(sdev,
sdev->vendor, sdev->vendor,
sdev->model); sdev->model);
/* XXX: bandaid until callers do refcounting */
scsi_device_put(sdev);
return SCSI_SCAN_LUN_PRESENT; return SCSI_SCAN_LUN_PRESENT;
} }
} }
...@@ -1232,14 +1233,25 @@ void scsi_scan_host(struct Scsi_Host *shost) ...@@ -1232,14 +1233,25 @@ void scsi_scan_host(struct Scsi_Host *shost)
void scsi_forget_host(struct Scsi_Host *shost) void scsi_forget_host(struct Scsi_Host *shost)
{ {
struct list_head *le, *lh; struct scsi_device *sdev, *tmp;
struct scsi_device *sdev; unsigned long flags;
list_for_each_safe(le, lh, &shost->my_devices) { /*
sdev = list_entry(le, struct scsi_device, siblings); * Ok, this look a bit strange. We always look for the first device
* on the list as scsi_remove_device removes them from it - thus we
* also have to release the lock.
* We don't need to get another reference to the device before
* releasing the lock as we already own the reference from
* scsi_register_device that's release in scsi_remove_device. And
* after that we don't look at sdev anymore.
*/
spin_lock_irqsave(shost->host_lock, flags);
list_for_each_entry_safe(sdev, tmp, &shost->__devices, siblings) {
spin_unlock_irqrestore(shost->host_lock, flags);
scsi_remove_device(sdev); scsi_remove_device(sdev);
spin_lock_irqsave(shost->host_lock, flags);
} }
spin_unlock_irqrestore(shost->host_lock, flags);
} }
/* /*
......
...@@ -18,13 +18,14 @@ ...@@ -18,13 +18,14 @@
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/dma.h> #include <asm/dma.h>
#include "scsi.h"
#include <scsi/scsi_driver.h> #include <scsi/scsi_driver.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_ioctl.h> #include <scsi/scsi_ioctl.h>
#include "hosts.h" #include <scsi/scsicam.h>
#include "scsi.h"
#include "scsi_logging.h" #include "scsi_logging.h"
#include <scsi/scsicam.h>
/* /*
* This source file contains the symbol table used by scsi loadable * This source file contains the symbol table used by scsi loadable
...@@ -82,8 +83,6 @@ EXPORT_SYMBOL(scsi_sleep); ...@@ -82,8 +83,6 @@ EXPORT_SYMBOL(scsi_sleep);
EXPORT_SYMBOL(scsi_io_completion); EXPORT_SYMBOL(scsi_io_completion);
EXPORT_SYMBOL(scsi_device_get);
EXPORT_SYMBOL(scsi_device_put);
EXPORT_SYMBOL(scsi_add_device); EXPORT_SYMBOL(scsi_add_device);
EXPORT_SYMBOL(scsi_remove_device); EXPORT_SYMBOL(scsi_remove_device);
EXPORT_SYMBOL(scsi_device_cancel); EXPORT_SYMBOL(scsi_device_cancel);
......
...@@ -11,8 +11,9 @@ ...@@ -11,8 +11,9 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/blkdev.h> #include <linux/blkdev.h>
#include <linux/device.h> #include <linux/device.h>
#include <scsi/scsi_host.h>
#include "scsi.h" #include "scsi.h"
#include "hosts.h"
#include "scsi_priv.h" #include "scsi_priv.h"
#include "scsi_logging.h" #include "scsi_logging.h"
...@@ -257,20 +258,12 @@ store_rescan_field (struct device *dev, const char *buf, size_t count) ...@@ -257,20 +258,12 @@ store_rescan_field (struct device *dev, const char *buf, size_t count)
scsi_rescan_device(dev); scsi_rescan_device(dev);
return count; return count;
} }
static DEVICE_ATTR(rescan, S_IWUSR, NULL, store_rescan_field) static DEVICE_ATTR(rescan, S_IWUSR, NULL, store_rescan_field)
static ssize_t sdev_store_delete(struct device *dev, const char *buf, static ssize_t sdev_store_delete(struct device *dev, const char *buf,
size_t count) size_t count)
{ {
struct scsi_device *sdev = to_scsi_device(dev); scsi_remove_device(to_scsi_device(dev));
/*
* FIXME and scsi_proc.c: racey use of access_count,
*/
if (atomic_read(&sdev->access_count))
return -EBUSY;
scsi_remove_device(sdev);
return count; return count;
}; };
static DEVICE_ATTR(delete, S_IWUSR, NULL, sdev_store_delete); static DEVICE_ATTR(delete, S_IWUSR, NULL, sdev_store_delete);
...@@ -403,22 +396,12 @@ int scsi_device_register(struct scsi_device *sdev) ...@@ -403,22 +396,12 @@ int scsi_device_register(struct scsi_device *sdev)
**/ **/
void scsi_remove_device(struct scsi_device *sdev) void scsi_remove_device(struct scsi_device *sdev)
{ {
struct class *class = class_get(&sdev_class);
class_device_unregister(&sdev->sdev_classdev); class_device_unregister(&sdev->sdev_classdev);
set_bit(SDEV_DEL, &sdev->sdev_state);
if (class) { if (sdev->host->hostt->slave_destroy)
down_write(&class->subsys.rwsem); sdev->host->hostt->slave_destroy(sdev);
set_bit(SDEV_DEL, &sdev->sdev_state); device_del(&sdev->sdev_gendev);
if (sdev->host->hostt->slave_destroy)
sdev->host->hostt->slave_destroy(sdev);
device_del(&sdev->sdev_gendev);
up_write(&class->subsys.rwsem);
}
put_device(&sdev->sdev_gendev); put_device(&sdev->sdev_gendev);
class_put(&sdev_class);
} }
int scsi_register_driver(struct device_driver *drv) int scsi_register_driver(struct device_driver *drv)
......
...@@ -914,7 +914,8 @@ sg_ioctl(struct inode *inode, struct file *filp, ...@@ -914,7 +914,8 @@ sg_ioctl(struct inode *inode, struct file *filp,
case SG_GET_VERSION_NUM: case SG_GET_VERSION_NUM:
return put_user(sg_version_num, (int *) arg); return put_user(sg_version_num, (int *) arg);
case SG_GET_ACCESS_COUNT: case SG_GET_ACCESS_COUNT:
val = (sdp->device ? atomic_read(&sdp->device->access_count) : 0); /* faked - we don't have a real access count anymore */
val = (sdp->device ? 1 : 0);
return put_user(val, (int *) arg); return put_user(val, (int *) arg);
case SG_GET_REQUEST_TABLE: case SG_GET_REQUEST_TABLE:
result = verify_area(VERIFY_WRITE, (void *) arg, result = verify_area(VERIFY_WRITE, (void *) arg,
...@@ -1627,7 +1628,7 @@ st_map_user_pages(struct scatterlist *sgl, const unsigned int max_pages, ...@@ -1627,7 +1628,7 @@ st_map_user_pages(struct scatterlist *sgl, const unsigned int max_pages,
unsigned int nr_pages; unsigned int nr_pages;
struct page **pages; struct page **pages;
nr_pages = ((uaddr & ~PAGE_MASK) + count - 1 + ~PAGE_MASK) >> PAGE_SHIFT; nr_pages = ((uaddr & ~PAGE_MASK) + count + ~PAGE_MASK) >> PAGE_SHIFT;
/* User attempted Overflow! */ /* User attempted Overflow! */
if ((uaddr + count) < uaddr) if ((uaddr + count) < uaddr)
...@@ -2903,7 +2904,7 @@ sg_proc_dev_info(char *buffer, int *len, off_t * begin, off_t offset, int size) ...@@ -2903,7 +2904,7 @@ sg_proc_dev_info(char *buffer, int *len, off_t * begin, off_t offset, int size)
PRINT_PROC("%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n", PRINT_PROC("%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n",
scsidp->host->host_no, scsidp->channel, scsidp->host->host_no, scsidp->channel,
scsidp->id, scsidp->lun, (int) scsidp->type, scsidp->id, scsidp->lun, (int) scsidp->type,
(int) atomic_read(&scsidp->access_count), 1,
(int) scsidp->queue_depth, (int) scsidp->queue_depth,
(int) scsidp->device_busy, (int) scsidp->device_busy,
(int) scsidp->online); (int) scsidp->online);
......
...@@ -90,6 +90,7 @@ static Scsi_Host_Template sim710_driver_template = { ...@@ -90,6 +90,7 @@ static Scsi_Host_Template sim710_driver_template = {
.name = "LSI (Symbios) 710 MCA/EISA", .name = "LSI (Symbios) 710 MCA/EISA",
.proc_name = "sim710", .proc_name = "sim710",
.this_id = 7, .this_id = 7,
.module = THIS_MODULE,
}; };
static __devinit int static __devinit int
......
...@@ -4036,7 +4036,7 @@ static int sgl_map_user_pages(struct scatterlist *sgl, const unsigned int max_pa ...@@ -4036,7 +4036,7 @@ static int sgl_map_user_pages(struct scatterlist *sgl, const unsigned int max_pa
unsigned int nr_pages; unsigned int nr_pages;
struct page **pages; struct page **pages;
nr_pages = ((uaddr & ~PAGE_MASK) + count - 1 + ~PAGE_MASK) >> PAGE_SHIFT; nr_pages = ((uaddr & ~PAGE_MASK) + count + ~PAGE_MASK) >> PAGE_SHIFT;
/* User attempted Overflow! */ /* User attempted Overflow! */
if ((uaddr + count) < uaddr) if ((uaddr + count) < uaddr)
......
...@@ -312,6 +312,9 @@ struct scsi_host_template usb_stor_host_template = { ...@@ -312,6 +312,9 @@ struct scsi_host_template usb_stor_host_template = {
/* lots of sg segments can be handled */ /* lots of sg segments can be handled */
.sg_tablesize = SG_ALL, .sg_tablesize = SG_ALL,
/* limit the total size of a transfer to 120 KB */
.max_sectors = 240,
/* merge commands... this seems to help performance, but /* merge commands... this seems to help performance, but
* periodically someone should test to see which setting is more * periodically someone should test to see which setting is more
* optimal. * optimal.
......
...@@ -22,10 +22,13 @@ enum { ...@@ -22,10 +22,13 @@ enum {
}; };
struct scsi_device { struct scsi_device {
struct list_head siblings; /* list of all devices on this host */
struct list_head same_target_siblings; /* just the devices sharing same target id */
struct Scsi_Host *host; struct Scsi_Host *host;
struct request_queue *request_queue; struct request_queue *request_queue;
/* the next two are protected by the host->host_lock */
struct list_head siblings; /* list of all devices on this host */
struct list_head same_target_siblings; /* just the devices sharing same target id */
volatile unsigned short device_busy; /* commands actually active on low-level */ volatile unsigned short device_busy; /* commands actually active on low-level */
spinlock_t sdev_lock; /* also the request queue_lock */ spinlock_t sdev_lock; /* also the request queue_lock */
spinlock_t list_lock; spinlock_t list_lock;
...@@ -45,8 +48,6 @@ struct scsi_device { ...@@ -45,8 +48,6 @@ struct scsi_device {
* vendor-specific cmd's */ * vendor-specific cmd's */
unsigned sector_size; /* size in bytes */ unsigned sector_size; /* size in bytes */
atomic_t access_count; /* Count of open channels/mounts */
void *hostdata; /* available to low-level driver */ void *hostdata; /* available to low-level driver */
char devfs_name[256]; /* devfs junk */ char devfs_name[256]; /* devfs junk */
char type; char type;
...@@ -108,14 +109,48 @@ struct scsi_device { ...@@ -108,14 +109,48 @@ struct scsi_device {
extern struct scsi_device *scsi_add_device(struct Scsi_Host *, extern struct scsi_device *scsi_add_device(struct Scsi_Host *,
uint, uint, uint); uint, uint, uint);
extern void scsi_remove_device(struct scsi_device *); extern void scsi_remove_device(struct scsi_device *);
extern int scsi_device_cancel_cb(struct device *, void *);
extern int scsi_device_cancel(struct scsi_device *, int); extern int scsi_device_cancel(struct scsi_device *, int);
extern int scsi_device_get(struct scsi_device *); extern int scsi_device_get(struct scsi_device *);
extern void scsi_device_put(struct scsi_device *); extern void scsi_device_put(struct scsi_device *);
extern struct scsi_device *scsi_device_lookup(struct Scsi_Host *,
uint, uint, uint);
extern struct scsi_device *__scsi_device_lookup(struct Scsi_Host *,
uint, uint, uint);
/* only exposed to implement shost_for_each_device */
extern struct scsi_device *__scsi_iterate_devices(struct Scsi_Host *,
struct scsi_device *);
/**
* shost_for_each_device - iterate over all devices of a host
* @sdev: iterator
* @host: host whiches devices we want to iterate over
*
* This traverses over each devices of @shost. The devices have
* a reference that must be released by scsi_host_put when breaking
* out of the loop.
*/
#define shost_for_each_device(sdev, shost) \ #define shost_for_each_device(sdev, shost) \
list_for_each_entry((sdev), &((shost)->my_devices), siblings) for ((sdev) = __scsi_iterate_devices((shost), NULL); \
(sdev); \
(sdev) = __scsi_iterate_devices((shost), (sdev)))
/**
* __shost_for_each_device - iterate over all devices of a host (UNLOCKED)
* @sdev: iterator
* @host: host whiches devices we want to iterate over
*
* This traverses over each devices of @shost. It does _not_ take a
* reference on the scsi_device, thus it the whole loop must be protected
* by shost->host_lock.
*
* Note: The only reason why drivers would want to use this is because
* they're need to access the device list in irq context. Otherwise you
* really want to use shost_for_each_device instead.
*/
#define __shost_for_each_device(sdev, shost) \
list_for_each_entry((sdev), &((shost)->__devices), siblings)
extern void scsi_adjust_queue_depth(struct scsi_device *, int, int); extern void scsi_adjust_queue_depth(struct scsi_device *, int, int);
extern int scsi_track_queue_full(struct scsi_device *, int); extern int scsi_track_queue_full(struct scsi_device *, int);
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include <linux/device.h> #include <linux/device.h>
struct module; struct module;
struct scsi_cmnd;
struct scsi_driver { struct scsi_driver {
......
...@@ -363,19 +363,30 @@ enum { ...@@ -363,19 +363,30 @@ enum {
}; };
struct Scsi_Host { struct Scsi_Host {
struct list_head my_devices; /*
* __devices is protected by the host_lock, but you should
* usually use scsi_device_lookup / shost_for_each_device
* to access it and don't care about locking yourself.
* In the rare case of beeing in irq context you can use
* their __ prefixed variants with the lock held. NEVER
* access this list directly from a driver.
*/
struct list_head __devices;
struct scsi_host_cmd_pool *cmd_pool; struct scsi_host_cmd_pool *cmd_pool;
spinlock_t free_list_lock; spinlock_t free_list_lock;
struct list_head free_list; /* backup store of cmd structs */ struct list_head free_list; /* backup store of cmd structs */
struct list_head starved_list; struct list_head starved_list;
spinlock_t default_lock; spinlock_t default_lock;
spinlock_t *host_lock; spinlock_t *host_lock;
struct semaphore scan_mutex;/* serialize scanning activity */
struct list_head eh_cmd_q; struct list_head eh_cmd_q;
struct task_struct * ehandler; /* Error recovery thread. */ struct task_struct * ehandler; /* Error recovery thread. */
struct semaphore * eh_wait; /* The error recovery thread waits on struct semaphore * eh_wait; /* The error recovery thread waits
this. */ on this. */
struct completion * eh_notify; /* wait for eh to begin or end */ struct completion * eh_notify; /* wait for eh to begin or end */
struct semaphore * eh_action; /* Wait for specific actions on the struct semaphore * eh_action; /* Wait for specific actions on the
host. */ host. */
...@@ -478,12 +489,6 @@ struct Scsi_Host { ...@@ -478,12 +489,6 @@ struct Scsi_Host {
*/ */
struct list_head sht_legacy_list; struct list_head sht_legacy_list;
/*
* This mutex serializes all scsi scanning activity from kernel- and
* userspace.
*/
struct semaphore scan_mutex;
/* /*
* We should ensure that this is aligned, both for better performance * We should ensure that this is aligned, both for better performance
* and also because some compilers (m68k) don't automatically force * and also because some compilers (m68k) don't automatically force
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment