ide: add warm-plug support for IDE devices (take 2)

* Add 'struct class ide_port_class' ('ide_port' class) and a 'struct
  device *portdev' ('ide_port' class device) in ide_hwif_t.

* Register 'ide_port' class in ide_init() and unregister it in
  cleanup_module().

* Create ->portdev in ide_register_port () and unregister it in
  ide_unregister().

* Add "delete_devices" class device attribute for unregistering IDE devices
  on a port and "scan" one for probing+registering IDE devices on a port.

* Add ide_sysfs_register_port() helper for registering "delete_devices"
  and "scan" attributes with ->portdev.  Call it in ide_device_add_all().

* Document IDE warm-plug support in Documentation/ide/warm-plug-howto.txt.

v2:
* Convert patch from using 'struct class_device' to use 'struct device'.
  (thanks to Kay Sievers for doing it)
Signed-off-by: default avatarBartlomiej Zolnierkiewicz <bzolnier@gmail.com>
parent 50672e5d
IDE warm-plug HOWTO
===================
To warm-plug devices on a port 'idex':
# echo -n "1" > /sys/class/ide_port/idex/delete_devices
unplug old device(s) and plug new device(s)
# echo -n "1" > /sys/class/ide_port/idex/scan
done
...@@ -623,7 +623,7 @@ static void hwif_release_dev (struct device *dev) ...@@ -623,7 +623,7 @@ static void hwif_release_dev (struct device *dev)
complete(&hwif->gendev_rel_comp); complete(&hwif->gendev_rel_comp);
} }
static void ide_register_port(ide_hwif_t *hwif) static int ide_register_port(ide_hwif_t *hwif)
{ {
int ret; int ret;
...@@ -639,9 +639,23 @@ static void ide_register_port(ide_hwif_t *hwif) ...@@ -639,9 +639,23 @@ static void ide_register_port(ide_hwif_t *hwif)
} }
hwif->gendev.release = hwif_release_dev; hwif->gendev.release = hwif_release_dev;
ret = device_register(&hwif->gendev); ret = device_register(&hwif->gendev);
if (ret < 0) if (ret < 0) {
printk(KERN_WARNING "IDE: %s: device_register error: %d\n", printk(KERN_WARNING "IDE: %s: device_register error: %d\n",
__FUNCTION__, ret); __FUNCTION__, ret);
goto out;
}
get_device(&hwif->gendev);
hwif->portdev = device_create(ide_port_class, &hwif->gendev,
MKDEV(0, 0), hwif->name);
if (IS_ERR(hwif->portdev)) {
ret = PTR_ERR(hwif->portdev);
device_unregister(&hwif->gendev);
}
dev_set_drvdata(hwif->portdev, hwif);
out:
return ret;
} }
/** /**
...@@ -1378,6 +1392,58 @@ static void ide_port_cable_detect(ide_hwif_t *hwif) ...@@ -1378,6 +1392,58 @@ static void ide_port_cable_detect(ide_hwif_t *hwif)
} }
} }
static ssize_t store_delete_devices(struct device *portdev,
struct device_attribute *attr,
const char *buf, size_t n)
{
ide_hwif_t *hwif = dev_get_drvdata(portdev);
if (strncmp(buf, "1", n))
return -EINVAL;
ide_port_unregister_devices(hwif);
return n;
};
static DEVICE_ATTR(delete_devices, S_IWUSR, NULL, store_delete_devices);
static ssize_t store_scan(struct device *portdev,
struct device_attribute *attr,
const char *buf, size_t n)
{
ide_hwif_t *hwif = dev_get_drvdata(portdev);
if (strncmp(buf, "1", n))
return -EINVAL;
ide_port_unregister_devices(hwif);
ide_port_scan(hwif);
return n;
};
static DEVICE_ATTR(scan, S_IWUSR, NULL, store_scan);
static struct device_attribute *ide_port_attrs[] = {
&dev_attr_delete_devices,
&dev_attr_scan,
NULL
};
static int ide_sysfs_register_port(ide_hwif_t *hwif)
{
int i, rc;
for (i = 0; ide_port_attrs[i]; i++) {
rc = device_create_file(hwif->portdev, ide_port_attrs[i]);
if (rc)
break;
}
return rc;
}
int ide_device_add_all(u8 *idx, const struct ide_port_info *d) int ide_device_add_all(u8 *idx, const struct ide_port_info *d)
{ {
ide_hwif_t *hwif, *mate = NULL; ide_hwif_t *hwif, *mate = NULL;
...@@ -1474,6 +1540,7 @@ int ide_device_add_all(u8 *idx, const struct ide_port_info *d) ...@@ -1474,6 +1540,7 @@ int ide_device_add_all(u8 *idx, const struct ide_port_info *d)
hwif = &ide_hwifs[idx[i]]; hwif = &ide_hwifs[idx[i]];
if (hwif->present) { if (hwif->present) {
ide_sysfs_register_port(hwif);
ide_proc_register_port(hwif); ide_proc_register_port(hwif);
ide_proc_port_register_devices(hwif); ide_proc_port_register_devices(hwif);
} }
......
...@@ -78,6 +78,8 @@ ...@@ -78,6 +78,8 @@
/* default maximum number of failures */ /* default maximum number of failures */
#define IDE_DEFAULT_MAX_FAILURES 1 #define IDE_DEFAULT_MAX_FAILURES 1
struct class *ide_port_class;
static const u8 ide_hwif_to_major[] = { IDE0_MAJOR, IDE1_MAJOR, static const u8 ide_hwif_to_major[] = { IDE0_MAJOR, IDE1_MAJOR,
IDE2_MAJOR, IDE3_MAJOR, IDE2_MAJOR, IDE3_MAJOR,
IDE4_MAJOR, IDE5_MAJOR, IDE4_MAJOR, IDE5_MAJOR,
...@@ -591,6 +593,7 @@ void ide_unregister(unsigned int index, int init_default, int restore) ...@@ -591,6 +593,7 @@ void ide_unregister(unsigned int index, int init_default, int restore)
ide_remove_port_from_hwgroup(hwif); ide_remove_port_from_hwgroup(hwif);
device_unregister(hwif->portdev);
device_unregister(&hwif->gendev); device_unregister(&hwif->gendev);
wait_for_completion(&hwif->gendev_rel_comp); wait_for_completion(&hwif->gendev_rel_comp);
...@@ -1590,6 +1593,13 @@ struct bus_type ide_bus_type = { ...@@ -1590,6 +1593,13 @@ struct bus_type ide_bus_type = {
EXPORT_SYMBOL_GPL(ide_bus_type); EXPORT_SYMBOL_GPL(ide_bus_type);
static void ide_port_class_release(struct device *portdev)
{
ide_hwif_t *hwif = dev_get_drvdata(portdev);
put_device(&hwif->gendev);
}
/* /*
* This is gets invoked once during initialization, to set *everything* up * This is gets invoked once during initialization, to set *everything* up
*/ */
...@@ -1610,11 +1620,23 @@ static int __init ide_init(void) ...@@ -1610,11 +1620,23 @@ static int __init ide_init(void)
return ret; return ret;
} }
ide_port_class = class_create(THIS_MODULE, "ide_port");
if (IS_ERR(ide_port_class)) {
ret = PTR_ERR(ide_port_class);
goto out_port_class;
}
ide_port_class->dev_release = ide_port_class_release;
init_ide_data(); init_ide_data();
proc_ide_create(); proc_ide_create();
return 0; return 0;
out_port_class:
bus_unregister(&ide_bus_type);
return ret;
} }
#ifdef MODULE #ifdef MODULE
...@@ -1651,6 +1673,8 @@ void __exit cleanup_module (void) ...@@ -1651,6 +1673,8 @@ void __exit cleanup_module (void)
proc_ide_destroy(); proc_ide_destroy();
class_destroy(ide_port_class);
bus_unregister(&ide_bus_type); bus_unregister(&ide_bus_type);
} }
......
...@@ -579,7 +579,9 @@ typedef struct hwif_s { ...@@ -579,7 +579,9 @@ typedef struct hwif_s {
unsigned mmio : 1; /* host uses MMIO */ unsigned mmio : 1; /* host uses MMIO */
unsigned straight8 : 1; /* Alan's straight 8 check */ unsigned straight8 : 1; /* Alan's straight 8 check */
struct device gendev; struct device gendev;
struct device *portdev;
struct completion gendev_rel_comp; /* To deal with device release() */ struct completion gendev_rel_comp; /* To deal with device release() */
void *hwif_data; /* extra hwif data */ void *hwif_data; /* extra hwif data */
...@@ -1275,6 +1277,7 @@ extern struct mutex ide_cfg_mtx; ...@@ -1275,6 +1277,7 @@ extern struct mutex ide_cfg_mtx;
#define local_irq_set(flags) do { local_save_flags((flags)); local_irq_enable_in_hardirq(); } while (0) #define local_irq_set(flags) do { local_save_flags((flags)); local_irq_enable_in_hardirq(); } while (0)
extern struct bus_type ide_bus_type; extern struct bus_type ide_bus_type;
extern struct class *ide_port_class;
/* check if CACHE FLUSH (EXT) command is supported (bits defined in ATA-6) */ /* check if CACHE FLUSH (EXT) command is supported (bits defined in ATA-6) */
#define ide_id_has_flush_cache(id) ((id)->cfs_enable_2 & 0x3000) #define ide_id_has_flush_cache(id) ((id)->cfs_enable_2 & 0x3000)
......
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