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