1. Add S3/S4 support, add .suspend and .resume function in pci_driver. 2. Pegasus take some to init, I create one thread to finish handshake to make OS can start faster. 3. According to (2), OS might send command to driver before handshake. Return SCSI_MLQUEUE_HOST_BUSY. --- drivers/scsi/stex.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c index 7a66a931..1e0b37e 100644 --- a/drivers/scsi/stex.c +++ b/drivers/scsi/stex.c @@ -369,6 +369,10 @@ static const char console_inq_page[] = 0x0C,0x20,0x20,0x20,0x20,0x20,0x20,0x20 }; +struct hba_handshake_workstruct { + struct st_hba *hba; + struct work_struct handshake_work; +}; MODULE_AUTHOR("Ed Lin"); MODULE_DESCRIPTION("Promise Technology SuperTrak EX Controllers"); MODULE_LICENSE("GPL"); @@ -630,7 +634,7 @@ stex_queuecommand_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) done(cmd); return 0; } - if (unlikely(hba->mu_status == MU_STATE_RESETTING)) + if (unlikely(hba->mu_status != MU_STATE_STARTED)) return SCSI_MLQUEUE_HOST_BUSY; switch (cmd->cmnd[0]) { @@ -1396,6 +1400,17 @@ static void stex_reset_work(struct work_struct *work) stex_do_reset(hba); } +static void resume_handshake(struct work_struct *work) +{ + struct st_hba *hba; + struct hba_handshake_workstruct *hswork; + + hswork = container_of(work, + struct hba_handshake_workstruct, + handshake_work); + hba = hswork->hba; + stex_handshake(hba); +} static int stex_biosparam(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int geom[]) @@ -1869,6 +1884,44 @@ static void stex_shutdown(struct pci_dev *pdev) } } +static int stex_choice_sleep_MIC(pm_message_t state) +{ + switch (state.event) { + case PM_EVENT_SUSPEND: + return ST_S3; + case PM_EVENT_FREEZE: + case PM_EVENT_HIBERNATE: + return ST_S4; + default: + return ST_S4; + } +} + +static int stex_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct st_hba *hba = pci_get_drvdata(pdev); + + if (hba->cardtype == st_yel && hba->yellowstone == 0) + stex_hba_stop(hba, stex_choice_sleep_MIC(state)); + else + stex_hba_stop(hba, ST_IGNORED); + return 0; +} + + +static int stex_resume(struct pci_dev *pdev) +{ + struct st_hba *hba = pci_get_drvdata(pdev); + struct hba_handshake_workstruct *hswork; + int sts; + + + hswork = kzalloc(sizeof(struct hba_handshake_workstruct), GFP_KERNEL); + INIT_WORK(&hswork->handshake_work, resume_handshake); + hswork->hba = hba; + sts = schedule_work(&hswork->handshake_work); + return 0; +} MODULE_DEVICE_TABLE(pci, stex_pci_tbl); static struct pci_driver stex_pci_driver = { @@ -1877,6 +1930,8 @@ static struct pci_driver stex_pci_driver = { .probe = stex_probe, .remove = stex_remove, .shutdown = stex_shutdown, + .suspend = stex_suspend, + .resume = stex_resume, }; static struct notifier_block stex_reboot_notifier = { -- ?頨{.n?????%??橆??w?{.n???{殺??孜?雰}?笙??j:+v??茶庫全?2??霅??腄冠嗓??z蹂z嫡?+???▏?w噮f