diff options
-rw-r--r-- | drivers/scsi/megaraid/megaraid_sas.c | 756 | ||||
-rw-r--r-- | drivers/scsi/megaraid/megaraid_sas.h | 88 |
2 files changed, 787 insertions, 57 deletions
diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c index 99e4478c3f3..55951f4d326 100644 --- a/drivers/scsi/megaraid/megaraid_sas.c +++ b/drivers/scsi/megaraid/megaraid_sas.c | |||
@@ -62,6 +62,11 @@ MODULE_VERSION(MEGASAS_VERSION); | |||
62 | MODULE_AUTHOR("megaraidlinux@lsi.com"); | 62 | MODULE_AUTHOR("megaraidlinux@lsi.com"); |
63 | MODULE_DESCRIPTION("LSI MegaRAID SAS Driver"); | 63 | MODULE_DESCRIPTION("LSI MegaRAID SAS Driver"); |
64 | 64 | ||
65 | static int megasas_transition_to_ready(struct megasas_instance *instance); | ||
66 | static int megasas_get_pd_list(struct megasas_instance *instance); | ||
67 | static int megasas_issue_init_mfi(struct megasas_instance *instance); | ||
68 | static int megasas_register_aen(struct megasas_instance *instance, | ||
69 | u32 seq_num, u32 class_locale_word); | ||
65 | /* | 70 | /* |
66 | * PCI ID table for all supported controllers | 71 | * PCI ID table for all supported controllers |
67 | */ | 72 | */ |
@@ -164,7 +169,7 @@ megasas_return_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd) | |||
164 | static inline void | 169 | static inline void |
165 | megasas_enable_intr_xscale(struct megasas_register_set __iomem * regs) | 170 | megasas_enable_intr_xscale(struct megasas_register_set __iomem * regs) |
166 | { | 171 | { |
167 | writel(1, &(regs)->outbound_intr_mask); | 172 | writel(0, &(regs)->outbound_intr_mask); |
168 | 173 | ||
169 | /* Dummy readl to force pci flush */ | 174 | /* Dummy readl to force pci flush */ |
170 | readl(®s->outbound_intr_mask); | 175 | readl(®s->outbound_intr_mask); |
@@ -200,24 +205,27 @@ static int | |||
200 | megasas_clear_intr_xscale(struct megasas_register_set __iomem * regs) | 205 | megasas_clear_intr_xscale(struct megasas_register_set __iomem * regs) |
201 | { | 206 | { |
202 | u32 status; | 207 | u32 status; |
208 | u32 mfiStatus = 0; | ||
203 | /* | 209 | /* |
204 | * Check if it is our interrupt | 210 | * Check if it is our interrupt |
205 | */ | 211 | */ |
206 | status = readl(®s->outbound_intr_status); | 212 | status = readl(®s->outbound_intr_status); |
207 | 213 | ||
208 | if (!(status & MFI_OB_INTR_STATUS_MASK)) { | 214 | if (status & MFI_OB_INTR_STATUS_MASK) |
209 | return 1; | 215 | mfiStatus = MFI_INTR_FLAG_REPLY_MESSAGE; |
210 | } | 216 | if (status & MFI_XSCALE_OMR0_CHANGE_INTERRUPT) |
217 | mfiStatus |= MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE; | ||
211 | 218 | ||
212 | /* | 219 | /* |
213 | * Clear the interrupt by writing back the same value | 220 | * Clear the interrupt by writing back the same value |
214 | */ | 221 | */ |
215 | writel(status, ®s->outbound_intr_status); | 222 | if (mfiStatus) |
223 | writel(status, ®s->outbound_intr_status); | ||
216 | 224 | ||
217 | /* Dummy readl to force pci flush */ | 225 | /* Dummy readl to force pci flush */ |
218 | readl(®s->outbound_intr_status); | 226 | readl(®s->outbound_intr_status); |
219 | 227 | ||
220 | return 0; | 228 | return mfiStatus; |
221 | } | 229 | } |
222 | 230 | ||
223 | /** | 231 | /** |
@@ -232,8 +240,69 @@ megasas_fire_cmd_xscale(struct megasas_instance *instance, | |||
232 | u32 frame_count, | 240 | u32 frame_count, |
233 | struct megasas_register_set __iomem *regs) | 241 | struct megasas_register_set __iomem *regs) |
234 | { | 242 | { |
243 | unsigned long flags; | ||
244 | spin_lock_irqsave(&instance->hba_lock, flags); | ||
235 | writel((frame_phys_addr >> 3)|(frame_count), | 245 | writel((frame_phys_addr >> 3)|(frame_count), |
236 | &(regs)->inbound_queue_port); | 246 | &(regs)->inbound_queue_port); |
247 | spin_unlock_irqrestore(&instance->hba_lock, flags); | ||
248 | } | ||
249 | |||
250 | /** | ||
251 | * megasas_adp_reset_xscale - For controller reset | ||
252 | * @regs: MFI register set | ||
253 | */ | ||
254 | static int | ||
255 | megasas_adp_reset_xscale(struct megasas_instance *instance, | ||
256 | struct megasas_register_set __iomem *regs) | ||
257 | { | ||
258 | u32 i; | ||
259 | u32 pcidata; | ||
260 | writel(MFI_ADP_RESET, ®s->inbound_doorbell); | ||
261 | |||
262 | for (i = 0; i < 3; i++) | ||
263 | msleep(1000); /* sleep for 3 secs */ | ||
264 | pcidata = 0; | ||
265 | pci_read_config_dword(instance->pdev, MFI_1068_PCSR_OFFSET, &pcidata); | ||
266 | printk(KERN_NOTICE "pcidata = %x\n", pcidata); | ||
267 | if (pcidata & 0x2) { | ||
268 | printk(KERN_NOTICE "mfi 1068 offset read=%x\n", pcidata); | ||
269 | pcidata &= ~0x2; | ||
270 | pci_write_config_dword(instance->pdev, | ||
271 | MFI_1068_PCSR_OFFSET, pcidata); | ||
272 | |||
273 | for (i = 0; i < 2; i++) | ||
274 | msleep(1000); /* need to wait 2 secs again */ | ||
275 | |||
276 | pcidata = 0; | ||
277 | pci_read_config_dword(instance->pdev, | ||
278 | MFI_1068_FW_HANDSHAKE_OFFSET, &pcidata); | ||
279 | printk(KERN_NOTICE "1068 offset handshake read=%x\n", pcidata); | ||
280 | if ((pcidata & 0xffff0000) == MFI_1068_FW_READY) { | ||
281 | printk(KERN_NOTICE "1068 offset pcidt=%x\n", pcidata); | ||
282 | pcidata = 0; | ||
283 | pci_write_config_dword(instance->pdev, | ||
284 | MFI_1068_FW_HANDSHAKE_OFFSET, pcidata); | ||
285 | } | ||
286 | } | ||
287 | return 0; | ||
288 | } | ||
289 | |||
290 | /** | ||
291 | * megasas_check_reset_xscale - For controller reset check | ||
292 | * @regs: MFI register set | ||
293 | */ | ||
294 | static int | ||
295 | megasas_check_reset_xscale(struct megasas_instance *instance, | ||
296 | struct megasas_register_set __iomem *regs) | ||
297 | { | ||
298 | u32 consumer; | ||
299 | consumer = *instance->consumer; | ||
300 | |||
301 | if ((instance->adprecovery != MEGASAS_HBA_OPERATIONAL) && | ||
302 | (*instance->consumer == MEGASAS_ADPRESET_INPROG_SIGN)) { | ||
303 | return 1; | ||
304 | } | ||
305 | return 0; | ||
237 | } | 306 | } |
238 | 307 | ||
239 | static struct megasas_instance_template megasas_instance_template_xscale = { | 308 | static struct megasas_instance_template megasas_instance_template_xscale = { |
@@ -243,6 +312,8 @@ static struct megasas_instance_template megasas_instance_template_xscale = { | |||
243 | .disable_intr = megasas_disable_intr_xscale, | 312 | .disable_intr = megasas_disable_intr_xscale, |
244 | .clear_intr = megasas_clear_intr_xscale, | 313 | .clear_intr = megasas_clear_intr_xscale, |
245 | .read_fw_status_reg = megasas_read_fw_status_reg_xscale, | 314 | .read_fw_status_reg = megasas_read_fw_status_reg_xscale, |
315 | .adp_reset = megasas_adp_reset_xscale, | ||
316 | .check_reset = megasas_check_reset_xscale, | ||
246 | }; | 317 | }; |
247 | 318 | ||
248 | /** | 319 | /** |
@@ -264,7 +335,7 @@ megasas_enable_intr_ppc(struct megasas_register_set __iomem * regs) | |||
264 | { | 335 | { |
265 | writel(0xFFFFFFFF, &(regs)->outbound_doorbell_clear); | 336 | writel(0xFFFFFFFF, &(regs)->outbound_doorbell_clear); |
266 | 337 | ||
267 | writel(~0x80000004, &(regs)->outbound_intr_mask); | 338 | writel(~0x80000000, &(regs)->outbound_intr_mask); |
268 | 339 | ||
269 | /* Dummy readl to force pci flush */ | 340 | /* Dummy readl to force pci flush */ |
270 | readl(®s->outbound_intr_mask); | 341 | readl(®s->outbound_intr_mask); |
@@ -307,7 +378,7 @@ megasas_clear_intr_ppc(struct megasas_register_set __iomem * regs) | |||
307 | status = readl(®s->outbound_intr_status); | 378 | status = readl(®s->outbound_intr_status); |
308 | 379 | ||
309 | if (!(status & MFI_REPLY_1078_MESSAGE_INTERRUPT)) { | 380 | if (!(status & MFI_REPLY_1078_MESSAGE_INTERRUPT)) { |
310 | return 1; | 381 | return 0; |
311 | } | 382 | } |
312 | 383 | ||
313 | /* | 384 | /* |
@@ -318,7 +389,7 @@ megasas_clear_intr_ppc(struct megasas_register_set __iomem * regs) | |||
318 | /* Dummy readl to force pci flush */ | 389 | /* Dummy readl to force pci flush */ |
319 | readl(®s->outbound_doorbell_clear); | 390 | readl(®s->outbound_doorbell_clear); |
320 | 391 | ||
321 | return 0; | 392 | return 1; |
322 | } | 393 | } |
323 | /** | 394 | /** |
324 | * megasas_fire_cmd_ppc - Sends command to the FW | 395 | * megasas_fire_cmd_ppc - Sends command to the FW |
@@ -332,10 +403,34 @@ megasas_fire_cmd_ppc(struct megasas_instance *instance, | |||
332 | u32 frame_count, | 403 | u32 frame_count, |
333 | struct megasas_register_set __iomem *regs) | 404 | struct megasas_register_set __iomem *regs) |
334 | { | 405 | { |
406 | unsigned long flags; | ||
407 | spin_lock_irqsave(&instance->hba_lock, flags); | ||
335 | writel((frame_phys_addr | (frame_count<<1))|1, | 408 | writel((frame_phys_addr | (frame_count<<1))|1, |
336 | &(regs)->inbound_queue_port); | 409 | &(regs)->inbound_queue_port); |
410 | spin_unlock_irqrestore(&instance->hba_lock, flags); | ||
411 | } | ||
412 | |||
413 | /** | ||
414 | * megasas_adp_reset_ppc - For controller reset | ||
415 | * @regs: MFI register set | ||
416 | */ | ||
417 | static int | ||
418 | megasas_adp_reset_ppc(struct megasas_instance *instance, | ||
419 | struct megasas_register_set __iomem *regs) | ||
420 | { | ||
421 | return 0; | ||
337 | } | 422 | } |
338 | 423 | ||
424 | /** | ||
425 | * megasas_check_reset_ppc - For controller reset check | ||
426 | * @regs: MFI register set | ||
427 | */ | ||
428 | static int | ||
429 | megasas_check_reset_ppc(struct megasas_instance *instance, | ||
430 | struct megasas_register_set __iomem *regs) | ||
431 | { | ||
432 | return 0; | ||
433 | } | ||
339 | static struct megasas_instance_template megasas_instance_template_ppc = { | 434 | static struct megasas_instance_template megasas_instance_template_ppc = { |
340 | 435 | ||
341 | .fire_cmd = megasas_fire_cmd_ppc, | 436 | .fire_cmd = megasas_fire_cmd_ppc, |
@@ -343,6 +438,8 @@ static struct megasas_instance_template megasas_instance_template_ppc = { | |||
343 | .disable_intr = megasas_disable_intr_ppc, | 438 | .disable_intr = megasas_disable_intr_ppc, |
344 | .clear_intr = megasas_clear_intr_ppc, | 439 | .clear_intr = megasas_clear_intr_ppc, |
345 | .read_fw_status_reg = megasas_read_fw_status_reg_ppc, | 440 | .read_fw_status_reg = megasas_read_fw_status_reg_ppc, |
441 | .adp_reset = megasas_adp_reset_ppc, | ||
442 | .check_reset = megasas_check_reset_ppc, | ||
346 | }; | 443 | }; |
347 | 444 | ||
348 | /** | 445 | /** |
@@ -397,7 +494,7 @@ megasas_clear_intr_skinny(struct megasas_register_set __iomem *regs) | |||
397 | status = readl(®s->outbound_intr_status); | 494 | status = readl(®s->outbound_intr_status); |
398 | 495 | ||
399 | if (!(status & MFI_SKINNY_ENABLE_INTERRUPT_MASK)) { | 496 | if (!(status & MFI_SKINNY_ENABLE_INTERRUPT_MASK)) { |
400 | return 1; | 497 | return 0; |
401 | } | 498 | } |
402 | 499 | ||
403 | /* | 500 | /* |
@@ -410,7 +507,7 @@ megasas_clear_intr_skinny(struct megasas_register_set __iomem *regs) | |||
410 | */ | 507 | */ |
411 | readl(®s->outbound_intr_status); | 508 | readl(®s->outbound_intr_status); |
412 | 509 | ||
413 | return 0; | 510 | return 1; |
414 | } | 511 | } |
415 | 512 | ||
416 | /** | 513 | /** |
@@ -426,11 +523,33 @@ megasas_fire_cmd_skinny(struct megasas_instance *instance, | |||
426 | struct megasas_register_set __iomem *regs) | 523 | struct megasas_register_set __iomem *regs) |
427 | { | 524 | { |
428 | unsigned long flags; | 525 | unsigned long flags; |
429 | spin_lock_irqsave(&instance->fire_lock, flags); | 526 | spin_lock_irqsave(&instance->hba_lock, flags); |
430 | writel(0, &(regs)->inbound_high_queue_port); | 527 | writel(0, &(regs)->inbound_high_queue_port); |
431 | writel((frame_phys_addr | (frame_count<<1))|1, | 528 | writel((frame_phys_addr | (frame_count<<1))|1, |
432 | &(regs)->inbound_low_queue_port); | 529 | &(regs)->inbound_low_queue_port); |
433 | spin_unlock_irqrestore(&instance->fire_lock, flags); | 530 | spin_unlock_irqrestore(&instance->hba_lock, flags); |
531 | } | ||
532 | |||
533 | /** | ||
534 | * megasas_adp_reset_skinny - For controller reset | ||
535 | * @regs: MFI register set | ||
536 | */ | ||
537 | static int | ||
538 | megasas_adp_reset_skinny(struct megasas_instance *instance, | ||
539 | struct megasas_register_set __iomem *regs) | ||
540 | { | ||
541 | return 0; | ||
542 | } | ||
543 | |||
544 | /** | ||
545 | * megasas_check_reset_skinny - For controller reset check | ||
546 | * @regs: MFI register set | ||
547 | */ | ||
548 | static int | ||
549 | megasas_check_reset_skinny(struct megasas_instance *instance, | ||
550 | struct megasas_register_set __iomem *regs) | ||
551 | { | ||
552 | return 0; | ||
434 | } | 553 | } |
435 | 554 | ||
436 | static struct megasas_instance_template megasas_instance_template_skinny = { | 555 | static struct megasas_instance_template megasas_instance_template_skinny = { |
@@ -440,6 +559,8 @@ static struct megasas_instance_template megasas_instance_template_skinny = { | |||
440 | .disable_intr = megasas_disable_intr_skinny, | 559 | .disable_intr = megasas_disable_intr_skinny, |
441 | .clear_intr = megasas_clear_intr_skinny, | 560 | .clear_intr = megasas_clear_intr_skinny, |
442 | .read_fw_status_reg = megasas_read_fw_status_reg_skinny, | 561 | .read_fw_status_reg = megasas_read_fw_status_reg_skinny, |
562 | .adp_reset = megasas_adp_reset_skinny, | ||
563 | .check_reset = megasas_check_reset_skinny, | ||
443 | }; | 564 | }; |
444 | 565 | ||
445 | 566 | ||
@@ -495,23 +616,29 @@ static int | |||
495 | megasas_clear_intr_gen2(struct megasas_register_set __iomem *regs) | 616 | megasas_clear_intr_gen2(struct megasas_register_set __iomem *regs) |
496 | { | 617 | { |
497 | u32 status; | 618 | u32 status; |
619 | u32 mfiStatus = 0; | ||
498 | /* | 620 | /* |
499 | * Check if it is our interrupt | 621 | * Check if it is our interrupt |
500 | */ | 622 | */ |
501 | status = readl(®s->outbound_intr_status); | 623 | status = readl(®s->outbound_intr_status); |
502 | 624 | ||
503 | if (!(status & MFI_GEN2_ENABLE_INTERRUPT_MASK)) | 625 | if (status & MFI_GEN2_ENABLE_INTERRUPT_MASK) { |
504 | return 1; | 626 | mfiStatus = MFI_INTR_FLAG_REPLY_MESSAGE; |
627 | } | ||
628 | if (status & MFI_G2_OUTBOUND_DOORBELL_CHANGE_INTERRUPT) { | ||
629 | mfiStatus |= MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE; | ||
630 | } | ||
505 | 631 | ||
506 | /* | 632 | /* |
507 | * Clear the interrupt by writing back the same value | 633 | * Clear the interrupt by writing back the same value |
508 | */ | 634 | */ |
509 | writel(status, ®s->outbound_doorbell_clear); | 635 | if (mfiStatus) |
636 | writel(status, ®s->outbound_doorbell_clear); | ||
510 | 637 | ||
511 | /* Dummy readl to force pci flush */ | 638 | /* Dummy readl to force pci flush */ |
512 | readl(®s->outbound_intr_status); | 639 | readl(®s->outbound_intr_status); |
513 | 640 | ||
514 | return 0; | 641 | return mfiStatus; |
515 | } | 642 | } |
516 | /** | 643 | /** |
517 | * megasas_fire_cmd_gen2 - Sends command to the FW | 644 | * megasas_fire_cmd_gen2 - Sends command to the FW |
@@ -525,8 +652,74 @@ megasas_fire_cmd_gen2(struct megasas_instance *instance, | |||
525 | u32 frame_count, | 652 | u32 frame_count, |
526 | struct megasas_register_set __iomem *regs) | 653 | struct megasas_register_set __iomem *regs) |
527 | { | 654 | { |
655 | unsigned long flags; | ||
656 | spin_lock_irqsave(&instance->hba_lock, flags); | ||
528 | writel((frame_phys_addr | (frame_count<<1))|1, | 657 | writel((frame_phys_addr | (frame_count<<1))|1, |
529 | &(regs)->inbound_queue_port); | 658 | &(regs)->inbound_queue_port); |
659 | spin_unlock_irqrestore(&instance->hba_lock, flags); | ||
660 | } | ||
661 | |||
662 | /** | ||
663 | * megasas_adp_reset_gen2 - For controller reset | ||
664 | * @regs: MFI register set | ||
665 | */ | ||
666 | static int | ||
667 | megasas_adp_reset_gen2(struct megasas_instance *instance, | ||
668 | struct megasas_register_set __iomem *reg_set) | ||
669 | { | ||
670 | u32 retry = 0 ; | ||
671 | u32 HostDiag; | ||
672 | |||
673 | writel(0, ®_set->seq_offset); | ||
674 | writel(4, ®_set->seq_offset); | ||
675 | writel(0xb, ®_set->seq_offset); | ||
676 | writel(2, ®_set->seq_offset); | ||
677 | writel(7, ®_set->seq_offset); | ||
678 | writel(0xd, ®_set->seq_offset); | ||
679 | msleep(1000); | ||
680 | |||
681 | HostDiag = (u32)readl(®_set->host_diag); | ||
682 | |||
683 | while ( !( HostDiag & DIAG_WRITE_ENABLE) ) { | ||
684 | msleep(100); | ||
685 | HostDiag = (u32)readl(®_set->host_diag); | ||
686 | printk(KERN_NOTICE "RESETGEN2: retry=%x, hostdiag=%x\n", | ||
687 | retry, HostDiag); | ||
688 | |||
689 | if (retry++ >= 100) | ||
690 | return 1; | ||
691 | |||
692 | } | ||
693 | |||
694 | printk(KERN_NOTICE "ADP_RESET_GEN2: HostDiag=%x\n", HostDiag); | ||
695 | |||
696 | writel((HostDiag | DIAG_RESET_ADAPTER), ®_set->host_diag); | ||
697 | |||
698 | ssleep(10); | ||
699 | |||
700 | HostDiag = (u32)readl(®_set->host_diag); | ||
701 | while ( ( HostDiag & DIAG_RESET_ADAPTER) ) { | ||
702 | msleep(100); | ||
703 | HostDiag = (u32)readl(®_set->host_diag); | ||
704 | printk(KERN_NOTICE "RESET_GEN2: retry=%x, hostdiag=%x\n", | ||
705 | retry, HostDiag); | ||
706 | |||
707 | if (retry++ >= 1000) | ||
708 | return 1; | ||
709 | |||
710 | } | ||
711 | return 0; | ||
712 | } | ||
713 | |||
714 | /** | ||
715 | * megasas_check_reset_gen2 - For controller reset check | ||
716 | * @regs: MFI register set | ||
717 | */ | ||
718 | static int | ||
719 | megasas_check_reset_gen2(struct megasas_instance *instance, | ||
720 | struct megasas_register_set __iomem *regs) | ||
721 | { | ||
722 | return 0; | ||
530 | } | 723 | } |
531 | 724 | ||
532 | static struct megasas_instance_template megasas_instance_template_gen2 = { | 725 | static struct megasas_instance_template megasas_instance_template_gen2 = { |
@@ -536,11 +729,13 @@ static struct megasas_instance_template megasas_instance_template_gen2 = { | |||
536 | .disable_intr = megasas_disable_intr_gen2, | 729 | .disable_intr = megasas_disable_intr_gen2, |
537 | .clear_intr = megasas_clear_intr_gen2, | 730 | .clear_intr = megasas_clear_intr_gen2, |
538 | .read_fw_status_reg = megasas_read_fw_status_reg_gen2, | 731 | .read_fw_status_reg = megasas_read_fw_status_reg_gen2, |
732 | .adp_reset = megasas_adp_reset_gen2, | ||
733 | .check_reset = megasas_check_reset_gen2, | ||
539 | }; | 734 | }; |
540 | 735 | ||
541 | /** | 736 | /** |
542 | * This is the end of set of functions & definitions | 737 | * This is the end of set of functions & definitions |
543 | * specific to ppc (deviceid : 0x60) controllers | 738 | * specific to gen2 (deviceid : 0x78, 0x79) controllers |
544 | */ | 739 | */ |
545 | 740 | ||
546 | /** | 741 | /** |
@@ -599,8 +794,7 @@ megasas_issue_blocked_cmd(struct megasas_instance *instance, | |||
599 | instance->instancet->fire_cmd(instance, | 794 | instance->instancet->fire_cmd(instance, |
600 | cmd->frame_phys_addr, 0, instance->reg_set); | 795 | cmd->frame_phys_addr, 0, instance->reg_set); |
601 | 796 | ||
602 | wait_event_timeout(instance->int_cmd_wait_q, (cmd->cmd_status != ENODATA), | 797 | wait_event(instance->int_cmd_wait_q, cmd->cmd_status != ENODATA); |
603 | MEGASAS_INTERNAL_CMD_WAIT_TIME*HZ); | ||
604 | 798 | ||
605 | return 0; | 799 | return 0; |
606 | } | 800 | } |
@@ -648,8 +842,8 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance, | |||
648 | /* | 842 | /* |
649 | * Wait for this cmd to complete | 843 | * Wait for this cmd to complete |
650 | */ | 844 | */ |
651 | wait_event_timeout(instance->abort_cmd_wait_q, (cmd->cmd_status != 0xFF), | 845 | wait_event(instance->abort_cmd_wait_q, cmd->cmd_status != 0xFF); |
652 | MEGASAS_INTERNAL_CMD_WAIT_TIME*HZ); | 846 | cmd->sync_cmd = 0; |
653 | 847 | ||
654 | megasas_return_cmd(instance, cmd); | 848 | megasas_return_cmd(instance, cmd); |
655 | return 0; | 849 | return 0; |
@@ -1131,14 +1325,22 @@ megasas_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *)) | |||
1131 | u32 frame_count; | 1325 | u32 frame_count; |
1132 | struct megasas_cmd *cmd; | 1326 | struct megasas_cmd *cmd; |
1133 | struct megasas_instance *instance; | 1327 | struct megasas_instance *instance; |
1328 | unsigned long flags; | ||
1134 | 1329 | ||
1135 | instance = (struct megasas_instance *) | 1330 | instance = (struct megasas_instance *) |
1136 | scmd->device->host->hostdata; | 1331 | scmd->device->host->hostdata; |
1137 | 1332 | ||
1138 | /* Don't process if we have already declared adapter dead */ | 1333 | if (instance->issuepend_done == 0) |
1139 | if (instance->hw_crit_error) | ||
1140 | return SCSI_MLQUEUE_HOST_BUSY; | 1334 | return SCSI_MLQUEUE_HOST_BUSY; |
1141 | 1335 | ||
1336 | spin_lock_irqsave(&instance->hba_lock, flags); | ||
1337 | if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) { | ||
1338 | spin_unlock_irqrestore(&instance->hba_lock, flags); | ||
1339 | return SCSI_MLQUEUE_HOST_BUSY; | ||
1340 | } | ||
1341 | |||
1342 | spin_unlock_irqrestore(&instance->hba_lock, flags); | ||
1343 | |||
1142 | scmd->scsi_done = done; | 1344 | scmd->scsi_done = done; |
1143 | scmd->result = 0; | 1345 | scmd->result = 0; |
1144 | 1346 | ||
@@ -1274,6 +1476,18 @@ static int megasas_slave_alloc(struct scsi_device *sdev) | |||
1274 | return 0; | 1476 | return 0; |
1275 | } | 1477 | } |
1276 | 1478 | ||
1479 | static void megaraid_sas_kill_hba(struct megasas_instance *instance) | ||
1480 | { | ||
1481 | if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) || | ||
1482 | (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY)) { | ||
1483 | writel(MFI_STOP_ADP, | ||
1484 | &instance->reg_set->reserved_0[0]); | ||
1485 | } else { | ||
1486 | writel(MFI_STOP_ADP, | ||
1487 | &instance->reg_set->inbound_doorbell); | ||
1488 | } | ||
1489 | } | ||
1490 | |||
1277 | /** | 1491 | /** |
1278 | * megasas_complete_cmd_dpc - Returns FW's controller structure | 1492 | * megasas_complete_cmd_dpc - Returns FW's controller structure |
1279 | * @instance_addr: Address of adapter soft state | 1493 | * @instance_addr: Address of adapter soft state |
@@ -1291,7 +1505,7 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr) | |||
1291 | unsigned long flags; | 1505 | unsigned long flags; |
1292 | 1506 | ||
1293 | /* If we have already declared adapter dead, donot complete cmds */ | 1507 | /* If we have already declared adapter dead, donot complete cmds */ |
1294 | if (instance->hw_crit_error) | 1508 | if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR ) |
1295 | return; | 1509 | return; |
1296 | 1510 | ||
1297 | spin_lock_irqsave(&instance->completion_lock, flags); | 1511 | spin_lock_irqsave(&instance->completion_lock, flags); |
@@ -1301,6 +1515,11 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr) | |||
1301 | 1515 | ||
1302 | while (consumer != producer) { | 1516 | while (consumer != producer) { |
1303 | context = instance->reply_queue[consumer]; | 1517 | context = instance->reply_queue[consumer]; |
1518 | if (context >= instance->max_fw_cmds) { | ||
1519 | printk(KERN_ERR "Unexpected context value %x\n", | ||
1520 | context); | ||
1521 | BUG(); | ||
1522 | } | ||
1304 | 1523 | ||
1305 | cmd = instance->cmd_list[context]; | 1524 | cmd = instance->cmd_list[context]; |
1306 | 1525 | ||
@@ -1350,7 +1569,76 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr) | |||
1350 | static int megasas_wait_for_outstanding(struct megasas_instance *instance) | 1569 | static int megasas_wait_for_outstanding(struct megasas_instance *instance) |
1351 | { | 1570 | { |
1352 | int i; | 1571 | int i; |
1572 | u32 reset_index; | ||
1353 | u32 wait_time = MEGASAS_RESET_WAIT_TIME; | 1573 | u32 wait_time = MEGASAS_RESET_WAIT_TIME; |
1574 | u8 adprecovery; | ||
1575 | unsigned long flags; | ||
1576 | struct list_head clist_local; | ||
1577 | struct megasas_cmd *reset_cmd; | ||
1578 | |||
1579 | spin_lock_irqsave(&instance->hba_lock, flags); | ||
1580 | adprecovery = instance->adprecovery; | ||
1581 | spin_unlock_irqrestore(&instance->hba_lock, flags); | ||
1582 | |||
1583 | if (adprecovery != MEGASAS_HBA_OPERATIONAL) { | ||
1584 | |||
1585 | INIT_LIST_HEAD(&clist_local); | ||
1586 | spin_lock_irqsave(&instance->hba_lock, flags); | ||
1587 | list_splice_init(&instance->internal_reset_pending_q, | ||
1588 | &clist_local); | ||
1589 | spin_unlock_irqrestore(&instance->hba_lock, flags); | ||
1590 | |||
1591 | printk(KERN_NOTICE "megasas: HBA reset wait ...\n"); | ||
1592 | for (i = 0; i < wait_time; i++) { | ||
1593 | msleep(1000); | ||
1594 | spin_lock_irqsave(&instance->hba_lock, flags); | ||
1595 | adprecovery = instance->adprecovery; | ||
1596 | spin_unlock_irqrestore(&instance->hba_lock, flags); | ||
1597 | if (adprecovery == MEGASAS_HBA_OPERATIONAL) | ||
1598 | break; | ||
1599 | } | ||
1600 | |||
1601 | if (adprecovery != MEGASAS_HBA_OPERATIONAL) { | ||
1602 | printk(KERN_NOTICE "megasas: reset: Stopping HBA.\n"); | ||
1603 | spin_lock_irqsave(&instance->hba_lock, flags); | ||
1604 | instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR; | ||
1605 | spin_unlock_irqrestore(&instance->hba_lock, flags); | ||
1606 | return FAILED; | ||
1607 | } | ||
1608 | |||
1609 | reset_index = 0; | ||
1610 | while (!list_empty(&clist_local)) { | ||
1611 | reset_cmd = list_entry((&clist_local)->next, | ||
1612 | struct megasas_cmd, list); | ||
1613 | list_del_init(&reset_cmd->list); | ||
1614 | if (reset_cmd->scmd) { | ||
1615 | reset_cmd->scmd->result = DID_RESET << 16; | ||
1616 | printk(KERN_NOTICE "%d:%p reset [%02x], %#lx\n", | ||
1617 | reset_index, reset_cmd, | ||
1618 | reset_cmd->scmd->cmnd[0], | ||
1619 | reset_cmd->scmd->serial_number); | ||
1620 | |||
1621 | reset_cmd->scmd->scsi_done(reset_cmd->scmd); | ||
1622 | megasas_return_cmd(instance, reset_cmd); | ||
1623 | } else if (reset_cmd->sync_cmd) { | ||
1624 | printk(KERN_NOTICE "megasas:%p synch cmds" | ||
1625 | "reset queue\n", | ||
1626 | reset_cmd); | ||
1627 | |||
1628 | reset_cmd->cmd_status = ENODATA; | ||
1629 | instance->instancet->fire_cmd(instance, | ||
1630 | reset_cmd->frame_phys_addr, | ||
1631 | 0, instance->reg_set); | ||
1632 | } else { | ||
1633 | printk(KERN_NOTICE "megasas: %p unexpected" | ||
1634 | "cmds lst\n", | ||
1635 | reset_cmd); | ||
1636 | } | ||
1637 | reset_index++; | ||
1638 | } | ||
1639 | |||
1640 | return SUCCESS; | ||
1641 | } | ||
1354 | 1642 | ||
1355 | for (i = 0; i < wait_time; i++) { | 1643 | for (i = 0; i < wait_time; i++) { |
1356 | 1644 | ||
@@ -1373,6 +1661,7 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance) | |||
1373 | } | 1661 | } |
1374 | 1662 | ||
1375 | if (atomic_read(&instance->fw_outstanding)) { | 1663 | if (atomic_read(&instance->fw_outstanding)) { |
1664 | printk(KERN_NOTICE "megaraid_sas: pending cmds after reset\n"); | ||
1376 | /* | 1665 | /* |
1377 | * Send signal to FW to stop processing any pending cmds. | 1666 | * Send signal to FW to stop processing any pending cmds. |
1378 | * The controller will be taken offline by the OS now. | 1667 | * The controller will be taken offline by the OS now. |
@@ -1388,10 +1677,14 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance) | |||
1388 | &instance->reg_set->inbound_doorbell); | 1677 | &instance->reg_set->inbound_doorbell); |
1389 | } | 1678 | } |
1390 | megasas_dump_pending_frames(instance); | 1679 | megasas_dump_pending_frames(instance); |
1391 | instance->hw_crit_error = 1; | 1680 | spin_lock_irqsave(&instance->hba_lock, flags); |
1681 | instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR; | ||
1682 | spin_unlock_irqrestore(&instance->hba_lock, flags); | ||
1392 | return FAILED; | 1683 | return FAILED; |
1393 | } | 1684 | } |
1394 | 1685 | ||
1686 | printk(KERN_NOTICE "megaraid_sas: no pending cmds after reset\n"); | ||
1687 | |||
1395 | return SUCCESS; | 1688 | return SUCCESS; |
1396 | } | 1689 | } |
1397 | 1690 | ||
@@ -1413,7 +1706,7 @@ static int megasas_generic_reset(struct scsi_cmnd *scmd) | |||
1413 | scmd_printk(KERN_NOTICE, scmd, "megasas: RESET -%ld cmd=%x retries=%x\n", | 1706 | scmd_printk(KERN_NOTICE, scmd, "megasas: RESET -%ld cmd=%x retries=%x\n", |
1414 | scmd->serial_number, scmd->cmnd[0], scmd->retries); | 1707 | scmd->serial_number, scmd->cmnd[0], scmd->retries); |
1415 | 1708 | ||
1416 | if (instance->hw_crit_error) { | 1709 | if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) { |
1417 | printk(KERN_ERR "megasas: cannot recover from previous reset " | 1710 | printk(KERN_ERR "megasas: cannot recover from previous reset " |
1418 | "failures\n"); | 1711 | "failures\n"); |
1419 | return FAILED; | 1712 | return FAILED; |
@@ -1568,7 +1861,8 @@ megasas_service_aen(struct megasas_instance *instance, struct megasas_cmd *cmd) | |||
1568 | instance->aen_cmd = NULL; | 1861 | instance->aen_cmd = NULL; |
1569 | megasas_return_cmd(instance, cmd); | 1862 | megasas_return_cmd(instance, cmd); |
1570 | 1863 | ||
1571 | if (instance->unload == 0) { | 1864 | if ((instance->unload == 0) && |
1865 | ((instance->issuepend_done == 1))) { | ||
1572 | struct megasas_aen_event *ev; | 1866 | struct megasas_aen_event *ev; |
1573 | ev = kzalloc(sizeof(*ev), GFP_ATOMIC); | 1867 | ev = kzalloc(sizeof(*ev), GFP_ATOMIC); |
1574 | if (!ev) { | 1868 | if (!ev) { |
@@ -1663,6 +1957,9 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd, | |||
1663 | struct megasas_header *hdr = &cmd->frame->hdr; | 1957 | struct megasas_header *hdr = &cmd->frame->hdr; |
1664 | unsigned long flags; | 1958 | unsigned long flags; |
1665 | 1959 | ||
1960 | /* flag for the retry reset */ | ||
1961 | cmd->retry_for_fw_reset = 0; | ||
1962 | |||
1666 | if (cmd->scmd) | 1963 | if (cmd->scmd) |
1667 | cmd->scmd->SCp.ptr = NULL; | 1964 | cmd->scmd->SCp.ptr = NULL; |
1668 | 1965 | ||
@@ -1783,39 +2080,301 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd, | |||
1783 | } | 2080 | } |
1784 | 2081 | ||
1785 | /** | 2082 | /** |
2083 | * megasas_issue_pending_cmds_again - issue all pending cmds | ||
2084 | * in FW again because of the fw reset | ||
2085 | * @instance: Adapter soft state | ||
2086 | */ | ||
2087 | static inline void | ||
2088 | megasas_issue_pending_cmds_again(struct megasas_instance *instance) | ||
2089 | { | ||
2090 | struct megasas_cmd *cmd; | ||
2091 | struct list_head clist_local; | ||
2092 | union megasas_evt_class_locale class_locale; | ||
2093 | unsigned long flags; | ||
2094 | u32 seq_num; | ||
2095 | |||
2096 | INIT_LIST_HEAD(&clist_local); | ||
2097 | spin_lock_irqsave(&instance->hba_lock, flags); | ||
2098 | list_splice_init(&instance->internal_reset_pending_q, &clist_local); | ||
2099 | spin_unlock_irqrestore(&instance->hba_lock, flags); | ||
2100 | |||
2101 | while (!list_empty(&clist_local)) { | ||
2102 | cmd = list_entry((&clist_local)->next, | ||
2103 | struct megasas_cmd, list); | ||
2104 | list_del_init(&cmd->list); | ||
2105 | |||
2106 | if (cmd->sync_cmd || cmd->scmd) { | ||
2107 | printk(KERN_NOTICE "megaraid_sas: command %p, %p:%d" | ||
2108 | "detected to be pending while HBA reset.\n", | ||
2109 | cmd, cmd->scmd, cmd->sync_cmd); | ||
2110 | |||
2111 | cmd->retry_for_fw_reset++; | ||
2112 | |||
2113 | if (cmd->retry_for_fw_reset == 3) { | ||
2114 | printk(KERN_NOTICE "megaraid_sas: cmd %p, %p:%d" | ||
2115 | "was tried multiple times during reset." | ||
2116 | "Shutting down the HBA\n", | ||
2117 | cmd, cmd->scmd, cmd->sync_cmd); | ||
2118 | megaraid_sas_kill_hba(instance); | ||
2119 | |||
2120 | instance->adprecovery = | ||
2121 | MEGASAS_HW_CRITICAL_ERROR; | ||
2122 | return; | ||
2123 | } | ||
2124 | } | ||
2125 | |||
2126 | if (cmd->sync_cmd == 1) { | ||
2127 | if (cmd->scmd) { | ||
2128 | printk(KERN_NOTICE "megaraid_sas: unexpected" | ||
2129 | "cmd attached to internal command!\n"); | ||
2130 | } | ||
2131 | printk(KERN_NOTICE "megasas: %p synchronous cmd" | ||
2132 | "on the internal reset queue," | ||
2133 | "issue it again.\n", cmd); | ||
2134 | cmd->cmd_status = ENODATA; | ||
2135 | instance->instancet->fire_cmd(instance, | ||
2136 | cmd->frame_phys_addr , | ||
2137 | 0, instance->reg_set); | ||
2138 | } else if (cmd->scmd) { | ||
2139 | printk(KERN_NOTICE "megasas: %p scsi cmd [%02x],%#lx" | ||
2140 | "detected on the internal queue, issue again.\n", | ||
2141 | cmd, cmd->scmd->cmnd[0], cmd->scmd->serial_number); | ||
2142 | |||
2143 | atomic_inc(&instance->fw_outstanding); | ||
2144 | instance->instancet->fire_cmd(instance, | ||
2145 | cmd->frame_phys_addr, | ||
2146 | cmd->frame_count-1, instance->reg_set); | ||
2147 | } else { | ||
2148 | printk(KERN_NOTICE "megasas: %p unexpected cmd on the" | ||
2149 | "internal reset defer list while re-issue!!\n", | ||
2150 | cmd); | ||
2151 | } | ||
2152 | } | ||
2153 | |||
2154 | if (instance->aen_cmd) { | ||
2155 | printk(KERN_NOTICE "megaraid_sas: aen_cmd in def process\n"); | ||
2156 | megasas_return_cmd(instance, instance->aen_cmd); | ||
2157 | |||
2158 | instance->aen_cmd = NULL; | ||
2159 | } | ||
2160 | |||
2161 | /* | ||
2162 | * Initiate AEN (Asynchronous Event Notification) | ||
2163 | */ | ||
2164 | seq_num = instance->last_seq_num; | ||
2165 | class_locale.members.reserved = 0; | ||
2166 | class_locale.members.locale = MR_EVT_LOCALE_ALL; | ||
2167 | class_locale.members.class = MR_EVT_CLASS_DEBUG; | ||
2168 | |||
2169 | megasas_register_aen(instance, seq_num, class_locale.word); | ||
2170 | } | ||
2171 | |||
2172 | /** | ||
2173 | * Move the internal reset pending commands to a deferred queue. | ||
2174 | * | ||
2175 | * We move the commands pending at internal reset time to a | ||
2176 | * pending queue. This queue would be flushed after successful | ||
2177 | * completion of the internal reset sequence. if the internal reset | ||
2178 | * did not complete in time, the kernel reset handler would flush | ||
2179 | * these commands. | ||
2180 | **/ | ||
2181 | static void | ||
2182 | megasas_internal_reset_defer_cmds(struct megasas_instance *instance) | ||
2183 | { | ||
2184 | struct megasas_cmd *cmd; | ||
2185 | int i; | ||
2186 | u32 max_cmd = instance->max_fw_cmds; | ||
2187 | u32 defer_index; | ||
2188 | unsigned long flags; | ||
2189 | |||
2190 | defer_index = 0; | ||
2191 | spin_lock_irqsave(&instance->cmd_pool_lock, flags); | ||
2192 | for (i = 0; i < max_cmd; i++) { | ||
2193 | cmd = instance->cmd_list[i]; | ||
2194 | if (cmd->sync_cmd == 1 || cmd->scmd) { | ||
2195 | printk(KERN_NOTICE "megasas: moving cmd[%d]:%p:%d:%p" | ||
2196 | "on the defer queue as internal\n", | ||
2197 | defer_index, cmd, cmd->sync_cmd, cmd->scmd); | ||
2198 | |||
2199 | if (!list_empty(&cmd->list)) { | ||
2200 | printk(KERN_NOTICE "megaraid_sas: ERROR while" | ||
2201 | " moving this cmd:%p, %d %p, it was" | ||
2202 | "discovered on some list?\n", | ||
2203 | cmd, cmd->sync_cmd, cmd->scmd); | ||
2204 | |||
2205 | list_del_init(&cmd->list); | ||
2206 | } | ||
2207 | defer_index++; | ||
2208 | list_add_tail(&cmd->list, | ||
2209 | &instance->internal_reset_pending_q); | ||
2210 | } | ||
2211 | } | ||
2212 | spin_unlock_irqrestore(&instance->cmd_pool_lock, flags); | ||
2213 | } | ||
2214 | |||
2215 | |||
2216 | static void | ||
2217 | process_fw_state_change_wq(struct work_struct *work) | ||
2218 | { | ||
2219 | struct megasas_instance *instance = | ||
2220 | container_of(work, struct megasas_instance, work_init); | ||
2221 | u32 wait; | ||
2222 | unsigned long flags; | ||
2223 | |||
2224 | if (instance->adprecovery != MEGASAS_ADPRESET_SM_INFAULT) { | ||
2225 | printk(KERN_NOTICE "megaraid_sas: error, recovery st %x \n", | ||
2226 | instance->adprecovery); | ||
2227 | return ; | ||
2228 | } | ||
2229 | |||
2230 | if (instance->adprecovery == MEGASAS_ADPRESET_SM_INFAULT) { | ||
2231 | printk(KERN_NOTICE "megaraid_sas: FW detected to be in fault" | ||
2232 | "state, restarting it...\n"); | ||
2233 | |||
2234 | instance->instancet->disable_intr(instance->reg_set); | ||
2235 | atomic_set(&instance->fw_outstanding, 0); | ||
2236 | |||
2237 | atomic_set(&instance->fw_reset_no_pci_access, 1); | ||
2238 | instance->instancet->adp_reset(instance, instance->reg_set); | ||
2239 | atomic_set(&instance->fw_reset_no_pci_access, 0 ); | ||
2240 | |||
2241 | printk(KERN_NOTICE "megaraid_sas: FW restarted successfully," | ||
2242 | "initiating next stage...\n"); | ||
2243 | |||
2244 | printk(KERN_NOTICE "megaraid_sas: HBA recovery state machine," | ||
2245 | "state 2 starting...\n"); | ||
2246 | |||
2247 | /*waitting for about 20 second before start the second init*/ | ||
2248 | for (wait = 0; wait < 30; wait++) { | ||
2249 | msleep(1000); | ||
2250 | } | ||
2251 | |||
2252 | if (megasas_transition_to_ready(instance)) { | ||
2253 | printk(KERN_NOTICE "megaraid_sas:adapter not ready\n"); | ||
2254 | |||
2255 | megaraid_sas_kill_hba(instance); | ||
2256 | instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR; | ||
2257 | return ; | ||
2258 | } | ||
2259 | |||
2260 | if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS1064R) || | ||
2261 | (instance->pdev->device == PCI_DEVICE_ID_DELL_PERC5) || | ||
2262 | (instance->pdev->device == PCI_DEVICE_ID_LSI_VERDE_ZCR) | ||
2263 | ) { | ||
2264 | *instance->consumer = *instance->producer; | ||
2265 | } else { | ||
2266 | *instance->consumer = 0; | ||
2267 | *instance->producer = 0; | ||
2268 | } | ||
2269 | |||
2270 | megasas_issue_init_mfi(instance); | ||
2271 | |||
2272 | spin_lock_irqsave(&instance->hba_lock, flags); | ||
2273 | instance->adprecovery = MEGASAS_HBA_OPERATIONAL; | ||
2274 | spin_unlock_irqrestore(&instance->hba_lock, flags); | ||
2275 | instance->instancet->enable_intr(instance->reg_set); | ||
2276 | |||
2277 | megasas_issue_pending_cmds_again(instance); | ||
2278 | instance->issuepend_done = 1; | ||
2279 | } | ||
2280 | return ; | ||
2281 | } | ||
2282 | |||
2283 | /** | ||
1786 | * megasas_deplete_reply_queue - Processes all completed commands | 2284 | * megasas_deplete_reply_queue - Processes all completed commands |
1787 | * @instance: Adapter soft state | 2285 | * @instance: Adapter soft state |
1788 | * @alt_status: Alternate status to be returned to | 2286 | * @alt_status: Alternate status to be returned to |
1789 | * SCSI mid-layer instead of the status | 2287 | * SCSI mid-layer instead of the status |
1790 | * returned by the FW | 2288 | * returned by the FW |
2289 | * Note: this must be called with hba lock held | ||
1791 | */ | 2290 | */ |
1792 | static int | 2291 | static int |
1793 | megasas_deplete_reply_queue(struct megasas_instance *instance, u8 alt_status) | 2292 | megasas_deplete_reply_queue(struct megasas_instance *instance, |
2293 | u8 alt_status) | ||
1794 | { | 2294 | { |
1795 | /* | 2295 | u32 mfiStatus; |
1796 | * Check if it is our interrupt | 2296 | u32 fw_state; |
1797 | * Clear the interrupt | 2297 | |
1798 | */ | 2298 | if ((mfiStatus = instance->instancet->check_reset(instance, |
1799 | if(instance->instancet->clear_intr(instance->reg_set)) | 2299 | instance->reg_set)) == 1) { |
2300 | return IRQ_HANDLED; | ||
2301 | } | ||
2302 | |||
2303 | if ((mfiStatus = instance->instancet->clear_intr( | ||
2304 | instance->reg_set) | ||
2305 | ) == 0) { | ||
1800 | return IRQ_NONE; | 2306 | return IRQ_NONE; |
2307 | } | ||
2308 | |||
2309 | instance->mfiStatus = mfiStatus; | ||
2310 | |||
2311 | if ((mfiStatus & MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE)) { | ||
2312 | fw_state = instance->instancet->read_fw_status_reg( | ||
2313 | instance->reg_set) & MFI_STATE_MASK; | ||
2314 | |||
2315 | if (fw_state != MFI_STATE_FAULT) { | ||
2316 | printk(KERN_NOTICE "megaraid_sas: fw state:%x\n", | ||
2317 | fw_state); | ||
2318 | } | ||
2319 | |||
2320 | if ((fw_state == MFI_STATE_FAULT) && | ||
2321 | (instance->disableOnlineCtrlReset == 0)) { | ||
2322 | printk(KERN_NOTICE "megaraid_sas: wait adp restart\n"); | ||
2323 | |||
2324 | if ((instance->pdev->device == | ||
2325 | PCI_DEVICE_ID_LSI_SAS1064R) || | ||
2326 | (instance->pdev->device == | ||
2327 | PCI_DEVICE_ID_DELL_PERC5) || | ||
2328 | (instance->pdev->device == | ||
2329 | PCI_DEVICE_ID_LSI_VERDE_ZCR)) { | ||
2330 | |||
2331 | *instance->consumer = | ||
2332 | MEGASAS_ADPRESET_INPROG_SIGN; | ||
2333 | } | ||
2334 | |||
2335 | |||
2336 | instance->instancet->disable_intr(instance->reg_set); | ||
2337 | instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT; | ||
2338 | instance->issuepend_done = 0; | ||
2339 | |||
2340 | atomic_set(&instance->fw_outstanding, 0); | ||
2341 | megasas_internal_reset_defer_cmds(instance); | ||
2342 | |||
2343 | printk(KERN_NOTICE "megasas: fwState=%x, stage:%d\n", | ||
2344 | fw_state, instance->adprecovery); | ||
2345 | |||
2346 | schedule_work(&instance->work_init); | ||
2347 | return IRQ_HANDLED; | ||
2348 | |||
2349 | } else { | ||
2350 | printk(KERN_NOTICE "megasas: fwstate:%x, dis_OCR=%x\n", | ||
2351 | fw_state, instance->disableOnlineCtrlReset); | ||
2352 | } | ||
2353 | } | ||
1801 | 2354 | ||
1802 | if (instance->hw_crit_error) | ||
1803 | goto out_done; | ||
1804 | /* | ||
1805 | * Schedule the tasklet for cmd completion | ||
1806 | */ | ||
1807 | tasklet_schedule(&instance->isr_tasklet); | 2355 | tasklet_schedule(&instance->isr_tasklet); |
1808 | out_done: | ||
1809 | return IRQ_HANDLED; | 2356 | return IRQ_HANDLED; |
1810 | } | 2357 | } |
1811 | |||
1812 | /** | 2358 | /** |
1813 | * megasas_isr - isr entry point | 2359 | * megasas_isr - isr entry point |
1814 | */ | 2360 | */ |
1815 | static irqreturn_t megasas_isr(int irq, void *devp) | 2361 | static irqreturn_t megasas_isr(int irq, void *devp) |
1816 | { | 2362 | { |
1817 | return megasas_deplete_reply_queue((struct megasas_instance *)devp, | 2363 | struct megasas_instance *instance; |
1818 | DID_OK); | 2364 | unsigned long flags; |
2365 | irqreturn_t rc; | ||
2366 | |||
2367 | if (atomic_read( | ||
2368 | &(((struct megasas_instance *)devp)->fw_reset_no_pci_access))) | ||
2369 | return IRQ_HANDLED; | ||
2370 | |||
2371 | instance = (struct megasas_instance *)devp; | ||
2372 | |||
2373 | spin_lock_irqsave(&instance->hba_lock, flags); | ||
2374 | rc = megasas_deplete_reply_queue(instance, DID_OK); | ||
2375 | spin_unlock_irqrestore(&instance->hba_lock, flags); | ||
2376 | |||
2377 | return rc; | ||
1819 | } | 2378 | } |
1820 | 2379 | ||
1821 | /** | 2380 | /** |
@@ -1972,7 +2531,7 @@ megasas_transition_to_ready(struct megasas_instance* instance) | |||
1972 | "in %d secs\n", fw_state, max_wait); | 2531 | "in %d secs\n", fw_state, max_wait); |
1973 | return -ENODEV; | 2532 | return -ENODEV; |
1974 | } | 2533 | } |
1975 | }; | 2534 | } |
1976 | printk(KERN_INFO "megasas: FW now in Ready state\n"); | 2535 | printk(KERN_INFO "megasas: FW now in Ready state\n"); |
1977 | 2536 | ||
1978 | return 0; | 2537 | return 0; |
@@ -2054,6 +2613,7 @@ static int megasas_create_frame_pool(struct megasas_instance *instance) | |||
2054 | */ | 2613 | */ |
2055 | sgl_sz = sge_sz * instance->max_num_sge; | 2614 | sgl_sz = sge_sz * instance->max_num_sge; |
2056 | frame_count = (sgl_sz + MEGAMFI_FRAME_SIZE - 1) / MEGAMFI_FRAME_SIZE; | 2615 | frame_count = (sgl_sz + MEGAMFI_FRAME_SIZE - 1) / MEGAMFI_FRAME_SIZE; |
2616 | frame_count = 15; | ||
2057 | 2617 | ||
2058 | /* | 2618 | /* |
2059 | * We need one extra frame for the MFI command | 2619 | * We need one extra frame for the MFI command |
@@ -2201,6 +2761,7 @@ static int megasas_alloc_cmds(struct megasas_instance *instance) | |||
2201 | cmd = instance->cmd_list[i]; | 2761 | cmd = instance->cmd_list[i]; |
2202 | memset(cmd, 0, sizeof(struct megasas_cmd)); | 2762 | memset(cmd, 0, sizeof(struct megasas_cmd)); |
2203 | cmd->index = i; | 2763 | cmd->index = i; |
2764 | cmd->scmd = NULL; | ||
2204 | cmd->instance = instance; | 2765 | cmd->instance = instance; |
2205 | 2766 | ||
2206 | list_add_tail(&cmd->list, &instance->cmd_pool); | 2767 | list_add_tail(&cmd->list, &instance->cmd_pool); |
@@ -2368,7 +2929,7 @@ megasas_get_ld_list(struct megasas_instance *instance) | |||
2368 | 2929 | ||
2369 | /* the following function will get the instance PD LIST */ | 2930 | /* the following function will get the instance PD LIST */ |
2370 | 2931 | ||
2371 | if ((ret == 0) && (ci->ldCount < MAX_LOGICAL_DRIVES)) { | 2932 | if ((ret == 0) && (ci->ldCount <= MAX_LOGICAL_DRIVES)) { |
2372 | memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS); | 2933 | memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS); |
2373 | 2934 | ||
2374 | for (ld_index = 0; ld_index < ci->ldCount; ld_index++) { | 2935 | for (ld_index = 0; ld_index < ci->ldCount; ld_index++) { |
@@ -2682,6 +3243,21 @@ static int megasas_init_mfi(struct megasas_instance *instance) | |||
2682 | if (megasas_issue_init_mfi(instance)) | 3243 | if (megasas_issue_init_mfi(instance)) |
2683 | goto fail_fw_init; | 3244 | goto fail_fw_init; |
2684 | 3245 | ||
3246 | instance->fw_support_ieee = 0; | ||
3247 | instance->fw_support_ieee = | ||
3248 | (instance->instancet->read_fw_status_reg(reg_set) & | ||
3249 | 0x04000000); | ||
3250 | |||
3251 | printk(KERN_NOTICE "megasas_init_mfi: fw_support_ieee=%d", | ||
3252 | instance->fw_support_ieee); | ||
3253 | |||
3254 | if (instance->fw_support_ieee) | ||
3255 | instance->flag_ieee = 1; | ||
3256 | |||
3257 | /** for passthrough | ||
3258 | * the following function will get the PD LIST. | ||
3259 | */ | ||
3260 | |||
2685 | memset(instance->pd_list, 0 , | 3261 | memset(instance->pd_list, 0 , |
2686 | (MEGASAS_MAX_PD * sizeof(struct megasas_pd_list))); | 3262 | (MEGASAS_MAX_PD * sizeof(struct megasas_pd_list))); |
2687 | megasas_get_pd_list(instance); | 3263 | megasas_get_pd_list(instance); |
@@ -2708,6 +3284,8 @@ static int megasas_init_mfi(struct megasas_instance *instance) | |||
2708 | max_sectors_2 = ctrl_info->max_request_size; | 3284 | max_sectors_2 = ctrl_info->max_request_size; |
2709 | 3285 | ||
2710 | tmp_sectors = min_t(u32, max_sectors_1 , max_sectors_2); | 3286 | tmp_sectors = min_t(u32, max_sectors_1 , max_sectors_2); |
3287 | instance->disableOnlineCtrlReset = | ||
3288 | ctrl_info->properties.OnOffProperties.disableOnlineCtrlReset; | ||
2711 | } | 3289 | } |
2712 | 3290 | ||
2713 | instance->max_sectors_per_req = instance->max_num_sge * | 3291 | instance->max_sectors_per_req = instance->max_num_sge * |
@@ -2929,6 +3507,7 @@ megasas_register_aen(struct megasas_instance *instance, u32 seq_num, | |||
2929 | dcmd->flags = MFI_FRAME_DIR_READ; | 3507 | dcmd->flags = MFI_FRAME_DIR_READ; |
2930 | dcmd->timeout = 0; | 3508 | dcmd->timeout = 0; |
2931 | dcmd->pad_0 = 0; | 3509 | dcmd->pad_0 = 0; |
3510 | instance->last_seq_num = seq_num; | ||
2932 | dcmd->data_xfer_len = sizeof(struct megasas_evt_detail); | 3511 | dcmd->data_xfer_len = sizeof(struct megasas_evt_detail); |
2933 | dcmd->opcode = MR_DCMD_CTRL_EVENT_WAIT; | 3512 | dcmd->opcode = MR_DCMD_CTRL_EVENT_WAIT; |
2934 | dcmd->mbox.w[0] = seq_num; | 3513 | dcmd->mbox.w[0] = seq_num; |
@@ -3097,6 +3676,7 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
3097 | 3676 | ||
3098 | instance = (struct megasas_instance *)host->hostdata; | 3677 | instance = (struct megasas_instance *)host->hostdata; |
3099 | memset(instance, 0, sizeof(*instance)); | 3678 | memset(instance, 0, sizeof(*instance)); |
3679 | atomic_set( &instance->fw_reset_no_pci_access, 0 ); | ||
3100 | 3680 | ||
3101 | instance->producer = pci_alloc_consistent(pdev, sizeof(u32), | 3681 | instance->producer = pci_alloc_consistent(pdev, sizeof(u32), |
3102 | &instance->producer_h); | 3682 | &instance->producer_h); |
@@ -3114,6 +3694,9 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
3114 | megasas_poll_wait_aen = 0; | 3694 | megasas_poll_wait_aen = 0; |
3115 | instance->flag_ieee = 0; | 3695 | instance->flag_ieee = 0; |
3116 | instance->ev = NULL; | 3696 | instance->ev = NULL; |
3697 | instance->issuepend_done = 1; | ||
3698 | instance->adprecovery = MEGASAS_HBA_OPERATIONAL; | ||
3699 | megasas_poll_wait_aen = 0; | ||
3117 | 3700 | ||
3118 | instance->evt_detail = pci_alloc_consistent(pdev, | 3701 | instance->evt_detail = pci_alloc_consistent(pdev, |
3119 | sizeof(struct | 3702 | sizeof(struct |
@@ -3130,6 +3713,7 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
3130 | * Initialize locks and queues | 3713 | * Initialize locks and queues |
3131 | */ | 3714 | */ |
3132 | INIT_LIST_HEAD(&instance->cmd_pool); | 3715 | INIT_LIST_HEAD(&instance->cmd_pool); |
3716 | INIT_LIST_HEAD(&instance->internal_reset_pending_q); | ||
3133 | 3717 | ||
3134 | atomic_set(&instance->fw_outstanding,0); | 3718 | atomic_set(&instance->fw_outstanding,0); |
3135 | 3719 | ||
@@ -3137,7 +3721,7 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
3137 | init_waitqueue_head(&instance->abort_cmd_wait_q); | 3721 | init_waitqueue_head(&instance->abort_cmd_wait_q); |
3138 | 3722 | ||
3139 | spin_lock_init(&instance->cmd_pool_lock); | 3723 | spin_lock_init(&instance->cmd_pool_lock); |
3140 | spin_lock_init(&instance->fire_lock); | 3724 | spin_lock_init(&instance->hba_lock); |
3141 | spin_lock_init(&instance->completion_lock); | 3725 | spin_lock_init(&instance->completion_lock); |
3142 | spin_lock_init(&poll_aen_lock); | 3726 | spin_lock_init(&poll_aen_lock); |
3143 | 3727 | ||
@@ -3162,6 +3746,9 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
3162 | instance->flag = 0; | 3746 | instance->flag = 0; |
3163 | instance->unload = 1; | 3747 | instance->unload = 1; |
3164 | instance->last_time = 0; | 3748 | instance->last_time = 0; |
3749 | instance->disableOnlineCtrlReset = 1; | ||
3750 | |||
3751 | INIT_WORK(&instance->work_init, process_fw_state_change_wq); | ||
3165 | 3752 | ||
3166 | /* | 3753 | /* |
3167 | * Initialize MFI Firmware | 3754 | * Initialize MFI Firmware |
@@ -3253,6 +3840,9 @@ static void megasas_flush_cache(struct megasas_instance *instance) | |||
3253 | struct megasas_cmd *cmd; | 3840 | struct megasas_cmd *cmd; |
3254 | struct megasas_dcmd_frame *dcmd; | 3841 | struct megasas_dcmd_frame *dcmd; |
3255 | 3842 | ||
3843 | if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) | ||
3844 | return; | ||
3845 | |||
3256 | cmd = megasas_get_cmd(instance); | 3846 | cmd = megasas_get_cmd(instance); |
3257 | 3847 | ||
3258 | if (!cmd) | 3848 | if (!cmd) |
@@ -3290,6 +3880,9 @@ static void megasas_shutdown_controller(struct megasas_instance *instance, | |||
3290 | struct megasas_cmd *cmd; | 3880 | struct megasas_cmd *cmd; |
3291 | struct megasas_dcmd_frame *dcmd; | 3881 | struct megasas_dcmd_frame *dcmd; |
3292 | 3882 | ||
3883 | if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) | ||
3884 | return; | ||
3885 | |||
3293 | cmd = megasas_get_cmd(instance); | 3886 | cmd = megasas_get_cmd(instance); |
3294 | 3887 | ||
3295 | if (!cmd) | 3888 | if (!cmd) |
@@ -3781,6 +4374,9 @@ static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg) | |||
3781 | struct megasas_iocpacket *ioc; | 4374 | struct megasas_iocpacket *ioc; |
3782 | struct megasas_instance *instance; | 4375 | struct megasas_instance *instance; |
3783 | int error; | 4376 | int error; |
4377 | int i; | ||
4378 | unsigned long flags; | ||
4379 | u32 wait_time = MEGASAS_RESET_WAIT_TIME; | ||
3784 | 4380 | ||
3785 | ioc = kmalloc(sizeof(*ioc), GFP_KERNEL); | 4381 | ioc = kmalloc(sizeof(*ioc), GFP_KERNEL); |
3786 | if (!ioc) | 4382 | if (!ioc) |
@@ -3797,8 +4393,8 @@ static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg) | |||
3797 | goto out_kfree_ioc; | 4393 | goto out_kfree_ioc; |
3798 | } | 4394 | } |
3799 | 4395 | ||
3800 | if (instance->hw_crit_error == 1) { | 4396 | if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) { |
3801 | printk(KERN_DEBUG "Controller in Crit ERROR\n"); | 4397 | printk(KERN_ERR "Controller in crit error\n"); |
3802 | error = -ENODEV; | 4398 | error = -ENODEV; |
3803 | goto out_kfree_ioc; | 4399 | goto out_kfree_ioc; |
3804 | } | 4400 | } |
@@ -3815,6 +4411,35 @@ static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg) | |||
3815 | error = -ERESTARTSYS; | 4411 | error = -ERESTARTSYS; |
3816 | goto out_kfree_ioc; | 4412 | goto out_kfree_ioc; |
3817 | } | 4413 | } |
4414 | |||
4415 | for (i = 0; i < wait_time; i++) { | ||
4416 | |||
4417 | spin_lock_irqsave(&instance->hba_lock, flags); | ||
4418 | if (instance->adprecovery == MEGASAS_HBA_OPERATIONAL) { | ||
4419 | spin_unlock_irqrestore(&instance->hba_lock, flags); | ||
4420 | break; | ||
4421 | } | ||
4422 | spin_unlock_irqrestore(&instance->hba_lock, flags); | ||
4423 | |||
4424 | if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) { | ||
4425 | printk(KERN_NOTICE "megasas: waiting" | ||
4426 | "for controller reset to finish\n"); | ||
4427 | } | ||
4428 | |||
4429 | msleep(1000); | ||
4430 | } | ||
4431 | |||
4432 | spin_lock_irqsave(&instance->hba_lock, flags); | ||
4433 | if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) { | ||
4434 | spin_unlock_irqrestore(&instance->hba_lock, flags); | ||
4435 | |||
4436 | printk(KERN_ERR "megaraid_sas: timed out while" | ||
4437 | "waiting for HBA to recover\n"); | ||
4438 | error = -ENODEV; | ||
4439 | goto out_kfree_ioc; | ||
4440 | } | ||
4441 | spin_unlock_irqrestore(&instance->hba_lock, flags); | ||
4442 | |||
3818 | error = megasas_mgmt_fw_ioctl(instance, user_ioc, ioc); | 4443 | error = megasas_mgmt_fw_ioctl(instance, user_ioc, ioc); |
3819 | up(&instance->ioctl_sem); | 4444 | up(&instance->ioctl_sem); |
3820 | 4445 | ||
@@ -3828,6 +4453,9 @@ static int megasas_mgmt_ioctl_aen(struct file *file, unsigned long arg) | |||
3828 | struct megasas_instance *instance; | 4453 | struct megasas_instance *instance; |
3829 | struct megasas_aen aen; | 4454 | struct megasas_aen aen; |
3830 | int error; | 4455 | int error; |
4456 | int i; | ||
4457 | unsigned long flags; | ||
4458 | u32 wait_time = MEGASAS_RESET_WAIT_TIME; | ||
3831 | 4459 | ||
3832 | if (file->private_data != file) { | 4460 | if (file->private_data != file) { |
3833 | printk(KERN_DEBUG "megasas: fasync_helper was not " | 4461 | printk(KERN_DEBUG "megasas: fasync_helper was not " |
@@ -3843,14 +4471,42 @@ static int megasas_mgmt_ioctl_aen(struct file *file, unsigned long arg) | |||
3843 | if (!instance) | 4471 | if (!instance) |
3844 | return -ENODEV; | 4472 | return -ENODEV; |
3845 | 4473 | ||
3846 | if (instance->hw_crit_error == 1) { | 4474 | if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) { |
3847 | error = -ENODEV; | 4475 | return -ENODEV; |
3848 | } | 4476 | } |
3849 | 4477 | ||
3850 | if (instance->unload == 1) { | 4478 | if (instance->unload == 1) { |
3851 | return -ENODEV; | 4479 | return -ENODEV; |
3852 | } | 4480 | } |
3853 | 4481 | ||
4482 | for (i = 0; i < wait_time; i++) { | ||
4483 | |||
4484 | spin_lock_irqsave(&instance->hba_lock, flags); | ||
4485 | if (instance->adprecovery == MEGASAS_HBA_OPERATIONAL) { | ||
4486 | spin_unlock_irqrestore(&instance->hba_lock, | ||
4487 | flags); | ||
4488 | break; | ||
4489 | } | ||
4490 | |||
4491 | spin_unlock_irqrestore(&instance->hba_lock, flags); | ||
4492 | |||
4493 | if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) { | ||
4494 | printk(KERN_NOTICE "megasas: waiting for" | ||
4495 | "controller reset to finish\n"); | ||
4496 | } | ||
4497 | |||
4498 | msleep(1000); | ||
4499 | } | ||
4500 | |||
4501 | spin_lock_irqsave(&instance->hba_lock, flags); | ||
4502 | if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) { | ||
4503 | spin_unlock_irqrestore(&instance->hba_lock, flags); | ||
4504 | printk(KERN_ERR "megaraid_sas: timed out while waiting" | ||
4505 | "for HBA to recover.\n"); | ||
4506 | return -ENODEV; | ||
4507 | } | ||
4508 | spin_unlock_irqrestore(&instance->hba_lock, flags); | ||
4509 | |||
3854 | mutex_lock(&instance->aen_mutex); | 4510 | mutex_lock(&instance->aen_mutex); |
3855 | error = megasas_register_aen(instance, aen.seq_num, | 4511 | error = megasas_register_aen(instance, aen.seq_num, |
3856 | aen.class_locale_word); | 4512 | aen.class_locale_word); |
diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 9d8b6bf605a..16a4f68a34b 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h | |||
@@ -60,6 +60,7 @@ | |||
60 | #define MFI_STATE_READY 0xB0000000 | 60 | #define MFI_STATE_READY 0xB0000000 |
61 | #define MFI_STATE_OPERATIONAL 0xC0000000 | 61 | #define MFI_STATE_OPERATIONAL 0xC0000000 |
62 | #define MFI_STATE_FAULT 0xF0000000 | 62 | #define MFI_STATE_FAULT 0xF0000000 |
63 | #define MFI_RESET_REQUIRED 0x00000001 | ||
63 | 64 | ||
64 | #define MEGAMFI_FRAME_SIZE 64 | 65 | #define MEGAMFI_FRAME_SIZE 64 |
65 | 66 | ||
@@ -73,6 +74,12 @@ | |||
73 | * HOTPLUG : Resume from Hotplug | 74 | * HOTPLUG : Resume from Hotplug |
74 | * MFI_STOP_ADP : Send signal to FW to stop processing | 75 | * MFI_STOP_ADP : Send signal to FW to stop processing |
75 | */ | 76 | */ |
77 | #define WRITE_SEQUENCE_OFFSET (0x0000000FC) /* I20 */ | ||
78 | #define HOST_DIAGNOSTIC_OFFSET (0x000000F8) /* I20 */ | ||
79 | #define DIAG_WRITE_ENABLE (0x00000080) | ||
80 | #define DIAG_RESET_ADAPTER (0x00000004) | ||
81 | |||
82 | #define MFI_ADP_RESET 0x00000040 | ||
76 | #define MFI_INIT_ABORT 0x00000001 | 83 | #define MFI_INIT_ABORT 0x00000001 |
77 | #define MFI_INIT_READY 0x00000002 | 84 | #define MFI_INIT_READY 0x00000002 |
78 | #define MFI_INIT_MFIMODE 0x00000004 | 85 | #define MFI_INIT_MFIMODE 0x00000004 |
@@ -402,8 +409,40 @@ struct megasas_ctrl_prop { | |||
402 | u16 ecc_bucket_leak_rate; | 409 | u16 ecc_bucket_leak_rate; |
403 | u8 restore_hotspare_on_insertion; | 410 | u8 restore_hotspare_on_insertion; |
404 | u8 expose_encl_devices; | 411 | u8 expose_encl_devices; |
405 | u8 reserved[38]; | 412 | u8 maintainPdFailHistory; |
413 | u8 disallowHostRequestReordering; | ||
414 | u8 abortCCOnError; | ||
415 | u8 loadBalanceMode; | ||
416 | u8 disableAutoDetectBackplane; | ||
417 | |||
418 | u8 snapVDSpace; | ||
419 | |||
420 | /* | ||
421 | * Add properties that can be controlled by | ||
422 | * a bit in the following structure. | ||
423 | */ | ||
406 | 424 | ||
425 | struct { | ||
426 | u32 copyBackDisabled : 1; | ||
427 | u32 SMARTerEnabled : 1; | ||
428 | u32 prCorrectUnconfiguredAreas : 1; | ||
429 | u32 useFdeOnly : 1; | ||
430 | u32 disableNCQ : 1; | ||
431 | u32 SSDSMARTerEnabled : 1; | ||
432 | u32 SSDPatrolReadEnabled : 1; | ||
433 | u32 enableSpinDownUnconfigured : 1; | ||
434 | u32 autoEnhancedImport : 1; | ||
435 | u32 enableSecretKeyControl : 1; | ||
436 | u32 disableOnlineCtrlReset : 1; | ||
437 | u32 allowBootWithPinnedCache : 1; | ||
438 | u32 disableSpinDownHS : 1; | ||
439 | u32 enableJBOD : 1; | ||
440 | u32 reserved :18; | ||
441 | } OnOffProperties; | ||
442 | u8 autoSnapVDSpace; | ||
443 | u8 viewSpace; | ||
444 | u16 spinDownTime; | ||
445 | u8 reserved[24]; | ||
407 | } __packed; | 446 | } __packed; |
408 | 447 | ||
409 | /* | 448 | /* |
@@ -704,6 +743,12 @@ struct megasas_ctrl_info { | |||
704 | */ | 743 | */ |
705 | #define IS_DMA64 (sizeof(dma_addr_t) == 8) | 744 | #define IS_DMA64 (sizeof(dma_addr_t) == 8) |
706 | 745 | ||
746 | #define MFI_XSCALE_OMR0_CHANGE_INTERRUPT 0x00000001 | ||
747 | |||
748 | #define MFI_INTR_FLAG_REPLY_MESSAGE 0x00000001 | ||
749 | #define MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE 0x00000002 | ||
750 | #define MFI_G2_OUTBOUND_DOORBELL_CHANGE_INTERRUPT 0x00000004 | ||
751 | |||
707 | #define MFI_OB_INTR_STATUS_MASK 0x00000002 | 752 | #define MFI_OB_INTR_STATUS_MASK 0x00000002 |
708 | #define MFI_POLL_TIMEOUT_SECS 60 | 753 | #define MFI_POLL_TIMEOUT_SECS 60 |
709 | #define MEGASAS_COMPLETION_TIMER_INTERVAL (HZ/10) | 754 | #define MEGASAS_COMPLETION_TIMER_INTERVAL (HZ/10) |
@@ -714,6 +759,9 @@ struct megasas_ctrl_info { | |||
714 | #define MFI_REPLY_SKINNY_MESSAGE_INTERRUPT 0x40000000 | 759 | #define MFI_REPLY_SKINNY_MESSAGE_INTERRUPT 0x40000000 |
715 | #define MFI_SKINNY_ENABLE_INTERRUPT_MASK (0x00000001) | 760 | #define MFI_SKINNY_ENABLE_INTERRUPT_MASK (0x00000001) |
716 | 761 | ||
762 | #define MFI_1068_PCSR_OFFSET 0x84 | ||
763 | #define MFI_1068_FW_HANDSHAKE_OFFSET 0x64 | ||
764 | #define MFI_1068_FW_READY 0xDDDD0000 | ||
717 | /* | 765 | /* |
718 | * register set for both 1068 and 1078 controllers | 766 | * register set for both 1068 and 1078 controllers |
719 | * structure extended for 1078 registers | 767 | * structure extended for 1078 registers |
@@ -755,8 +803,10 @@ struct megasas_register_set { | |||
755 | u32 inbound_high_queue_port ; /*00C4h*/ | 803 | u32 inbound_high_queue_port ; /*00C4h*/ |
756 | 804 | ||
757 | u32 reserved_5; /*00C8h*/ | 805 | u32 reserved_5; /*00C8h*/ |
758 | u32 index_registers[820]; /*00CCh*/ | 806 | u32 res_6[11]; /*CCh*/ |
759 | 807 | u32 host_diag; | |
808 | u32 seq_offset; | ||
809 | u32 index_registers[807]; /*00CCh*/ | ||
760 | } __attribute__ ((packed)); | 810 | } __attribute__ ((packed)); |
761 | 811 | ||
762 | struct megasas_sge32 { | 812 | struct megasas_sge32 { |
@@ -1226,11 +1276,12 @@ struct megasas_instance { | |||
1226 | 1276 | ||
1227 | struct megasas_cmd **cmd_list; | 1277 | struct megasas_cmd **cmd_list; |
1228 | struct list_head cmd_pool; | 1278 | struct list_head cmd_pool; |
1279 | /* used to sync fire the cmd to fw */ | ||
1229 | spinlock_t cmd_pool_lock; | 1280 | spinlock_t cmd_pool_lock; |
1281 | /* used to sync fire the cmd to fw */ | ||
1282 | spinlock_t hba_lock; | ||
1230 | /* used to synch producer, consumer ptrs in dpc */ | 1283 | /* used to synch producer, consumer ptrs in dpc */ |
1231 | spinlock_t completion_lock; | 1284 | spinlock_t completion_lock; |
1232 | /* used to sync fire the cmd to fw */ | ||
1233 | spinlock_t fire_lock; | ||
1234 | struct dma_pool *frame_dma_pool; | 1285 | struct dma_pool *frame_dma_pool; |
1235 | struct dma_pool *sense_dma_pool; | 1286 | struct dma_pool *sense_dma_pool; |
1236 | 1287 | ||
@@ -1247,19 +1298,36 @@ struct megasas_instance { | |||
1247 | 1298 | ||
1248 | struct pci_dev *pdev; | 1299 | struct pci_dev *pdev; |
1249 | u32 unique_id; | 1300 | u32 unique_id; |
1301 | u32 fw_support_ieee; | ||
1250 | 1302 | ||
1251 | atomic_t fw_outstanding; | 1303 | atomic_t fw_outstanding; |
1252 | u32 hw_crit_error; | 1304 | atomic_t fw_reset_no_pci_access; |
1253 | 1305 | ||
1254 | struct megasas_instance_template *instancet; | 1306 | struct megasas_instance_template *instancet; |
1255 | struct tasklet_struct isr_tasklet; | 1307 | struct tasklet_struct isr_tasklet; |
1308 | struct work_struct work_init; | ||
1256 | 1309 | ||
1257 | u8 flag; | 1310 | u8 flag; |
1258 | u8 unload; | 1311 | u8 unload; |
1259 | u8 flag_ieee; | 1312 | u8 flag_ieee; |
1313 | u8 issuepend_done; | ||
1314 | u8 disableOnlineCtrlReset; | ||
1315 | u8 adprecovery; | ||
1260 | unsigned long last_time; | 1316 | unsigned long last_time; |
1317 | u32 mfiStatus; | ||
1318 | u32 last_seq_num; | ||
1261 | 1319 | ||
1262 | struct timer_list io_completion_timer; | 1320 | struct timer_list io_completion_timer; |
1321 | struct list_head internal_reset_pending_q; | ||
1322 | }; | ||
1323 | |||
1324 | enum { | ||
1325 | MEGASAS_HBA_OPERATIONAL = 0, | ||
1326 | MEGASAS_ADPRESET_SM_INFAULT = 1, | ||
1327 | MEGASAS_ADPRESET_SM_FW_RESET_SUCCESS = 2, | ||
1328 | MEGASAS_ADPRESET_SM_OPERATIONAL = 3, | ||
1329 | MEGASAS_HW_CRITICAL_ERROR = 4, | ||
1330 | MEGASAS_ADPRESET_INPROG_SIGN = 0xDEADDEAD, | ||
1263 | }; | 1331 | }; |
1264 | 1332 | ||
1265 | struct megasas_instance_template { | 1333 | struct megasas_instance_template { |
@@ -1272,6 +1340,10 @@ struct megasas_instance_template { | |||
1272 | int (*clear_intr)(struct megasas_register_set __iomem *); | 1340 | int (*clear_intr)(struct megasas_register_set __iomem *); |
1273 | 1341 | ||
1274 | u32 (*read_fw_status_reg)(struct megasas_register_set __iomem *); | 1342 | u32 (*read_fw_status_reg)(struct megasas_register_set __iomem *); |
1343 | int (*adp_reset)(struct megasas_instance *, \ | ||
1344 | struct megasas_register_set __iomem *); | ||
1345 | int (*check_reset)(struct megasas_instance *, \ | ||
1346 | struct megasas_register_set __iomem *); | ||
1275 | }; | 1347 | }; |
1276 | 1348 | ||
1277 | #define MEGASAS_IS_LOGICAL(scp) \ | 1349 | #define MEGASAS_IS_LOGICAL(scp) \ |
@@ -1291,7 +1363,9 @@ struct megasas_cmd { | |||
1291 | u32 index; | 1363 | u32 index; |
1292 | u8 sync_cmd; | 1364 | u8 sync_cmd; |
1293 | u8 cmd_status; | 1365 | u8 cmd_status; |
1294 | u16 abort_aen; | 1366 | u8 abort_aen; |
1367 | u8 retry_for_fw_reset; | ||
1368 | |||
1295 | 1369 | ||
1296 | struct list_head list; | 1370 | struct list_head list; |
1297 | struct scsi_cmnd *scmd; | 1371 | struct scsi_cmnd *scmd; |