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 99e4478c3f3e..55951f4d3260 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 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; |
