Commit 75e306e3 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.5
parents 1096ae58 2a329e52
...@@ -385,7 +385,7 @@ static int __init NCR_D700_init(void) ...@@ -385,7 +385,7 @@ static int __init NCR_D700_init(void)
static void __exit NCR_D700_exit(void) static void __exit NCR_D700_exit(void)
{ {
mca_unregister_driver(&NCR_D700_driver); mca_unregister_driver(&NCR_D700_driver);
scsi_sysfs_release_attributes(); scsi_sysfs_release_attributes(&NCR_D700_driver_template);
} }
module_init(NCR_D700_init); module_init(NCR_D700_init);
......
...@@ -21,26 +21,6 @@ ...@@ -21,26 +21,6 @@
* 1+ (800) 334-5454 * 1+ (800) 334-5454
*/ */
/*
* Options :
*
* PARITY - enable parity checking. Not supported.
*
* SCSI2 - enable support for SCSI-II tagged queueing. Untested.
*
* USLEEP - enable support for devices that don't disconnect. Untested.
*/
/*
* $Log: ecoscsi.c,v $
* Revision 1.2 1998/03/08 05:49:47 davem
* Merge to 2.1.89
*
* Revision 1.1 1998/02/23 02:45:24 davem
* Merge to 2.1.88
*
*/
#include <linux/module.h> #include <linux/module.h>
#include <linux/signal.h> #include <linux/signal.h>
#include <linux/sched.h> #include <linux/sched.h>
...@@ -94,71 +74,8 @@ static void ecoscsi_write(struct Scsi_Host *instance, int reg, int value) ...@@ -94,71 +74,8 @@ static void ecoscsi_write(struct Scsi_Host *instance, int reg, int value)
* *
*/ */
void ecoscsi_setup(char *str, int *ints) { void ecoscsi_setup(char *str, int *ints)
}
/*
* Function : int ecoscsi_detect(Scsi_Host_Template * tpnt)
*
* Purpose : initializes ecoscsi NCR5380 driver based on the
* command line / compile time port and irq definitions.
*
* Inputs : tpnt - template for this SCSI adapter.
*
* Returns : 1 if a host adapter was found, 0 if not.
*
*/
int ecoscsi_detect(Scsi_Host_Template * tpnt)
{
struct Scsi_Host *host;
tpnt->proc_name = "ecoscsi";
host = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
if (!host)
return 0;
host->io_port = 0x80ce8000;
host->n_io_port = 144;
host->irq = IRQ_NONE;
if ( !(request_region(host->io_port, host->n_io_port, "ecoscsi")) )
goto unregister_scsi;
ecoscsi_write (host, MODE_REG, 0x20); /* Is it really SCSI? */
if (ecoscsi_read (host, MODE_REG) != 0x20) /* Write to a reg. */
goto release_reg;
ecoscsi_write( host, MODE_REG, 0x00 ); /* it back. */
if (ecoscsi_read (host, MODE_REG) != 0x00)
goto release_reg;
NCR5380_init(host, 0);
printk("scsi%d: at port 0x%08lx irqs disabled", host->host_no, host->io_port);
printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
host->can_queue, host->cmd_per_lun, ECOSCSI_PUBLIC_RELEASE);
printk("\nscsi%d:", host->host_no);
NCR5380_print_options(host);
printk("\n");
return 1;
release_reg:
release_region(host->io_port, host->n_io_port);
unregister_scsi:
scsi_unregister(host);
return 0;
}
int ecoscsi_release (struct Scsi_Host *shpnt)
{ {
if (shpnt->irq != IRQ_NONE)
free_irq (shpnt->irq, NULL);
if (shpnt->io_port)
release_region (shpnt->io_port, shpnt->n_io_port);
return 0;
} }
const char * ecoscsi_info (struct Scsi_Host *spnt) const char * ecoscsi_info (struct Scsi_Host *spnt)
...@@ -241,8 +158,7 @@ printk("reading %p len %d\n",addr, len); ...@@ -241,8 +158,7 @@ printk("reading %p len %d\n",addr, len);
static Scsi_Host_Template ecoscsi_template = { static Scsi_Host_Template ecoscsi_template = {
.module = THIS_MODULE, .module = THIS_MODULE,
.name = "Serial Port EcoSCSI NCR5380", .name = "Serial Port EcoSCSI NCR5380",
.detect = ecoscsi_detect, .proc_name = "ecoscsi",
.release = ecoscsi_release,
.info = ecoscsi_info, .info = ecoscsi_info,
.queuecommand = ecoscsi_queue_command, .queuecommand = ecoscsi_queue_command,
.eh_abort_handler = NCR5380_abort, .eh_abort_handler = NCR5380_abort,
...@@ -256,19 +172,60 @@ static Scsi_Host_Template ecoscsi_template = { ...@@ -256,19 +172,60 @@ static Scsi_Host_Template ecoscsi_template = {
.use_clustering = DISABLE_CLUSTERING .use_clustering = DISABLE_CLUSTERING
}; };
static struct Scsi_Host *host;
static int __init ecoscsi_init(void) static int __init ecoscsi_init(void)
{ {
scsi_register_host(&ecoscsi_template);
if (ecoscsi_template.present) host = scsi_register(tpnt, sizeof(struct NCR5380_hostdata));
if (!host)
return 0; return 0;
scsi_unregister_host(&ecoscsi_template); host->io_port = 0x80ce8000;
host->n_io_port = 144;
host->irq = IRQ_NONE;
if (!(request_region(host->io_port, host->n_io_port, "ecoscsi")) )
goto unregister_scsi;
ecoscsi_write(host, MODE_REG, 0x20); /* Is it really SCSI? */
if (ecoscsi_read(host, MODE_REG) != 0x20) /* Write to a reg. */
goto release_reg;
ecoscsi_write(host, MODE_REG, 0x00 ); /* it back. */
if (ecoscsi_read(host, MODE_REG) != 0x00)
goto release_reg;
NCR5380_init(host, 0);
printk("scsi%d: at port 0x%08lx irqs disabled", host->host_no, host->io_port);
printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
host->can_queue, host->cmd_per_lun, ECOSCSI_PUBLIC_RELEASE);
printk("\nscsi%d:", host->host_no);
NCR5380_print_options(host);
printk("\n");
scsi_add_host(host, NULL);
return 0;
release_reg:
release_region(host->io_port, host->n_io_port);
unregister_scsi:
scsi_unregister(host);
return -ENODEV; return -ENODEV;
} }
static void __exit ecoscsi_exit(void) static void __exit ecoscsi_exit(void)
{ {
scsi_unregister_host(&ecoscsi_template); scsi_remove_host(host);
if (shpnt->irq != IRQ_NONE)
free_irq(shpnt->irq, NULL);
if (shpnt->io_port)
release_region(shpnt->io_port, shpnt->n_io_port);
scsi_unregister(host);
return 0;
} }
module_init(ecoscsi_init); module_init(ecoscsi_init);
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -234,27 +234,18 @@ int scsi_remove_host(struct Scsi_Host *shost) ...@@ -234,27 +234,18 @@ int scsi_remove_host(struct Scsi_Host *shost)
int scsi_add_host(struct Scsi_Host *shost, struct device *dev) int scsi_add_host(struct Scsi_Host *shost, struct device *dev)
{ {
Scsi_Host_Template *sht = shost->hostt; Scsi_Host_Template *sht = shost->hostt;
struct scsi_device *sdev; int error;
int error = 0, saved_error = 0;
printk(KERN_INFO "scsi%d : %s\n", shost->host_no, printk(KERN_INFO "scsi%d : %s\n", shost->host_no,
sht->info ? sht->info(shost) : sht->name); sht->info ? sht->info(shost) : sht->name);
error = scsi_sysfs_add_host(shost, dev); error = scsi_sysfs_add_host(shost, dev);
if (error) if (!error) {
return error; scsi_proc_host_add(shost);
scsi_scan_host(shost);
scsi_proc_host_add(shost); };
scsi_scan_host(shost);
list_for_each_entry (sdev, &shost->my_devices, siblings) { return error;
error = scsi_attach_device(sdev);
if (error)
saved_error = error;
}
return saved_error;
} }
/** /**
...@@ -500,60 +491,43 @@ int scsi_unregister_host(Scsi_Host_Template *shost_tp) ...@@ -500,60 +491,43 @@ int scsi_unregister_host(Scsi_Host_Template *shost_tp)
} }
/** /**
* *scsi_host_get_next - get scsi host and inc ref count * scsi_host_lookup - get a reference to a Scsi_Host by host no
* @shost: pointer to a Scsi_Host or NULL to start. *
* @hostnum: host number to locate
* *
* Return value: * Return value:
* A pointer to next Scsi_Host in list or NULL. * A pointer to located Scsi_Host or NULL.
**/ **/
struct Scsi_Host *scsi_host_get_next(struct Scsi_Host *shost) struct Scsi_Host *scsi_host_lookup(unsigned short hostnum)
{ {
struct list_head *lh = NULL; struct class *class = class_get(&shost_class);
struct class_device *cdev;
spin_lock(&scsi_host_list_lock); struct Scsi_Host *shost = NULL, *p;
if (shost) {
/* XXX Dec ref on cur shost */ if (class) {
lh = shost->sh_list.next; down_read(&class->subsys.rwsem);
} else { list_for_each_entry(cdev, &class->children, node) {
lh = scsi_host_list.next; p = class_to_shost(cdev);
} if (p->host_no == hostnum) {
scsi_host_get(p);
if (lh == &scsi_host_list) { shost = p;
shost = (struct Scsi_Host *)NULL; break;
goto done; }
}
up_read(&class->subsys.rwsem);
} }
shost = list_entry(lh, struct Scsi_Host, sh_list);
/* XXX Inc ref count */
done:
spin_unlock(&scsi_host_list_lock);
return shost; return shost;
} }
/**
* scsi_host_hn_get - get a Scsi_Host by host no and inc ref count
* @host_no: host number to locate
*
* Return value:
* A pointer to located Scsi_Host or NULL.
**/
struct Scsi_Host *scsi_host_hn_get(unsigned short host_no)
{
/* XXX Inc ref count */
return scsi_find_host_by_num(host_no);
}
/** /**
* *scsi_host_get - inc a Scsi_Host ref count * *scsi_host_get - inc a Scsi_Host ref count
* @shost: Pointer to Scsi_Host to inc. * @shost: Pointer to Scsi_Host to inc.
**/ **/
void scsi_host_get(struct Scsi_Host *shost) void scsi_host_get(struct Scsi_Host *shost)
{ {
get_device(&shost->host_gendev); get_device(&shost->host_gendev);
class_device_get(&shost->class_dev); class_device_get(&shost->class_dev);
return;
} }
/** /**
...@@ -565,7 +539,6 @@ void scsi_host_put(struct Scsi_Host *shost) ...@@ -565,7 +539,6 @@ void scsi_host_put(struct Scsi_Host *shost)
class_device_put(&shost->class_dev); class_device_put(&shost->class_dev);
put_device(&shost->host_gendev); put_device(&shost->host_gendev);
return;
} }
/** /**
......
...@@ -542,25 +542,23 @@ static inline struct device *scsi_get_device(struct Scsi_Host *shost) ...@@ -542,25 +542,23 @@ static inline struct device *scsi_get_device(struct Scsi_Host *shost)
return shost->host_gendev.parent; return shost->host_gendev.parent;
} }
struct Scsi_Device_Template struct scsi_driver {
{ struct module *owner;
struct list_head list; struct device_driver gendrv;
const char * name;
struct module * module; /* Used for loadable modules */ int (*init_command)(struct scsi_cmnd *);
unsigned char scsi_type; void (*rescan)(struct device *);
int (*attach)(Scsi_Device *); /* Attach devices to arrays */
void (*detach)(Scsi_Device *);
int (*init_command)(Scsi_Cmnd *); /* Used by new queueing code.
Selects command for blkdevs */
void (*rescan)(Scsi_Device *);
struct device_driver scsi_driverfs_driver;
}; };
#define to_scsi_driver(drv) \
container_of((drv), struct scsi_driver, gendrv)
/* extern int scsi_register_driver(struct device_driver *);
* Highlevel driver registration/unregistration. #define scsi_unregister_driver(drv) \
*/ driver_unregister(drv);
extern int scsi_register_device(struct Scsi_Device_Template *);
extern int scsi_unregister_device(struct Scsi_Device_Template *); extern int scsi_register_interface(struct class_interface *);
#define scsi_unregister_interface(intf) \
class_interface_unregister(intf)
/* /*
* HBA allocation/freeing. * HBA allocation/freeing.
......
...@@ -771,6 +771,10 @@ static inline struct bio *idescsi_dma_bio(ide_drive_t *drive, idescsi_pc_t *pc) ...@@ -771,6 +771,10 @@ static inline struct bio *idescsi_dma_bio(ide_drive_t *drive, idescsi_pc_t *pc)
static inline int should_transform(ide_drive_t *drive, Scsi_Cmnd *cmd) static inline int should_transform(ide_drive_t *drive, Scsi_Cmnd *cmd)
{ {
idescsi_scsi_t *scsi = drive_to_idescsi(drive); idescsi_scsi_t *scsi = drive_to_idescsi(drive);
/* this was a layering violation and we can't support it
anymore, sorry. */
#if 0
struct gendisk *disk = cmd->request->rq_disk; struct gendisk *disk = cmd->request->rq_disk;
if (disk) { if (disk) {
...@@ -778,6 +782,7 @@ static inline int should_transform(ide_drive_t *drive, Scsi_Cmnd *cmd) ...@@ -778,6 +782,7 @@ static inline int should_transform(ide_drive_t *drive, Scsi_Cmnd *cmd)
if (strcmp((*p)->scsi_driverfs_driver.name, "sg") == 0) if (strcmp((*p)->scsi_driverfs_driver.name, "sg") == 0)
return test_bit(IDESCSI_SG_TRANSFORM, &scsi->transform); return test_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);
} }
#endif
return test_bit(IDESCSI_TRANSFORM, &scsi->transform); return test_bit(IDESCSI_TRANSFORM, &scsi->transform);
} }
......
...@@ -254,7 +254,7 @@ static inline int imm_proc_write(int hostno, char *buffer, int length) ...@@ -254,7 +254,7 @@ static inline int imm_proc_write(int hostno, char *buffer, int length)
} }
int imm_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int imm_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
int length, int hostno, int inout) int length, int inout)
{ {
int i; int i;
int len = 0; int len = 0;
......
...@@ -159,6 +159,7 @@ int imm_command(Scsi_Cmnd *); ...@@ -159,6 +159,7 @@ int imm_command(Scsi_Cmnd *);
int imm_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); int imm_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
int imm_abort(Scsi_Cmnd *); int imm_abort(Scsi_Cmnd *);
int imm_reset(Scsi_Cmnd *); int imm_reset(Scsi_Cmnd *);
int imm_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int);
int imm_biosparam(struct scsi_device *, struct block_device *, int imm_biosparam(struct scsi_device *, struct block_device *,
sector_t, int *); sector_t, int *);
......
...@@ -278,14 +278,12 @@ static const int nsp32_table_pci_num = ...@@ -278,14 +278,12 @@ static const int nsp32_table_pci_num =
/* /*
* function declaration * function declaration
*/ */
static int nsp32_detect(Scsi_Host_Template *);
static int nsp32_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); static int nsp32_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
static const char *nsp32_info(struct Scsi_Host *); static const char *nsp32_info(struct Scsi_Host *);
static int nsp32_eh_abort(Scsi_Cmnd *); static int nsp32_eh_abort(Scsi_Cmnd *);
static int nsp32_eh_bus_reset(Scsi_Cmnd *); static int nsp32_eh_bus_reset(Scsi_Cmnd *);
static int nsp32_eh_host_reset(Scsi_Cmnd *); static int nsp32_eh_host_reset(Scsi_Cmnd *);
static int nsp32_reset(Scsi_Cmnd *, unsigned int); static int nsp32_reset(Scsi_Cmnd *, unsigned int);
static int nsp32_release(struct Scsi_Host *);
static int nsp32_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int); static int nsp32_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int);
static int __devinit nsp32_probe(struct pci_dev *, const struct pci_device_id *); static int __devinit nsp32_probe(struct pci_dev *, const struct pci_device_id *);
static void __devexit nsp32_remove(struct pci_dev *); static void __devexit nsp32_remove(struct pci_dev *);
...@@ -335,11 +333,10 @@ static inline int nsp32_prom_get(nsp32_hw_data *, int); ...@@ -335,11 +333,10 @@ static inline int nsp32_prom_get(nsp32_hw_data *, int);
/* /*
* max_sectors is currently limited up to 128. * max_sectors is currently limited up to 128.
*/ */
static Scsi_Host_Template driver_template = { static Scsi_Host_Template nsp32_template = {
.proc_name = "nsp32",
.name = "Workbit NinjaSCSI-32Bi/UDE", .name = "Workbit NinjaSCSI-32Bi/UDE",
.proc_name = "nsp32",
.proc_info = nsp32_proc_info, .proc_info = nsp32_proc_info,
.detect = nsp32_detect,
.info = nsp32_info, .info = nsp32_info,
.queuecommand = nsp32_queuecommand, .queuecommand = nsp32_queuecommand,
.can_queue = 1, .can_queue = 1,
...@@ -352,12 +349,6 @@ static Scsi_Host_Template driver_template = { ...@@ -352,12 +349,6 @@ static Scsi_Host_Template driver_template = {
.eh_device_reset_handler = NULL, .eh_device_reset_handler = NULL,
.eh_bus_reset_handler = nsp32_eh_bus_reset, .eh_bus_reset_handler = nsp32_eh_bus_reset,
.eh_host_reset_handler = nsp32_eh_host_reset, .eh_host_reset_handler = nsp32_eh_host_reset,
.release = nsp32_release,
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,2))
.use_new_eh_code = 1,
#else
/* .highmem_io = 1, */
#endif
}; };
#include "nsp32_io.h" #include "nsp32_io.h"
...@@ -1618,7 +1609,7 @@ static int nsp32_proc_info(struct Scsi_Host *host, char *buffer, ...@@ -1618,7 +1609,7 @@ static int nsp32_proc_info(struct Scsi_Host *host, char *buffer,
* 0x900-0xbff: (map same 0x800-0x8ff I/O port image repeatedly) * 0x900-0xbff: (map same 0x800-0x8ff I/O port image repeatedly)
* 0xc00-0xfff: CardBus status registers * 0xc00-0xfff: CardBus status registers
*/ */
static int nsp32_detect(Scsi_Host_Template *sht) static int nsp32_detect(struct pci_dev *pdev)
{ {
struct Scsi_Host *host; /* registered host structure */ struct Scsi_Host *host; /* registered host structure */
int ret; int ret;
...@@ -1630,7 +1621,7 @@ static int nsp32_detect(Scsi_Host_Template *sht) ...@@ -1630,7 +1621,7 @@ static int nsp32_detect(Scsi_Host_Template *sht)
/* /*
* register this HBA as SCSI device * register this HBA as SCSI device
*/ */
host = scsi_register(sht, sizeof(nsp32_hw_data)); host = scsi_register(&nsp32_template, sizeof(nsp32_hw_data));
if (host == NULL) { if (host == NULL) {
nsp32_msg (KERN_ERR, "failed to scsi register"); nsp32_msg (KERN_ERR, "failed to scsi register");
goto err; goto err;
...@@ -1793,8 +1784,6 @@ static int nsp32_detect(Scsi_Host_Template *sht) ...@@ -1793,8 +1784,6 @@ static int nsp32_detect(Scsi_Host_Template *sht)
"NinjaSCSI-32Bi/UDE: irq %d, io 0x%lx+0x%x", "NinjaSCSI-32Bi/UDE: irq %d, io 0x%lx+0x%x",
host->irq, host->io_port, host->n_io_port); host->irq, host->io_port, host->n_io_port);
sht->name = data->info_str;
/* /*
* SCSI bus reset * SCSI bus reset
* *
...@@ -1832,7 +1821,9 @@ static int nsp32_detect(Scsi_Host_Template *sht) ...@@ -1832,7 +1821,9 @@ static int nsp32_detect(Scsi_Host_Template *sht)
goto free_irq; goto free_irq;
} }
return 1; scsi_add_host(host, &pdev->dev);
pci_set_drvdata(pdev, host);
return 0;
free_irq: free_irq:
free_irq(host->irq, data); free_irq(host->irq, data);
...@@ -1852,43 +1843,7 @@ static int nsp32_detect(Scsi_Host_Template *sht) ...@@ -1852,43 +1843,7 @@ static int nsp32_detect(Scsi_Host_Template *sht)
scsi_unregister(host); scsi_unregister(host);
err: err:
return 0; return 1;
}
static int nsp32_release(struct Scsi_Host *shpnt)
{
nsp32_hw_data *data = (nsp32_hw_data *)shpnt->hostdata;
if (data->lunt_list) {
kfree(data->lunt_list);
}
if (data->autoparam) {
pci_free_consistent(data->Pci, AUTOPARAM_SIZE,
data->autoparam, data->apaddr);
}
if (data->sg_list) {
pci_free_consistent(data->Pci,
(sizeof(struct nsp32_sgtable) * NSP_SG_SIZE * MAX_TARGET * MAX_LUN),
data->sg_list, data->sgaddr);
}
DEBUG(0, "free irq\n");
if (shpnt->irq) {
free_irq(shpnt->irq, data);
}
DEBUG(0, "free io\n");
if (shpnt->io_port && shpnt->n_io_port) {
release_region(shpnt->io_port, shpnt->n_io_port);
}
if (data->MmioAddress != 0) {
iounmap((void *)(data->MmioAddress));
}
return 0;
} }
static const char *nsp32_info(struct Scsi_Host *shpnt) static const char *nsp32_info(struct Scsi_Host *shpnt)
...@@ -2031,11 +1986,7 @@ static int __devinit nsp32_probe(struct pci_dev *pdev, const struct pci_device_i ...@@ -2031,11 +1986,7 @@ static int __devinit nsp32_probe(struct pci_dev *pdev, const struct pci_device_i
pci_set_master(pdev); pci_set_master(pdev);
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2)) ret = nsp32_detect(pdev);
scsi_register_host(&driver_template);
#else
scsi_register_module(MODULE_SCSI_HA, &driver_template);
#endif
nsp32_msg(KERN_INFO, "nsp32 irq: %i mmio: 0x%lx slot: %s model: %s", nsp32_msg(KERN_INFO, "nsp32 irq: %i mmio: 0x%lx slot: %s model: %s",
pdev->irq, data->MmioAddress, pdev->slot_name, pdev->irq, data->MmioAddress, pdev->slot_name,
...@@ -2043,18 +1994,23 @@ static int __devinit nsp32_probe(struct pci_dev *pdev, const struct pci_device_i ...@@ -2043,18 +1994,23 @@ static int __devinit nsp32_probe(struct pci_dev *pdev, const struct pci_device_i
nsp32_dbg(NSP32_DEBUG_REGISTER, "exit"); nsp32_dbg(NSP32_DEBUG_REGISTER, "exit");
return 0; return ret;
} }
static void __devexit nsp32_remove(struct pci_dev *pdev) static void __devexit nsp32_remove(struct pci_dev *pdev)
{ {
nsp32_dbg(NSP32_DEBUG_REGISTER, "enter"); struct Scsi_Host *shpnt = pci_get_drvdata(pdev);
nsp32_hw_data *data = (nsp32_hw_data *)shpnt->hostdata;
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2))
scsi_unregister_host(&driver_template); kfree(data->lunt_list);
#else pci_free_consistent(data->Pci, AUTOPARAM_SIZE,
scsi_unregister_module(MODULE_SCSI_HA, &driver_template); data->autoparam, data->apaddr);
#endif pci_free_consistent(data->Pci,
(sizeof(struct nsp32_sgtable) * NSP_SG_SIZE*MAX_TARGET*MAX_LUN),
data->sg_list, data->sgaddr);
free_irq(shpnt->irq, data);
release_region(shpnt->io_port, shpnt->n_io_port);
iounmap((void *)(data->MmioAddress));
} }
static struct pci_device_id nsp32_pci_table[] __devinitdata = { static struct pci_device_id nsp32_pci_table[] __devinitdata = {
......
...@@ -160,19 +160,15 @@ static int osst_zero_buffer_tail(OSST_buffer *); ...@@ -160,19 +160,15 @@ static int osst_zero_buffer_tail(OSST_buffer *);
static int osst_copy_to_buffer(OSST_buffer *, unsigned char *); static int osst_copy_to_buffer(OSST_buffer *, unsigned char *);
static int osst_copy_from_buffer(OSST_buffer *, unsigned char *); static int osst_copy_from_buffer(OSST_buffer *, unsigned char *);
static int osst_attach(Scsi_Device *); static int osst_probe(struct device *);
static void osst_detach(Scsi_Device *); static int osst_remove(struct device *);
struct Scsi_Device_Template osst_template = struct scsi_driver osst_template = {
{ .owner = THIS_MODULE,
.module = THIS_MODULE, .gendrv = {
.list = LIST_HEAD_INIT(osst_template.list), .name = "osst",
.name = "OnStream Tape", .probe = osst_probe,
.scsi_type = TYPE_TAPE, .remove = osst_remove,
.attach = osst_attach,
.detach = osst_detach,
.scsi_driverfs_driver = {
.name = "osst",
} }
}; };
...@@ -5326,22 +5322,6 @@ __setup("osst=", osst_setup); ...@@ -5326,22 +5322,6 @@ __setup("osst=", osst_setup);
#endif #endif
/* Driverfs file support */
static ssize_t osst_device_kdev_read(struct device *driverfs_dev, char *page)
{
kdev_t kdev;
kdev.value=(int)(long)driverfs_dev->driver_data;
return sprintf(page, "%x\n",kdev.value);
}
static DEVICE_ATTR(kdev,S_IRUGO,osst_device_kdev_read,NULL);
static ssize_t osst_device_type_read(struct device *driverfs_dev, char *page)
{
return sprintf (page, "CHR\n");
}
static DEVICE_ATTR(type,S_IRUGO,osst_device_type_read,NULL);
static struct file_operations osst_fops = { static struct file_operations osst_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.read = osst_read, .read = osst_read,
...@@ -5384,8 +5364,9 @@ static struct osst_support_data support_list[] = { ...@@ -5384,8 +5364,9 @@ static struct osst_support_data support_list[] = {
* osst startup / cleanup code * osst startup / cleanup code
*/ */
static int osst_attach(Scsi_Device * SDp) static int osst_probe(struct device *dev)
{ {
Scsi_Device * SDp = to_scsi_device(dev);
OS_Scsi_Tape * tpnt; OS_Scsi_Tape * tpnt;
ST_mode * STm; ST_mode * STm;
ST_partstat * STps; ST_partstat * STps;
...@@ -5394,12 +5375,12 @@ static int osst_attach(Scsi_Device * SDp) ...@@ -5394,12 +5375,12 @@ static int osst_attach(Scsi_Device * SDp)
int i, mode, dev_num; int i, mode, dev_num;
if (SDp->type != TYPE_TAPE || !osst_supports(SDp)) if (SDp->type != TYPE_TAPE || !osst_supports(SDp))
return 1; return -ENODEV;
drive = alloc_disk(1); drive = alloc_disk(1);
if (!drive) { if (!drive) {
printk(KERN_ERR "osst :E: Out of memory. Device not attached.\n"); printk(KERN_ERR "osst :E: Out of memory. Device not attached.\n");
return 1; return -ENODEV;
} }
/* if this is the first attach, build the infrastructure */ /* if this is the first attach, build the infrastructure */
...@@ -5521,45 +5502,12 @@ static int osst_attach(Scsi_Device * SDp) ...@@ -5521,45 +5502,12 @@ static int osst_attach(Scsi_Device * SDp)
write_unlock(&os_scsi_tapes_lock); write_unlock(&os_scsi_tapes_lock);
for (mode = 0; mode < ST_NBR_MODES; ++mode) { for (mode = 0; mode < ST_NBR_MODES; ++mode) {
char name[8];
/* Rewind entry */ /* Rewind entry */
sprintf(name, "ot%s", osst_formats[mode]);
sprintf(tpnt->driverfs_dev_r[mode].bus_id, "%s:%s",
SDp->sdev_driverfs_dev.bus_id, 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 = SDp->sdev_driverfs_dev.bus;
tpnt->driverfs_dev_r[mode].driver_data =
(void *)(long)__mkdev(OSST_MAJOR, dev_num + (mode << 5));
device_register(&tpnt->driverfs_dev_r[mode]);
device_create_file(&tpnt->driverfs_dev_r[mode],
&dev_attr_type);
device_create_file(&tpnt->driverfs_dev_r[mode], &dev_attr_kdev);
devfs_mk_cdev(MKDEV(OSST_MAJOR, dev_num + (mode << 5)), devfs_mk_cdev(MKDEV(OSST_MAJOR, dev_num + (mode << 5)),
S_IFCHR | S_IRUGO | S_IWUGO, S_IFCHR | S_IRUGO | S_IWUGO,
"%s/ot%s", SDp->devfs_name, osst_formats[mode]); "%s/ot%s", SDp->devfs_name, osst_formats[mode]);
/* No-rewind entry */ /* No-rewind entry */
sprintf (name, "ot%sn", osst_formats[mode]);
sprintf(tpnt->driverfs_dev_n[mode].bus_id, "%s:%s",
SDp->sdev_driverfs_dev.bus_id, 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 = SDp->sdev_driverfs_dev.bus;
tpnt->driverfs_dev_n[mode].driver_data =
(void *)(long)__mkdev(OSST_MAJOR, dev_num + (mode << 5) + 128);
device_register(&tpnt->driverfs_dev_n[mode]);
device_create_file(&tpnt->driverfs_dev_n[mode],
&dev_attr_type);
device_create_file(&tpnt->driverfs_dev_n[mode],
&dev_attr_kdev);
devfs_mk_cdev(MKDEV(OSST_MAJOR, dev_num + (mode << 5) + 128), devfs_mk_cdev(MKDEV(OSST_MAJOR, dev_num + (mode << 5) + 128),
S_IFCHR | S_IRUGO | S_IWUGO, S_IFCHR | S_IRUGO | S_IWUGO,
"%s/ot%sn", SDp->devfs_name, osst_formats[mode]); "%s/ot%sn", SDp->devfs_name, osst_formats[mode]);
...@@ -5574,16 +5522,17 @@ static int osst_attach(Scsi_Device * SDp) ...@@ -5574,16 +5522,17 @@ static int osst_attach(Scsi_Device * SDp)
out_put_disk: out_put_disk:
put_disk(drive); put_disk(drive);
return 1; return -ENODEV;
}; };
static void osst_detach(Scsi_Device * SDp) static int osst_remove(struct device *dev)
{ {
Scsi_Device * SDp = to_scsi_device(dev);
OS_Scsi_Tape * tpnt; OS_Scsi_Tape * tpnt;
int i, mode; int i, mode;
if ((SDp->type != TYPE_TAPE) || (osst_nr_dev <= 0)) if ((SDp->type != TYPE_TAPE) || (osst_nr_dev <= 0))
return; return 0;
write_lock(&os_scsi_tapes_lock); write_lock(&os_scsi_tapes_lock);
for(i=0; i < osst_max_dev; i++) { for(i=0; i < osst_max_dev; i++) {
...@@ -5598,29 +5547,17 @@ static void osst_detach(Scsi_Device * SDp) ...@@ -5598,29 +5547,17 @@ static void osst_detach(Scsi_Device * SDp)
os_scsi_tapes[i] = NULL; os_scsi_tapes[i] = NULL;
osst_nr_dev--; osst_nr_dev--;
write_unlock(&os_scsi_tapes_lock); write_unlock(&os_scsi_tapes_lock);
for (mode = 0; mode < ST_NBR_MODES; ++mode) {
device_remove_file(&tpnt->driverfs_dev_r[mode],
&dev_attr_type);
device_remove_file(&tpnt->driverfs_dev_r[mode],
&dev_attr_kdev);
device_unregister(&tpnt->driverfs_dev_r[mode]);
device_remove_file(&tpnt->driverfs_dev_n[mode],
&dev_attr_type);
device_remove_file(&tpnt->driverfs_dev_n[mode],
&dev_attr_kdev);
device_unregister(&tpnt->driverfs_dev_n[mode]);
}
if (tpnt->header_cache != NULL) vfree(tpnt->header_cache); if (tpnt->header_cache != NULL) vfree(tpnt->header_cache);
if (tpnt->buffer) { if (tpnt->buffer) {
normalize_buffer(tpnt->buffer); normalize_buffer(tpnt->buffer);
kfree(tpnt->buffer); kfree(tpnt->buffer);
} }
kfree(tpnt); kfree(tpnt);
return; return 0;
} }
} }
write_unlock(&os_scsi_tapes_lock); write_unlock(&os_scsi_tapes_lock);
return; return 0;
} }
static int __init init_osst(void) static int __init init_osst(void)
...@@ -5629,7 +5566,7 @@ static int __init init_osst(void) ...@@ -5629,7 +5566,7 @@ static int __init init_osst(void)
validate_options(); validate_options();
if ((register_chrdev(OSST_MAJOR,"osst", &osst_fops) < 0) || scsi_register_device(&osst_template)) { if ((register_chrdev(OSST_MAJOR,"osst", &osst_fops) < 0) || scsi_register_driver(&osst_template.gendrv)) {
printk(KERN_ERR "osst :E: Unable to register major %d for OnStream tapes\n", OSST_MAJOR); printk(KERN_ERR "osst :E: Unable to register major %d for OnStream tapes\n", OSST_MAJOR);
return 1; return 1;
} }
...@@ -5642,7 +5579,7 @@ static void __exit exit_osst (void) ...@@ -5642,7 +5579,7 @@ static void __exit exit_osst (void)
int i; int i;
OS_Scsi_Tape * STp; OS_Scsi_Tape * STp;
scsi_unregister_device(&osst_template); scsi_unregister_driver(&osst_template.gendrv);
unregister_chrdev(OSST_MAJOR, "osst"); unregister_chrdev(OSST_MAJOR, "osst");
if (os_scsi_tapes) { if (os_scsi_tapes) {
......
...@@ -530,7 +530,7 @@ typedef struct { ...@@ -530,7 +530,7 @@ typedef struct {
/* The OnStream tape drive descriptor */ /* The OnStream tape drive descriptor */
typedef struct { typedef struct {
struct Scsi_Device_Template *driver; struct scsi_driver *driver;
unsigned capacity; unsigned capacity;
Scsi_Device* device; Scsi_Device* device;
struct semaphore lock; /* for serialization */ struct semaphore lock; /* for serialization */
...@@ -555,8 +555,6 @@ typedef struct { ...@@ -555,8 +555,6 @@ typedef struct {
/* Mode characteristics */ /* Mode characteristics */
ST_mode modes[ST_NBR_MODES]; ST_mode modes[ST_NBR_MODES];
int current_mode; int current_mode;
struct device driverfs_dev_r[ST_NBR_MODES];
struct device driverfs_dev_n[ST_NBR_MODES];
/* Status variables */ /* Status variables */
int partition; int partition;
......
...@@ -277,7 +277,7 @@ int ppa_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offs ...@@ -277,7 +277,7 @@ int ppa_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offs
int len = 0; int len = 0;
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
if (ppa_hosts[i] == host) if (ppa_hosts[i].host == host->host_no)
break; break;
if (inout) if (inout)
......
...@@ -85,12 +85,6 @@ unsigned long scsi_pid; ...@@ -85,12 +85,6 @@ unsigned long scsi_pid;
struct scsi_cmnd *last_cmnd; struct scsi_cmnd *last_cmnd;
static unsigned long serial_number; static unsigned long serial_number;
/*
* List of all highlevel drivers.
*/
LIST_HEAD(scsi_devicelist);
static DECLARE_RWSEM(scsi_devicelist_mutex);
/* /*
* Note - the initial logging level can be set here to log events at boot time. * Note - the initial logging level can be set here to log events at boot time.
* After the system is up, you may enable logging via the /proc interface. * After the system is up, you may enable logging via the /proc interface.
...@@ -931,50 +925,6 @@ int scsi_track_queue_full(struct scsi_device *sdev, int depth) ...@@ -931,50 +925,6 @@ int scsi_track_queue_full(struct scsi_device *sdev, int depth)
return depth; return depth;
} }
int scsi_attach_device(struct scsi_device *sdev)
{
struct Scsi_Device_Template *sdt;
down_read(&scsi_devicelist_mutex);
list_for_each_entry(sdt, &scsi_devicelist, list) {
if (!try_module_get(sdt->module))
continue;
(*sdt->attach)(sdev);
module_put(sdt->module);
}
up_read(&scsi_devicelist_mutex);
return 0;
}
void scsi_detach_device(struct scsi_device *sdev)
{
struct Scsi_Device_Template *sdt;
down_read(&scsi_devicelist_mutex);
list_for_each_entry(sdt, &scsi_devicelist, list) {
if (!try_module_get(sdt->module))
continue;
(*sdt->detach)(sdev);
module_put(sdt->module);
}
up_read(&scsi_devicelist_mutex);
}
void scsi_rescan_device(struct scsi_device *sdev)
{
struct Scsi_Device_Template *sdt;
down_read(&scsi_devicelist_mutex);
list_for_each_entry(sdt, &scsi_devicelist, list) {
if (!try_module_get(sdt->module))
continue;
if (*sdt->rescan)
(*sdt->rescan)(sdev);
module_put(sdt->module);
}
up_read(&scsi_devicelist_mutex);
}
int scsi_device_get(struct scsi_device *sdev) int scsi_device_get(struct scsi_device *sdev)
{ {
if (!try_module_get(sdev->host->hostt->module)) if (!try_module_get(sdev->host->hostt->module))
...@@ -1030,71 +980,6 @@ void scsi_set_device_offline(struct scsi_device *sdev) ...@@ -1030,71 +980,6 @@ void scsi_set_device_offline(struct scsi_device *sdev)
} }
} }
/*
* This entry point is called from the upper level module's module_init()
* routine. That implies that when this function is called, the
* scsi_mod module is locked down because of upper module layering and
* that the high level driver module is locked down by being in it's
* init routine. So, the *only* thing we have to do to protect adds
* we perform in this function is to make sure that all call's
* to the high level driver's attach() and detach() call in points, other
* than via scsi_register_device and scsi_unregister_device which are in
* the module_init and module_exit code respectively and therefore already
* locked down by the kernel module loader, are wrapped by try_module_get()
* and module_put() to avoid races on device adds and removes.
*/
int scsi_register_device(struct Scsi_Device_Template *tpnt)
{
struct scsi_device *sdev;
struct Scsi_Host *shpnt;
#ifdef CONFIG_KMOD
if (scsi_host_get_next(NULL) == NULL)
request_module("scsi_hostadapter");
#endif
if (!list_empty(&tpnt->list))
return 1;
down_write(&scsi_devicelist_mutex);
list_add_tail(&tpnt->list, &scsi_devicelist);
up_write(&scsi_devicelist_mutex);
scsi_upper_driver_register(tpnt);
for (shpnt = scsi_host_get_next(NULL); shpnt;
shpnt = scsi_host_get_next(shpnt))
list_for_each_entry(sdev, &shpnt->my_devices, siblings)
(*tpnt->attach)(sdev);
return 0;
}
int scsi_unregister_device(struct Scsi_Device_Template *tpnt)
{
struct scsi_device *sdev;
struct Scsi_Host *shpnt;
/*
* Next, detach the devices from the driver.
*/
for (shpnt = scsi_host_get_next(NULL); shpnt;
shpnt = scsi_host_get_next(shpnt)) {
list_for_each_entry(sdev, &shpnt->my_devices, siblings)
(*tpnt->detach)(sdev);
}
/*
* Extract the template from the linked list.
*/
down_write(&scsi_devicelist_mutex);
list_del(&tpnt->list);
up_write(&scsi_devicelist_mutex);
scsi_upper_driver_unregister(tpnt);
return 0;
}
MODULE_DESCRIPTION("SCSI core"); MODULE_DESCRIPTION("SCSI core");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
......
...@@ -316,6 +316,7 @@ extern const char *scsi_extd_sense_format(unsigned char, unsigned char); ...@@ -316,6 +316,7 @@ extern const char *scsi_extd_sense_format(unsigned char, unsigned char);
*/ */
struct scsi_device { struct scsi_device {
struct class_device sdev_classdev;
/* /*
* This information is private to the scsi mid-layer. * This information is private to the scsi mid-layer.
*/ */
......
...@@ -612,29 +612,6 @@ static void scsi_release_buffers(struct scsi_cmnd *cmd) ...@@ -612,29 +612,6 @@ static void scsi_release_buffers(struct scsi_cmnd *cmd)
cmd->request_bufflen = 0; cmd->request_bufflen = 0;
} }
/*
* Function: scsi_get_request_dev()
*
* Purpose: Find the upper-level driver that is responsible for this
* request
*
* Arguments: request - I/O request we are preparing to queue.
*
* Lock status: No locks assumed to be held, but as it happens the
* q->queue_lock is held when this is called.
*
* Returns: Nothing
*
* Notes: The requests in the request queue may have originated
* from any block device driver. We need to find out which
* one so that we can later form the appropriate command.
*/
static struct Scsi_Device_Template *scsi_get_request_dev(struct request *req)
{
struct gendisk *p = req->rq_disk;
return p ? *(struct Scsi_Device_Template **)p->private_data : NULL;
}
/* /*
* Function: scsi_io_completion() * Function: scsi_io_completion()
* *
...@@ -849,11 +826,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, int good_sectors, ...@@ -849,11 +826,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, int good_sectors,
return; return;
} }
if (result) { if (result) {
struct Scsi_Device_Template *sdt; printk("SCSI error : <%d %d %d %d> return code = 0x%x\n",
sdt = scsi_get_request_dev(cmd->request);
printk("SCSI %s error : <%d %d %d %d> return code = 0x%x\n",
(sdt ? sdt->name : "device"),
cmd->device->host->host_no, cmd->device->host->host_no,
cmd->device->channel, cmd->device->channel,
cmd->device->id, cmd->device->id,
...@@ -947,7 +920,6 @@ static int scsi_init_io(struct scsi_cmnd *cmd) ...@@ -947,7 +920,6 @@ static int scsi_init_io(struct scsi_cmnd *cmd)
static int scsi_prep_fn(struct request_queue *q, struct request *req) static int scsi_prep_fn(struct request_queue *q, struct request *req)
{ {
struct Scsi_Device_Template *sdt;
struct scsi_device *sdev = q->queuedata; struct scsi_device *sdev = q->queuedata;
struct scsi_cmnd *cmd; struct scsi_cmnd *cmd;
...@@ -1003,6 +975,7 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req) ...@@ -1003,6 +975,7 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req)
* happening now. * happening now.
*/ */
if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) { if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) {
struct scsi_driver *drv;
int ret; int ret;
/* /*
...@@ -1017,8 +990,6 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req) ...@@ -1017,8 +990,6 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req)
* some kinds of consistency checking may cause the * some kinds of consistency checking may cause the
* request to be rejected immediately. * request to be rejected immediately.
*/ */
sdt = scsi_get_request_dev(req);
BUG_ON(!sdt);
/* /*
* This sets up the scatter-gather table (allocating if * This sets up the scatter-gather table (allocating if
...@@ -1031,7 +1002,8 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req) ...@@ -1031,7 +1002,8 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req)
/* /*
* Initialize the actual SCSI command for this request. * Initialize the actual SCSI command for this request.
*/ */
if (unlikely(!sdt->init_command(cmd))) { drv = *(struct scsi_driver **)req->rq_disk->private_data;
if (unlikely(!drv->init_command(cmd))) {
scsi_release_buffers(cmd); scsi_release_buffers(cmd);
scsi_put_command(cmd); scsi_put_command(cmd);
return BLKPREP_KILL; return BLKPREP_KILL;
......
...@@ -15,21 +15,6 @@ ...@@ -15,21 +15,6 @@
#include "hosts.h" #include "hosts.h"
/* XXX - For now, we assume the first (i.e. having the least host_no)
real (i.e. non-emulated) host adapter shall be BIOS-controlled one.
We *SHOULD* invent another way. */
static inline struct Scsi_Host *first_real_host(void)
{
struct Scsi_Host *shost = NULL;
while ((shost = scsi_host_get_next(shost))) {
if (!shost->hostt->emulated)
break;
}
return shost;
}
static int pc98_first_bios_param(struct scsi_device *sdev, int *ip) static int pc98_first_bios_param(struct scsi_device *sdev, int *ip)
{ {
const u8 *p = (&__PC9800SCA(u8, PC9800SCA_SCSI_PARAMS) + sdev->id * 4); const u8 *p = (&__PC9800SCA(u8, PC9800SCA_SCSI_PARAMS) + sdev->id * 4);
...@@ -50,7 +35,16 @@ int pc98_bios_param(struct scsi_device *sdev, struct block_device *bdev, ...@@ -50,7 +35,16 @@ int pc98_bios_param(struct scsi_device *sdev, struct block_device *bdev,
{ {
struct Scsi_Host *first_real = first_real_host(); struct Scsi_Host *first_real = first_real_host();
if (sdev->host == first_real && sdev->id < 7 && /*
* XXX
* XXX This needs to become a sysfs attribute that's set
* XXX by code that knows which host is the first one.
* XXX
* XXX Currently we support only one host on with a
* XXX PC98ish HBA.
* XXX
*/
if (1 || sdev->host == first_real && sdev->id < 7 &&
__PC9800SCA_TEST_BIT(PC9800SCA_DISK_EQUIPS, sdev->id)) __PC9800SCA_TEST_BIT(PC9800SCA_DISK_EQUIPS, sdev->id))
return pc98_first_bios_param(sdev, ip); return pc98_first_bios_param(sdev, ip);
......
...@@ -41,9 +41,6 @@ ...@@ -41,9 +41,6 @@
#define SCSI_SENSE_VALID(scmd) \ #define SCSI_SENSE_VALID(scmd) \
(((scmd)->sense_buffer[0] & 0x70) == 0x70) (((scmd)->sense_buffer[0] & 0x70) == 0x70)
struct Scsi_Device_Template;
/* /*
* scsi_target: representation of a scsi target, for now, this is only * 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, * used for single_lun devices. If no one has active IO to the target,
...@@ -58,8 +55,7 @@ struct scsi_target { ...@@ -58,8 +55,7 @@ struct scsi_target {
/* hosts.c */ /* hosts.c */
extern void scsi_host_busy_inc(struct Scsi_Host *, Scsi_Device *); extern void scsi_host_busy_inc(struct Scsi_Host *, Scsi_Device *);
extern void scsi_host_busy_dec_and_test(struct Scsi_Host *, Scsi_Device *); extern void scsi_host_busy_dec_and_test(struct Scsi_Host *, Scsi_Device *);
extern struct Scsi_Host *scsi_host_get_next(struct Scsi_Host *); extern struct Scsi_Host *scsi_host_lookup(unsigned short);
extern struct Scsi_Host *scsi_host_hn_get(unsigned short);
extern void scsi_host_put(struct Scsi_Host *); extern void scsi_host_put(struct Scsi_Host *);
extern void scsi_host_init(void); extern void scsi_host_init(void);
...@@ -70,9 +66,6 @@ extern void scsi_destroy_command_freelist(struct Scsi_Host *shost); ...@@ -70,9 +66,6 @@ extern void scsi_destroy_command_freelist(struct Scsi_Host *shost);
extern void scsi_done(struct scsi_cmnd *cmd); extern void scsi_done(struct scsi_cmnd *cmd);
extern void scsi_finish_command(struct scsi_cmnd *cmd); extern void scsi_finish_command(struct scsi_cmnd *cmd);
extern int scsi_retry_command(struct scsi_cmnd *cmd); extern int scsi_retry_command(struct scsi_cmnd *cmd);
extern int scsi_attach_device(struct scsi_device *sdev);
extern void scsi_detach_device(struct scsi_device *sdev);
extern void scsi_rescan_device(struct scsi_device *sdev);
extern int scsi_insert_special_req(struct scsi_request *sreq, int); extern int scsi_insert_special_req(struct scsi_request *sreq, int);
extern void scsi_init_cmd_from_req(struct scsi_cmnd *cmd, extern void scsi_init_cmd_from_req(struct scsi_cmnd *cmd,
struct scsi_request *sreq); struct scsi_request *sreq);
...@@ -119,12 +112,11 @@ extern void scsi_forget_host(struct Scsi_Host *shost); ...@@ -119,12 +112,11 @@ extern void scsi_forget_host(struct Scsi_Host *shost);
extern void scsi_free_sdev(struct scsi_device *); extern void scsi_free_sdev(struct scsi_device *);
extern void scsi_free_shost(struct Scsi_Host *); extern void scsi_free_shost(struct Scsi_Host *);
extern void scsi_host_get(struct Scsi_Host *); extern void scsi_host_get(struct Scsi_Host *);
extern void scsi_rescan_device(struct device *dev);
/* scsi_sysfs.c */ /* scsi_sysfs.c */
extern int scsi_device_register(struct scsi_device *); extern int scsi_device_register(struct scsi_device *);
extern void scsi_device_unregister(struct scsi_device *); extern void scsi_device_unregister(struct scsi_device *);
extern int scsi_upper_driver_register(struct Scsi_Device_Template *);
extern void scsi_upper_driver_unregister(struct Scsi_Device_Template *);
extern void scsi_sysfs_init_host(struct Scsi_Host *); extern void scsi_sysfs_init_host(struct Scsi_Host *);
extern int scsi_sysfs_add_host(struct Scsi_Host *, struct device *); extern int scsi_sysfs_add_host(struct Scsi_Host *, struct device *);
extern void scsi_sysfs_remove_host(struct Scsi_Host *); extern void scsi_sysfs_remove_host(struct Scsi_Host *);
...@@ -136,4 +128,7 @@ extern void scsi_sysfs_unregister(void); ...@@ -136,4 +128,7 @@ extern void scsi_sysfs_unregister(void);
extern struct class_device_attribute *scsi_sysfs_shost_attrs[]; extern struct class_device_attribute *scsi_sysfs_shost_attrs[];
extern struct device_attribute *scsi_sysfs_sdev_attrs[]; extern struct device_attribute *scsi_sysfs_sdev_attrs[];
extern struct class shost_class;
extern struct bus_type scsi_bus_type;
#endif /* _SCSI_PRIV_H */ #endif /* _SCSI_PRIV_H */
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/blk.h> #include <linux/blk.h>
#include <linux/seq_file.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include "scsi.h" #include "scsi.h"
...@@ -86,7 +87,7 @@ static int proc_scsi_read(char *buffer, char **start, off_t offset, ...@@ -86,7 +87,7 @@ static int proc_scsi_read(char *buffer, char **start, off_t offset,
return n; return n;
} }
static int proc_scsi_write(struct file *file, const char *buf, static int proc_scsi_write_proc(struct file *file, const char *buf,
unsigned long count, void *data) unsigned long count, void *data)
{ {
struct Scsi_Host *shost = data; struct Scsi_Host *shost = data;
...@@ -137,7 +138,7 @@ void scsi_proc_host_add(struct Scsi_Host *shost) ...@@ -137,7 +138,7 @@ void scsi_proc_host_add(struct Scsi_Host *shost)
return; return;
} }
p->write_proc = proc_scsi_write; p->write_proc = proc_scsi_write_proc;
p->owner = shost->hostt->module; p->owner = shost->hostt->module;
} }
...@@ -152,96 +153,52 @@ void scsi_proc_host_rm(struct Scsi_Host *shost) ...@@ -152,96 +153,52 @@ void scsi_proc_host_rm(struct Scsi_Host *shost)
remove_proc_entry(shost->hostt->proc_name, proc_scsi); remove_proc_entry(shost->hostt->proc_name, proc_scsi);
} }
static void proc_print_scsidevice(struct scsi_device* sdev, char *buffer, static int proc_print_scsidevice(struct device *dev, void *data)
int *size, int len)
{ {
struct scsi_device *sdev = to_scsi_device(dev);
int x, y = *size; struct seq_file *s = data;
extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE]; int i;
y = sprintf(buffer + len, seq_printf(s,
"Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n Vendor: ", "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n Vendor: ",
sdev->host->host_no, sdev->channel, sdev->id, sdev->lun); sdev->host->host_no, sdev->channel, sdev->id, sdev->lun);
for (x = 0; x < 8; x++) { for (i = 0; i < 8; i++) {
if (sdev->vendor[x] >= 0x20) if (sdev->vendor[i] >= 0x20)
y += sprintf(buffer + len + y, "%c", sdev->vendor[x]); seq_printf(s, "%c", sdev->vendor[i]);
else else
y += sprintf(buffer + len + y, " "); seq_printf(s, " ");
} }
y += sprintf(buffer + len + y, " Model: ");
for (x = 0; x < 16; x++) { seq_printf(s, " Model: ");
if (sdev->model[x] >= 0x20) for (i = 0; i < 16; i++) {
y += sprintf(buffer + len + y, "%c", sdev->model[x]); if (sdev->model[i] >= 0x20)
seq_printf(s, "%c", sdev->model[i]);
else else
y += sprintf(buffer + len + y, " "); seq_printf(s, " ");
} }
y += sprintf(buffer + len + y, " Rev: ");
for (x = 0; x < 4; x++) { seq_printf(s, " Rev: ");
if (sdev->rev[x] >= 0x20) for (i = 0; i < 4; i++) {
y += sprintf(buffer + len + y, "%c", sdev->rev[x]); if (sdev->rev[i] >= 0x20)
seq_printf(s, "%c", sdev->rev[i]);
else else
y += sprintf(buffer + len + y, " "); seq_printf(s, " ");
} }
y += sprintf(buffer + len + y, "\n");
y += sprintf(buffer + len + y, " Type: %s ", seq_printf(s, "\n");
seq_printf(s, " Type: %s ",
sdev->type < MAX_SCSI_DEVICE_CODE ? sdev->type < MAX_SCSI_DEVICE_CODE ?
scsi_device_types[(int) sdev->type] : "Unknown "); scsi_device_types[(int) sdev->type] : "Unknown ");
y += sprintf(buffer + len + y, " ANSI" seq_printf(s, " ANSI"
" SCSI revision: %02x", (sdev->scsi_level - 1) ? " SCSI revision: %02x", (sdev->scsi_level - 1) ?
sdev->scsi_level - 1 : 1); sdev->scsi_level - 1 : 1);
if (sdev->scsi_level == 2) if (sdev->scsi_level == 2)
y += sprintf(buffer + len + y, " CCS\n"); seq_printf(s, " CCS\n");
else else
y += sprintf(buffer + len + y, "\n"); seq_printf(s, "\n");
*size = y;
return;
}
static int scsi_proc_info(char *buffer, char **start, off_t offset, int length) return 0;
{
struct Scsi_Host *shost;
Scsi_Device *sdev;
int size, len = 0;
off_t begin = 0;
off_t pos = 0;
/*
* First, see if there are any attached devices or not.
*/
for (shost = scsi_host_get_next(NULL); shost;
shost = scsi_host_get_next(shost)) {
if (!list_empty(&shost->my_devices)) {
break;
}
}
size = sprintf(buffer + len, "Attached devices: %s\n",
(shost) ? "" : "none");
len += size;
pos = begin + len;
for (shost = scsi_host_get_next(NULL); shost;
shost = scsi_host_get_next(shost)) {
list_for_each_entry(sdev, &shost->my_devices, siblings) {
proc_print_scsidevice(sdev, buffer, &size, len);
len += size;
pos = begin + len;
if (pos < offset) {
len = 0;
begin = pos;
}
if (pos > offset + length)
goto stop_output;
}
}
stop_output:
*start = buffer + (offset - begin); /* Start of wanted data */
len -= (offset - begin); /* Start slop */
if (len > length)
len = length; /* Ending slop */
return (len);
} }
static int scsi_add_single_device(uint host, uint channel, uint id, uint lun) static int scsi_add_single_device(uint host, uint channel, uint id, uint lun)
...@@ -250,7 +207,7 @@ static int scsi_add_single_device(uint host, uint channel, uint id, uint lun) ...@@ -250,7 +207,7 @@ static int scsi_add_single_device(uint host, uint channel, uint id, uint lun)
struct scsi_device *sdev; struct scsi_device *sdev;
int error = -ENODEV; int error = -ENODEV;
shost = scsi_host_hn_get(host); shost = scsi_host_lookup(host);
if (!shost) if (!shost)
return -ENODEV; return -ENODEV;
...@@ -272,7 +229,7 @@ static int scsi_remove_single_device(uint host, uint channel, uint id, uint lun) ...@@ -272,7 +229,7 @@ static int scsi_remove_single_device(uint host, uint channel, uint id, uint lun)
struct Scsi_Host *shost; struct Scsi_Host *shost;
int error = -ENODEV; int error = -ENODEV;
shost = scsi_host_hn_get(host); shost = scsi_host_lookup(host);
if (!shost) if (!shost)
return -ENODEV; return -ENODEV;
sdev = scsi_find_device(shost, channel, id, lun); sdev = scsi_find_device(shost, channel, id, lun);
...@@ -287,8 +244,8 @@ static int scsi_remove_single_device(uint host, uint channel, uint id, uint lun) ...@@ -287,8 +244,8 @@ static int scsi_remove_single_device(uint host, uint channel, uint id, uint lun)
return error; return error;
} }
static int proc_scsi_gen_write(struct file * file, const char * buf, static int proc_scsi_write(struct file *file, const char* buf,
unsigned long length, void *data) size_t length, loff_t *ppos)
{ {
int host, channel, id, lun; int host, channel, id, lun;
char *buffer, *p; char *buffer, *p;
...@@ -431,6 +388,30 @@ static int proc_scsi_gen_write(struct file * file, const char * buf, ...@@ -431,6 +388,30 @@ static int proc_scsi_gen_write(struct file * file, const char * buf,
return err; return err;
} }
static int proc_scsi_show(struct seq_file *s, void *p)
{
seq_printf(s, "Attached devices:\n");
bus_for_each_dev(&scsi_bus_type, NULL, s, proc_print_scsidevice);
return 0;
}
static int proc_scsi_open(struct inode *inode, struct file *file)
{
/*
* We don't really needs this for the write case but it doesn't
* harm either.
*/
return single_open(file, proc_scsi_show, NULL);
}
static struct file_operations proc_scsi_operations = {
.open = proc_scsi_open,
.read = seq_read,
.write = proc_scsi_write,
.llseek = seq_lseek,
.release = single_release,
};
int __init scsi_init_procfs(void) int __init scsi_init_procfs(void)
{ {
struct proc_dir_entry *pde; struct proc_dir_entry *pde;
...@@ -439,10 +420,10 @@ int __init scsi_init_procfs(void) ...@@ -439,10 +420,10 @@ int __init scsi_init_procfs(void)
if (!proc_scsi) if (!proc_scsi)
goto err1; goto err1;
pde = create_proc_info_entry("scsi/scsi", 0, 0, scsi_proc_info); pde = create_proc_entry("scsi/scsi", 0, NULL);
if (!pde) if (!pde)
goto err2; goto err2;
pde->write_proc = proc_scsi_gen_write; pde->proc_fops = &proc_scsi_operations;
return 0; return 0;
......
...@@ -1098,24 +1098,31 @@ struct scsi_device *scsi_add_device(struct Scsi_Host *shost, ...@@ -1098,24 +1098,31 @@ struct scsi_device *scsi_add_device(struct Scsi_Host *shost,
uint channel, uint id, uint lun) uint channel, uint id, uint lun)
{ {
struct scsi_device *sdev; struct scsi_device *sdev;
int error = -ENODEV, res; 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);
if (res == SCSI_SCAN_LUN_PRESENT) if (res != SCSI_SCAN_LUN_PRESENT)
error = scsi_attach_device(sdev); sdev = ERR_PTR(-ENODEV);
if (error)
sdev = ERR_PTR(error);
return sdev; return sdev;
} }
int scsi_remove_device(struct scsi_device *sdev) int scsi_remove_device(struct scsi_device *sdev)
{ {
scsi_detach_device(sdev);
scsi_device_unregister(sdev); scsi_device_unregister(sdev);
return 0; return 0;
} }
void scsi_rescan_device(struct device *dev)
{
struct scsi_driver *drv = to_scsi_driver(dev->driver);
if (try_module_get(drv->owner)) {
if (drv->rescan)
drv->rescan(dev);
module_put(drv->owner);
}
}
/** /**
* scsi_scan_target - scan a target id, possibly including all LUNs on the * scsi_scan_target - scan a target id, possibly including all LUNs on the
* target. * target.
......
...@@ -29,8 +29,8 @@ ...@@ -29,8 +29,8 @@
* This source file contains the symbol table used by scsi loadable * This source file contains the symbol table used by scsi loadable
* modules. * modules.
*/ */
EXPORT_SYMBOL(scsi_register_device); EXPORT_SYMBOL(scsi_register_driver);
EXPORT_SYMBOL(scsi_unregister_device); EXPORT_SYMBOL(scsi_register_interface);
EXPORT_SYMBOL(scsi_register_host); EXPORT_SYMBOL(scsi_register_host);
EXPORT_SYMBOL(scsi_unregister_host); EXPORT_SYMBOL(scsi_unregister_host);
EXPORT_SYMBOL(scsi_add_host); EXPORT_SYMBOL(scsi_add_host);
......
...@@ -54,37 +54,21 @@ struct class_device_attribute *scsi_sysfs_shost_attrs[] = { ...@@ -54,37 +54,21 @@ struct class_device_attribute *scsi_sysfs_shost_attrs[] = {
NULL NULL
}; };
static struct class shost_class = { struct class shost_class = {
.name = "scsi_host", .name = "scsi_host",
}; };
/** static struct class sdev_class = {
* scsi_bus_match: .name = "scsi_device",
* @dev: };
* @dev_driver:
* /* all probing is done in the individual ->probe routines */
* Return value: static int scsi_bus_match(struct device *dev, struct device_driver *gendrv)
**/
static int scsi_bus_match(struct device *dev,
struct device_driver *dev_driver)
{ {
if (!strcmp("sg", dev_driver->name)) { return 1;
if (strstr(dev->bus_id, ":gen"))
return 1;
} else if (!strcmp("st",dev_driver->name)) {
if (strstr(dev->bus_id,":mt"))
return 1;
} else if (!strcmp("sd", dev_driver->name)) {
if ((!strstr(dev->bus_id, ":gen")) &&
(!strstr(dev->bus_id, ":mt"))) {
return 1;
}
}
return 0;
} }
struct bus_type scsi_bus_type = {
static struct bus_type scsi_bus_type = {
.name = "scsi", .name = "scsi",
.match = scsi_bus_match, .match = scsi_bus_match,
}; };
...@@ -99,45 +83,26 @@ int scsi_sysfs_register(void) ...@@ -99,45 +83,26 @@ int scsi_sysfs_register(void)
return error; return error;
error = class_register(&shost_class); error = class_register(&shost_class);
if (error) if (error)
return error; goto bus_unregister;
error = class_register(&sdev_class);
if (error)
goto class_unregister;
return 0;
class_unregister:
class_unregister(&shost_class);
bus_unregister:
bus_unregister(&scsi_bus_type);
return error; return error;
} }
void scsi_sysfs_unregister(void) void scsi_sysfs_unregister(void)
{ {
class_unregister(&sdev_class);
class_unregister(&shost_class); class_unregister(&shost_class);
bus_unregister(&scsi_bus_type); bus_unregister(&scsi_bus_type);
} }
/**
* scsi_upper_driver_register - register upper level driver.
* @sdev_tp: Upper level driver to register with the scsi bus.
*
* Return value:
* 0 on Success / non-zero on Failure
**/
int scsi_upper_driver_register(struct Scsi_Device_Template *sdev_tp)
{
int error = 0;
sdev_tp->scsi_driverfs_driver.bus = &scsi_bus_type;
error = driver_register(&sdev_tp->scsi_driverfs_driver);
return error;
}
/**
* scsi_upper_driver_unregister - unregister upper level driver
* @sdev_tp: Upper level driver to unregister with the scsi bus.
*
**/
void scsi_upper_driver_unregister(struct Scsi_Device_Template *sdev_tp)
{
driver_unregister(&sdev_tp->scsi_driverfs_driver);
}
/* /*
* sdev_show_function: macro to create an attr function that can be used to * sdev_show_function: macro to create an attr function that can be used to
* show a non-bit field. * show a non-bit field.
...@@ -238,7 +203,7 @@ show_rescan_field (struct device *dev, char *buf) ...@@ -238,7 +203,7 @@ show_rescan_field (struct device *dev, char *buf)
static ssize_t static ssize_t
store_rescan_field (struct device *dev, const char *buf, size_t count) store_rescan_field (struct device *dev, const char *buf, size_t count)
{ {
scsi_rescan_device(to_scsi_device(dev)); scsi_rescan_device(dev);
return 0; return 0;
} }
...@@ -280,15 +245,30 @@ int scsi_device_register(struct scsi_device *sdev) ...@@ -280,15 +245,30 @@ int scsi_device_register(struct scsi_device *sdev)
{ {
int error = 0, i; int error = 0, i;
device_initialize(&sdev->sdev_driverfs_dev);
sprintf(sdev->sdev_driverfs_dev.bus_id,"%d:%d:%d:%d", sprintf(sdev->sdev_driverfs_dev.bus_id,"%d:%d:%d:%d",
sdev->host->host_no, sdev->channel, sdev->id, sdev->lun); sdev->host->host_no, sdev->channel, sdev->id, sdev->lun);
sdev->sdev_driverfs_dev.parent = &sdev->host->host_gendev; sdev->sdev_driverfs_dev.parent = &sdev->host->host_gendev;
sdev->sdev_driverfs_dev.bus = &scsi_bus_type; sdev->sdev_driverfs_dev.bus = &scsi_bus_type;
sdev->sdev_driverfs_dev.release = scsi_device_release; sdev->sdev_driverfs_dev.release = scsi_device_release;
error = device_register(&sdev->sdev_driverfs_dev); class_device_initialize(&sdev->sdev_classdev);
if (error) sdev->sdev_classdev.dev = &sdev->sdev_driverfs_dev;
sdev->sdev_classdev.class = &sdev_class;
snprintf(sdev->sdev_classdev.class_id, BUS_ID_SIZE, "%d:%d:%d:%d",
sdev->host->host_no, sdev->channel, sdev->id, sdev->lun);
error = device_add(&sdev->sdev_driverfs_dev);
if (error) {
printk(KERN_INFO "error 1\n");
return error; return error;
}
error = class_device_add(&sdev->sdev_classdev);
if (error) {
printk(KERN_INFO "error 2\n");
device_unregister(&sdev->sdev_driverfs_dev);
return error;
}
for (i = 0; !error && sdev->host->hostt->sdev_attrs[i] != NULL; i++) for (i = 0; !error && sdev->host->hostt->sdev_attrs[i] != NULL; i++)
error = device_create_file(&sdev->sdev_driverfs_dev, error = device_create_file(&sdev->sdev_driverfs_dev,
...@@ -310,9 +290,24 @@ void scsi_device_unregister(struct scsi_device *sdev) ...@@ -310,9 +290,24 @@ void scsi_device_unregister(struct scsi_device *sdev)
for (i = 0; sdev->host->hostt->sdev_attrs[i] != NULL; i++) for (i = 0; sdev->host->hostt->sdev_attrs[i] != NULL; i++)
device_remove_file(&sdev->sdev_driverfs_dev, sdev->host->hostt->sdev_attrs[i]); device_remove_file(&sdev->sdev_driverfs_dev, sdev->host->hostt->sdev_attrs[i]);
class_device_unregister(&sdev->sdev_classdev);
device_unregister(&sdev->sdev_driverfs_dev); device_unregister(&sdev->sdev_driverfs_dev);
} }
int scsi_register_driver(struct device_driver *drv)
{
drv->bus = &scsi_bus_type;
return driver_register(drv);
}
int scsi_register_interface(struct class_interface *intf)
{
intf->class = &sdev_class;
return class_interface_register(intf);
}
static void scsi_host_release(struct device *dev) static void scsi_host_release(struct device *dev)
{ {
struct Scsi_Host *shost; struct Scsi_Host *shost;
...@@ -350,7 +345,7 @@ int scsi_sysfs_add_host(struct Scsi_Host *shost, struct device *dev) ...@@ -350,7 +345,7 @@ int scsi_sysfs_add_host(struct Scsi_Host *shost, struct device *dev)
int i, error; int i, error;
if (!shost->host_gendev.parent) if (!shost->host_gendev.parent)
shost->host_gendev.parent = (dev) ? dev : &legacy_bus; shost->host_gendev.parent = dev ? dev : &legacy_bus;
error = device_add(&shost->host_gendev); error = device_add(&shost->host_gendev);
if (error) if (error)
......
...@@ -73,8 +73,7 @@ ...@@ -73,8 +73,7 @@
#define SD_MAX_RETRIES 5 #define SD_MAX_RETRIES 5
struct scsi_disk { struct scsi_disk {
struct list_head list; /* list of all scsi_disks */ struct scsi_driver *driver; /* always &sd_template */
struct Scsi_Device_Template *driver; /* always &sd_template */
struct scsi_device *device; struct scsi_device *device;
struct gendisk *disk; struct gendisk *disk;
sector_t capacity; /* size in 512-byte sectors */ sector_t capacity; /* size in 512-byte sectors */
...@@ -85,37 +84,31 @@ struct scsi_disk { ...@@ -85,37 +84,31 @@ struct scsi_disk {
unsigned RCD : 1; /* state of disk RCD bit, unused */ unsigned RCD : 1; /* state of disk RCD bit, unused */
}; };
static LIST_HEAD(sd_devlist);
static spinlock_t sd_devlist_lock = SPIN_LOCK_UNLOCKED;
static unsigned long sd_index_bits[SD_DISKS / BITS_PER_LONG]; static unsigned long sd_index_bits[SD_DISKS / BITS_PER_LONG];
static spinlock_t sd_index_lock = SPIN_LOCK_UNLOCKED; static spinlock_t sd_index_lock = SPIN_LOCK_UNLOCKED;
static void sd_init_onedisk(struct scsi_disk * sdkp, struct gendisk *disk); static void sd_init_onedisk(struct scsi_disk * sdkp, struct gendisk *disk);
static void sd_rw_intr(struct scsi_cmnd * SCpnt); static void sd_rw_intr(struct scsi_cmnd * SCpnt);
static int sd_attach(struct scsi_device *); static int sd_probe(struct device *);
static void sd_detach(struct scsi_device *); static int sd_remove(struct device *);
static void sd_rescan(struct scsi_device *); static void sd_shutdown(struct device *dev);
static void sd_rescan(struct device *);
static int sd_init_command(struct scsi_cmnd *); static int sd_init_command(struct scsi_cmnd *);
static int sd_synchronize_cache(struct scsi_disk *, int); static int sd_synchronize_cache(struct scsi_disk *, int);
static int sd_notifier(struct notifier_block *, unsigned long, void *);
static void sd_read_capacity(struct scsi_disk *sdkp, char *diskname, static void sd_read_capacity(struct scsi_disk *sdkp, char *diskname,
struct scsi_request *SRpnt, unsigned char *buffer); struct scsi_request *SRpnt, unsigned char *buffer);
static struct notifier_block sd_notifier_block = {sd_notifier, NULL, 0};
static struct scsi_driver sd_template = {
static struct Scsi_Device_Template sd_template = { .owner = THIS_MODULE,
.module = THIS_MODULE, .gendrv = {
.list = LIST_HEAD_INIT(sd_template.list), .name = "sd",
.name = "disk", .probe = sd_probe,
.scsi_type = TYPE_DISK, .remove = sd_remove,
.attach = sd_attach, .shutdown = sd_shutdown,
.detach = sd_detach,
.rescan = sd_rescan,
.init_command = sd_init_command,
.scsi_driverfs_driver = {
.name = "sd",
}, },
.rescan = sd_rescan,
.init_command = sd_init_command,
}; };
static int sd_major(int major_idx) static int sd_major(int major_idx)
...@@ -133,36 +126,6 @@ static int sd_major(int major_idx) ...@@ -133,36 +126,6 @@ static int sd_major(int major_idx)
} }
} }
static struct scsi_disk *sd_find_by_sdev(Scsi_Device *sd)
{
struct scsi_disk *sdkp;
spin_lock(&sd_devlist_lock);
list_for_each_entry(sdkp, &sd_devlist, list) {
if (sdkp->device == sd) {
spin_unlock(&sd_devlist_lock);
return sdkp;
}
}
spin_unlock(&sd_devlist_lock);
return NULL;
}
static inline void sd_devlist_insert(struct scsi_disk *sdkp)
{
spin_lock(&sd_devlist_lock);
list_add(&sdkp->list, &sd_devlist);
spin_unlock(&sd_devlist_lock);
}
static inline void sd_devlist_remove(struct scsi_disk *sdkp)
{
spin_lock(&sd_devlist_lock);
list_del(&sdkp->list);
spin_unlock(&sd_devlist_lock);
}
static inline struct scsi_disk *scsi_disk(struct gendisk *disk) static inline struct scsi_disk *scsi_disk(struct gendisk *disk)
{ {
return container_of(disk->private_data, struct scsi_disk, driver); return container_of(disk->private_data, struct scsi_disk, driver);
...@@ -636,12 +599,13 @@ static int sd_media_changed(struct gendisk *disk) ...@@ -636,12 +599,13 @@ static int sd_media_changed(struct gendisk *disk)
return 1; return 1;
} }
static void sd_rescan(struct scsi_device * sdp) static void sd_rescan(struct device *dev)
{ {
unsigned char *buffer; struct scsi_device *sdp = to_scsi_device(dev);
struct scsi_disk *sdkp = sd_find_by_sdev(sdp); struct scsi_disk *sdkp = dev_get_drvdata(dev);
struct gendisk *gd; struct gendisk *gd;
struct scsi_request *SRpnt; struct scsi_request *SRpnt;
unsigned char *buffer;
if (!sdkp || sdp->online == FALSE || !sdkp->media_present) if (!sdkp || sdp->online == FALSE || !sdkp->media_present)
return; return;
...@@ -1312,10 +1276,10 @@ sd_init_onedisk(struct scsi_disk * sdkp, struct gendisk *disk) ...@@ -1312,10 +1276,10 @@ sd_init_onedisk(struct scsi_disk * sdkp, struct gendisk *disk)
} }
/** /**
* sd_attach - called during driver initialization and whenever a * sd_probe - called during driver initialization and whenever a
* new scsi device is attached to the system. It is called once * new scsi device is attached to the system. It is called once
* for each scsi device (not just disks) present. * for each scsi device (not just disks) present.
* @sdp: pointer to mid level scsi device object * @dev: pointer to device object
* *
* Returns 0 if successful (or not interested in this scsi device * Returns 0 if successful (or not interested in this scsi device
* (e.g. scanner)); 1 when there is an error. * (e.g. scanner)); 1 when there is an error.
...@@ -1327,17 +1291,19 @@ sd_init_onedisk(struct scsi_disk * sdkp, struct gendisk *disk) ...@@ -1327,17 +1291,19 @@ sd_init_onedisk(struct scsi_disk * sdkp, struct gendisk *disk)
* and minor number that is chosen here. * and minor number that is chosen here.
* *
* Assume sd_attach is not re-entrant (for time being) * Assume sd_attach is not re-entrant (for time being)
* Also think about sd_attach() and sd_detach() running coincidentally. * Also think about sd_attach() and sd_remove() running coincidentally.
**/ **/
static int sd_attach(struct scsi_device * sdp) static int sd_probe(struct device *dev)
{ {
struct scsi_device *sdp = to_scsi_device(dev);
struct scsi_disk *sdkp; struct scsi_disk *sdkp;
struct gendisk *gd; struct gendisk *gd;
u32 index; u32 index;
int error; int error;
error = -ENODEV;
if ((sdp->type != TYPE_DISK) && (sdp->type != TYPE_MOD)) if ((sdp->type != TYPE_DISK) && (sdp->type != TYPE_MOD))
return 1; goto out;
SCSI_LOG_HLQUEUE(3, printk("sd_attach: scsi device: <%d,%d,%d,%d>\n", SCSI_LOG_HLQUEUE(3, printk("sd_attach: scsi device: <%d,%d,%d,%d>\n",
sdp->host->host_no, sdp->channel, sdp->id, sdp->lun)); sdp->host->host_no, sdp->channel, sdp->id, sdp->lun));
...@@ -1389,8 +1355,8 @@ static int sd_attach(struct scsi_device * sdp) ...@@ -1389,8 +1355,8 @@ static int sd_attach(struct scsi_device * sdp)
gd->private_data = &sdkp->driver; gd->private_data = &sdkp->driver;
gd->queue = sdkp->device->request_queue; gd->queue = sdkp->device->request_queue;
sd_devlist_insert(sdkp);
set_capacity(gd, sdkp->capacity); set_capacity(gd, sdkp->capacity);
dev_set_drvdata(dev, sdkp);
add_disk(gd); add_disk(gd);
printk(KERN_NOTICE "Attached scsi %sdisk %s at scsi%d, channel %d, " printk(KERN_NOTICE "Attached scsi %sdisk %s at scsi%d, channel %d, "
...@@ -1409,44 +1375,42 @@ static int sd_attach(struct scsi_device * sdp) ...@@ -1409,44 +1375,42 @@ static int sd_attach(struct scsi_device * sdp)
} }
/** /**
* sd_detach - called whenever a scsi disk (previously recognized by * sd_remove - called whenever a scsi disk (previously recognized by
* sd_attach) is detached from the system. It is called (potentially * sd_probe) is detached from the system. It is called (potentially
* multiple times) during sd module unload. * multiple times) during sd module unload.
* @sdp: pointer to mid level scsi device object * @sdp: pointer to mid level scsi device object
* *
* Note: this function is invoked from the scsi mid-level. * Note: this function is invoked from the scsi mid-level.
* This function potentially frees up a device name (e.g. /dev/sdc) * This function potentially frees up a device name (e.g. /dev/sdc)
* that could be re-used by a subsequent sd_attach(). * that could be re-used by a subsequent sd_probe().
* This function is not called when the built-in sd driver is "exit-ed". * This function is not called when the built-in sd driver is "exit-ed".
**/ **/
static void sd_detach(struct scsi_device * sdp) static int sd_remove(struct device *dev)
{ {
struct scsi_disk *sdkp; struct scsi_disk *sdkp = dev_get_drvdata(dev);
SCSI_LOG_HLQUEUE(3, printk("sd_detach: <%d,%d,%d,%d>\n",
sdp->host->host_no, sdp->channel, sdp->id,
sdp->lun));
sdkp = sd_find_by_sdev(sdp);
if (!sdkp)
return;
/* check that we actually have a write back cache to synchronize */
if (sdkp->WCE) {
printk(KERN_NOTICE "Synchronizing SCSI cache: ");
sd_synchronize_cache(sdkp, 1);
printk("\n");
}
sd_devlist_remove(sdkp);
del_gendisk(sdkp->disk); del_gendisk(sdkp->disk);
spin_lock(&sd_index_lock); spin_lock(&sd_index_lock);
clear_bit(sdkp->index, sd_index_bits); clear_bit(sdkp->index, sd_index_bits);
spin_unlock(&sd_index_lock); spin_unlock(&sd_index_lock);
sd_shutdown(dev);
put_disk(sdkp->disk); put_disk(sdkp->disk);
kfree(sdkp); kfree(sdkp);
return 0;
}
static void sd_shutdown(struct device *dev)
{
struct scsi_disk *sdkp = dev_get_drvdata(dev);
if (sdkp->WCE) {
printk(KERN_NOTICE "Synchronizing SCSI cache: ");
sd_synchronize_cache(sdkp, 1);
printk("\n");
}
} }
/** /**
...@@ -1457,7 +1421,7 @@ static void sd_detach(struct scsi_device * sdp) ...@@ -1457,7 +1421,7 @@ static void sd_detach(struct scsi_device * sdp)
**/ **/
static int __init init_sd(void) static int __init init_sd(void)
{ {
int majors = 0, rc = -ENODEV, i; int majors = 0, i;
SCSI_LOG_HLQUEUE(3, printk("init_sd: sd driver entry point\n")); SCSI_LOG_HLQUEUE(3, printk("init_sd: sd driver entry point\n"));
...@@ -1468,11 +1432,7 @@ static int __init init_sd(void) ...@@ -1468,11 +1432,7 @@ static int __init init_sd(void)
if (!majors) if (!majors)
return -ENODEV; return -ENODEV;
rc = scsi_register_device(&sd_template); return scsi_register_driver(&sd_template.gendrv);
if (rc)
return rc;
register_reboot_notifier(&sd_notifier_block);
return rc;
} }
/** /**
...@@ -1486,37 +1446,11 @@ static void __exit exit_sd(void) ...@@ -1486,37 +1446,11 @@ static void __exit exit_sd(void)
SCSI_LOG_HLQUEUE(3, printk("exit_sd: exiting sd driver\n")); SCSI_LOG_HLQUEUE(3, printk("exit_sd: exiting sd driver\n"));
unregister_reboot_notifier(&sd_notifier_block); scsi_unregister_driver(&sd_template.gendrv);
scsi_unregister_device(&sd_template);
for (i = 0; i < SD_MAJORS; i++) for (i = 0; i < SD_MAJORS; i++)
unregister_blkdev(sd_major(i), "sd"); unregister_blkdev(sd_major(i), "sd");
} }
/*
* XXX: this function does not take sd_devlist_lock to synchronize
* access to sd_devlist. This should be safe as no other reboot
* notifier can access it.
*/
static int sd_notifier(struct notifier_block *n, unsigned long event, void *p)
{
if (event != SYS_RESTART &&
event != SYS_HALT &&
event != SYS_POWER_OFF)
return NOTIFY_DONE;
if (!list_empty(&sd_devlist)) {
struct scsi_disk *sdkp;
printk(KERN_NOTICE "Synchronizing SCSI caches: ");
list_for_each_entry(sdkp, &sd_devlist, list)
if (sdkp->WCE)
sd_synchronize_cache(sdkp, 1);
printk("\n");
}
return NOTIFY_OK;
}
/* send a SYNCHRONIZE CACHE instruction down to the device through the /* send a SYNCHRONIZE CACHE instruction down to the device through the
* normal SCSI command structure. Wait for the command to complete (must * normal SCSI command structure. Wait for the command to complete (must
* have user context) */ * have user context) */
......
...@@ -18,8 +18,8 @@ ...@@ -18,8 +18,8 @@
* *
*/ */
#include <linux/config.h> #include <linux/config.h>
static char *sg_version_str = "3.5.28 [20030308]"; static char *sg_version_str = "3.5.29 [20030529]";
static int sg_version_num = 30528; /* 2 digits for each component */ static int sg_version_num = 30529; /* 2 digits for each component */
/* /*
* D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes: * D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes:
* - scsi logging is available via SCSI_LOG_TIMEOUT macros. First * - scsi logging is available via SCSI_LOG_TIMEOUT macros. First
...@@ -112,24 +112,17 @@ static int sg_allow_dio = SG_ALLOW_DIO_DEF; ...@@ -112,24 +112,17 @@ static int sg_allow_dio = SG_ALLOW_DIO_DEF;
#define SG_DEV_ARR_LUMP 6 /* amount to over allocate sg_dev_arr by */ #define SG_DEV_ARR_LUMP 6 /* amount to over allocate sg_dev_arr by */
static int sg_attach(Scsi_Device *); static int sg_add(struct class_device *);
static void sg_detach(Scsi_Device *); static void sg_remove(struct class_device *);
static Scsi_Request *dummy_cmdp; /* only used for sizeof */ static Scsi_Request *dummy_cmdp; /* only used for sizeof */
static rwlock_t sg_dev_arr_lock = RW_LOCK_UNLOCKED; /* Also used to lock static rwlock_t sg_dev_arr_lock = RW_LOCK_UNLOCKED; /* Also used to lock
file descriptor list for device */ file descriptor list for device */
static struct Scsi_Device_Template sg_template = { static struct class_interface sg_interface = {
.module = THIS_MODULE, .add = sg_add,
.list = LIST_HEAD_INIT(sg_template.list), .remove = sg_remove,
.name = "generic",
.scsi_type = 0xff,
.attach = sg_attach,
.detach = sg_detach,
.scsi_driverfs_driver = {
.name = "sg",
},
}; };
typedef struct sg_scatter_hold { /* holding area for scsi scatter gather info */ typedef struct sg_scatter_hold { /* holding area for scsi scatter gather info */
...@@ -180,15 +173,13 @@ typedef struct sg_fd { /* holds the state of a file descriptor */ ...@@ -180,15 +173,13 @@ typedef struct sg_fd { /* holds the state of a file descriptor */
} Sg_fd; } Sg_fd;
typedef struct sg_device { /* holds the state of each scsi generic device */ typedef struct sg_device { /* holds the state of each scsi generic device */
struct Scsi_Device_Template *driver; struct scsi_device *device;
Scsi_Device *device;
wait_queue_head_t o_excl_wait; /* queue open() when O_EXCL in use */ wait_queue_head_t o_excl_wait; /* queue open() when O_EXCL in use */
int sg_tablesize; /* adapter's max scatter-gather table size */ int sg_tablesize; /* adapter's max scatter-gather table size */
Sg_fd *headfp; /* first open fd belonging to this device */ Sg_fd *headfp; /* first open fd belonging to this device */
volatile char detached; /* 0->attached, 1->detached pending removal */ volatile char detached; /* 0->attached, 1->detached pending removal */
volatile char exclude; /* opened for exclusive access */ volatile char exclude; /* opened for exclusive access */
char sgdebug; /* 0->off, 1->sense, 9->dump dev, 10-> all devs */ char sgdebug; /* 0->off, 1->sense, 9->dump dev, 10-> all devs */
struct device sg_driverfs_dev;
struct gendisk *disk; struct gendisk *disk;
} Sg_device; } Sg_device;
...@@ -1328,27 +1319,10 @@ static struct file_operations sg_fops = { ...@@ -1328,27 +1319,10 @@ static struct file_operations sg_fops = {
.fasync = sg_fasync, .fasync = sg_fasync,
}; };
/* Driverfs file support */
static ssize_t
sg_device_kdev_read(struct device *driverfs_dev, char *page)
{
Sg_device *sdp = list_entry(driverfs_dev, Sg_device, sg_driverfs_dev);
return sprintf(page, "%x\n", MKDEV(sdp->disk->major,
sdp->disk->first_minor));
}
static DEVICE_ATTR(kdev,S_IRUGO,sg_device_kdev_read,NULL);
static ssize_t
sg_device_type_read(struct device *driverfs_dev, char *page)
{
return sprintf(page, "CHR\n");
}
static DEVICE_ATTR(type,S_IRUGO,sg_device_type_read,NULL);
static int static int
sg_attach(Scsi_Device * scsidp) sg_add(struct class_device *cdev)
{ {
struct scsi_device *scsidp = to_scsi_device(cdev->dev);
struct gendisk *disk; struct gendisk *disk;
Sg_device *sdp = NULL; Sg_device *sdp = NULL;
unsigned long iflags; unsigned long iflags;
...@@ -1416,8 +1390,6 @@ sg_attach(Scsi_Device * scsidp) ...@@ -1416,8 +1390,6 @@ sg_attach(Scsi_Device * scsidp)
SCSI_LOG_TIMEOUT(3, printk("sg_attach: dev=%d \n", k)); SCSI_LOG_TIMEOUT(3, printk("sg_attach: dev=%d \n", k));
memset(sdp, 0, sizeof(*sdp)); memset(sdp, 0, sizeof(*sdp));
sdp->driver = &sg_template;
disk->private_data = &sdp->driver;
sprintf(disk->disk_name, "sg%d", k); sprintf(disk->disk_name, "sg%d", k);
disk->major = SCSI_GENERIC_MAJOR; disk->major = SCSI_GENERIC_MAJOR;
disk->first_minor = k; disk->first_minor = k;
...@@ -1430,40 +1402,20 @@ sg_attach(Scsi_Device * scsidp) ...@@ -1430,40 +1402,20 @@ sg_attach(Scsi_Device * scsidp)
sdp->detached = 0; sdp->detached = 0;
sdp->sg_tablesize = scsidp->host ? scsidp->host->sg_tablesize : 0; sdp->sg_tablesize = scsidp->host ? scsidp->host->sg_tablesize : 0;
memset(&sdp->sg_driverfs_dev, 0, sizeof (struct device));
snprintf(sdp->sg_driverfs_dev.bus_id, BUS_ID_SIZE, "%s:gen",
scsidp->sdev_driverfs_dev.bus_id);
snprintf(sdp->sg_driverfs_dev.name, DEVICE_NAME_SIZE, "%sgeneric",
scsidp->sdev_driverfs_dev.name);
sdp->sg_driverfs_dev.parent = &scsidp->sdev_driverfs_dev;
sdp->sg_driverfs_dev.bus = scsidp->sdev_driverfs_dev.bus;
sg_nr_dev++; sg_nr_dev++;
sg_dev_arr[k] = sdp; sg_dev_arr[k] = sdp;
write_unlock_irqrestore(&sg_dev_arr_lock, iflags); write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
device_register(&sdp->sg_driverfs_dev);
device_create_file(&sdp->sg_driverfs_dev, &dev_attr_type);
device_create_file(&sdp->sg_driverfs_dev, &dev_attr_kdev);
devfs_mk_cdev(MKDEV(SCSI_GENERIC_MAJOR, k), devfs_mk_cdev(MKDEV(SCSI_GENERIC_MAJOR, k),
S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,
"%s/generic", scsidp->devfs_name); "%s/generic", scsidp->devfs_name);
switch (scsidp->type) { printk(KERN_NOTICE
case TYPE_DISK: "Attached scsi generic sg%d at scsi%d, channel"
case TYPE_MOD: " %d, id %d, lun %d, type %d\n", k,
case TYPE_ROM: scsidp->host->host_no, scsidp->channel, scsidp->id,
case TYPE_WORM: scsidp->lun, scsidp->type);
case TYPE_TAPE:
break;
default:
printk(KERN_NOTICE
"Attached scsi generic sg%d at scsi%d, channel"
" %d, id %d, lun %d, type %d\n", k,
scsidp->host->host_no, scsidp->channel, scsidp->id,
scsidp->lun, scsidp->type);
}
return 0; return 0;
out: out:
...@@ -1472,8 +1424,9 @@ sg_attach(Scsi_Device * scsidp) ...@@ -1472,8 +1424,9 @@ sg_attach(Scsi_Device * scsidp)
} }
static void static void
sg_detach(Scsi_Device * scsidp) sg_remove(struct class_device *cdev)
{ {
struct scsi_device *scsidp = to_scsi_device(cdev->dev);
Sg_device *sdp = NULL; Sg_device *sdp = NULL;
unsigned long iflags; unsigned long iflags;
Sg_fd *sfp; Sg_fd *sfp;
...@@ -1524,9 +1477,6 @@ sg_detach(Scsi_Device * scsidp) ...@@ -1524,9 +1477,6 @@ sg_detach(Scsi_Device * scsidp)
if (sdp) { if (sdp) {
devfs_remove("%s/generic", scsidp->devfs_name); devfs_remove("%s/generic", scsidp->devfs_name);
device_remove_file(&sdp->sg_driverfs_dev, &dev_attr_type);
device_remove_file(&sdp->sg_driverfs_dev, &dev_attr_kdev);
device_unregister(&sdp->sg_driverfs_dev);
put_disk(sdp->disk); put_disk(sdp->disk);
sdp->disk = NULL; sdp->disk = NULL;
if (NULL == sdp->headfp) if (NULL == sdp->headfp)
...@@ -1550,64 +1500,6 @@ MODULE_LICENSE("GPL"); ...@@ -1550,64 +1500,6 @@ MODULE_LICENSE("GPL");
MODULE_PARM_DESC(def_reserved_size, "size of buffer reserved for each fd"); MODULE_PARM_DESC(def_reserved_size, "size of buffer reserved for each fd");
static ssize_t sg_allow_dio_show(struct device_driver * ddp, char * buf)
{
return snprintf(buf, PAGE_SIZE, "%d\n", sg_allow_dio);
}
static ssize_t sg_allow_dio_store(struct device_driver * ddp,
const char * buf, size_t count)
{
if (1 == sscanf(buf, "%d", &sg_allow_dio)) {
sg_allow_dio = sg_allow_dio ? 1 : 0;
return count;
}
return -EINVAL;
}
DRIVER_ATTR(allow_dio, S_IRUGO | S_IWUSR, sg_allow_dio_show,
sg_allow_dio_store)
static ssize_t sg_def_reserved_show(struct device_driver * ddp, char * buf)
{
return snprintf(buf, PAGE_SIZE, "%d\n", sg_big_buff);
}
static ssize_t sg_def_reserved_store(struct device_driver * ddp,
const char * buf, size_t count)
{
if (1 == sscanf(buf, "%d", &def_reserved_size)) {
if (def_reserved_size >= 0) {
sg_big_buff = def_reserved_size;
return count;
}
}
return -EINVAL;
}
DRIVER_ATTR(def_reserved_size, S_IRUGO | S_IWUSR, sg_def_reserved_show,
sg_def_reserved_store)
static ssize_t sg_version_show(struct device_driver * ddp, char * buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n", sg_version_str);
}
DRIVER_ATTR(version, S_IRUGO, sg_version_show, NULL)
static void do_create_driverfs_files(void)
{
struct device_driver * driverfs = &sg_template.scsi_driverfs_driver;
driver_create_file(driverfs, &driver_attr_allow_dio);
driver_create_file(driverfs, &driver_attr_def_reserved_size);
driver_create_file(driverfs, &driver_attr_version);
}
static void do_remove_driverfs_files(void)
{
struct device_driver * driverfs = &sg_template.scsi_driverfs_driver;
driver_remove_file(driverfs, &driver_attr_version);
driver_remove_file(driverfs, &driver_attr_def_reserved_size);
driver_remove_file(driverfs, &driver_attr_allow_dio);
}
static int __init static int __init
init_sg(void) init_sg(void)
{ {
...@@ -1619,24 +1511,22 @@ init_sg(void) ...@@ -1619,24 +1511,22 @@ init_sg(void)
rc = register_chrdev(SCSI_GENERIC_MAJOR, "sg", &sg_fops); rc = register_chrdev(SCSI_GENERIC_MAJOR, "sg", &sg_fops);
if (rc) if (rc)
return rc; return rc;
rc = scsi_register_device(&sg_template); rc = scsi_register_interface(&sg_interface);
if (rc) if (rc)
return rc; return rc;
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
sg_proc_init(); sg_proc_init();
#endif /* CONFIG_PROC_FS */ #endif /* CONFIG_PROC_FS */
do_create_driverfs_files();
return 0; return 0;
} }
static void __exit static void __exit
exit_sg(void) exit_sg(void)
{ {
do_remove_driverfs_files();
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
sg_proc_cleanup(); sg_proc_cleanup();
#endif /* CONFIG_PROC_FS */ #endif /* CONFIG_PROC_FS */
scsi_unregister_device(&sg_template); scsi_unregister_interface(&sg_interface);
unregister_chrdev(SCSI_GENERIC_MAJOR, "sg"); unregister_chrdev(SCSI_GENERIC_MAJOR, "sg");
if (sg_dev_arr != NULL) { if (sg_dev_arr != NULL) {
vfree((char *) sg_dev_arr); vfree((char *) sg_dev_arr);
...@@ -1994,11 +1884,8 @@ sg_write_xfer(Sg_request * srp) ...@@ -1994,11 +1884,8 @@ sg_write_xfer(Sg_request * srp)
if (res) if (res)
return res; return res;
for (; k < schp->k_use_sg; ++k, ++sclp) { for (; p; ++sclp, ksglen = (int) sclp->length,
ksglen = (int) sclp->length; p = sg_scatg2virt(sclp)) {
p = sg_scatg2virt(sclp);
if (NULL == p)
break;
if (usglen <= 0) if (usglen <= 0)
break; break;
if (ksglen > usglen) { if (ksglen > usglen) {
...@@ -2025,6 +1912,9 @@ sg_write_xfer(Sg_request * srp) ...@@ -2025,6 +1912,9 @@ sg_write_xfer(Sg_request * srp)
up += ksglen; up += ksglen;
usglen -= ksglen; usglen -= ksglen;
} }
++k;
if (k >= schp->k_use_sg)
return 0;
} }
} }
} }
...@@ -2151,11 +2041,8 @@ sg_read_xfer(Sg_request * srp) ...@@ -2151,11 +2041,8 @@ sg_read_xfer(Sg_request * srp)
if (res) if (res)
return res; return res;
for (; k < schp->k_use_sg; ++k, ++sclp) { for (; p; ++sclp, ksglen = (int) sclp->length,
ksglen = (int) sclp->length; p = sg_scatg2virt(sclp)) {
p = sg_scatg2virt(sclp);
if (NULL == p)
break;
if (usglen <= 0) if (usglen <= 0)
break; break;
if (ksglen > usglen) { if (ksglen > usglen) {
...@@ -2182,6 +2069,9 @@ sg_read_xfer(Sg_request * srp) ...@@ -2182,6 +2069,9 @@ sg_read_xfer(Sg_request * srp)
up += ksglen; up += ksglen;
usglen -= ksglen; usglen -= ksglen;
} }
++k;
if (k >= schp->k_use_sg)
return 0;
} }
} }
} }
......
...@@ -67,26 +67,20 @@ MODULE_PARM(xa_test, "i"); /* see sr_ioctl.c */ ...@@ -67,26 +67,20 @@ MODULE_PARM(xa_test, "i"); /* see sr_ioctl.c */
CDC_PLAY_AUDIO|CDC_RESET|CDC_IOCTLS|CDC_DRIVE_STATUS| \ CDC_PLAY_AUDIO|CDC_RESET|CDC_IOCTLS|CDC_DRIVE_STATUS| \
CDC_CD_R|CDC_CD_RW|CDC_DVD|CDC_DVD_R|CDC_GENERIC_PACKET) CDC_CD_R|CDC_CD_RW|CDC_DVD|CDC_DVD_R|CDC_GENERIC_PACKET)
static int sr_attach(struct scsi_device *); static int sr_probe(struct device *);
static void sr_detach(struct scsi_device *); static int sr_remove(struct device *);
static int sr_init_command(struct scsi_cmnd *); static int sr_init_command(struct scsi_cmnd *);
static struct Scsi_Device_Template sr_template = { static struct scsi_driver sr_template = {
.module = THIS_MODULE, .owner = THIS_MODULE,
.list = LIST_HEAD_INIT(sr_template.list), .gendrv = {
.name = "cdrom", .name = "sr",
.scsi_type = TYPE_ROM, .probe = sr_probe,
.attach = sr_attach, .remove = sr_remove,
.detach = sr_detach,
.init_command = sr_init_command,
.scsi_driverfs_driver = {
.name = "sr",
}, },
.init_command = sr_init_command,
}; };
static LIST_HEAD(sr_devlist);
static spinlock_t sr_devlist_lock = SPIN_LOCK_UNLOCKED;
static unsigned long sr_index_bits[SR_DISKS / BITS_PER_LONG]; static unsigned long sr_index_bits[SR_DISKS / BITS_PER_LONG];
static spinlock_t sr_index_lock = SPIN_LOCK_UNLOCKED; static spinlock_t sr_index_lock = SPIN_LOCK_UNLOCKED;
...@@ -99,37 +93,6 @@ static void get_capabilities(struct scsi_cd *); ...@@ -99,37 +93,6 @@ static void get_capabilities(struct scsi_cd *);
static int sr_media_change(struct cdrom_device_info *, int); static int sr_media_change(struct cdrom_device_info *, int);
static int sr_packet(struct cdrom_device_info *, struct cdrom_generic_command *); static int sr_packet(struct cdrom_device_info *, struct cdrom_generic_command *);
static Scsi_CD *sr_find_by_sdev(Scsi_Device *sd)
{
struct list_head *p;
Scsi_CD *cd;
spin_lock(&sr_devlist_lock);
list_for_each(p, &sr_devlist) {
cd = list_entry(p, Scsi_CD, list);
if (cd->device == sd) {
spin_unlock(&sr_devlist_lock);
return cd;
}
}
spin_unlock(&sr_devlist_lock);
return NULL;
}
static inline void sr_devlist_insert(Scsi_CD *cd)
{
spin_lock(&sr_devlist_lock);
list_add(&cd->list, &sr_devlist);
spin_unlock(&sr_devlist_lock);
}
static inline void sr_devlist_remove(Scsi_CD *cd)
{
spin_lock(&sr_devlist_lock);
list_del(&cd->list);
spin_unlock(&sr_devlist_lock);
}
static struct cdrom_device_ops sr_dops = { static struct cdrom_device_ops sr_dops = {
.open = sr_open, .open = sr_open,
.release = sr_release, .release = sr_release,
...@@ -506,14 +469,16 @@ static void sr_release(struct cdrom_device_info *cdi) ...@@ -506,14 +469,16 @@ static void sr_release(struct cdrom_device_info *cdi)
scsi_device_put(cd->device); scsi_device_put(cd->device);
} }
static int sr_attach(struct scsi_device *sdev) static int sr_probe(struct device *dev)
{ {
struct scsi_device *sdev = to_scsi_device(dev);
struct gendisk *disk; struct gendisk *disk;
struct scsi_cd *cd; struct scsi_cd *cd;
int minor, error; int minor, error;
error = -ENODEV;
if (sdev->type != TYPE_ROM && sdev->type != TYPE_WORM) if (sdev->type != TYPE_ROM && sdev->type != TYPE_WORM)
return 1; goto fail;
error = -ENOMEM; error = -ENOMEM;
cd = kmalloc(sizeof(*cd), GFP_KERNEL); cd = kmalloc(sizeof(*cd), GFP_KERNEL);
...@@ -575,8 +540,8 @@ static int sr_attach(struct scsi_device *sdev) ...@@ -575,8 +540,8 @@ static int sr_attach(struct scsi_device *sdev)
disk->private_data = &cd->driver; disk->private_data = &cd->driver;
disk->queue = sdev->request_queue; disk->queue = sdev->request_queue;
dev_set_drvdata(dev, cd);
add_disk(disk); add_disk(disk);
sr_devlist_insert(cd);
printk(KERN_DEBUG printk(KERN_DEBUG
"Attached scsi CD-ROM %s at scsi%d, channel %d, id %d, lun %d\n", "Attached scsi CD-ROM %s at scsi%d, channel %d, id %d, lun %d\n",
...@@ -807,15 +772,10 @@ static int sr_packet(struct cdrom_device_info *cdi, ...@@ -807,15 +772,10 @@ static int sr_packet(struct cdrom_device_info *cdi,
return cgc->stat; return cgc->stat;
} }
static void sr_detach(struct scsi_device * SDp) static int sr_remove(struct device *dev)
{ {
struct scsi_cd *cd; struct scsi_cd *cd = dev_get_drvdata(dev);
cd = sr_find_by_sdev(SDp);
if (!cd)
return;
sr_devlist_remove(cd);
del_gendisk(cd->disk); del_gendisk(cd->disk);
spin_lock(&sr_index_lock); spin_lock(&sr_index_lock);
...@@ -825,6 +785,8 @@ static void sr_detach(struct scsi_device * SDp) ...@@ -825,6 +785,8 @@ static void sr_detach(struct scsi_device * SDp)
put_disk(cd->disk); put_disk(cd->disk);
unregister_cdrom(&cd->cdi); unregister_cdrom(&cd->cdi);
kfree(cd); kfree(cd);
return 0;
} }
static int __init init_sr(void) static int __init init_sr(void)
...@@ -834,12 +796,12 @@ static int __init init_sr(void) ...@@ -834,12 +796,12 @@ static int __init init_sr(void)
rc = register_blkdev(SCSI_CDROM_MAJOR, "sr"); rc = register_blkdev(SCSI_CDROM_MAJOR, "sr");
if (rc) if (rc)
return rc; return rc;
return scsi_register_device(&sr_template); return scsi_register_driver(&sr_template.gendrv);
} }
static void __exit exit_sr(void) static void __exit exit_sr(void)
{ {
scsi_unregister_device(&sr_template); scsi_unregister_driver(&sr_template.gendrv);
unregister_blkdev(SCSI_CDROM_MAJOR, "sr"); unregister_blkdev(SCSI_CDROM_MAJOR, "sr");
} }
......
...@@ -25,8 +25,7 @@ ...@@ -25,8 +25,7 @@
#define IOCTL_TIMEOUT 30*HZ #define IOCTL_TIMEOUT 30*HZ
typedef struct scsi_cd { typedef struct scsi_cd {
struct Scsi_Device_Template *driver; struct scsi_driver *driver;
struct list_head list;
unsigned capacity; /* size in blocks */ unsigned capacity; /* size in blocks */
Scsi_Device *device; Scsi_Device *device;
unsigned int vendor; /* vendor code, see sr_vendor.c */ unsigned int vendor; /* vendor code, see sr_vendor.c */
......
...@@ -170,22 +170,19 @@ static int sgl_map_user_pages(struct scatterlist *, const unsigned int, ...@@ -170,22 +170,19 @@ static int sgl_map_user_pages(struct scatterlist *, const unsigned int,
unsigned long, size_t, int); unsigned long, size_t, int);
static int sgl_unmap_user_pages(struct scatterlist *, const unsigned int, int); static int sgl_unmap_user_pages(struct scatterlist *, const unsigned int, int);
static int st_attach(Scsi_Device *); static int st_probe(struct device *);
static void st_detach(Scsi_Device *); static int st_remove(struct device *);
static void do_create_driverfs_files(void); static void do_create_driverfs_files(void);
static void do_remove_driverfs_files(void); static void do_remove_driverfs_files(void);
static struct Scsi_Device_Template st_template = { static struct scsi_driver st_template = {
.module = THIS_MODULE, .owner = THIS_MODULE,
.list = LIST_HEAD_INIT(st_template.list), .gendrv = {
.name = "tape", .name = "st",
.scsi_type = TYPE_TAPE, .probe = st_probe,
.attach = st_attach, .remove = st_remove,
.detach = st_detach,
.scsi_driverfs_driver = {
.name = "st",
}, },
}; };
...@@ -3704,8 +3701,9 @@ static struct file_operations st_fops = ...@@ -3704,8 +3701,9 @@ static struct file_operations st_fops =
.release = st_release, .release = st_release,
}; };
static int st_attach(Scsi_Device * SDp) static int st_probe(struct device *dev)
{ {
struct scsi_device *SDp = to_scsi_device(dev);
struct gendisk *disk; struct gendisk *disk;
Scsi_Tape *tpnt; Scsi_Tape *tpnt;
ST_mode *STm; ST_mode *STm;
...@@ -3716,13 +3714,13 @@ static int st_attach(Scsi_Device * SDp) ...@@ -3716,13 +3714,13 @@ static int st_attach(Scsi_Device * SDp)
u64 bounce_limit; u64 bounce_limit;
if (SDp->type != TYPE_TAPE) if (SDp->type != TYPE_TAPE)
return 1; return -ENODEV;
if ((stp = st_incompatible(SDp))) { if ((stp = st_incompatible(SDp))) {
printk(KERN_INFO printk(KERN_INFO
"st: Found incompatible tape at scsi%d, channel %d, id %d, lun %d\n", "st: Found incompatible tape at scsi%d, channel %d, id %d, lun %d\n",
SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
printk(KERN_INFO "st: The suggested driver is %s.\n", stp); printk(KERN_INFO "st: The suggested driver is %s.\n", stp);
return 1; return -ENODEV;
} }
i = SDp->host->sg_tablesize; i = SDp->host->sg_tablesize;
...@@ -3862,43 +3860,11 @@ static int st_attach(Scsi_Device * SDp) ...@@ -3862,43 +3860,11 @@ static int st_attach(Scsi_Device * SDp)
write_unlock(&st_dev_arr_lock); write_unlock(&st_dev_arr_lock);
for (mode = 0; mode < ST_NBR_MODES; ++mode) { for (mode = 0; mode < ST_NBR_MODES; ++mode) {
char name[8];
/* Rewind entry */ /* Rewind entry */
sprintf(name, "mt%s", st_formats[mode]);
sprintf(tpnt->driverfs_dev_r[mode].bus_id, "%s:%s",
SDp->sdev_driverfs_dev.bus_id, 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 = SDp->sdev_driverfs_dev.bus;
tpnt->driverfs_dev_r[mode].driver_data =
(void *)(long)__mkdev(SCSI_TAPE_MAJOR, dev_num + (mode << 5));
device_register(&tpnt->driverfs_dev_r[mode]);
device_create_file(&tpnt->driverfs_dev_r[mode],
&dev_attr_type);
device_create_file(&tpnt->driverfs_dev_r[mode], &dev_attr_kdev);
devfs_mk_cdev(MKDEV(SCSI_TAPE_MAJOR, dev_num + (mode << 5)), devfs_mk_cdev(MKDEV(SCSI_TAPE_MAJOR, dev_num + (mode << 5)),
S_IFCHR | S_IRUGO | S_IWUGO, S_IFCHR | S_IRUGO | S_IWUGO,
"%s/mt%s", SDp->devfs_name, st_formats[mode]); "%s/mt%s", SDp->devfs_name, st_formats[mode]);
/* No-rewind entry */ /* No-rewind entry */
sprintf (name, "mt%sn", st_formats[mode]);
sprintf(tpnt->driverfs_dev_n[mode].bus_id, "%s:%s",
SDp->sdev_driverfs_dev.bus_id, 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 = SDp->sdev_driverfs_dev.bus;
tpnt->driverfs_dev_n[mode].driver_data =
(void *)(long)__mkdev(SCSI_TAPE_MAJOR, dev_num + (mode << 5) + 128);
device_register(&tpnt->driverfs_dev_n[mode]);
device_create_file(&tpnt->driverfs_dev_n[mode],
&dev_attr_type);
device_create_file(&tpnt->driverfs_dev_n[mode],
&dev_attr_kdev);
devfs_mk_cdev(MKDEV(SCSI_TAPE_MAJOR, dev_num + (mode << 5) + 128), devfs_mk_cdev(MKDEV(SCSI_TAPE_MAJOR, dev_num + (mode << 5) + 128),
S_IFCHR | S_IRUGO | S_IWUGO, S_IFCHR | S_IRUGO | S_IWUGO,
"%s/mt%sn", SDp->devfs_name, st_formats[mode]); "%s/mt%sn", SDp->devfs_name, st_formats[mode]);
...@@ -3918,11 +3884,12 @@ static int st_attach(Scsi_Device * SDp) ...@@ -3918,11 +3884,12 @@ static int st_attach(Scsi_Device * SDp)
out_buffer_free: out_buffer_free:
kfree(buffer); kfree(buffer);
out: out:
return 1; return -ENODEV;
}; };
static void st_detach(Scsi_Device * SDp) static int st_remove(struct device *dev)
{ {
Scsi_Device *SDp = to_scsi_device(dev);
Scsi_Tape *tpnt; Scsi_Tape *tpnt;
int i, mode; int i, mode;
...@@ -3937,16 +3904,6 @@ static void st_detach(Scsi_Device * SDp) ...@@ -3937,16 +3904,6 @@ static void st_detach(Scsi_Device * SDp)
for (mode = 0; mode < ST_NBR_MODES; ++mode) { for (mode = 0; mode < ST_NBR_MODES; ++mode) {
devfs_remove("%s/mt%s", SDp->devfs_name, st_formats[mode]); devfs_remove("%s/mt%s", SDp->devfs_name, st_formats[mode]);
devfs_remove("%s/mt%sn", SDp->devfs_name, st_formats[mode]); devfs_remove("%s/mt%sn", SDp->devfs_name, st_formats[mode]);
device_remove_file(&tpnt->driverfs_dev_r[mode],
&dev_attr_type);
device_remove_file(&tpnt->driverfs_dev_r[mode],
&dev_attr_kdev);
device_unregister(&tpnt->driverfs_dev_r[mode]);
device_remove_file(&tpnt->driverfs_dev_n[mode],
&dev_attr_type);
device_remove_file(&tpnt->driverfs_dev_n[mode],
&dev_attr_kdev);
device_unregister(&tpnt->driverfs_dev_n[mode]);
} }
tpnt->device = NULL; tpnt->device = NULL;
...@@ -3957,12 +3914,12 @@ static void st_detach(Scsi_Device * SDp) ...@@ -3957,12 +3914,12 @@ static void st_detach(Scsi_Device * SDp)
} }
put_disk(tpnt->disk); put_disk(tpnt->disk);
kfree(tpnt); kfree(tpnt);
return; return 0;
} }
} }
write_unlock(&st_dev_arr_lock); write_unlock(&st_dev_arr_lock);
return; return 0;
} }
static int __init init_st(void) static int __init init_st(void)
...@@ -3974,7 +3931,7 @@ static int __init init_st(void) ...@@ -3974,7 +3931,7 @@ static int __init init_st(void)
verstr, st_fixed_buffer_size, st_max_sg_segs); verstr, st_fixed_buffer_size, st_max_sg_segs);
if (register_chrdev(SCSI_TAPE_MAJOR, "st", &st_fops) >= 0) { if (register_chrdev(SCSI_TAPE_MAJOR, "st", &st_fops) >= 0) {
if (scsi_register_device(&st_template) == 0) { if (scsi_register_driver(&st_template.gendrv) == 0) {
do_create_driverfs_files(); do_create_driverfs_files();
return 0; return 0;
} }
...@@ -3987,20 +3944,10 @@ static int __init init_st(void) ...@@ -3987,20 +3944,10 @@ static int __init init_st(void)
static void __exit exit_st(void) static void __exit exit_st(void)
{ {
int i;
do_remove_driverfs_files(); do_remove_driverfs_files();
scsi_unregister_device(&st_template); scsi_unregister_driver(&st_template.gendrv);
unregister_chrdev(SCSI_TAPE_MAJOR, "st"); unregister_chrdev(SCSI_TAPE_MAJOR, "st");
if (scsi_tapes != NULL) { kfree(scsi_tapes);
for (i=0; i < st_dev_max; ++i)
if (scsi_tapes[i]) {
printk(KERN_WARNING "st: scsi_tapes[] not "
"empty after scsi_unregister_device\n");
st_detach(scsi_tapes[i]->device);
}
kfree(scsi_tapes);
}
printk(KERN_INFO "st: Unloaded.\n"); printk(KERN_INFO "st: Unloaded.\n");
} }
...@@ -4035,7 +3982,7 @@ static DRIVER_ATTR(version, S_IRUGO, st_version_show, NULL); ...@@ -4035,7 +3982,7 @@ static DRIVER_ATTR(version, S_IRUGO, st_version_show, NULL);
static void do_create_driverfs_files(void) static void do_create_driverfs_files(void)
{ {
struct device_driver *driverfs = &st_template.scsi_driverfs_driver; struct device_driver *driverfs = &st_template.gendrv;
driver_create_file(driverfs, &driver_attr_try_direct_io); driver_create_file(driverfs, &driver_attr_try_direct_io);
driver_create_file(driverfs, &driver_attr_fixed_buffer_size); driver_create_file(driverfs, &driver_attr_fixed_buffer_size);
...@@ -4045,7 +3992,7 @@ static void do_create_driverfs_files(void) ...@@ -4045,7 +3992,7 @@ static void do_create_driverfs_files(void)
static void do_remove_driverfs_files(void) static void do_remove_driverfs_files(void)
{ {
struct device_driver *driverfs = &st_template.scsi_driverfs_driver; struct device_driver *driverfs = &st_template.gendrv;
driver_remove_file(driverfs, &driver_attr_version); driver_remove_file(driverfs, &driver_attr_version);
driver_remove_file(driverfs, &driver_attr_max_sg_segs); driver_remove_file(driverfs, &driver_attr_max_sg_segs);
......
...@@ -70,7 +70,7 @@ typedef struct { ...@@ -70,7 +70,7 @@ typedef struct {
/* The tape drive descriptor */ /* The tape drive descriptor */
typedef struct { typedef struct {
struct Scsi_Device_Template *driver; struct scsi_driver *driver;
Scsi_Device *device; Scsi_Device *device;
struct semaphore lock; /* For serialization */ struct semaphore lock; /* For serialization */
struct completion wait; /* For SCSI commands */ struct completion wait; /* For SCSI commands */
...@@ -103,8 +103,6 @@ typedef struct { ...@@ -103,8 +103,6 @@ typedef struct {
/* Mode characteristics */ /* Mode characteristics */
ST_mode modes[ST_NBR_MODES]; ST_mode modes[ST_NBR_MODES];
int current_mode; int current_mode;
struct device driverfs_dev_r[ST_NBR_MODES];
struct device driverfs_dev_n[ST_NBR_MODES];
/* Status variables */ /* Status variables */
int partition; int partition;
......
...@@ -9,11 +9,18 @@ ...@@ -9,11 +9,18 @@
Original driver (sg.h): Original driver (sg.h):
* Copyright (C) 1992 Lawrence Foard * Copyright (C) 1992 Lawrence Foard
Version 2 and 3 extensions to driver: Version 2 and 3 extensions to driver:
* Copyright (C) 1998 - 2002 Douglas Gilbert * Copyright (C) 1998 - 2003 Douglas Gilbert
Version: 3.5.27 (20020812) Version: 3.5.29 (20030529)
This version is for 2.5 series kernels. This version is for 2.5 series kernels.
Changes since 3.5.28 (20030308)
- fix bug introduced in version 3.1.24 (last segment of sgat list)
Changes since 3.5.27 (20020812)
- remove procfs entries: hosts, host_hdr + host_strs (now in sysfs)
- add sysfs sg driver params: def_reserved_size, allow_dio, version
- new boot option: "sg_allow_dio" and module parameter: "allow_dio"
- multiple internal changes due to scsi subsystem rework
Changes since 3.5.26 (20020708) Changes since 3.5.26 (20020708)
- re-add direct IO using Kai Makisara's work - re-add direct IO using Kai Makisara's work
- re-tab to 8, start using C99-isms - re-tab to 8, start using C99-isms
...@@ -237,7 +244,7 @@ typedef struct sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */ ...@@ -237,7 +244,7 @@ typedef struct sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */
read/written by a single scsi command. The user can find the value of read/written by a single scsi command. The user can find the value of
PAGE_SIZE by calling getpagesize() defined in unistd.h . */ PAGE_SIZE by calling getpagesize() defined in unistd.h . */
#define SG_DEFAULT_RETRIES 1 #define SG_DEFAULT_RETRIES 0
/* Defaults, commented if they differ from original sg driver */ /* Defaults, commented if they differ from original sg driver */
#define SG_DEF_FORCE_LOW_DMA 0 /* was 1 -> memory below 16MB on i386 */ #define SG_DEF_FORCE_LOW_DMA 0 /* was 1 -> memory below 16MB on i386 */
......
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