Commit bede2c88 authored by James Bottomley's avatar James Bottomley

Merge raven.il.steeleye.com:/home/jejb/BK/scsi-misc-2.5

into raven.il.steeleye.com:/home/jejb/BK/scsi-for-linus-2.6
parents db82f17d 4277ddc2
This diff is collapsed.
......@@ -40,6 +40,16 @@
static int scsi_host_next_hn; /* host_no for next new host */
static void scsi_host_cls_release(struct class_device *class_dev)
{
put_device(&class_to_shost(class_dev)->shost_gendev);
}
static struct class shost_class = {
.name = "scsi_host",
.release = scsi_host_cls_release,
};
/**
* scsi_host_cancel - cancel outstanding IO to this host
* @shost: pointer to struct Scsi_Host
......@@ -64,10 +74,18 @@ void scsi_host_cancel(struct Scsi_Host *shost, int recovery)
**/
void scsi_remove_host(struct Scsi_Host *shost)
{
unsigned long flags;
scsi_host_cancel(shost, 0);
scsi_proc_host_rm(shost);
scsi_forget_host(shost);
scsi_sysfs_remove_host(shost);
spin_lock_irqsave(shost->host_lock, flags);
set_bit(SHOST_DEL, &shost->shost_state);
spin_unlock_irqrestore(shost->host_lock, flags);
class_device_unregister(&shost->shost_classdev);
device_del(&shost->shost_gendev);
}
/**
......@@ -89,21 +107,45 @@ int scsi_add_host(struct Scsi_Host *shost, struct device *dev)
if (!shost->can_queue) {
printk(KERN_ERR "%s: can_queue = 0 no longer supported\n",
sht->name);
error = -EINVAL;
return -EINVAL;
}
error = scsi_sysfs_add_host(shost, dev);
if (!error)
scsi_proc_host_add(shost);
if (!shost->shost_gendev.parent)
shost->shost_gendev.parent = dev ? dev : &legacy_bus;
error = device_add(&shost->shost_gendev);
if (error)
goto out;
set_bit(SHOST_ADD, &shost->shost_state);
get_device(shost->shost_gendev.parent);
error = class_device_add(&shost->shost_classdev);
if (error)
goto out_del_gendev;
get_device(&shost->shost_gendev);
error = scsi_sysfs_add_host(shost);
if (error)
goto out_del_classdev;
scsi_proc_host_add(shost);
return error;
out_del_classdev:
class_device_del(&shost->shost_classdev);
out_del_gendev:
device_del(&shost->shost_gendev);
out:
return error;
}
/**
* scsi_free_sdev - free a scsi hosts resources
* @shost: scsi host to free
**/
void scsi_free_shost(struct Scsi_Host *shost)
static void scsi_host_dev_release(struct device *dev)
{
struct Scsi_Host *shost = dev_to_shost(dev);
struct device *parent = dev->parent;
if (shost->ehandler) {
DECLARE_COMPLETION(sem);
shost->eh_notify = &sem;
......@@ -115,6 +157,8 @@ void scsi_free_shost(struct Scsi_Host *shost)
scsi_proc_hostdir_rm(shost->hostt);
scsi_destroy_command_freelist(shost);
put_device(parent);
kfree(shost);
}
......@@ -214,7 +258,16 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
if (rval)
goto fail;
scsi_sysfs_init_host(shost);
device_initialize(&shost->shost_gendev);
snprintf(shost->shost_gendev.bus_id, BUS_ID_SIZE, "host%d",
shost->host_no);
shost->shost_gendev.release = scsi_host_dev_release;
class_device_initialize(&shost->shost_classdev);
shost->shost_classdev.dev = &shost->shost_gendev;
shost->shost_classdev.class = &shost_class;
snprintf(shost->shost_classdev.class_id, BUS_ID_SIZE, "host%d",
shost->host_no);
shost->eh_notify = &complete;
/* XXX(hch): handle error return */
......@@ -299,3 +352,13 @@ void scsi_host_put(struct Scsi_Host *shost)
{
put_device(&shost->shost_gendev);
}
int scsi_init_hosts(void)
{
return class_register(&shost_class);
}
void scsi_exit_hosts(void)
{
class_unregister(&shost_class);
}
This diff is collapsed.
......@@ -106,8 +106,10 @@
#define IPS_REMOVE_HOST(shost)
#define IPS_SCSI_SET_DEVICE(sh,ha) scsi_set_pci_device(sh, (ha)->pcidev)
#define IPS_PRINTK(level, pcidev, format, arg...) \
printk(level "%s %s:" format , (pcidev)->driver->name , \
pci_name(pcidev) , ## arg)
printk(level "%s %s:" format , "ips" , \
(pcidev)->slot_name , ## arg)
#define scsi_host_alloc(sh,size) scsi_register(sh,size)
#define scsi_host_put(sh) scsi_unregister(sh)
#else
#define IPS_REGISTER_HOSTS(SHT) (!ips_detect(SHT))
#define IPS_UNREGISTER_HOSTS(SHT)
......@@ -126,22 +128,13 @@
#define min(x,y) ((x) < (y) ? x : y)
#endif
#define pci_dma_hi32(a) ((a >> 16) >> 16)
#define pci_dma_lo32(a) (a & 0xffffffff)
#if (BITS_PER_LONG > 32) || (defined CONFIG_HIGHMEM64G && defined IPS_HIGHIO)
#define IPS_ENABLE_DMA64 (1)
#define pci_dma_hi32(a) (a >> 32)
#else
#define IPS_ENABLE_DMA64 (0)
#define pci_dma_hi32(a) (0)
#endif
#if defined(__ia64__)
#define IPS_ATOMIC_GFP (GFP_DMA | GFP_ATOMIC)
#define IPS_INIT_GFP GFP_DMA
#else
#define IPS_ATOMIC_GFP GFP_ATOMIC
#define IPS_INIT_GFP GFP_KERNEL
#endif
/*
......@@ -451,9 +444,11 @@
* Scsi_Host Template
*/
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
static int ips_proc24_info(char *, char **, off_t, int, int, int);
static void ips_select_queue_depth(struct Scsi_Host *, Scsi_Device *);
static int ips_biosparam(Disk *disk, kdev_t dev, int geom[]);
#else
int ips_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int);
static int ips_biosparam(struct scsi_device *sdev, struct block_device *bdev,
sector_t capacity, int geom[]);
int ips_slave_configure(Scsi_Device *SDptr);
......@@ -1106,7 +1101,8 @@ typedef struct ips_ha {
uint16_t device_id; /* PCI device ID */
uint8_t slot_num; /* PCI Slot Number */
uint16_t subdevice_id; /* Subsystem device ID */
uint8_t ioctl_order; /* Number of pages in ioctl */
int ioctl_len; /* size of ioctl buffer */
dma_addr_t ioctl_busaddr; /* dma address of ioctl buffer*/
uint8_t bios_version[8]; /* BIOS Revision */
uint32_t mem_addr; /* Memory mapped address */
uint32_t io_len; /* Size of IO Address */
......@@ -1116,8 +1112,10 @@ typedef struct ips_ha {
ips_hw_func_t func; /* hw function pointers */
struct pci_dev *pcidev; /* PCI device handle */
char *flash_data; /* Save Area for flash data */
u8 flash_order; /* Save Area for flash size order */
int flash_len; /* length of flash buffer */
u32 flash_datasize; /* Save Area for flash data size */
dma_addr_t flash_busaddr; /* dma address of flash buffer*/
dma_addr_t enq_busaddr; /* dma address of enq struct */
uint8_t requires_esl; /* Requires an EraseStripeLock */
} ips_ha_t;
......@@ -1203,25 +1201,29 @@ typedef struct {
*
*************************************************************************/
#define IPS_VER_MAJOR 5
#define IPS_VER_MAJOR_STRING "5"
#define IPS_VER_MINOR 99
#define IPS_VER_MINOR_STRING "99"
#define IPS_VER_BUILD 00
#define IPS_VER_BUILD_STRING "00"
#define IPS_VER_STRING "5.99.00"
#define IPS_BUILD_IDENT 1132
#define IPS_VER_MAJOR 6
#define IPS_VER_MAJOR_STRING "6"
#define IPS_VER_MINOR 10
#define IPS_VER_MINOR_STRING "10"
#define IPS_VER_BUILD 90
#define IPS_VER_BUILD_STRING "90"
#define IPS_VER_STRING "6.10.90"
#define IPS_RELEASE_ID 0x00010000
#define IPS_BUILD_IDENT 364
#define IPS_LEGALCOPYRIGHT_STRING "(C) Copyright IBM Corp. 1994, 2003. All Rights Reserved."
#define IPS_ADAPTECCOPYRIGHT_STRING "(c) Copyright Adaptec, Inc. 2002 to present. All Rights Reserved."
#define IPS_NT_LEGALCOPYRIGHT_STRING "(C) Copyright IBM Corp. 1994, 2003."
/* Version numbers for various adapters */
#define IPS_VER_SERVERAID1 "2.25.01"
#define IPS_VER_SERVERAID2 "2.88.13"
#define IPS_VER_NAVAJO "2.88.13"
#define IPS_VER_SERVERAID3 "5.11.05"
#define IPS_VER_SERVERAID4H "5.11.05"
#define IPS_VER_SERVERAID4MLx "5.11.05"
#define IPS_VER_SARASOTA "5.11.05"
#define IPS_VER_MARCO "0.00.00"
#define IPS_VER_SEBRING "0.00.00"
#define IPS_VER_SERVERAID3 "6.10.24"
#define IPS_VER_SERVERAID4H "6.10.24"
#define IPS_VER_SERVERAID4MLx "6.10.24"
#define IPS_VER_SARASOTA "6.10.24"
#define IPS_VER_MARCO "6.10.24"
#define IPS_VER_SEBRING "6.10.24"
/* Compatability IDs for various adapters */
#define IPS_COMPAT_UNKNOWN ""
......@@ -1230,17 +1232,17 @@ typedef struct {
#define IPS_COMPAT_SERVERAID2 "2.88.13"
#define IPS_COMPAT_NAVAJO "2.88.13"
#define IPS_COMPAT_KIOWA "2.88.13"
#define IPS_COMPAT_SERVERAID3H "SA510"
#define IPS_COMPAT_SERVERAID3L "SA510"
#define IPS_COMPAT_SERVERAID4H "SA510"
#define IPS_COMPAT_SERVERAID4M "SA510"
#define IPS_COMPAT_SERVERAID4L "SA510"
#define IPS_COMPAT_SERVERAID4Mx "SA510"
#define IPS_COMPAT_SERVERAID4Lx "SA510"
#define IPS_COMPAT_SARASOTA "SA510"
#define IPS_COMPAT_MARCO "SA000"
#define IPS_COMPAT_SEBRING "SA000"
#define IPS_COMPAT_BIOS "SA510"
#define IPS_COMPAT_SERVERAID3H "SB610"
#define IPS_COMPAT_SERVERAID3L "SB610"
#define IPS_COMPAT_SERVERAID4H "SB610"
#define IPS_COMPAT_SERVERAID4M "SB610"
#define IPS_COMPAT_SERVERAID4L "SB610"
#define IPS_COMPAT_SERVERAID4Mx "SB610"
#define IPS_COMPAT_SERVERAID4Lx "SB610"
#define IPS_COMPAT_SARASOTA "SB610"
#define IPS_COMPAT_MARCO "SB610"
#define IPS_COMPAT_SEBRING "SB610"
#define IPS_COMPAT_BIOS "SB610"
#define IPS_COMPAT_MAX_ADAPTER_TYPE 16
#define IPS_COMPAT_ID_LENGTH 8
......
......@@ -86,14 +86,10 @@ lasi700_driver_callback(struct parisc_device *dev)
struct NCR_700_Host_Parameters *hostdata;
struct Scsi_Host *host;
snprintf(dev->dev.name, sizeof(dev->dev.name), "%s",
(dev->id.sversion == LASI_700_SVERSION) ?
"lasi700" : "lasi710");
hostdata = kmalloc(sizeof(*hostdata), GFP_KERNEL);
if (!hostdata) {
printk(KERN_ERR "%s: Failed to allocate host data\n",
dev->dev.name);
dev->dev.bus_id);
return 1;
}
memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters));
......@@ -121,9 +117,9 @@ lasi700_driver_callback(struct parisc_device *dev)
host->irq = dev->irq;
if (request_irq(dev->irq, NCR_700_intr, SA_SHIRQ,
dev->dev.name, host)) {
dev->dev.bus_id, host)) {
printk(KERN_ERR "%s: irq problem, detaching\n",
dev->dev.name);
dev->dev.bus_id);
goto out_put_host;
}
......
......@@ -177,13 +177,8 @@ static void aha152x_detach(dev_link_t *link)
if (*linkp == NULL)
return;
if (link->state & DEV_CONFIG) {
if (link->state & DEV_CONFIG)
aha152x_release_cs(link);
if (link->state & DEV_STALE_CONFIG) {
link->state |= DEV_STALE_LINK;
return;
}
}
if (link->handle)
CardServices(DeregisterClient, link->handle);
......@@ -302,9 +297,6 @@ static void aha152x_release_cs(dev_link_t *link)
link->state &= ~DEV_CONFIG;
scsi_unregister(info->host);
if (link->state & DEV_STALE_LINK)
aha152x_detach(link);
}
static int aha152x_event(event_t event, int priority,
......
......@@ -166,13 +166,8 @@ static void fdomain_detach(dev_link_t *link)
if (*linkp == NULL)
return;
if (link->state & DEV_CONFIG) {
if (link->state & DEV_CONFIG)
fdomain_release(link);
if (link->state & DEV_STALE_CONFIG) {
link->state |= DEV_STALE_LINK;
return;
}
}
if (link->handle)
CardServices(DeregisterClient, link->handle);
......@@ -283,9 +278,7 @@ static void fdomain_release(dev_link_t *link)
scsi_unregister(info->host);
link->state &= ~DEV_CONFIG;
if (link->state & DEV_STALE_LINK)
fdomain_detach(link);
} /* fdomain_release */
}
/*====================================================================*/
......
......@@ -1553,18 +1553,12 @@ static void nsp_cs_detach(dev_link_t *link)
return;
}
if (link->state & DEV_CONFIG) {
if (link->state & DEV_CONFIG)
nsp_cs_release(link);
if (link->state & DEV_STALE_CONFIG) {
link->state |= DEV_STALE_LINK;
return;
}
}
/* Break the link with Card Services */
if (link->handle) {
if (link->handle)
CardServices(DeregisterClient, link->handle);
}
/* Unlink device structure, free bits */
*linkp = link->next;
......@@ -1792,17 +1786,6 @@ static void nsp_cs_release(dev_link_t *link)
DEBUG(0, "%s(0x%p)\n", __FUNCTION__, link);
/*
* If the device is currently in use, we won't release until it
* is actually closed.
*/
if (link->open) {
DEBUG(1, "nsp_cs: release postponed, '%s' still open\n",
link->dev->dev_name);
link->state |= DEV_STALE_CONFIG;
return;
}
/* Unlink the device chain */
#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,2))
scsi_unregister_module(MODULE_SCSI_HA, &nsp_driver_template);
......@@ -1824,11 +1807,7 @@ static void nsp_cs_release(dev_link_t *link)
CardServices(ReleaseIRQ, link->handle, &link->irq);
}
link->state &= ~DEV_CONFIG;
if (link->state & DEV_STALE_LINK) {
nsp_cs_detach(link);
}
} /* nsp_cs_release */
}
/*======================================================================
......
......@@ -165,13 +165,8 @@ static void qlogic_detach(dev_link_t * link)
if (*linkp == NULL)
return;
if (link->state & DEV_CONFIG) {
if (link->state & DEV_CONFIG)
qlogic_release(link);
if (link->state & DEV_STALE_CONFIG) {
link->state |= DEV_STALE_LINK;
return;
}
}
if (link->handle)
CardServices(DeregisterClient, link->handle);
......@@ -296,9 +291,7 @@ static void qlogic_release(dev_link_t *link)
scsi_unregister(info->host);
link->state &= ~DEV_CONFIG;
if (link->state & DEV_STALE_LINK)
qlogic_detach(link);
} /* qlogic_release */
}
/*====================================================================*/
......
......@@ -76,6 +76,7 @@ int ppa_release(struct Scsi_Host *host)
int host_no = host->unique_id;
printk("Releasing ppa%i\n", host_no);
scsi_unregister(host);
parport_unregister_device(ppa_hosts[host_no].dev);
return 0;
}
......
......@@ -16,9 +16,11 @@
* General Public License for more details.
*
******************************************************************************/
#define QLA1280_VERSION "3.23.34"
#define QLA1280_VERSION "3.23.35"
/*****************************************************************************
Revision History:
Rev 3.23.35 August 14, 2003, Jes Sorensen
- Build against 2.6
Rev 3.23.34 July 23, 2003, Jes Sorensen
- Remove pointless TRUE/FALSE macros
- Clean up vchan handling
......@@ -296,14 +298,12 @@
#include <linux/sched.h>
#include <linux/pci.h>
#include <linux/proc_fs.h>
#include <linux/blk.h>
#include <linux/stat.h>
#include <linux/slab.h>
#include <linux/pci_ids.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/byteorder.h>
......@@ -312,7 +312,10 @@
#include <asm/system.h>
#if LINUX_VERSION_CODE < 0x020545
#include <linux/blk.h>
#include "sd.h"
#else
#include <scsi/scsi_host.h>
#endif
#include "scsi.h"
#include "hosts.h"
......@@ -634,11 +637,14 @@ static int ql_debug_level = 1;
*************************************************************************/
#define PROC_BUF &qla1280_buffer[len]
int
qla1280_proc_info(char *buffer, char **start, off_t offset, int length,
int hostno, int inout)
#if LINUX_VERSION_CODE < 0x020600
int qla1280_proc_info(char *buffer, char **start, off_t offset, int length,
int hostno, int inout)
#else
int qla1280_proc_info(struct Scsi_Host *host, char *buffer, char **start,
off_t offset, int length, int inout)
#endif
{
struct Scsi_Host *host;
struct scsi_qla_host *ha;
int size = 0;
int len = 0;
......@@ -647,7 +653,10 @@ qla1280_proc_info(char *buffer, char **start, off_t offset, int length,
struct scsi_lu *up;
uint32_t b, t, l;
#endif
#if LINUX_VERSION_CODE >= 0x020600
ha = (struct scsi_qla_host *)host->hostdata;
#else
struct Scsi_Host *host;
/* Find the host that was specified */
for (ha = qla1280_hostlist; (ha != NULL)
&& ha->host->host_no != hostno; ha = ha->next) ;
......@@ -664,6 +673,7 @@ qla1280_proc_info(char *buffer, char **start, off_t offset, int length,
}
host = ha->host;
#endif
if (inout)
return -ENOSYS;
......@@ -1828,7 +1838,7 @@ qla1280_done(struct scsi_qla_host *ha, struct srb ** done_q_first,
CMD_HANDLE(sp->cmd) = (unsigned char *)INVALID_HANDLE;
ha->actthreads--;
#if LINUX_KERNEL_VERSION < 0x020500
#if LINUX_VERSION_CODE < 0x020500
if (cmd->cmnd[0] == INQUIRY)
qla1280_get_target_options(cmd, ha);
#endif
......@@ -4497,7 +4507,7 @@ qla1280_rst_aen(struct scsi_qla_host *ha)
}
#if LINUX_KERNEL_VERSION < 0x020500
#if LINUX_VERSION_CODE < 0x020500
/*
*
*/
......
......@@ -1111,7 +1111,11 @@ struct scsi_qla_host {
/*
* Linux - SCSI Driver Interface Function Prototypes.
*/
#if LINUX_VERSION_CODE < 0x020600
int qla1280_proc_info(char *, char **, off_t, int, int, int);
#else
int qla1280_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int);
#endif
const char *qla1280_info(struct Scsi_Host *host);
int qla1280_detect(Scsi_Host_Template *);
int qla1280_release(struct Scsi_Host *);
......@@ -1147,8 +1151,6 @@ int qla1280_eh_adapter_reset(struct scsi_cmnd *cmd);
.detect = qla1280_detect, \
.release = qla1280_release, \
.info = qla1280_info, \
.ioctl = NULL, \
.command = NULL, \
.queuecommand = qla1280_queuecommand, \
.eh_strategy_handler = NULL, \
.eh_abort_handler = qla1280_eh_abort, \
......
......@@ -1003,9 +1003,12 @@ static int __init init_scsi(void)
error = scsi_init_devinfo();
if (error)
goto cleanup_procfs;
error = scsi_sysfs_register();
error = scsi_init_hosts();
if (error)
goto cleanup_devlist;
error = scsi_sysfs_register();
if (error)
goto cleanup_hosts;
for (i = 0; i < NR_CPUS; i++)
INIT_LIST_HEAD(&done_q[i]);
......@@ -1015,6 +1018,8 @@ static int __init init_scsi(void)
printk(KERN_NOTICE "SCSI subsystem initialized\n");
return 0;
cleanup_hosts:
scsi_exit_hosts();
cleanup_devlist:
scsi_exit_devinfo();
cleanup_procfs:
......@@ -1029,6 +1034,7 @@ static int __init init_scsi(void)
static void __exit exit_scsi(void)
{
scsi_sysfs_unregister();
scsi_exit_hosts();
scsi_exit_devinfo();
devfs_remove("scsi");
scsi_exit_procfs();
......
......@@ -1285,7 +1285,12 @@ int scsi_decide_disposition(struct scsi_cmnd *scmd)
maybe_retry:
if ((++scmd->retries) < scmd->allowed) {
/* we requeue for retry because the error was retryable, and
* the request was not marked fast fail. Note that above,
* even if the request is marked fast fail, we still requeue
* for queue congestion conditions (QUEUE_FULL or BUSY) */
if ((++scmd->retries) < scmd->allowed
&& !blk_noretry_request(scmd->request)) {
return NEEDS_RETRY;
} else {
/*
......
......@@ -502,14 +502,22 @@ static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int uptodate,
* to queue the remainder of them.
*/
if (end_that_request_first(req, uptodate, sectors)) {
if (requeue) {
/*
* Bleah. Leftovers again. Stick the leftovers in
* the front of the queue, and goose the queue again.
*/
scsi_requeue_command(q, cmd);
int leftover = req->hard_nr_sectors - sectors;
/* kill remainder if no retrys */
if (!uptodate && blk_noretry_request(req))
end_that_request_first(req, 0, leftover);
else {
if (requeue)
/*
* Bleah. Leftovers again. Stick the
* leftovers in the front of the
* queue, and goose the queue again.
*/
scsi_requeue_command(q, cmd);
return cmd;
}
return cmd;
}
add_disk_randomness(req->rq_disk);
......
......@@ -41,6 +41,12 @@
#define SCSI_SENSE_VALID(scmd) \
(((scmd)->sense_buffer[0] & 0x70) == 0x70)
/*
* Special value for scanning to specify scanning or rescanning of all
* possible channels, (target) ids, or luns on a given shost.
*/
#define SCAN_WILD_CARD ~0
/*
* scsi_target: representation of a scsi target, for now, this is only
* used for single_lun devices. If no one has active IO to the target,
......@@ -51,6 +57,9 @@ struct scsi_target {
unsigned int starget_refcnt;
};
/* hosts.c */
extern int scsi_init_hosts(void);
extern void scsi_exit_hosts(void);
/* scsi.c */
extern int scsi_dispatch_cmd(struct scsi_cmnd *cmd);
......@@ -106,20 +115,18 @@ extern void scsi_exit_procfs(void);
#endif /* CONFIG_PROC_FS */
/* scsi_scan.c */
int scsi_scan_host_selected(struct Scsi_Host *, unsigned int, unsigned int,
unsigned int, int);
extern void scsi_forget_host(struct Scsi_Host *);
extern void scsi_free_sdev(struct scsi_device *);
extern void scsi_free_shost(struct Scsi_Host *);
extern void scsi_rescan_device(struct device *);
/* scsi_sysfs.c */
extern int scsi_device_register(struct scsi_device *);
extern void scsi_sysfs_init_host(struct Scsi_Host *);
extern int scsi_sysfs_add_host(struct Scsi_Host *, struct device *);
extern void scsi_sysfs_remove_host(struct Scsi_Host *);
extern int scsi_sysfs_add_host(struct Scsi_Host *);
extern int scsi_sysfs_register(void);
extern void scsi_sysfs_unregister(void);
extern struct class shost_class;
extern struct class sdev_class;
extern struct bus_type scsi_bus_type;
......
......@@ -81,6 +81,9 @@ static int proc_scsi_write_proc(struct file *file, const char *buf,
void scsi_proc_hostdir_add(struct scsi_host_template *sht)
{
if (!sht->proc_info)
return;
down(&global_host_template_sem);
if (!sht->present++) {
sht->proc_dir = proc_mkdir(sht->proc_name, proc_scsi);
......@@ -96,6 +99,9 @@ void scsi_proc_hostdir_add(struct scsi_host_template *sht)
void scsi_proc_hostdir_rm(struct scsi_host_template *sht)
{
if (!sht->proc_info)
return;
down(&global_host_template_sem);
if (!--sht->present && sht->proc_dir) {
remove_proc_entry(sht->proc_name, proc_scsi);
......@@ -189,21 +195,13 @@ static int proc_print_scsidevice(struct device *dev, void *data)
static int scsi_add_single_device(uint host, uint channel, uint id, uint lun)
{
struct Scsi_Host *shost;
struct scsi_device *sdev;
int error = -ENXIO;
shost = scsi_host_lookup(host);
if (IS_ERR(shost))
return PTR_ERR(shost);
if (!scsi_find_device(shost, channel, id, lun)) {
sdev = scsi_add_device(shost, channel, id, lun);
if (IS_ERR(sdev))
error = PTR_ERR(sdev);
else
error = 0;
}
error = scsi_scan_host_selected(shost, channel, id, lun, 1);
scsi_host_put(shost);
return error;
}
......
......@@ -656,13 +656,32 @@ static int scsi_add_lun(struct scsi_device *sdev, char *inq_result, int *bflags)
**/
static int scsi_probe_and_add_lun(struct Scsi_Host *host,
uint channel, uint id, uint lun, int *bflagsp,
struct scsi_device **sdevp)
struct scsi_device **sdevp, int rescan)
{
struct scsi_device *sdev;
struct scsi_request *sreq;
unsigned char *result;
int bflags, res = SCSI_SCAN_NO_RESPONSE;
/*
* The rescan flag is used as an optimization, the first scan of a
* host adapter calls into here with rescan == 0.
*/
if (rescan) {
sdev = scsi_find_device(host, channel, id, lun);
if (sdev) {
SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO
"scsi scan: device exists on <%d:%d:%d:%d>\n",
host->host_no, channel, id, lun));
if (sdevp)
*sdevp = sdev;
if (bflagsp)
*bflagsp = scsi_get_device_flags(sdev->vendor,
sdev->model);
return SCSI_SCAN_LUN_PRESENT;
}
}
sdev = scsi_alloc_sdev(host, channel, id, lun);
if (!sdev)
goto out;
......@@ -737,7 +756,7 @@ static int scsi_probe_and_add_lun(struct Scsi_Host *host,
* Modifies sdevscan->lun.
**/
static void scsi_sequential_lun_scan(struct Scsi_Host *shost, uint channel,
uint id, int bflags, int lun0_res, int scsi_level)
uint id, int bflags, int lun0_res, int scsi_level, int rescan)
{
unsigned int sparse_lun, lun, max_dev_lun;
......@@ -806,7 +825,8 @@ static void scsi_sequential_lun_scan(struct Scsi_Host *shost, uint channel,
*/
for (lun = 1; lun < max_dev_lun; ++lun)
if ((scsi_probe_and_add_lun(shost, channel, id, lun,
NULL, NULL) != SCSI_SCAN_LUN_PRESENT) && !sparse_lun)
NULL, NULL, rescan) != SCSI_SCAN_LUN_PRESENT) &&
!sparse_lun)
return;
}
......@@ -857,7 +877,8 @@ static int scsilun_to_int(struct scsi_lun *scsilun)
* 0: scan completed (or no memory, so further scanning is futile)
* 1: no report lun scan, or not configured
**/
static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags)
static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags,
int rescan)
{
char devname[64];
unsigned char scsi_cmd[MAX_COMMAND_SIZE];
......@@ -1011,7 +1032,7 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags)
int res;
res = scsi_probe_and_add_lun(sdev->host, sdev->channel,
sdev->id, lun, NULL, NULL);
sdev->id, lun, NULL, NULL, rescan);
if (res == SCSI_SCAN_NO_RESPONSE) {
/*
* Got some results, but now none, abort.
......@@ -1037,7 +1058,7 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags)
return 0;
}
#else
# define scsi_report_lun_scan(sdev, blags) (1)
# define scsi_report_lun_scan(sdev, blags, rescan) (1)
#endif /* CONFIG_SCSI_REPORT_LUNS */
struct scsi_device *scsi_add_device(struct Scsi_Host *shost,
......@@ -1046,7 +1067,7 @@ struct scsi_device *scsi_add_device(struct Scsi_Host *shost,
struct scsi_device *sdev;
int res;
res = scsi_probe_and_add_lun(shost, channel, id, lun, NULL, &sdev);
res = scsi_probe_and_add_lun(shost, channel, id, lun, NULL, &sdev, 1);
if (res != SCSI_SCAN_LUN_PRESENT)
sdev = ERR_PTR(-ENODEV);
return sdev;
......@@ -1083,7 +1104,7 @@ void scsi_rescan_device(struct device *dev)
* sequential scan of LUNs on the target id.
**/
static void scsi_scan_target(struct Scsi_Host *shost, unsigned int channel,
unsigned int id)
unsigned int id, unsigned int lun, int rescan)
{
int bflags = 0;
int res;
......@@ -1095,19 +1116,29 @@ static void scsi_scan_target(struct Scsi_Host *shost, unsigned int channel,
*/
return;
if (lun != SCAN_WILD_CARD) {
/*
* Scan for a specific host/chan/id/lun.
*/
scsi_probe_and_add_lun(shost, channel, id, lun, NULL, NULL,
rescan);
return;
}
/*
* Scan LUN 0, if there is some response, scan further. Ideally, we
* would not configure LUN 0 until all LUNs are scanned.
*/
res = scsi_probe_and_add_lun(shost, channel, id, 0, &bflags, &sdev);
res = scsi_probe_and_add_lun(shost, channel, id, 0, &bflags, &sdev,
rescan);
if (res == SCSI_SCAN_LUN_PRESENT) {
if (scsi_report_lun_scan(sdev, bflags) != 0)
if (scsi_report_lun_scan(sdev, bflags, rescan) != 0)
/*
* The REPORT LUN did not scan the target,
* do a sequential scan.
*/
scsi_sequential_lun_scan(shost, channel, id, bflags,
res, sdev->scsi_level);
res, sdev->scsi_level, rescan);
} else if (res == SCSI_SCAN_TARGET_PRESENT) {
/*
* There's a target here, but lun 0 is offline so we
......@@ -1116,37 +1147,26 @@ static void scsi_scan_target(struct Scsi_Host *shost, unsigned int channel,
* a default scsi level of SCSI_2
*/
scsi_sequential_lun_scan(shost, channel, id, BLIST_SPARSELUN,
SCSI_SCAN_TARGET_PRESENT, SCSI_2);
SCSI_SCAN_TARGET_PRESENT, SCSI_2, rescan);
}
}
/**
* scsi_scan_host - scan the given adapter
* @shost: adapter to scan
*
* Description:
* Iterate and call scsi_scan_target to scan all possible target id's
* on all possible channels.
**/
void scsi_scan_host(struct Scsi_Host *shost)
static void scsi_scan_channel(struct Scsi_Host *shost, unsigned int channel,
unsigned int id, unsigned int lun, int rescan)
{
uint channel, id, order_id;
uint order_id;
/*
* The sdevscan host, channel, id and lun are filled in as
* needed to scan.
*/
for (channel = 0; channel <= shost->max_channel; channel++) {
/*
* XXX adapter drivers when possible (FCP, iSCSI)
* could modify max_id to match the current max,
* not the absolute max.
*
* XXX add a shost id iterator, so for example,
* the FC ID can be the same as a target id
* without a huge overhead of sparse id's.
*/
if (id == SCAN_WILD_CARD)
for (id = 0; id < shost->max_id; ++id) {
/*
* XXX adapter drivers when possible (FCP, iSCSI)
* could modify max_id to match the current max,
* not the absolute max.
*
* XXX add a shost id iterator, so for example,
* the FC ID can be the same as a target id
* without a huge overhead of sparse id's.
*/
if (shost->reverse_ordering)
/*
* Scan from high to low id.
......@@ -1154,9 +1174,39 @@ void scsi_scan_host(struct Scsi_Host *shost)
order_id = shost->max_id - id - 1;
else
order_id = id;
scsi_scan_target(shost, channel, order_id);
scsi_scan_target(shost, channel, order_id, lun, rescan);
}
}
else
scsi_scan_target(shost, channel, id, lun, rescan);
}
int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel,
unsigned int id, unsigned int lun, int rescan)
{
SCSI_LOG_SCAN_BUS(3, printk (KERN_INFO "%s: <%u:%u:%u:%u>\n",
__FUNCTION__, shost->host_no, channel, id, lun));
if (((channel != SCAN_WILD_CARD) && (channel > shost->max_channel)) ||
((id != SCAN_WILD_CARD) && (id > shost->max_id)) ||
((lun != SCAN_WILD_CARD) && (lun > shost->max_lun)))
return -EINVAL;
if (channel == SCAN_WILD_CARD)
for (channel = 0; channel <= shost->max_channel; channel++)
scsi_scan_channel(shost, channel, id, lun, rescan);
else
scsi_scan_channel(shost, channel, id, lun, rescan);
return 0;
}
/**
* scsi_scan_host - scan the given adapter
* @shost: adapter to scan
**/
void scsi_scan_host(struct Scsi_Host *shost)
{
scsi_scan_host_selected(shost, SCAN_WILD_CARD, SCAN_WILD_CARD,
SCAN_WILD_CARD, 0);
}
void scsi_forget_host(struct Scsi_Host *shost)
......
......@@ -15,6 +15,43 @@
#include "hosts.h"
#include "scsi_priv.h"
#include "scsi_logging.h"
static int check_set(unsigned int *val, char *src)
{
char *last;
if (strncmp(src, "-", 20) == 0) {
*val = SCAN_WILD_CARD;
} else {
/*
* Doesn't check for int overflow
*/
*val = simple_strtoul(src, &last, 0);
if (*last != '\0')
return 1;
}
return 0;
}
static int scsi_scan(struct Scsi_Host *shost, const char *str)
{
char s1[15], s2[15], s3[15], junk;
unsigned int channel, id, lun;
int res;
res = sscanf(str, "%10s %10s %10s %c", s1, s2, s3, &junk);
if (res != 3)
return -EINVAL;
if (check_set(&channel, s1))
return -EINVAL;
if (check_set(&id, s2))
return -EINVAL;
if (check_set(&lun, s3))
return -EINVAL;
res = scsi_scan_host_selected(shost, channel, id, lun, 1);
return res;
}
/*
* shost_show_function: macro to create an attr function that can be used to
......@@ -39,6 +76,20 @@ static CLASS_DEVICE_ATTR(field, S_IRUGO, show_##field, NULL)
/*
* Create the actual show/store functions and data structures.
*/
static ssize_t store_scan(struct class_device *class_dev, const char *buf,
size_t count)
{
struct Scsi_Host *shost = class_to_shost(class_dev);
int res;
res = scsi_scan(shost, buf);
if (res == 0)
res = count;
return res;
};
static CLASS_DEVICE_ATTR(scan, S_IWUSR, NULL, store_scan);
shost_rd_attr(unique_id, "%u\n");
shost_rd_attr(host_busy, "%hu\n");
shost_rd_attr(cmd_per_lun, "%hd\n");
......@@ -51,33 +102,10 @@ static struct class_device_attribute *scsi_sysfs_shost_attrs[] = {
&class_device_attr_cmd_per_lun,
&class_device_attr_sg_tablesize,
&class_device_attr_unchecked_isa_dma,
&class_device_attr_scan,
NULL
};
static void scsi_host_cls_release(struct class_device *class_dev)
{
struct Scsi_Host *shost;
shost = class_to_shost(class_dev);
put_device(&shost->shost_gendev);
}
static void scsi_host_dev_release(struct device *dev)
{
struct Scsi_Host *shost;
struct device *parent;
parent = dev->parent;
shost = dev_to_shost(dev);
scsi_free_shost(shost);
put_device(parent);
}
struct class shost_class = {
.name = "scsi_host",
.release = scsi_host_cls_release,
};
static void scsi_device_cls_release(struct class_device *class_dev)
{
struct scsi_device *sdev;
......@@ -113,33 +141,23 @@ struct bus_type scsi_bus_type = {
.match = scsi_bus_match,
};
int scsi_sysfs_register(void)
{
int error;
error = bus_register(&scsi_bus_type);
if (error)
return error;
error = class_register(&shost_class);
if (error)
goto bus_unregister;
error = class_register(&sdev_class);
if (error)
goto class_unregister;
return 0;
if (!error) {
error = class_register(&sdev_class);
if (error)
bus_unregister(&scsi_bus_type);
}
class_unregister:
class_unregister(&shost_class);
bus_unregister:
bus_unregister(&scsi_bus_type);
return error;
}
void scsi_sysfs_unregister(void)
{
class_unregister(&sdev_class);
class_unregister(&shost_class);
bus_unregister(&scsi_bus_type);
}
......@@ -243,6 +261,24 @@ store_rescan_field (struct device *dev, const char *buf, size_t count)
static DEVICE_ATTR(rescan, S_IWUSR, NULL, store_rescan_field)
static ssize_t sdev_store_delete(struct device *dev, const char *buf,
size_t count)
{
struct scsi_device *sdev = to_scsi_device(dev);
int res = count;
if (sdev->access_count)
/*
* FIXME and scsi_proc.c: racey use of access_count,
* possibly add a new arg to scsi_remove_device.
*/
res = -EBUSY;
else
scsi_remove_device(sdev);
return res;
};
static DEVICE_ATTR(delete, S_IWUSR, NULL, sdev_store_delete);
/* Default template for device attributes. May NOT be modified */
static struct device_attribute *scsi_sysfs_sdev_attrs[] = {
&dev_attr_device_blocked,
......@@ -255,6 +291,7 @@ static struct device_attribute *scsi_sysfs_sdev_attrs[] = {
&dev_attr_rev,
&dev_attr_online,
&dev_attr_rescan,
&dev_attr_delete,
NULL
};
......@@ -403,20 +440,6 @@ int scsi_register_interface(struct class_interface *intf)
}
void scsi_sysfs_init_host(struct Scsi_Host *shost)
{
device_initialize(&shost->shost_gendev);
snprintf(shost->shost_gendev.bus_id, BUS_ID_SIZE, "host%d",
shost->host_no);
shost->shost_gendev.release = scsi_host_dev_release;
class_device_initialize(&shost->shost_classdev);
shost->shost_classdev.dev = &shost->shost_gendev;
shost->shost_classdev.class = &shost_class;
snprintf(shost->shost_classdev.class_id, BUS_ID_SIZE, "host%d",
shost->host_no);
}
static struct class_device_attribute *class_attr_overridden(
struct class_device_attribute **attrs,
struct class_device_attribute *attr)
......@@ -459,31 +482,16 @@ static int class_attr_add(struct class_device *classdev,
* @shost: scsi host struct to add to subsystem
* @dev: parent struct device pointer
**/
int scsi_sysfs_add_host(struct Scsi_Host *shost, struct device *dev)
int scsi_sysfs_add_host(struct Scsi_Host *shost)
{
int error, i;
if (!shost->shost_gendev.parent)
shost->shost_gendev.parent = dev ? dev : &legacy_bus;
error = device_add(&shost->shost_gendev);
if (error)
return error;
set_bit(SHOST_ADD, &shost->shost_state);
get_device(shost->shost_gendev.parent);
error = class_device_add(&shost->shost_classdev);
if (error)
goto clean_device;
get_device(&shost->shost_gendev);
if (shost->hostt->shost_attrs) {
for (i = 0; shost->hostt->shost_attrs[i]; i++) {
error = class_attr_add(&shost->shost_classdev,
shost->hostt->shost_attrs[i]);
if (error)
goto clean_class;
return error;
}
}
......@@ -493,31 +501,9 @@ int scsi_sysfs_add_host(struct Scsi_Host *shost, struct device *dev)
error = class_device_create_file(&shost->shost_classdev,
scsi_sysfs_shost_attrs[i]);
if (error)
goto clean_class;
return error;
}
}
return error;
clean_class:
class_device_del(&shost->shost_classdev);
clean_device:
device_del(&shost->shost_gendev);
return error;
}
/**
* scsi_sysfs_remove_host - remove scsi host from subsystem
* @shost: scsi host to remove from subsystem
**/
void scsi_sysfs_remove_host(struct Scsi_Host *shost)
{
unsigned long flags;
spin_lock_irqsave(shost->host_lock, flags);
set_bit(SHOST_DEL, &shost->shost_state);
spin_unlock_irqrestore(shost->host_lock, flags);
class_device_unregister(&shost->shost_classdev);
device_del(&shost->shost_gendev);
return 0;
}
......@@ -308,6 +308,8 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
SCpnt->cmnd[4] = (unsigned char) this_count;
SCpnt->cmnd[5] = 0;
}
SCpnt->request_bufflen = SCpnt->bufflen =
this_count * sdp->sector_size;
/*
* We shouldn't disconnect in the middle of a sector, so with a dumb
......@@ -1353,10 +1355,14 @@ static int sd_remove(struct device *dev)
static void sd_shutdown(struct device *dev)
{
struct scsi_device *sdp = to_scsi_device(dev);
struct scsi_disk *sdkp = dev_get_drvdata(dev);
struct scsi_disk *sdkp;
struct scsi_request *sreq;
int retries, res;
sdkp = dev_get_drvdata(dev);
if (!sdkp)
return; /* this can happen */
if (!sdp->online || !sdkp->WCE)
return;
......
......@@ -340,6 +340,20 @@ static int sr_init_command(struct scsi_cmnd * SCpnt)
return 0;
}
{
struct scatterlist *sg = SCpnt->request_buffer;
int i, size = 0;
for (i = 0; i < SCpnt->use_sg; i++)
size += sg[i].length;
if (size != SCpnt->request_bufflen && SCpnt->use_sg) {
printk(KERN_ERR "sr: mismatch count %d, bytes %d\n",
size, SCpnt->request_bufflen);
if (SCpnt->request_bufflen > size)
SCpnt->request_bufflen = SCpnt->bufflen = size;
}
}
/*
* request doesn't start on hw block boundary, add scatter pads
*/
......@@ -361,8 +375,11 @@ static int sr_init_command(struct scsi_cmnd * SCpnt)
SCpnt->cmnd[1] = 0;
block = (unsigned int)SCpnt->request->sector / (s_size >> 9);
if (this_count > 0xffff)
if (this_count > 0xffff) {
this_count = 0xffff;
SCpnt->request_bufflen = SCpnt->bufflen =
this_count * s_size;
}
SCpnt->cmnd[2] = (unsigned char) (block >> 24) & 0xff;
SCpnt->cmnd[3] = (unsigned char) (block >> 16) & 0xff;
......@@ -390,18 +407,6 @@ static int sr_init_command(struct scsi_cmnd * SCpnt)
*/
SCpnt->done = rw_intr;
{
struct scatterlist *sg = SCpnt->request_buffer;
int i, size = 0;
for (i = 0; i < SCpnt->use_sg; i++)
size += sg[i].length;
if (size != SCpnt->request_bufflen && SCpnt->use_sg) {
printk("sr: mismatch count %d, bytes %d\n", size, SCpnt->request_bufflen);
SCpnt->request_bufflen = size;
}
}
/*
* This indicates that the command is ready from our end to be
* queued.
......
......@@ -2029,7 +2029,7 @@ sym_attach (struct scsi_host_template *tpnt, int unit, sym_device *dev)
printf_info("%s: giving up ...\n", sym_name(np));
if (np)
sym_free_resources(np);
scsi_unregister(instance);
scsi_host_put(instance);
return -1;
}
......
......@@ -5942,14 +5942,7 @@ int sym_hcb_attach(hcb_p np, struct sym_fw *fw)
*/
return 0;
/*
* We have failed.
* We will try to free all the resources we have
* allocated, but if we are a boot device, this
* will not help that much.;)
*/
attach_failed:
sym_hcb_free(np);
return -ENXIO;
}
......
......@@ -135,11 +135,9 @@ zalon_scsi_callback(struct parisc_device *dev)
if(!host)
goto fail;
strlcpy(dev->dev.name, "zalon7xx", sizeof(dev->dev.name));
if(request_irq(irq, ncr53c8xx_intr, SA_SHIRQ, dev->dev.name, host)) {
if(request_irq(irq, ncr53c8xx_intr, SA_SHIRQ, dev->dev.bus_id, host)) {
printk(KERN_ERR "%s: irq problem with %d, detaching\n ",
dev->dev.name, irq);
dev->dev.bus_id, irq);
goto fail;
}
......
......@@ -16,6 +16,8 @@
*/
#include <linux/types.h>
/*
* SCSI command lengths
*/
......
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