aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/megaraid
diff options
context:
space:
mode:
authorYang, Bo <Bo.Yang@lsi.com>2009-10-06 16:47:35 -0400
committerJames Bottomley <James.Bottomley@suse.de>2009-10-29 13:03:21 -0400
commit0c79e681eef10810a5ed41a2eb1dce244ab1c37d (patch)
treec6b389d9acafd043ddbc5b8ea159f1ee1d4fc899 /drivers/scsi/megaraid
parentf4c9a1317d32bb0af7546ef0c1dcc3be52dc8d0a (diff)
[SCSI] megaraid_sas: Fix the fix for fw hang caused by megaraid sas application
Add a lock to the skinny firmware initialisation sequence to prevent the two stage write being non atomic if multiple instances use it. Add a flag to the driver shutdown sequence to prevent aen ioctls being called after shutdown begins. Signed-off-by Bo Yang<bo.yang@lsi.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/megaraid')
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.c75
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.h25
2 files changed, 77 insertions, 23 deletions
diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c
index 4c04a68bad6c..6d998e050338 100644
--- a/drivers/scsi/megaraid/megaraid_sas.c
+++ b/drivers/scsi/megaraid/megaraid_sas.c
@@ -226,7 +226,10 @@ megasas_clear_intr_xscale(struct megasas_register_set __iomem * regs)
226 * @regs : MFI register set 226 * @regs : MFI register set
227 */ 227 */
228static inline void 228static inline void
229megasas_fire_cmd_xscale(dma_addr_t frame_phys_addr,u32 frame_count, struct megasas_register_set __iomem *regs) 229megasas_fire_cmd_xscale(struct megasas_instance *instance,
230 dma_addr_t frame_phys_addr,
231 u32 frame_count,
232 struct megasas_register_set __iomem *regs)
230{ 233{
231 writel((frame_phys_addr >> 3)|(frame_count), 234 writel((frame_phys_addr >> 3)|(frame_count),
232 &(regs)->inbound_queue_port); 235 &(regs)->inbound_queue_port);
@@ -323,7 +326,10 @@ megasas_clear_intr_ppc(struct megasas_register_set __iomem * regs)
323 * @regs : MFI register set 326 * @regs : MFI register set
324 */ 327 */
325static inline void 328static inline void
326megasas_fire_cmd_ppc(dma_addr_t frame_phys_addr, u32 frame_count, struct megasas_register_set __iomem *regs) 329megasas_fire_cmd_ppc(struct megasas_instance *instance,
330 dma_addr_t frame_phys_addr,
331 u32 frame_count,
332 struct megasas_register_set __iomem *regs)
327{ 333{
328 writel((frame_phys_addr | (frame_count<<1))|1, 334 writel((frame_phys_addr | (frame_count<<1))|1,
329 &(regs)->inbound_queue_port); 335 &(regs)->inbound_queue_port);
@@ -413,12 +419,17 @@ megasas_clear_intr_skinny(struct megasas_register_set __iomem *regs)
413 * @regs : MFI register set 419 * @regs : MFI register set
414 */ 420 */
415static inline void 421static inline void
416megasas_fire_cmd_skinny(dma_addr_t frame_phys_addr, u32 frame_count, 422megasas_fire_cmd_skinny(struct megasas_instance *instance,
423 dma_addr_t frame_phys_addr,
424 u32 frame_count,
417 struct megasas_register_set __iomem *regs) 425 struct megasas_register_set __iomem *regs)
418{ 426{
427 unsigned long flags;
428 spin_lock_irqsave(&instance->fire_lock, flags);
419 writel(0, &(regs)->inbound_high_queue_port); 429 writel(0, &(regs)->inbound_high_queue_port);
420 writel((frame_phys_addr | (frame_count<<1))|1, 430 writel((frame_phys_addr | (frame_count<<1))|1,
421 &(regs)->inbound_low_queue_port); 431 &(regs)->inbound_low_queue_port);
432 spin_unlock_irqrestore(&instance->fire_lock, flags);
422} 433}
423 434
424static struct megasas_instance_template megasas_instance_template_skinny = { 435static struct megasas_instance_template megasas_instance_template_skinny = {
@@ -508,7 +519,9 @@ megasas_clear_intr_gen2(struct megasas_register_set __iomem *regs)
508 * @regs : MFI register set 519 * @regs : MFI register set
509 */ 520 */
510static inline void 521static inline void
511megasas_fire_cmd_gen2(dma_addr_t frame_phys_addr, u32 frame_count, 522megasas_fire_cmd_gen2(struct megasas_instance *instance,
523 dma_addr_t frame_phys_addr,
524 u32 frame_count,
512 struct megasas_register_set __iomem *regs) 525 struct megasas_register_set __iomem *regs)
513{ 526{
514 writel((frame_phys_addr | (frame_count<<1))|1, 527 writel((frame_phys_addr | (frame_count<<1))|1,
@@ -550,7 +563,8 @@ megasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd)
550 /* 563 /*
551 * Issue the frame using inbound queue port 564 * Issue the frame using inbound queue port
552 */ 565 */
553 instance->instancet->fire_cmd(cmd->frame_phys_addr ,0,instance->reg_set); 566 instance->instancet->fire_cmd(instance,
567 cmd->frame_phys_addr, 0, instance->reg_set);
554 568
555 /* 569 /*
556 * Wait for cmd_status to change 570 * Wait for cmd_status to change
@@ -581,7 +595,8 @@ megasas_issue_blocked_cmd(struct megasas_instance *instance,
581{ 595{
582 cmd->cmd_status = ENODATA; 596 cmd->cmd_status = ENODATA;
583 597
584 instance->instancet->fire_cmd(cmd->frame_phys_addr ,0,instance->reg_set); 598 instance->instancet->fire_cmd(instance,
599 cmd->frame_phys_addr, 0, instance->reg_set);
585 600
586 wait_event_timeout(instance->int_cmd_wait_q, (cmd->cmd_status != ENODATA), 601 wait_event_timeout(instance->int_cmd_wait_q, (cmd->cmd_status != ENODATA),
587 MEGASAS_INTERNAL_CMD_WAIT_TIME*HZ); 602 MEGASAS_INTERNAL_CMD_WAIT_TIME*HZ);
@@ -626,7 +641,8 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
626 cmd->sync_cmd = 1; 641 cmd->sync_cmd = 1;
627 cmd->cmd_status = 0xFF; 642 cmd->cmd_status = 0xFF;
628 643
629 instance->instancet->fire_cmd(cmd->frame_phys_addr ,0,instance->reg_set); 644 instance->instancet->fire_cmd(instance,
645 cmd->frame_phys_addr, 0, instance->reg_set);
630 646
631 /* 647 /*
632 * Wait for this cmd to complete 648 * Wait for this cmd to complete
@@ -1153,7 +1169,8 @@ megasas_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *))
1153 */ 1169 */
1154 atomic_inc(&instance->fw_outstanding); 1170 atomic_inc(&instance->fw_outstanding);
1155 1171
1156 instance->instancet->fire_cmd(cmd->frame_phys_addr ,cmd->frame_count-1,instance->reg_set); 1172 instance->instancet->fire_cmd(instance, cmd->frame_phys_addr,
1173 cmd->frame_count-1, instance->reg_set);
1157 /* 1174 /*
1158 * Check if we have pend cmds to be completed 1175 * Check if we have pend cmds to be completed
1159 */ 1176 */
@@ -1346,8 +1363,16 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
1346 * Send signal to FW to stop processing any pending cmds. 1363 * Send signal to FW to stop processing any pending cmds.
1347 * The controller will be taken offline by the OS now. 1364 * The controller will be taken offline by the OS now.
1348 */ 1365 */
1349 writel(MFI_STOP_ADP, 1366 if ((instance->pdev->device ==
1367 PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
1368 (instance->pdev->device ==
1369 PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
1370 writel(MFI_STOP_ADP,
1371 &instance->reg_set->reserved_0[0]);
1372 } else {
1373 writel(MFI_STOP_ADP,
1350 &instance->reg_set->inbound_doorbell); 1374 &instance->reg_set->inbound_doorbell);
1375 }
1351 megasas_dump_pending_frames(instance); 1376 megasas_dump_pending_frames(instance);
1352 instance->hw_crit_error = 1; 1377 instance->hw_crit_error = 1;
1353 return FAILED; 1378 return FAILED;
@@ -1799,7 +1824,7 @@ megasas_transition_to_ready(struct megasas_instance* instance)
1799 /* 1824 /*
1800 * Set the CLR bit in inbound doorbell 1825 * Set the CLR bit in inbound doorbell
1801 */ 1826 */
1802 if ((instance->pdev->device == \ 1827 if ((instance->pdev->device ==
1803 PCI_DEVICE_ID_LSI_SAS0073SKINNY) || 1828 PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
1804 (instance->pdev->device == 1829 (instance->pdev->device ==
1805 PCI_DEVICE_ID_LSI_SAS0071SKINNY)) { 1830 PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
@@ -2799,7 +2824,8 @@ megasas_register_aen(struct megasas_instance *instance, u32 seq_num,
2799 /* 2824 /*
2800 * Issue the aen registration frame 2825 * Issue the aen registration frame
2801 */ 2826 */
2802 instance->instancet->fire_cmd(cmd->frame_phys_addr ,0,instance->reg_set); 2827 instance->instancet->fire_cmd(instance,
2828 cmd->frame_phys_addr, 0, instance->reg_set);
2803 2829
2804 return 0; 2830 return 0;
2805} 2831}
@@ -2983,6 +3009,7 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
2983 init_waitqueue_head(&instance->abort_cmd_wait_q); 3009 init_waitqueue_head(&instance->abort_cmd_wait_q);
2984 3010
2985 spin_lock_init(&instance->cmd_pool_lock); 3011 spin_lock_init(&instance->cmd_pool_lock);
3012 spin_lock_init(&instance->fire_lock);
2986 spin_lock_init(&instance->completion_lock); 3013 spin_lock_init(&instance->completion_lock);
2987 spin_lock_init(&poll_aen_lock); 3014 spin_lock_init(&poll_aen_lock);
2988 3015
@@ -3005,7 +3032,7 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
3005 3032
3006 megasas_dbg_lvl = 0; 3033 megasas_dbg_lvl = 0;
3007 instance->flag = 0; 3034 instance->flag = 0;
3008 instance->unload = 0; 3035 instance->unload = 1;
3009 instance->last_time = 0; 3036 instance->last_time = 0;
3010 3037
3011 /* 3038 /*
@@ -3051,6 +3078,7 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
3051 if (megasas_io_attach(instance)) 3078 if (megasas_io_attach(instance))
3052 goto fail_io_attach; 3079 goto fail_io_attach;
3053 3080
3081 instance->unload = 0;
3054 return 0; 3082 return 0;
3055 3083
3056 fail_start_aen: 3084 fail_start_aen:
@@ -3174,6 +3202,7 @@ megasas_suspend(struct pci_dev *pdev, pm_message_t state)
3174 3202
3175 instance = pci_get_drvdata(pdev); 3203 instance = pci_get_drvdata(pdev);
3176 host = instance->host; 3204 host = instance->host;
3205 instance->unload = 1;
3177 3206
3178 if (poll_mode_io) 3207 if (poll_mode_io)
3179 del_timer_sync(&instance->io_completion_timer); 3208 del_timer_sync(&instance->io_completion_timer);
@@ -3269,6 +3298,8 @@ megasas_resume(struct pci_dev *pdev)
3269 megasas_start_timer(instance, &instance->io_completion_timer, 3298 megasas_start_timer(instance, &instance->io_completion_timer,
3270 megasas_io_completion_timer, 3299 megasas_io_completion_timer,
3271 MEGASAS_COMPLETION_TIMER_INTERVAL); 3300 MEGASAS_COMPLETION_TIMER_INTERVAL);
3301 instance->unload = 0;
3302
3272 return 0; 3303 return 0;
3273 3304
3274fail_irq: 3305fail_irq:
@@ -3366,6 +3397,7 @@ static void __devexit megasas_detach_one(struct pci_dev *pdev)
3366static void megasas_shutdown(struct pci_dev *pdev) 3397static void megasas_shutdown(struct pci_dev *pdev)
3367{ 3398{
3368 struct megasas_instance *instance = pci_get_drvdata(pdev); 3399 struct megasas_instance *instance = pci_get_drvdata(pdev);
3400 instance->unload = 1;
3369 megasas_flush_cache(instance); 3401 megasas_flush_cache(instance);
3370 megasas_shutdown_controller(instance, MR_DCMD_CTRL_SHUTDOWN); 3402 megasas_shutdown_controller(instance, MR_DCMD_CTRL_SHUTDOWN);
3371} 3403}
@@ -3615,6 +3647,17 @@ static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg)
3615 goto out_kfree_ioc; 3647 goto out_kfree_ioc;
3616 } 3648 }
3617 3649
3650 if (instance->hw_crit_error == 1) {
3651 printk(KERN_DEBUG "Controller in Crit ERROR\n");
3652 error = -ENODEV;
3653 goto out_kfree_ioc;
3654 }
3655
3656 if (instance->unload == 1) {
3657 error = -ENODEV;
3658 goto out_kfree_ioc;
3659 }
3660
3618 /* 3661 /*
3619 * We will allow only MEGASAS_INT_CMDS number of parallel ioctl cmds 3662 * We will allow only MEGASAS_INT_CMDS number of parallel ioctl cmds
3620 */ 3663 */
@@ -3650,6 +3693,14 @@ static int megasas_mgmt_ioctl_aen(struct file *file, unsigned long arg)
3650 if (!instance) 3693 if (!instance)
3651 return -ENODEV; 3694 return -ENODEV;
3652 3695
3696 if (instance->hw_crit_error == 1) {
3697 error = -ENODEV;
3698 }
3699
3700 if (instance->unload == 1) {
3701 return -ENODEV;
3702 }
3703
3653 mutex_lock(&instance->aen_mutex); 3704 mutex_lock(&instance->aen_mutex);
3654 error = megasas_register_aen(instance, aen.seq_num, 3705 error = megasas_register_aen(instance, aen.seq_num,
3655 aen.class_locale_word); 3706 aen.class_locale_word);
diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
index a1fd44bc1817..13ac37e80075 100644
--- a/drivers/scsi/megaraid/megaraid_sas.h
+++ b/drivers/scsi/megaraid/megaraid_sas.h
@@ -1157,17 +1157,6 @@ struct megasas_evt_detail {
1157 1157
1158} __attribute__ ((packed)); 1158} __attribute__ ((packed));
1159 1159
1160 struct megasas_instance_template {
1161 void (*fire_cmd)(dma_addr_t ,u32 ,struct megasas_register_set __iomem *);
1162
1163 void (*enable_intr)(struct megasas_register_set __iomem *) ;
1164 void (*disable_intr)(struct megasas_register_set __iomem *);
1165
1166 int (*clear_intr)(struct megasas_register_set __iomem *);
1167
1168 u32 (*read_fw_status_reg)(struct megasas_register_set __iomem *);
1169 };
1170
1171struct megasas_instance { 1160struct megasas_instance {
1172 1161
1173 u32 *producer; 1162 u32 *producer;
@@ -1193,6 +1182,8 @@ struct megasas_instance {
1193 spinlock_t cmd_pool_lock; 1182 spinlock_t cmd_pool_lock;
1194 /* used to synch producer, consumer ptrs in dpc */ 1183 /* used to synch producer, consumer ptrs in dpc */
1195 spinlock_t completion_lock; 1184 spinlock_t completion_lock;
1185 /* used to sync fire the cmd to fw */
1186 spinlock_t fire_lock;
1196 struct dma_pool *frame_dma_pool; 1187 struct dma_pool *frame_dma_pool;
1197 struct dma_pool *sense_dma_pool; 1188 struct dma_pool *sense_dma_pool;
1198 1189
@@ -1224,6 +1215,18 @@ struct megasas_instance {
1224 struct timer_list io_completion_timer; 1215 struct timer_list io_completion_timer;
1225}; 1216};
1226 1217
1218struct megasas_instance_template {
1219 void (*fire_cmd)(struct megasas_instance *, dma_addr_t, \
1220 u32, struct megasas_register_set __iomem *);
1221
1222 void (*enable_intr)(struct megasas_register_set __iomem *) ;
1223 void (*disable_intr)(struct megasas_register_set __iomem *);
1224
1225 int (*clear_intr)(struct megasas_register_set __iomem *);
1226
1227 u32 (*read_fw_status_reg)(struct megasas_register_set __iomem *);
1228};
1229
1227#define MEGASAS_IS_LOGICAL(scp) \ 1230#define MEGASAS_IS_LOGICAL(scp) \
1228 (scp->device->channel < MEGASAS_MAX_PD_CHANNELS) ? 0 : 1 1231 (scp->device->channel < MEGASAS_MAX_PD_CHANNELS) ? 0 : 1
1229 1232