diff -urN oldtree/drivers/ata/ahci.c newtree/drivers/ata/ahci.c --- oldtree/drivers/ata/ahci.c 2006-10-05 15:26:55.000000000 -0400 +++ newtree/drivers/ata/ahci.c 2006-10-06 18:14:46.000000000 -0400 @@ -240,6 +240,7 @@ .bios_param = ata_std_bios_param, .suspend = ata_scsi_device_suspend, .resume = ata_scsi_device_resume, + .shutdown = ata_scsi_device_shutdown, }; static const struct ata_port_operations ahci_ops = { diff -urN oldtree/drivers/ata/ata_piix.c newtree/drivers/ata/ata_piix.c --- oldtree/drivers/ata/ata_piix.c 2006-10-05 15:26:55.000000000 -0400 +++ newtree/drivers/ata/ata_piix.c 2006-10-06 18:14:46.000000000 -0400 @@ -267,6 +267,7 @@ .bios_param = ata_std_bios_param, .resume = ata_scsi_device_resume, .suspend = ata_scsi_device_suspend, + .shutdown = ata_scsi_device_shutdown, }; static const struct ata_port_operations piix_pata_ops = { diff -urN oldtree/drivers/ata/libata-core.c newtree/drivers/ata/libata-core.c --- oldtree/drivers/ata/libata-core.c 2006-10-05 15:26:55.000000000 -0400 +++ newtree/drivers/ata/libata-core.c 2006-10-06 18:14:46.000000000 -0400 @@ -6203,6 +6203,7 @@ EXPORT_SYMBOL_GPL(ata_scsi_device_suspend); EXPORT_SYMBOL_GPL(ata_scsi_device_resume); +EXPORT_SYMBOL_GPL(ata_scsi_device_shutdown); EXPORT_SYMBOL_GPL(ata_eng_timeout); EXPORT_SYMBOL_GPL(ata_port_schedule_eh); diff -urN oldtree/drivers/ata/libata-scsi.c newtree/drivers/ata/libata-scsi.c --- oldtree/drivers/ata/libata-scsi.c 2006-10-05 15:26:55.000000000 -0400 +++ newtree/drivers/ata/libata-scsi.c 2006-10-06 18:14:46.000000000 -0400 @@ -555,6 +555,52 @@ } /** + * ata_scsi_device_shutdown - prepares ATA device associated + * with sdev for shutdown + * @sdev: the SCSI device to resume + * + * Request suspend EH action on the ATA device associated + * with @sdev in order to flush its cache and unload heads, + * and wait for the operation to complete. + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0. + */ +int ata_scsi_device_shutdown(struct scsi_device *sdev) +{ + struct ata_port *ap = ata_shost_to_port(sdev->host); + struct ata_device *dev = ata_scsi_find_dev(ap, sdev); + unsigned long flags; + unsigned int action; + + if (!dev) + return 0; + + /* if @sdev is already detached, nothing to do */ + if (sdev->sdev_state == SDEV_OFFLINE || + sdev->sdev_state == SDEV_CANCEL || sdev->sdev_state == SDEV_DEL) + return 0; + + spin_lock_irqsave(ap->lock, flags); + + /* request suspend to flush cache and unload device heads */ + action = ATA_EH_SUSPEND; + ap->eh_info.dev_action[dev->devno] |= action; + ap->eh_info.flags |= ATA_EHI_QUIET; + ata_port_schedule_eh(ap); + + spin_unlock_irqrestore(ap->lock, flags); + + /* wait for EH to do the job */ + ata_port_wait_eh(ap); + + return 0; +} + +/** * ata_to_sense_error - convert ATA error to SCSI error * @id: ATA device number * @drv_stat: value contained in ATA status register diff -urN oldtree/drivers/ata/pdc_adma.c newtree/drivers/ata/pdc_adma.c --- oldtree/drivers/ata/pdc_adma.c 2006-10-05 15:26:55.000000000 -0400 +++ newtree/drivers/ata/pdc_adma.c 2006-10-06 18:14:46.000000000 -0400 @@ -154,6 +154,7 @@ .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .shutdown = ata_scsi_device_shutdown, }; static const struct ata_port_operations adma_ata_ops = { diff -urN oldtree/drivers/ata/sata_mv.c newtree/drivers/ata/sata_mv.c --- oldtree/drivers/ata/sata_mv.c 2006-10-05 15:26:55.000000000 -0400 +++ newtree/drivers/ata/sata_mv.c 2006-10-06 18:14:46.000000000 -0400 @@ -392,6 +392,7 @@ .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .shutdown = ata_scsi_device_shutdown, }; static const struct ata_port_operations mv5_ops = { diff -urN oldtree/drivers/ata/sata_nv.c newtree/drivers/ata/sata_nv.c --- oldtree/drivers/ata/sata_nv.c 2006-10-05 15:26:55.000000000 -0400 +++ newtree/drivers/ata/sata_nv.c 2006-10-06 18:14:46.000000000 -0400 @@ -157,6 +157,7 @@ .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .shutdown = ata_scsi_device_shutdown, }; static const struct ata_port_operations nv_generic_ops = { diff -urN oldtree/drivers/ata/sata_promise.c newtree/drivers/ata/sata_promise.c --- oldtree/drivers/ata/sata_promise.c 2006-10-05 15:26:55.000000000 -0400 +++ newtree/drivers/ata/sata_promise.c 2006-10-06 18:14:46.000000000 -0400 @@ -123,6 +123,7 @@ .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .shutdown = ata_scsi_device_shutdown, }; static const struct ata_port_operations pdc_sata_ops = { diff -urN oldtree/drivers/ata/sata_qstor.c newtree/drivers/ata/sata_qstor.c --- oldtree/drivers/ata/sata_qstor.c 2006-10-05 15:26:55.000000000 -0400 +++ newtree/drivers/ata/sata_qstor.c 2006-10-06 18:14:46.000000000 -0400 @@ -144,6 +144,7 @@ .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .shutdown = ata_scsi_device_shutdown, }; static const struct ata_port_operations qs_ata_ops = { diff -urN oldtree/drivers/ata/sata_sil.c newtree/drivers/ata/sata_sil.c --- oldtree/drivers/ata/sata_sil.c 2006-10-05 15:26:55.000000000 -0400 +++ newtree/drivers/ata/sata_sil.c 2006-10-06 18:14:46.000000000 -0400 @@ -184,6 +184,7 @@ .bios_param = ata_std_bios_param, .suspend = ata_scsi_device_suspend, .resume = ata_scsi_device_resume, + .shutdown = ata_scsi_device_shutdown, }; static const struct ata_port_operations sil_ops = { diff -urN oldtree/drivers/ata/sata_sil24.c newtree/drivers/ata/sata_sil24.c --- oldtree/drivers/ata/sata_sil24.c 2006-10-05 15:26:55.000000000 -0400 +++ newtree/drivers/ata/sata_sil24.c 2006-10-06 18:14:46.000000000 -0400 @@ -383,6 +383,7 @@ .bios_param = ata_std_bios_param, .suspend = ata_scsi_device_suspend, .resume = ata_scsi_device_resume, + .shutdown = ata_scsi_device_shutdown, }; static const struct ata_port_operations sil24_ops = { diff -urN oldtree/drivers/ata/sata_sis.c newtree/drivers/ata/sata_sis.c --- oldtree/drivers/ata/sata_sis.c 2006-10-05 15:26:55.000000000 -0400 +++ newtree/drivers/ata/sata_sis.c 2006-10-06 18:14:46.000000000 -0400 @@ -97,6 +97,7 @@ .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .shutdown = ata_scsi_device_shutdown, }; static const struct ata_port_operations sis_ops = { diff -urN oldtree/drivers/ata/sata_svw.c newtree/drivers/ata/sata_svw.c --- oldtree/drivers/ata/sata_svw.c 2006-10-05 15:26:55.000000000 -0400 +++ newtree/drivers/ata/sata_svw.c 2006-10-06 18:14:46.000000000 -0400 @@ -303,6 +303,7 @@ .proc_info = k2_sata_proc_info, #endif .bios_param = ata_std_bios_param, + .shutdown = ata_scsi_device_shutdown, }; diff -urN oldtree/drivers/ata/sata_sx4.c newtree/drivers/ata/sata_sx4.c --- oldtree/drivers/ata/sata_sx4.c 2006-10-05 15:26:55.000000000 -0400 +++ newtree/drivers/ata/sata_sx4.c 2006-10-06 18:14:46.000000000 -0400 @@ -193,6 +193,7 @@ .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .shutdown = ata_scsi_device_shutdown, }; static const struct ata_port_operations pdc_20621_ops = { diff -urN oldtree/drivers/ata/sata_uli.c newtree/drivers/ata/sata_uli.c --- oldtree/drivers/ata/sata_uli.c 2006-10-05 15:26:55.000000000 -0400 +++ newtree/drivers/ata/sata_uli.c 2006-10-06 18:14:46.000000000 -0400 @@ -91,6 +91,7 @@ .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .shutdown = ata_scsi_device_shutdown, }; static const struct ata_port_operations uli_ops = { diff -urN oldtree/drivers/ata/sata_via.c newtree/drivers/ata/sata_via.c --- oldtree/drivers/ata/sata_via.c 2006-10-05 15:26:55.000000000 -0400 +++ newtree/drivers/ata/sata_via.c 2006-10-06 18:14:46.000000000 -0400 @@ -107,6 +107,7 @@ .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .shutdown = ata_scsi_device_shutdown, }; static const struct ata_port_operations vt6420_sata_ops = { diff -urN oldtree/drivers/ata/sata_vsc.c newtree/drivers/ata/sata_vsc.c --- oldtree/drivers/ata/sata_vsc.c 2006-10-05 15:26:55.000000000 -0400 +++ newtree/drivers/ata/sata_vsc.c 2006-10-06 18:14:46.000000000 -0400 @@ -281,6 +281,7 @@ .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .shutdown = ata_scsi_device_shutdown, }; diff -urN oldtree/drivers/scsi/scsi_sysfs.c newtree/drivers/scsi/scsi_sysfs.c --- oldtree/drivers/scsi/scsi_sysfs.c 2006-10-05 15:26:55.000000000 -0400 +++ newtree/drivers/scsi/scsi_sysfs.c 2006-10-06 18:14:46.000000000 -0400 @@ -304,11 +304,28 @@ return err; } +static void scsi_bus_shutdown(struct device * dev) +{ + struct scsi_device *sdev = to_scsi_device(dev); + struct scsi_host_template *sht = sdev->host->hostt; + int err; + + err = scsi_device_quiesce(sdev); + if (err) + printk(KERN_DEBUG "%s: error (0x%x) during shutdown\n", + __FUNCTION__, err); + + if (sht->shutdown) + err = sht->shutdown(sdev); + +} + struct bus_type scsi_bus_type = { .name = "scsi", .match = scsi_bus_match, .suspend = scsi_bus_suspend, .resume = scsi_bus_resume, + .shutdown = scsi_bus_shutdown, }; int scsi_sysfs_register(void) diff -urN oldtree/include/linux/libata.h newtree/include/linux/libata.h --- oldtree/include/linux/libata.h 2006-10-05 15:26:55.000000000 -0400 +++ newtree/include/linux/libata.h 2006-10-06 18:14:46.000000000 -0400 @@ -750,6 +750,7 @@ extern int ata_port_offline(struct ata_port *ap); extern int ata_scsi_device_resume(struct scsi_device *); extern int ata_scsi_device_suspend(struct scsi_device *, pm_message_t mesg); +extern int ata_scsi_device_shutdown(struct scsi_device *); extern int ata_host_suspend(struct ata_host *host, pm_message_t mesg); extern void ata_host_resume(struct ata_host *host); extern int ata_ratelimit(void); diff -urN oldtree/include/scsi/scsi_host.h newtree/include/scsi/scsi_host.h --- oldtree/include/scsi/scsi_host.h 2006-10-05 15:26:55.000000000 -0400 +++ newtree/include/scsi/scsi_host.h 2006-10-06 18:14:46.000000000 -0400 @@ -321,6 +321,7 @@ */ int (*resume)(struct scsi_device *); int (*suspend)(struct scsi_device *, pm_message_t state); + int (*shutdown)(struct scsi_device *); /* * Name of proc directory