Commit c9761c4d authored by James Bottomley's avatar James Bottomley

Merge

parents 62420867 cc236b9a
......@@ -431,6 +431,11 @@ int unregister_cdrom(struct cdrom_device_info *unreg)
topCdromPtr = cdi->next;
cdi->ops->n_minors--;
devfs_unregister (cdi->de);
if (atomic_read (&cdi->cdrom_driverfs_dev.refcount)) {
device_remove_file (&cdi->cdrom_driverfs_dev, "name");
device_remove_file (&cdi->cdrom_driverfs_dev, "kdev");
put_device (&cdi->cdrom_driverfs_dev);
}
devfs_dealloc_unique_number (&cdrom_numspace, cdi->number);
cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" unregistered\n", cdi->name);
return 0;
......
......@@ -425,6 +425,11 @@ struct Scsi_Host
*/
struct pci_dev *pci_dev;
/*
* Support for driverfs filesystem
*/
struct device host_driverfs_dev;
/*
* We should ensure that this is aligned, both for better performance
* and also because some compilers (m68k) don't automatically force
......@@ -485,6 +490,7 @@ static inline void scsi_set_pci_device(struct Scsi_Host *SHpnt,
struct pci_dev *pdev)
{
SHpnt->pci_dev = pdev;
SHpnt->host_driverfs_dev.parent=&pdev->dev;
}
......@@ -523,6 +529,7 @@ struct Scsi_Device_Template
void (*detach)(Scsi_Device *);
int (*init_command)(Scsi_Cmnd *); /* Used by new queueing code.
Selects command for blkdevs */
struct device_driver scsi_driverfs_driver;
};
void scsi_initialize_queue(Scsi_Device * SDpnt, struct Scsi_Host * SHpnt);
......
......@@ -1950,6 +1950,11 @@ int scsi_register_host(Scsi_Host_Template * tpnt)
}
printk(KERN_INFO "scsi%d : %s\n", /* And print a little message */
shpnt->host_no, name);
strncpy(shpnt->host_driverfs_dev.name,name,
DEVICE_NAME_SIZE-1);
sprintf(shpnt->host_driverfs_dev.bus_id,
"scsi%d",
shpnt->host_no);
}
}
......@@ -1958,6 +1963,8 @@ int scsi_register_host(Scsi_Host_Template * tpnt)
*/
for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
if (shpnt->hostt == tpnt) {
/* first register parent with driverfs */
device_register(&shpnt->host_driverfs_dev);
scan_scsis(shpnt, 0, 0, 0, 0);
if (shpnt->select_queue_depths != NULL) {
(shpnt->select_queue_depths) (shpnt, shpnt->host_queue);
......@@ -2113,6 +2120,7 @@ int scsi_unregister_host(Scsi_Host_Template * tpnt)
goto err_out;
}
devfs_unregister (SDpnt->de);
put_device(&SDpnt->sdev_driverfs_dev);
}
}
......@@ -2163,6 +2171,7 @@ int scsi_unregister_host(Scsi_Host_Template * tpnt)
/* Remove the /proc/scsi directory entry */
sprintf(name,"%d",shpnt->host_no);
remove_proc_entry(name, tpnt->proc_dir);
put_device(&shpnt->host_driverfs_dev);
if (tpnt->release)
(*tpnt->release) (shpnt);
else {
......@@ -2511,6 +2520,34 @@ void scsi_free_sgtable(struct scatterlist *sgl, int index)
mempool_free(sgl, sgp->pool);
}
static int scsi_bus_match(struct device *scsi_driverfs_dev,
struct device_driver *scsi_driverfs_drv)
{
char *p=0;
if (!strcmp("sd", scsi_driverfs_drv->name)) {
if ((p = strstr(scsi_driverfs_dev->bus_id, ":disc")) ||
(p = strstr(scsi_driverfs_dev->bus_id, ":p"))) {
return 1;
}
} else if (!strcmp("sg", scsi_driverfs_drv->name)) {
if (strstr(scsi_driverfs_dev->bus_id, ":gen"))
return 1;
} else if (!strcmp("sr",scsi_driverfs_drv->name)) {
if (strstr(scsi_driverfs_dev->bus_id,":cd"))
return 1;
} else if (!strcmp("st",scsi_driverfs_drv->name)) {
if (strstr(scsi_driverfs_dev->bus_id,":mt"))
return 1;
}
return 0;
}
struct bus_type scsi_driverfs_bus_type = {
name: "scsi",
match: scsi_bus_match,
};
static int __init init_scsi(void)
{
struct proc_dir_entry *generic;
......@@ -2557,6 +2594,8 @@ static int __init init_scsi(void)
printk(KERN_INFO "scsi: host order: %s\n", scsihosts);
scsi_host_no_init (scsihosts);
bus_register(&scsi_driverfs_bus_type);
return 0;
}
......
......@@ -417,6 +417,8 @@ extern unsigned int scsi_need_isa_buffer; /* True if some devices need indirecti
extern volatile int in_scan_scsis;
extern const unsigned char scsi_command_size[8];
extern struct bus_type scsi_driverfs_bus_type;
/*
* These are the error handling functions defined in scsi_error.c
......@@ -623,6 +625,7 @@ struct scsi_device {
// Flag to allow revalidate to succeed in sd_open
int allow_revalidate;
struct device sdev_driverfs_dev;
};
......
......@@ -54,6 +54,7 @@ static void scan_scsis_target(unsigned int channel, unsigned int dev,
char *scsi_result);
static int find_lun0_scsi_level(unsigned int channel, unsigned int dev,
struct Scsi_Host *shpnt);
static void scsi_load_identifier(Scsi_Device *SDpnt, Scsi_Request * SRpnt);
struct dev_info {
const char *vendor;
......@@ -288,6 +289,31 @@ static int scsilun_to_int(ScsiLun *scsilun_pnt)
}
#endif
/* Driverfs file content handlers */
static ssize_t scsi_device_type_read(struct device *driverfs_dev, char *page,
size_t count, loff_t off)
{
struct scsi_device *SDpnt = list_entry(driverfs_dev,
struct scsi_device, sdev_driverfs_dev);
if ((SDpnt->type <= MAX_SCSI_DEVICE_CODE) &&
(scsi_device_types[(int)SDpnt->type] != NULL))
return off ? 0 :
sprintf(page, "%s\n",
scsi_device_types[(int)SDpnt->type]);
else
return off ? 0 : sprintf(page, "UNKNOWN\n");
return 0;
}
static struct driver_file_entry scsi_device_type_file = {
name: "type",
mode: S_IRUGO,
show: scsi_device_type_read,
};
/* end content handlers */
static void print_inquiry(unsigned char *data)
{
int i;
......@@ -786,6 +812,22 @@ static int scan_scsis_single(unsigned int channel, unsigned int dev,
print_inquiry(scsi_result);
/* interrogate scsi target to provide device identifier */
scsi_load_identifier(SDpnt, SRpnt);
/* create driverfs files */
sprintf(SDpnt->sdev_driverfs_dev.bus_id,"%d:%d:%d:%d",
SDpnt->host->host_no, SDpnt->channel, SDpnt->id, SDpnt->lun);
SDpnt->sdev_driverfs_dev.parent = &SDpnt->host->host_driverfs_dev;
SDpnt->sdev_driverfs_dev.bus = &scsi_driverfs_bus_type;
device_register(&SDpnt->sdev_driverfs_dev);
/* Create driverfs file entries */
device_create_file(&SDpnt->sdev_driverfs_dev,
&scsi_device_type_file);
sprintf (devname, "host%d/bus%d/target%d/lun%d",
SDpnt->host->host_no, SDpnt->channel, SDpnt->id, SDpnt->lun);
if (SDpnt->de) printk ("DEBUG: dir: \"%s\" already exists\n", devname);
......@@ -1306,3 +1348,374 @@ static int find_lun0_scsi_level(unsigned int channel, unsigned int dev,
/* haven't found lun0, should send INQUIRY but take easy route */
return res;
}
#define SCSI_UID_DEV_ID 'U'
#define SCSI_UID_SER_NUM 'S'
#define SCSI_UID_UNKNOWN 'Z'
unsigned char *scsi_get_evpd_page(Scsi_Device *SDpnt, Scsi_Request * SRpnt)
{
unsigned char *evpd_page = NULL;
unsigned char *scsi_cmd = NULL;
int lun = SDpnt->lun;
int scsi_level = SDpnt->scsi_level;
evpd_page = kmalloc(255,
(SDpnt->host->unchecked_isa_dma ? GFP_DMA : GFP_ATOMIC));
if (!evpd_page)
return NULL;
scsi_cmd = kmalloc(MAX_COMMAND_SIZE, GFP_ATOMIC);
if (!scsi_cmd) {
kfree(evpd_page);
return NULL;
}
/* Use vital product pages to determine serial number */
/* Try Supported vital product data pages 0x00 first */
scsi_cmd[0] = INQUIRY;
if ((lun > 0) && (scsi_level <= SCSI_2))
scsi_cmd[1] = ((lun << 5) & 0xe0) | 0x01;
else
scsi_cmd[1] = 0x01; /* SCSI_3 and higher, don't touch */
scsi_cmd[2] = 0x00;
scsi_cmd[3] = 0;
scsi_cmd[4] = 255;
scsi_cmd[5] = 0;
SRpnt->sr_cmd_len = 0;
SRpnt->sr_sense_buffer[0] = 0;
SRpnt->sr_sense_buffer[2] = 0;
SRpnt->sr_data_direction = SCSI_DATA_READ;
scsi_wait_req(SRpnt, (void *) scsi_cmd, (void *) evpd_page,
255, SCSI_TIMEOUT+4*HZ, 3);
if (SRpnt->sr_result) {
kfree(scsi_cmd);
kfree(evpd_page);
return NULL;
}
/* check to see if response was truncated */
if (evpd_page[3] > 255) {
int max_lgth = evpd_page[3] + 4;
kfree(evpd_page);
evpd_page = kmalloc(max_lgth, (SDpnt->host->unchecked_isa_dma ?
GFP_DMA : GFP_ATOMIC));
if (!evpd_page) {
kfree(scsi_cmd);
return NULL;
}
memset(scsi_cmd, 0, MAX_COMMAND_SIZE);
scsi_cmd[0] = INQUIRY;
if ((lun > 0) && (scsi_level <= SCSI_2))
scsi_cmd[1] = ((lun << 5) & 0xe0) | 0x01;
else
scsi_cmd[1] = 0x01; /* SCSI_3 and higher, don't touch */
scsi_cmd[2] = 0x00;
scsi_cmd[3] = 0;
scsi_cmd[4] = max_lgth;
scsi_cmd[5] = 0;
SRpnt->sr_cmd_len = 0;
SRpnt->sr_sense_buffer[0] = 0;
SRpnt->sr_sense_buffer[2] = 0;
SRpnt->sr_data_direction = SCSI_DATA_READ;
scsi_wait_req(SRpnt, (void *) scsi_cmd, (void *) evpd_page,
max_lgth, SCSI_TIMEOUT+4*HZ, 3);
if (SRpnt->sr_result) {
kfree(scsi_cmd);
kfree(evpd_page);
return NULL;
}
}
kfree(scsi_cmd);
/* some ill behaved devices return the std inquiry here rather than
the evpd data. snoop the data to verify */
if (evpd_page[3] > 16) {
/* if vend id appears in the evpd page assume evpd is invalid */
if (!strncmp(&evpd_page[8], SDpnt->vendor, 8)) {
kfree(evpd_page);
return NULL;
}
}
return evpd_page;
}
int scsi_get_deviceid(Scsi_Device *SDpnt,Scsi_Request * SRpnt)
{
unsigned char *id_page = NULL;
unsigned char *scsi_cmd = NULL;
int scnt, i, j, idtype;
char * id = SDpnt->sdev_driverfs_dev.name;
int lun = SDpnt->lun;
int scsi_level = SDpnt->scsi_level;
id_page = kmalloc(255,
(SDpnt->host->unchecked_isa_dma ? GFP_DMA : GFP_ATOMIC));
if (!id_page)
return 0;
scsi_cmd = kmalloc(MAX_COMMAND_SIZE, GFP_ATOMIC);
if (!scsi_cmd)
goto leave;
/* Use vital product pages to determine serial number */
/* Try Supported vital product data pages 0x00 first */
scsi_cmd[0] = INQUIRY;
if ((lun > 0) && (scsi_level <= SCSI_2))
scsi_cmd[1] = ((lun << 5) & 0xe0) | 0x01;
else
scsi_cmd[1] = 0x01; /* SCSI_3 and higher, don't touch */
scsi_cmd[2] = 0x83;
scsi_cmd[3] = 0;
scsi_cmd[4] = 255;
scsi_cmd[5] = 0;
SRpnt->sr_cmd_len = 0;
SRpnt->sr_sense_buffer[0] = 0;
SRpnt->sr_sense_buffer[2] = 0;
SRpnt->sr_data_direction = SCSI_DATA_READ;
scsi_wait_req(SRpnt, (void *) scsi_cmd, (void *) id_page,
255, SCSI_TIMEOUT+4*HZ, 3);
if (SRpnt->sr_result) {
kfree(scsi_cmd);
goto leave;
}
/* check to see if response was truncated */
if (id_page[3] > 255) {
int max_lgth = id_page[3] + 4;
kfree(id_page);
id_page = kmalloc(max_lgth,
(SDpnt->host->unchecked_isa_dma ?
GFP_DMA : GFP_ATOMIC));
if (!id_page) {
kfree(scsi_cmd);
return 0;
}
memset(scsi_cmd, 0, MAX_COMMAND_SIZE);
scsi_cmd[0] = INQUIRY;
if ((lun > 0) && (scsi_level <= SCSI_2))
scsi_cmd[1] = ((lun << 5) & 0xe0) | 0x01;
else
scsi_cmd[1] = 0x01; /* SCSI_3 and higher, don't touch */
scsi_cmd[2] = 0x83;
scsi_cmd[3] = 0;
scsi_cmd[4] = max_lgth;
scsi_cmd[5] = 0;
SRpnt->sr_cmd_len = 0;
SRpnt->sr_sense_buffer[0] = 0;
SRpnt->sr_sense_buffer[2] = 0;
SRpnt->sr_data_direction = SCSI_DATA_READ;
scsi_wait_req(SRpnt, (void *) scsi_cmd, (void *) id_page,
max_lgth, SCSI_TIMEOUT+4*HZ, 3);
if (SRpnt->sr_result) {
kfree(scsi_cmd);
goto leave;
}
}
kfree(scsi_cmd);
idtype = 3;
while (idtype > 0) {
for(scnt = 4; scnt <= id_page[3] + 3;
scnt += id_page[scnt + 3] + 4) {
if ((id_page[scnt + 1] & 0x0f) != idtype) {
continue;
}
if ((id_page[scnt] & 0x0f) == 2) {
for(i = scnt + 4, j = 1;
i < scnt + 4 + id_page[scnt + 3];
i++) {
if (id_page[i] > 0x20) {
if (j == DEVICE_NAME_SIZE) {
memset(id, 0,
DEVICE_NAME_SIZE);
break;
}
id[j++] = id_page[i];
}
}
} else if ((id_page[scnt] & 0x0f) == 1) {
static const char hex_str[]="0123456789abcdef";
for(i = scnt + 4, j = 1;
i < scnt + 4 + id_page[scnt + 3];
i++) {
if ((j + 1) == DEVICE_NAME_SIZE) {
memset(id, 0, DEVICE_NAME_SIZE);
break;
}
id[j++] = hex_str[(id_page[i] & 0xf0) >>
4];
id[j++] = hex_str[id_page[i] & 0x0f];
}
}
if (id[1] != 0) goto leave;
}
idtype--;
}
leave:
kfree(id_page);
if (id[1] != 0) {
id[0] = SCSI_UID_DEV_ID;
return 1;
}
return 0;
}
int scsi_get_serialnumber(Scsi_Device *SDpnt, Scsi_Request * SRpnt)
{
unsigned char *serialnumber_page = NULL;
unsigned char *scsi_cmd = NULL;
int lun = SDpnt->lun;
int scsi_level = SDpnt->scsi_level;
int i, j;
serialnumber_page = kmalloc(255, (SDpnt->host->unchecked_isa_dma ?
GFP_DMA : GFP_ATOMIC));
if (!serialnumber_page)
return 0;
scsi_cmd = kmalloc(MAX_COMMAND_SIZE, GFP_ATOMIC);
if (!scsi_cmd)
goto leave;
/* Use vital product pages to determine serial number */
/* Try Supported vital product data pages 0x00 first */
scsi_cmd[0] = INQUIRY;
if ((lun > 0) && (scsi_level <= SCSI_2))
scsi_cmd[1] = ((lun << 5) & 0xe0) | 0x01;
else
scsi_cmd[1] = 0x01; /* SCSI_3 and higher, don't touch */
scsi_cmd[2] = 0x80;
scsi_cmd[3] = 0;
scsi_cmd[4] = 255;
scsi_cmd[5] = 0;
SRpnt->sr_cmd_len = 0;
SRpnt->sr_sense_buffer[0] = 0;
SRpnt->sr_sense_buffer[2] = 0;
SRpnt->sr_data_direction = SCSI_DATA_READ;
scsi_wait_req(SRpnt, (void *) scsi_cmd, (void *) serialnumber_page,
255, SCSI_TIMEOUT+4*HZ, 3);
if (SRpnt->sr_result) {
kfree(scsi_cmd);
goto leave;
}
/* check to see if response was truncated */
if (serialnumber_page[3] > 255) {
int max_lgth = serialnumber_page[3] + 4;
kfree(serialnumber_page);
serialnumber_page = kmalloc(max_lgth,
(SDpnt->host->unchecked_isa_dma ?
GFP_DMA : GFP_ATOMIC));
if (!serialnumber_page) {
kfree(scsi_cmd);
return 0;
}
memset(scsi_cmd, 0, MAX_COMMAND_SIZE);
scsi_cmd[0] = INQUIRY;
if ((lun > 0) && (scsi_level <= SCSI_2))
scsi_cmd[1] = ((lun << 5) & 0xe0) | 0x01;
else
scsi_cmd[1] = 0x01; /* SCSI_3 and higher, don't touch */
scsi_cmd[2] = 0x80;
scsi_cmd[3] = 0;
scsi_cmd[4] = max_lgth;
scsi_cmd[5] = 0;
SRpnt->sr_cmd_len = 0;
SRpnt->sr_sense_buffer[0] = 0;
SRpnt->sr_sense_buffer[2] = 0;
SRpnt->sr_data_direction = SCSI_DATA_READ;
scsi_wait_req(SRpnt, (void *) scsi_cmd,
(void *) serialnumber_page,
max_lgth, SCSI_TIMEOUT+4*HZ, 3);
if (SRpnt->sr_result) {
kfree(scsi_cmd);
goto leave;
}
}
kfree(scsi_cmd);
SDpnt->sdev_driverfs_dev.name[0] = SCSI_UID_SER_NUM;
for(i = 0, j = 1; i < serialnumber_page[3]; i++) {
if (serialnumber_page[4 + i] > 0x20)
SDpnt->sdev_driverfs_dev.name[j++] =
serialnumber_page[4 + i];
}
for(i = 0, j = strlen(SDpnt->sdev_driverfs_dev.name); i < 8; i++) {
if (SDpnt->vendor[i] > 0x20) {
SDpnt->sdev_driverfs_dev.name[j++] = SDpnt->vendor[i];
}
}
kfree(serialnumber_page);
return 1;
leave:
memset(SDpnt->sdev_driverfs_dev.name, 0, DEVICE_NAME_SIZE);
kfree(serialnumber_page);
return 0;
}
int scsi_get_default_name(Scsi_Device *SDpnt)
{
int i, j;
SDpnt->sdev_driverfs_dev.name[0] = SCSI_UID_UNKNOWN;
for(i = 0, j = 1; i < 8; i++) {
if (SDpnt->vendor[i] > 0x20) {
SDpnt->sdev_driverfs_dev.name[j++] =
SDpnt->vendor[i];
}
}
for(i = 0, j = strlen(SDpnt->sdev_driverfs_dev.name);
i < 16; i++) {
if (SDpnt->model[i] > 0x20) {
SDpnt->sdev_driverfs_dev.name[j++] =
SDpnt->model[i];
}
}
for(i = 0, j = strlen(SDpnt->sdev_driverfs_dev.name); i < 4; i++) {
if (SDpnt->rev[i] > 0x20) {
SDpnt->sdev_driverfs_dev.name[j++] = SDpnt->rev[i];
}
}
return 1;
}
static void scsi_load_identifier(Scsi_Device *SDpnt, Scsi_Request * SRpnt)
{
unsigned char *evpd_page = NULL;
int cnt;
memset(SDpnt->sdev_driverfs_dev.name, 0, DEVICE_NAME_SIZE);
evpd_page = scsi_get_evpd_page(SDpnt, SRpnt);
if (!evpd_page) {
/* try to obtain serial number anyway */
if (!scsi_get_serialnumber(SDpnt, SRpnt))
goto leave;
goto leave;
}
for(cnt = 4; cnt <= evpd_page[3] + 3; cnt++) {
if (evpd_page[cnt] == 0x83) {
if (scsi_get_deviceid(SDpnt, SRpnt))
goto leave;
}
}
for(cnt = 4; cnt <= evpd_page[3] + 3; cnt++) {
if (evpd_page[cnt] == 0x80) {
if (scsi_get_serialnumber(SDpnt, SRpnt))
goto leave;
}
}
leave:
if (SDpnt->sdev_driverfs_dev.name[0] == 0)
scsi_get_default_name(SDpnt);
if (evpd_page) kfree(evpd_page);
return;
}
......@@ -101,3 +101,8 @@ extern void scsi_add_timer(Scsi_Cmnd *, int, void ((*) (Scsi_Cmnd *)));
extern int scsi_delete_timer(Scsi_Cmnd *);
EXPORT_SYMBOL(scsi_add_timer);
EXPORT_SYMBOL(scsi_delete_timer);
/*
* driverfs support for determining driver types
*/
EXPORT_SYMBOL(scsi_driverfs_bus_type);
......@@ -129,6 +129,7 @@ static void sd_rw_intr(Scsi_Cmnd * SCpnt);
static Scsi_Disk * sd_get_sdisk(int index);
extern void driverfs_remove_partitions(struct gendisk *hd, int minor);
#if defined(CONFIG_PPC32)
/**
......@@ -1277,12 +1278,15 @@ static int sd_init()
init_mem_lth(sd_gendisks[k].de_arr, N);
init_mem_lth(sd_gendisks[k].flags, N);
init_mem_lth(sd_gendisks[k].driverfs_dev_arr, N);
if (!sd_gendisks[k].de_arr || !sd_gendisks[k].flags)
if (!sd_gendisks[k].de_arr || !sd_gendisks[k].flags ||
!sd_gendisks[k].driverfs_dev_arr)
goto cleanup_gendisks;
zero_mem_lth(sd_gendisks[k].de_arr, N);
zero_mem_lth(sd_gendisks[k].flags, N);
zero_mem_lth(sd_gendisks[k].driverfs_dev_arr, N);
sd_gendisks[k].major = SD_MAJOR(k);
sd_gendisks[k].major_name = "sd";
......@@ -1291,7 +1295,6 @@ static int sd_init()
sd_gendisks[k].sizes = sd_sizes + k * (N << 4);
sd_gendisks[k].nr_real = 0;
}
return 0;
#undef init_mem_lth
......@@ -1302,6 +1305,7 @@ static int sd_init()
for (k = 0; k < N_USED_SD_MAJORS; k++) {
vfree(sd_gendisks[k].de_arr);
vfree(sd_gendisks[k].flags);
vfree(sd_gendisks[k].driverfs_dev_arr);
}
cleanup_mem:
vfree(sd_gendisks);
......@@ -1436,6 +1440,8 @@ static int sd_attach(Scsi_Device * sdp)
SD_GENDISK(dsk_nr).nr_real++;
devnum = dsk_nr % SCSI_DISKS_PER_MAJOR;
SD_GENDISK(dsk_nr).de_arr[devnum] = sdp->de;
SD_GENDISK(dsk_nr).driverfs_dev_arr[devnum] =
&sdp->sdev_driverfs_dev;
if (sdp->removable)
SD_GENDISK(dsk_nr).flags[devnum] |= GENHD_FL_REMOVABLE;
sd_dskname(dsk_nr, diskname);
......@@ -1535,6 +1541,8 @@ static void sd_detach(Scsi_Device * sdp)
max_p = 1 << sd_gendisk.minor_shift;
start = dsk_nr << sd_gendisk.minor_shift;
dev = MKDEV_SD_PARTITION(start);
driverfs_remove_partitions(&SD_GENDISK (dsk_nr),
SD_MINOR_NUMBER (start));
wipe_partitions(dev);
for (j = max_p - 1; j >= 0; j--)
sd_sizes[start + j] = 0;
......@@ -1556,9 +1564,16 @@ static void sd_detach(Scsi_Device * sdp)
**/
static int __init init_sd(void)
{
int rc;
SCSI_LOG_HLQUEUE(3, printk("init_sd: sd driver entry point\n"));
sd_template.module = THIS_MODULE;
return scsi_register_device(&sd_template);
rc = scsi_register_device(&sd_template);
if (!rc) {
sd_template.scsi_driverfs_driver.name = (char *)sd_template.tag;
sd_template.scsi_driverfs_driver.bus = &scsi_driverfs_bus_type;
driver_register(&sd_template.scsi_driverfs_driver);
}
return rc;
}
/**
......@@ -1591,6 +1606,7 @@ static void __exit exit_sd(void)
sd_template.dev_max = 0;
if (sd_gendisks != &sd_gendisk)
vfree(sd_gendisks);
remove_driver(&sd_template.scsi_driverfs_driver);
}
static Scsi_Disk * sd_get_sdisk(int index)
......
......@@ -194,6 +194,7 @@ typedef struct sg_device /* holds the state of each scsi generic device */
volatile char detached; /* 0->attached, 1->detached pending removal */
volatile char exclude; /* opened for exclusive access */
char sgdebug; /* 0->off, 1->sense, 9->dump dev, 10-> all devs */
struct device sg_driverfs_dev;
} Sg_device; /* 36 bytes long on i386 */
......@@ -1370,6 +1371,29 @@ static int __init sg_def_reserved_size_setup(char *str)
__setup("sg_def_reserved_size=", sg_def_reserved_size_setup);
#endif
/* Driverfs file support */
static ssize_t sg_device_kdev_read(struct device *driverfs_dev, char *page,
size_t count, loff_t off)
{
Sg_device * sdp=list_entry(driverfs_dev, Sg_device, sg_driverfs_dev);
return off ? 0 : sprintf(page, "%x\n",sdp->i_rdev.value);
}
static struct driver_file_entry sg_device_kdev_file = {
name: "kdev",
mode: S_IRUGO,
show: sg_device_kdev_read,
};
static ssize_t sg_device_type_read(struct device *driverfs_dev, char *page,
size_t count, loff_t off)
{
return off ? 0 : sprintf (page, "CHR\n");
}
static struct driver_file_entry sg_device_type_file = {
name: "type",
mode: S_IRUGO,
show: sg_device_type_read,
};
static int sg_attach(Scsi_Device * scsidp)
{
......@@ -1428,6 +1452,18 @@ static int sg_attach(Scsi_Device * scsidp)
sdp->detached = 0;
sdp->sg_tablesize = scsidp->host ? scsidp->host->sg_tablesize : 0;
sdp->i_rdev = mk_kdev(SCSI_GENERIC_MAJOR, k);
memset(&sdp->sg_driverfs_dev, 0, sizeof(struct device));
sprintf(sdp->sg_driverfs_dev.bus_id, "%s:gen",
scsidp->sdev_driverfs_dev.bus_id);
sprintf(sdp->sg_driverfs_dev.name, "%sgeneric",
scsidp->sdev_driverfs_dev.name);
sdp->sg_driverfs_dev.parent = &scsidp->sdev_driverfs_dev;
sdp->sg_driverfs_dev.bus = &scsi_driverfs_bus_type;
device_register(&sdp->sg_driverfs_dev);
device_create_file(&sdp->sg_driverfs_dev, &sg_device_type_file);
device_create_file(&sdp->sg_driverfs_dev, &sg_device_kdev_file);
sdp->de = devfs_register (scsidp->de, "generic", DEVFS_FL_DEFAULT,
SCSI_GENERIC_MAJOR, k,
S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,
......@@ -1496,6 +1532,9 @@ static void sg_detach(Scsi_Device * scsidp)
}
SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d, dirty\n", k));
devfs_unregister (sdp->de);
device_remove_file(&sdp->sg_driverfs_dev,sg_device_type_file.name);
device_remove_file(&sdp->sg_driverfs_dev,sg_device_kdev_file.name);
put_device(&sdp->sg_driverfs_dev);
sdp->de = NULL;
if (NULL == sdp->headfp) {
kfree((char *)sdp);
......@@ -1505,6 +1544,7 @@ static void sg_detach(Scsi_Device * scsidp)
else { /* nothing active, simple case */
SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d\n", k));
devfs_unregister (sdp->de);
put_device(&sdp->sg_driverfs_dev);
kfree((char *)sdp);
sg_dev_arr[k] = NULL;
}
......@@ -1529,9 +1569,16 @@ MODULE_PARM(def_reserved_size, "i");
MODULE_PARM_DESC(def_reserved_size, "size of buffer reserved for each fd");
static int __init init_sg(void) {
int rc;
if (def_reserved_size >= 0)
sg_big_buff = def_reserved_size;
return scsi_register_device(&sg_template);
rc = scsi_register_device(&sg_template);
if (!rc) {
sg_template.scsi_driverfs_driver.name = (char *)sg_template.tag;
sg_template.scsi_driverfs_driver.bus = &scsi_driverfs_bus_type;
driver_register(&sg_template.scsi_driverfs_driver);
}
return rc;
}
static void __exit exit_sg( void)
......@@ -1546,6 +1593,7 @@ static void __exit exit_sg( void)
sg_dev_arr = NULL;
}
sg_template.dev_max = 0;
remove_driver(&sg_template.scsi_driverfs_driver);
}
......
......@@ -731,6 +731,32 @@ static int sr_init()
return 1;
}
/* Driverfs file support */
static ssize_t sr_device_kdev_read(struct device *driverfs_dev,
char *page, size_t count, loff_t off)
{
kdev_t kdev;
kdev.value=(int)driverfs_dev->driver_data;
return off ? 0 : sprintf(page, "%x\n",kdev.value);
}
static struct driver_file_entry sr_device_kdev_file = {
name: "kdev",
mode: S_IRUGO,
show: sr_device_kdev_read,
};
static ssize_t sr_device_type_read(struct device *driverfs_dev,
char *page, size_t count, loff_t off)
{
return off ? 0 : sprintf (page, "CHR\n");
}
static struct driver_file_entry sr_device_type_file = {
name: "type",
mode: S_IRUGO,
show: sr_device_type_read,
};
void sr_finish()
{
int i;
......@@ -776,6 +802,20 @@ void sr_finish()
sprintf(name, "sr%d", i);
strcpy(SCp->cdi.name, name);
sprintf(SCp->cdi.cdrom_driverfs_dev.bus_id, "%s:cd",
SCp->device->sdev_driverfs_dev.bus_id);
sprintf(SCp->cdi.cdrom_driverfs_dev.name, "%scdrom",
SCp->device->sdev_driverfs_dev.name);
SCp->cdi.cdrom_driverfs_dev.parent =
&SCp->device->sdev_driverfs_dev;
SCp->cdi.cdrom_driverfs_dev.bus = &scsi_driverfs_bus_type;
SCp->cdi.cdrom_driverfs_dev.driver_data =
(void *)__mkdev(MAJOR_NR, i);
device_register(&SCp->cdi.cdrom_driverfs_dev);
device_create_file(&SCp->cdi.cdrom_driverfs_dev,
&sr_device_type_file);
device_create_file(&SCp->cdi.cdrom_driverfs_dev,
&sr_device_kdev_file);
SCp->cdi.de = devfs_register(SCp->device->de, "cd",
DEVFS_FL_DEFAULT, MAJOR_NR, i,
S_IFBLK | S_IRUGO | S_IWUGO,
......@@ -816,7 +856,14 @@ static void sr_detach(Scsi_Device * SDp)
static int __init init_sr(void)
{
return scsi_register_device(&sr_template);
int rc;
rc = scsi_register_device(&sr_template);
if (!rc) {
sr_template.scsi_driverfs_driver.name = (char *)sr_template.tag;
sr_template.scsi_driverfs_driver.bus = &scsi_driverfs_bus_type;
driver_register(&sr_template.scsi_driverfs_driver);
}
return rc;
}
static void __exit exit_sr(void)
......@@ -833,6 +880,7 @@ static void __exit exit_sr(void)
blk_clear(MAJOR_NR);
sr_template.dev_max = 0;
remove_driver(&sr_template.scsi_driverfs_driver);
}
module_init(init_sr);
......
......@@ -3531,6 +3531,31 @@ __setup("st=", st_setup);
#endif
/* Driverfs file support */
static ssize_t st_device_kdev_read(struct device *driverfs_dev,
char *page, size_t count, loff_t off)
{
kdev_t kdev;
kdev.value=(int)driverfs_dev->driver_data;
return off ? 0 : sprintf(page, "%x\n",kdev.value);
}
static struct driver_file_entry st_device_kdev_file = {
name: "kdev",
mode: S_IRUGO,
show: st_device_kdev_read,
};
static ssize_t st_device_type_read(struct device *driverfs_dev,
char *page, size_t count, loff_t off)
{
return off ? 0 : sprintf (page, "CHR\n");
}
static struct driver_file_entry st_device_type_file = {
name: "type",
mode: S_IRUGO,
show: st_device_type_read,
};
static struct file_operations st_fops =
{
......@@ -3632,6 +3657,18 @@ static int st_attach(Scsi_Device * SDp)
/* Rewind entry */
sprintf (name, "mt%s", formats[mode]);
sprintf(tpnt->driverfs_dev_r[mode].bus_id, "%s:%s",
SDp->sdev_driverfs_dev.name, name);
sprintf(tpnt->driverfs_dev_r[mode].name, "%s%s",
SDp->sdev_driverfs_dev.name, name);
tpnt->driverfs_dev_r[mode].parent = &SDp->sdev_driverfs_dev;
tpnt->driverfs_dev_r[mode].bus = &scsi_driverfs_bus_type;
tpnt->driverfs_dev_r[mode].driver_data =
(void *)__mkdev(MAJOR_NR, i + (mode << 5));
device_register(&tpnt->driverfs_dev_r[mode]);
device_create_file(&tpnt->driverfs_dev_r[mode],
&st_device_type_file);
device_create_file(&tpnt->driverfs_dev_r[mode], &st_device_kdev_file);
tpnt->de_r[mode] =
devfs_register (SDp->de, name, DEVFS_FL_DEFAULT,
MAJOR_NR, i + (mode << 5),
......@@ -3639,6 +3676,19 @@ static int st_attach(Scsi_Device * SDp)
&st_fops, NULL);
/* No-rewind entry */
sprintf (name, "mt%sn", formats[mode]);
sprintf(tpnt->driverfs_dev_n[mode].bus_id, "%s:%s",
SDp->sdev_driverfs_dev.name, name);
sprintf(tpnt->driverfs_dev_n[mode].name, "%s%s",
SDp->sdev_driverfs_dev.name, name);
tpnt->driverfs_dev_n[mode].parent= &SDp->sdev_driverfs_dev;
tpnt->driverfs_dev_n[mode].bus = &scsi_driverfs_bus_type;
tpnt->driverfs_dev_n[mode].driver_data =
(void *)__mkdev(MAJOR_NR, i + (mode << 5) + 128);
device_register(&tpnt->driverfs_dev_n[mode]);
device_create_file(&tpnt->driverfs_dev_n[mode],
&st_device_type_file);
device_create_file(&tpnt->driverfs_dev_n[mode],
&st_device_kdev_file);
tpnt->de_n[mode] =
devfs_register (SDp->de, name, DEVFS_FL_DEFAULT,
MAJOR_NR, i + (mode << 5) + 128,
......@@ -3738,8 +3788,18 @@ static void st_detach(Scsi_Device * SDp)
for (mode = 0; mode < ST_NBR_MODES; ++mode) {
devfs_unregister (tpnt->de_r[mode]);
tpnt->de_r[mode] = NULL;
device_remove_file(&tpnt->driverfs_dev_r[mode],
st_device_type_file.name);
device_remove_file(&tpnt->driverfs_dev_r[mode],
st_device_kdev_file.name);
put_device(&tpnt->driverfs_dev_r[mode]);
devfs_unregister (tpnt->de_n[mode]);
tpnt->de_n[mode] = NULL;
device_remove_file(&tpnt->driverfs_dev_n[mode],
st_device_type_file.name);
device_remove_file(&tpnt->driverfs_dev_n[mode],
st_device_kdev_file.name);
put_device(&tpnt->driverfs_dev_n[mode]);
}
if (tpnt->buffer) {
tpnt->buffer->orig_sg_segs = 0;
......@@ -3770,8 +3830,16 @@ static int __init init_st(void)
verstr, st_fixed_buffer_size, st_write_threshold,
st_max_sg_segs);
if (devfs_register_chrdev(SCSI_TAPE_MAJOR, "st", &st_fops) >= 0)
return scsi_register_device(&st_template);
if (devfs_register_chrdev(SCSI_TAPE_MAJOR, "st", &st_fops) >= 0) {
if (scsi_register_device(&st_template) == 0) {
st_template.scsi_driverfs_driver.name =
(char *)st_template.tag;
st_template.scsi_driverfs_driver.bus =
&scsi_driverfs_bus_type;
driver_register(&st_template.scsi_driverfs_driver);
return 0;
}
}
printk(KERN_ERR "Unable to get major %d for SCSI tapes\n", MAJOR_NR);
return 1;
......@@ -3790,6 +3858,7 @@ static void __exit exit_st(void)
kfree(scsi_tapes);
}
st_template.dev_max = 0;
remove_driver(&st_template.scsi_driverfs_driver);
printk(KERN_INFO "st: Unloaded.\n");
}
......
......@@ -94,6 +94,8 @@ typedef struct {
int current_mode;
devfs_handle_t de_r[ST_NBR_MODES]; /* Rewind entries */
devfs_handle_t de_n[ST_NBR_MODES]; /* No-rewind entries */
struct device driverfs_dev_r[ST_NBR_MODES];
struct device driverfs_dev_n[ST_NBR_MODES];
/* Status variables */
int partition;
......
......@@ -22,6 +22,7 @@
#include <linux/init.h>
#include <linux/raid/md.h>
#include <linux/buffer_head.h> /* for invalidate_bdev() */
#include <linux/kmod.h>
#include "check.h"
......@@ -225,6 +226,136 @@ void add_gd_partition(struct gendisk *hd, int minor, int start, int size)
#endif
}
/* Driverfs file support */
static ssize_t partition_device_kdev_read(struct device *driverfs_dev,
char *page, size_t count, loff_t off)
{
kdev_t kdev;
kdev.value=(int)driverfs_dev->driver_data;
return off ? 0 : sprintf (page, "%x\n",kdev.value);
}
static struct driver_file_entry partition_device_kdev_file = {
name: "kdev",
mode: S_IRUGO,
show: partition_device_kdev_read,
};
static ssize_t partition_device_type_read(struct device *driverfs_dev,
char *page, size_t count, loff_t off)
{
return off ? 0 : sprintf (page, "BLK\n");
}
static struct driver_file_entry partition_device_type_file = {
name: "type",
mode: S_IRUGO,
show: partition_device_type_read,
};
void driverfs_create_partitions(struct gendisk *hd, int minor)
{
int pos = -1;
int devnum = minor >> hd->minor_shift;
char dirname[256];
struct device *parent = 0;
int max_p;
int part;
devfs_handle_t dir = 0;
/* get parent driverfs device structure */
if (hd->driverfs_dev_arr)
parent = hd->driverfs_dev_arr[devnum];
else /* if driverfs not supported by subsystem, skip partitions */
return;
/* get parent device node directory name */
if (hd->de_arr) {
dir = hd->de_arr[devnum];
if (dir)
pos = devfs_generate_path (dir, dirname,
sizeof dirname);
}
if (pos < 0) {
disk_name(hd, minor, dirname);
pos = 0;
}
max_p = (1 << hd->minor_shift);
/* for all partitions setup parents and device node names */
for(part=0; part < max_p; part++) {
if ((part == 0) || (hd->part[minor + part].nr_sects >= 1)) {
struct device * current_driverfs_dev =
&hd->part[minor+part].hd_driverfs_dev;
current_driverfs_dev->parent = parent;
/* handle disc case */
current_driverfs_dev->driver_data =
(void *)__mkdev(hd->major, minor+part);
if (part == 0) {
if (parent) {
sprintf(current_driverfs_dev->name,
"%sdisc", parent->name);
sprintf(current_driverfs_dev->bus_id,
"%s:disc", parent->bus_id);
} else {
sprintf(current_driverfs_dev->name,
"disc");
sprintf(current_driverfs_dev->bus_id,
"disc");
}
} else { /* this is a partition */
if (parent) {
sprintf(current_driverfs_dev->name,
"%spart%d", parent->name, part);
sprintf(current_driverfs_dev->bus_id,
"%s:p%d", parent->bus_id, part);
} else {
sprintf(current_driverfs_dev->name,
"part%d", part);
sprintf(current_driverfs_dev->bus_id,
"p%d" ,part);
}
}
if (parent) current_driverfs_dev->bus = parent->bus;
device_register(current_driverfs_dev);
device_create_file(current_driverfs_dev,
&partition_device_type_file);
device_create_file(current_driverfs_dev,
&partition_device_kdev_file);
}
}
return;
}
void driverfs_remove_partitions(struct gendisk *hd, int minor)
{
int max_p;
int part;
struct device * current_driverfs_dev;
max_p=(1 << hd->minor_shift);
/* for all parts setup parent relationships and device node names */
for(part=1; part < max_p; part++) {
if ((hd->part[minor + part].nr_sects >= 1)) {
current_driverfs_dev =
&hd->part[minor + part].hd_driverfs_dev;
device_remove_file(current_driverfs_dev,
partition_device_type_file.name);
device_remove_file(current_driverfs_dev,
partition_device_kdev_file.name);
put_device(current_driverfs_dev);
}
}
current_driverfs_dev = &hd->part[minor].hd_driverfs_dev;
device_remove_file(current_driverfs_dev,
partition_device_type_file.name);
device_remove_file(current_driverfs_dev,
partition_device_kdev_file.name);
put_device(current_driverfs_dev);
return;
}
static void check_partition(struct gendisk *hd, kdev_t dev, int first_part_minor)
{
devfs_handle_t de = NULL;
......@@ -285,6 +416,13 @@ static void check_partition(struct gendisk *hd, kdev_t dev, int first_part_minor
truncate_inode_pages(bdev->bd_inode->i_mapping, 0);
bdput(bdev);
i = first_part_minor - 1;
/* Setup driverfs tree */
if (hd->sizes)
driverfs_create_partitions(hd, i);
else
driverfs_remove_partitions(hd, i);
devfs_register_partitions (hd, i, hd->sizes ? 0 : 1);
}
......
......@@ -716,6 +716,7 @@ struct request_sense {
#ifdef __KERNEL__
#include <linux/devfs_fs_kernel.h>
#include <linux/device.h>
struct cdrom_write_settings {
unsigned char fpacket; /* fixed/variable packets */
......@@ -730,6 +731,7 @@ struct cdrom_device_info {
struct cdrom_device_info *next; /* next device_info for this major */
void *handle; /* driver-dependent data */
devfs_handle_t de; /* real driver should create this */
struct device cdrom_driverfs_dev; /* driverfs implementation */
int number; /* generic driver updates this */
/* specifications */
kdev_t dev; /* device number */
......
......@@ -12,6 +12,7 @@
#include <linux/config.h>
#include <linux/types.h>
#include <linux/major.h>
#include <linux/device.h>
enum {
/* These three have identical behaviour; use the second one if DOS fdisk gets
......@@ -62,6 +63,7 @@ struct hd_struct {
unsigned long nr_sects;
devfs_handle_t de; /* primary (master) devfs entry */
int number; /* stupid old code wastes space */
struct device hd_driverfs_dev; /* support driverfs hiearchy */
};
#define GENHD_FL_REMOVABLE 1
......@@ -80,6 +82,7 @@ struct gendisk {
struct block_device_operations *fops;
devfs_handle_t *de_arr; /* one per physical disc */
struct device **driverfs_dev_arr;/* support driverfs hierarchy */
char *flags; /* one per physical disc */
};
......@@ -241,6 +244,7 @@ char *disk_name (struct gendisk *hd, int minor, char *buf);
extern void devfs_register_partitions (struct gendisk *dev, int minor,
int unregister);
extern void driverfs_remove_partitions (struct gendisk *hd, int minor);
static inline unsigned int disk_index (kdev_t dev)
{
......
......@@ -334,6 +334,7 @@ EXPORT_SYMBOL(bdev_read_only);
EXPORT_SYMBOL(set_device_ro);
EXPORT_SYMBOL(bmap);
EXPORT_SYMBOL(devfs_register_partitions);
EXPORT_SYMBOL(driverfs_remove_partitions);
EXPORT_SYMBOL(blkdev_open);
EXPORT_SYMBOL(blkdev_get);
EXPORT_SYMBOL(blkdev_put);
......
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