+/*driver power management handler for pm_ops*/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32))
+static int ssd_hio_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+#else
+static int ssd_hio_suspend(struct device *ddev)
+{
+ struct pci_dev *pdev = to_pci_dev(ddev);
+#endif
+ struct ssd_device *dev;
+
+
+ if (!pdev) {
+ return -EINVAL;
+ }
+
+ dev = pci_get_drvdata(pdev);
+ if (!dev) {
+ return -EINVAL;
+ }
+
+ hio_warn("%s: suspend disk start.\n", dev->name);
+ ssd_unregister_sysfs(dev);
+
+ /* offline firstly */
+ test_and_clear_bit(SSD_ONLINE, &dev->state);
+
+ /* clean work queue first */
+ if (!dev->slave) {
+ test_and_clear_bit(SSD_INIT_WORKQ, &dev->state);
+ ssd_cleanup_workq(dev);
+ }
+
+ /* flush cache */
+ (void)ssd_flush(dev);
+ (void)ssd_save_md(dev);
+
+ /* save smart */
+ if (!dev->slave) {
+ ssd_save_smart(dev);
+ }
+
+ /* clean routine */
+ if (!dev->slave) {
+ ssd_cleanup_routine(dev);
+ }
+
+ ssd_cleanup_thread(dev);
+
+ ssd_free_irq(dev);
+
+ if (!dev->slave) {
+ ssd_cleanup_log(dev);
+ }
+
+ if (dev->reload_fw) { //reload fw
+ ssd_reg32_write(dev->ctrlp + SSD_RELOAD_FW_REG, SSD_RELOAD_FW);
+ }
+
+ /* unmap physical adress */
+ if (dev->ctrlp) {
+#ifdef LINUX_SUSE_OS
+ iounmap(dev->ctrlp);
+#else
+ pci_iounmap(pdev, dev->ctrlp);
+#endif
+ dev->ctrlp = NULL;
+ }
+
+ if (dev->mmio_base) {
+ release_mem_region(dev->mmio_base, dev->mmio_len);
+ dev->mmio_base = 0;
+ }
+
+ pci_disable_device(pdev);
+
+ hio_warn("%s: suspend disk finish.\n", dev->name);
+
+ return 0;
+}
+
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32))
+static int ssd_hio_resume(struct pci_dev *pdev)
+{
+#else
+static int ssd_hio_resume(struct device *ddev)
+{
+ struct pci_dev *pdev = to_pci_dev(ddev);
+#endif
+ struct ssd_device *dev = NULL;
+ int ret = 0;
+
+ if (!pdev ) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ dev = pci_get_drvdata(pdev);
+ if (!dev) {
+ ret = -ENOMEM;
+ goto out_alloc_dev;
+ }
+
+ hio_warn("%s: resume disk start.\n", dev->name);
+ ret = pci_enable_device(pdev);
+ if (ret) {
+ hio_warn("%s: can not enable device\n", dev->name);
+ goto out_enable_device;
+ }
+
+ pci_set_master(pdev);
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31))
+ ret = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
+#else
+ ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
+#endif
+ if (ret) {
+ hio_warn("%s: set dma mask: failed\n", dev->name);
+ goto out_set_dma_mask;
+ }
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31))
+ ret = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+#else
+ ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
+#endif
+ if (ret) {
+ hio_warn("%s: set consistent dma mask: failed\n", dev->name);
+ goto out_set_dma_mask;
+ }
+
+ dev->mmio_base = pci_resource_start(pdev, 0);
+ dev->mmio_len = pci_resource_len(pdev, 0);
+
+ if (!request_mem_region(dev->mmio_base, dev->mmio_len, SSD_DEV_NAME)) {
+ hio_warn("%s: can not reserve MMIO region 0\n", dev->name);
+ ret = -EBUSY;
+ goto out_request_mem_region;
+ }
+
+ /* 2.6.9 kernel bug */
+ dev->ctrlp = pci_iomap(pdev, 0, 0);
+ if (!dev->ctrlp) {
+ hio_warn("%s: can not remap IO region 0\n", dev->name);
+ ret = -ENOMEM;
+ goto out_pci_iomap;
+ }
+
+ ret = ssd_check_hw(dev);
+ if (ret) {
+ hio_err("%s: check hardware failed\n", dev->name);
+ goto out_check_hw;
+ }
+
+ /* alarm led ? */
+ ssd_clear_alarm(dev);
+
+ ret = ssd_init_fw_info(dev);
+ if (ret) {
+ hio_err("%s: init firmware info failed\n", dev->name);
+ /* alarm led */
+ ssd_set_alarm(dev);
+ goto out_init_fw_info;
+ }
+
+ /* slave port ? */
+ if (dev->slave) {
+ goto init_next1;
+ }
+
+ ret = ssd_init_rom_info(dev);
+ if (ret) {
+ hio_err("%s: init rom info failed\n", dev->name);
+ /* alarm led */
+ ssd_set_alarm(dev);
+ goto out_init_rom_info;
+ }
+
+ ret = ssd_init_label(dev);
+ if (ret) {
+ hio_err("%s: init label failed\n", dev->name);
+ /* alarm led */
+ ssd_set_alarm(dev);
+ goto out_init_label;
+ }
+
+ ret = ssd_init_workq(dev);
+ if (ret) {
+ hio_warn("%s: init workq failed\n", dev->name);
+ goto out_init_workq;
+ }
+ (void)test_and_set_bit(SSD_INIT_WORKQ, &dev->state);
+
+ ret = ssd_init_log(dev);
+ if (ret) {
+ hio_err("%s: init log failed\n", dev->name);
+ /* alarm led */
+ ssd_set_alarm(dev);
+ goto out_init_log;
+ }
+
+ ret = ssd_init_smart(dev);
+ if (ret) {
+ hio_err("%s: init info failed\n", dev->name);
+ /* alarm led */
+ ssd_set_alarm(dev);
+ goto out_init_smart;
+ }
+
+init_next1:
+ ret = ssd_init_hw_info(dev);
+ if (ret) {
+ hio_err("%s: init hardware info failed\n", dev->name);
+ /* alarm led */
+ ssd_set_alarm(dev);
+ goto out_init_hw_info;
+ }
+
+ /* slave port ? */
+ if (dev->slave) {
+ goto init_next2;
+ }
+
+ ret = ssd_init_sensor(dev);
+ if (ret) {
+ hio_err("%s: init sensor failed\n", dev->name);
+ /* alarm led */
+ ssd_set_alarm(dev);
+ goto out_init_sensor;
+ }
+
+ ret = ssd_init_pl_cap(dev);
+ if (ret) {
+ hio_err("%s: int pl_cap failed\n", dev->name);
+ /* alarm led */
+ ssd_set_alarm(dev);
+ goto out_init_pl_cap;
+ }
+
+init_next2:
+ ret = ssd_check_init_state(dev);
+ if (ret) {
+ hio_err("%s: check init state failed\n", dev->name);
+ /* alarm led */
+ ssd_set_alarm(dev);
+ goto out_check_init_state;
+ }
+
+ //flush all base pointer to ssd
+ (void)ssd_reload_ssd_ptr(dev);
+
+ ret = ssd_init_irq(dev);
+ if (ret) {
+ hio_warn("%s: init irq failed\n", dev->name);
+ goto out_init_irq;
+ }
+
+ ret = ssd_init_thread(dev);
+ if (ret) {
+ hio_warn("%s: init thread failed\n", dev->name);
+ goto out_init_thread;
+ }
+
+ /* */
+ (void)test_and_set_bit(SSD_ONLINE, &dev->state);
+
+ /* slave port ? */
+ if (dev->slave) {
+ goto init_next3;
+ }
+
+ ret = ssd_init_ot_protect(dev);
+ if (ret) {
+ hio_err("%s: int ot_protect failed\n", dev->name);
+ /* alarm led */
+ ssd_set_alarm(dev);
+ goto out_int_ot_protect;
+ }
+
+ ret = ssd_init_wmode(dev);
+ if (ret) {
+ hio_warn("%s: init write mode\n", dev->name);
+ goto out_init_wmode;
+ }
+
+ /* init routine after hw is ready */
+ ret = ssd_init_routine(dev);
+ if (ret) {
+ hio_warn("%s: init routine\n", dev->name);
+ goto out_init_routine;
+ }
+
+init_next3:
+ (void)test_and_set_bit(SSD_INIT_BD, &dev->state);
+
+ dev->save_md = 1;
+
+ hio_warn("%s: resume disk finish.\n", dev->name);
+
+ return 0;
+
+out_init_routine:
+out_init_wmode:
+out_int_ot_protect:
+ ssd_cleanup_thread(dev);
+out_init_thread:
+ ssd_free_irq(dev);
+out_init_irq:
+out_check_init_state:
+out_init_pl_cap:
+out_init_sensor:
+out_init_hw_info:
+out_init_smart:
+ /* slave port ? */
+ if (!dev->slave) {
+ ssd_cleanup_log(dev);
+ }
+out_init_log:
+ /* slave port ? */
+ if (!dev->slave) {
+ test_and_clear_bit(SSD_INIT_WORKQ, &dev->state);
+ ssd_cleanup_workq(dev);
+ }
+out_init_workq:
+out_init_label:
+out_init_rom_info:
+out_init_fw_info:
+out_check_hw:
+#ifdef LINUX_SUSE_OS
+ iounmap(dev->ctrlp);
+#else
+ pci_iounmap(pdev, dev->ctrlp);
+#endif
+out_pci_iomap:
+ release_mem_region(dev->mmio_base, dev->mmio_len);
+out_request_mem_region:
+out_set_dma_mask:
+ pci_disable_device(pdev);
+out_enable_device:
+out_alloc_dev:
+out:
+
+ hio_warn("%s: resume disk fail.\n", dev->name);
+
+ return ret;
+}
+
+MODULE_DEVICE_TABLE(pci, ssd_pci_tbl);
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32))
+#else
+SIMPLE_DEV_PM_OPS(hio_pm_ops, ssd_hio_suspend, ssd_hio_resume);
+#endif
+
+MODULE_DEVICE_TABLE(pci, ssd_pci_tbl);
+struct pci_driver ssd_driver = {
+ .name = MODULE_NAME,
+ .id_table = ssd_pci_tbl,
+ .probe = ssd_init_one,
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38))
+ .remove = __devexit_p(ssd_remove_one),