scsi:stex.c Add reboot support
PATCH v2 3/4 scsi:stex.c Add reboot support
From 5eac0f3209e0857c983c986786a68eac0d67247b Mon Sep 17 00:00:00 2001
From: Charles Chiou <[email protected]>
Date: Wed, 5 Nov 2014 19:29:46 +0800
Subject: [PATCH 3/4] scsi:stex.c Add reboot support
1. Add reboot support, Pegasus devices should be notified that the host is going to shutdown/reboot. I register reboot callback function to distinct host is going to shutdown or to reboot.
2. Pegasus FW shutdown flow is sensitive to host behavior (host is going to S3/S4/shutdown/reboot). To this, I add one argument in stex_hba_stop to support various stop command.
3. For backward compatibility, I used ST_IGNORED variable to specified shutdown should be the old flow.
4. Sometimes Pegasus need to more time to start. Expand delay time from 120 to 240.
--- drivers/scsi/stex.c | 48 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 5 deletions(-)
drivers/scsi/stex.c +43 -5
@@ -24,6 +24,7 @@#include <linux/interrupt.h> #include <linux/types.h> #include <linux/module.h> +#include <linux/reboot.h> #include <linux/spinlock.h> #include <asm/io.h> #include <asm/irq.h>
@@ -86,7 +87,7 @@ enum {MU_STATE_STOP =5 ,MU_STATE_NOCONNECT =6 , -MU_MAX_DELAY =120 , +MU_MAX_DELAY =240 ,MU_HANDSHAKE_SIGNATURE =0x55aaaa55 ,MU_HANDSHAKE_SIGNATURE_HALF =0x5a5a0000 , MU_HARD_RESET_WAIT = 30000,
@@ -166,6 +167,13 @@ enum {ST_ADDITIONAL_MEM =0x200000 ,ST_ADDITIONAL_MEM_MIN =0x80000 , +PMIC_SHUTDOWN =0x0D , +PMIC_REUMSE =0x10 , +ST_IGNORED =-1 , +ST_S3 =3 , +ST_S4 =4 , +ST_S5 =5 , + ST_S6 = 6, }; struct st_sgitem {
@@ -344,6 +352,7 @@ struct st_card_info {u16 sts_count; }; +static int isRestart;static int msi;module_param (msi, int,0 );MODULE_PARM_DESC (msi,"Enable Message Signaled Interrupts(0=off, 1=on)" );
@@ -364,6 +373,14 @@ MODULE_AUTHOR("Ed Lin");MODULE_DESCRIPTION ("Promise Technology SuperTrak EX Controllers" );MODULE_LICENSE ("GPL" );MODULE_VERSION (ST_DRIVER_VERSION ); +static int stex_reboot_callback (struct notifier_block *self, +unsigned long val, +void *data) +{ +if (val ==SYS_RESTART ) + isRestart =1 ; +return NOTIFY_OK ; +}static void stex_gettime (__le64 *time) {
@@ -1563,6 +1580,7 @@ static int stex_probe(struct pci_dev *pdev, const struct pci_device_id *id)u32 subID;int err; + isRestart =0 ; err =pci_enable_device (pdev);if (err)return err;
@@ -1749,7 +1767,7 @@ out_disable:return err; } -static void stex_hba_stop (struct st_hba *hba) +static void stex_hba_stop (struct st_hba *hba,int st_sleep_mic) {struct req_msg *req;struct st_msg_header *msg_h;
@@ -1765,11 +1783,18 @@ static void stex_hba_stop(struct st_hba *hba) }else memset (req,0 , hba->rq_size); -if (hba->cardtype == st_yosemite || hba->cardtype == st_yel) { +if ((hba->cardtype == st_yosemite || hba->cardtype == st_yel) + && st_sleep_mic ==ST_IGNORED ) { req->cdb[0 ] =MGT_CMD ; req->cdb[1 ] =MGT_CMD_SIGNATURE ; req->cdb[2 ] =CTLR_CONFIG_CMD ; req->cdb[3 ] =CTLR_SHUTDOWN ; + }else if (hba->cardtype == st_yel && st_sleep_mic !=ST_IGNORED ) { + req->cdb[0 ] =MGT_CMD ; + req->cdb[1 ] =MGT_CMD_SIGNATURE ; + req->cdb[2 ] =CTLR_CONFIG_CMD ; + req->cdb[3 ] =PMIC_SHUTDOWN ; + req->cdb[4 ] = st_sleep_mic; }else { req->cdb[0 ] =CONTROLLER_CMD ; req->cdb[1 ] =CTLR_POWER_STATE_CHANGE ;
@@ -1789,10 +1814,12 @@ static void stex_hba_stop(struct st_hba *hba)while (hba->ccb[tag].req_type &PASSTHRU_REQ_TYPE ) {if (time_after (jiffies, before +ST_INTERNAL_TIMEOUT *HZ )) { hba->ccb[tag].req_type =0 ; + hba->mu_status =MU_STATE_STOP ;return ; }msleep (1 ); } + hba->mu_status =MU_STATE_STOP ; }static void stex_hba_free (struct st_hba *hba)
@@ -1832,7 +1859,14 @@ static void stex_shutdown(struct pci_dev *pdev) {struct st_hba *hba =pci_get_drvdata (pdev); -stex_hba_stop (hba); +if (hba->yellowstone ==1 ) +stex_hba_stop (hba,ST_IGNORED ); +else { +if (isRestart) +stex_hba_stop (hba,ST_S6 ); +else +stex_hba_stop (hba,ST_S5 ); + } }MODULE_DEVICE_TABLE (pci, stex_pci_tbl);
@@ -1845,18 +1879,22 @@ static struct pci_driver stex_pci_driver = { .shutdown = stex_shutdown, }; +static struct notifier_block stex_reboot_notifier = { + stex_reboot_callback,NULL ,0 +};static int __init stex_init (void ) { printk(KERN_INFO DRV_NAME": Promise SuperTrak EX Driver version: %s\n" , ST_DRIVER_VERSION); - +register_reboot_notifier (&stex_reboot_notifier);return pci_register_driver (&stex_pci_driver); } static void __exit stex_exit(void) {pci_unregister_driver (&stex_pci_driver); +unregister_reboot_notifier (&stex_reboot_notifier); }module_init (stex_init);
Signature · 1 line
1.9.1
Quoted 12 lines
drivers/scsi/stex.c +8
-0+static int stex_reboot_callback (struct notifier_block *self, +unsigned long val, +void *data) +{ +if (val ==SYS_RESTART ) + isRestart =1 ; +return NOTIFY_OK ; +}@@ -1832,7 +1859,14 @@ static void stex_shutdown(struct pci_dev *pdev) {struct st_hba *hba =pci_get_drvdata (pdev);
drivers/scsi/stex.c static void stex_shutdown(struct pci_dev *pdev) · line 1869
Quoted 10 lines
drivers/scsi/stex.c +8
-1-stex_hba_stop (hba); +if (hba->yellowstone ==1 ) +stex_hba_stop (hba,ST_IGNORED ); +else { +if (isRestart) +stex_hba_stop (hba,ST_S6 ); +else +stex_hba_stop (hba,ST_S5 ); + }
This sort of check for reboot vs restart isn't really something we want in drivers. I don't really know how we could find this out assuming we even want drivers to behave differently.
Maybe Greg or someone on lkml has an idea how to best handle this case.
Quoted 27 lines · Christoph Hellwig
Quoted 12 lines
drivers/scsi/stex.c +8
-0+static int stex_reboot_callback (struct notifier_block *self, +unsigned long val, +void *data) +{ +if (val ==SYS_RESTART ) + isRestart =1 ; +return NOTIFY_OK ; +}@@ -1832,7 +1859,14 @@ static void stex_shutdown(struct pci_dev *pdev) {struct st_hba *hba =pci_get_drvdata (pdev);drivers/scsi/stex.c static void stex_shutdown(struct pci_dev *pdev) · line 1869
Quoted 10 lines
drivers/scsi/stex.c +8
-1-stex_hba_stop (hba); +if (hba->yellowstone ==1 ) +stex_hba_stop (hba,ST_IGNORED ); +else { +if (isRestart) +stex_hba_stop (hba,ST_S6 ); +else +stex_hba_stop (hba,ST_S5 ); + }This sort of check for reboot vs restart isn't really something we want in drivers. I don't really know how we could find this out assuming we even want drivers to behave differently.
Quoted 2 lines
Maybe Greg or someone on lkml has an idea how to best handle this case.
I have no idea to distinguish OS is going to reboot or shut down without this approach. I'll try to find it out. Charles
Quoted 30 lines · Charles Chiou
Quoted 27 lines · Christoph Hellwig
Quoted 12 lines
drivers/scsi/stex.c +8
-0+static int stex_reboot_callback (struct notifier_block *self, +unsigned long val, +void *data) +{ +if (val ==SYS_RESTART ) + isRestart =1 ; +return NOTIFY_OK ; +}@@ -1832,7 +1859,14 @@ static void stex_shutdown(struct pci_dev *pdev) {struct st_hba *hba =pci_get_drvdata (pdev);drivers/scsi/stex.c static void stex_shutdown(struct pci_dev *pdev) · line 1869
Quoted 10 lines
drivers/scsi/stex.c +8
-1-stex_hba_stop (hba); +if (hba->yellowstone ==1 ) +stex_hba_stop (hba,ST_IGNORED ); +else { +if (isRestart) +stex_hba_stop (hba,ST_S6 ); +else +stex_hba_stop (hba,ST_S5 ); + }This sort of check for reboot vs restart isn't really something we want in drivers. I don't really know how we could find this out assuming we even want drivers to behave differently.
Quoted 1 line
Quoted 1 line
Maybe Greg or someone on lkml has an idea how to best handle this case.
Hi, we don't attempt to check for restart vs reboot,
sorry for confusing. When host is going to restart/reboot, Pegasus need to restart too. Pegasus use same flow for restart and reboot.
Maybe I could change variable name "isRestart" to "isReboot"?
Quoted 27 lines · Christoph Hellwig
Quoted 12 lines
drivers/scsi/stex.c +8
-0+static int stex_reboot_callback (struct notifier_block *self, +unsigned long val, +void *data) +{ +if (val ==SYS_RESTART ) + isRestart =1 ; +return NOTIFY_OK ; +}@@ -1832,7 +1859,14 @@ static void stex_shutdown(struct pci_dev *pdev) {struct st_hba *hba =pci_get_drvdata (pdev);drivers/scsi/stex.c static void stex_shutdown(struct pci_dev *pdev) · line 1869
Quoted 10 lines
drivers/scsi/stex.c +8
-1-stex_hba_stop (hba); +if (hba->yellowstone ==1 ) +stex_hba_stop (hba,ST_IGNORED ); +else { +if (isRestart) +stex_hba_stop (hba,ST_S6 ); +else +stex_hba_stop (hba,ST_S5 ); + }This sort of check for reboot vs restart isn't really something we want in drivers. I don't really know how we could find this out assuming we even want drivers to behave differently.
Quoted 1 line
Maybe Greg or someone on lkml has an idea how to best handle this case.
What is "this case"?
And yes, I agree, we shouldn't care, in drivers, about reboot vs. restart, as they should both be the same thing, along with "disconnect", right?
thanks,
greg k-h