diff options
author | James Smart <james.smart@emulex.com> | 2010-03-15 11:25:20 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2010-04-11 10:23:50 -0400 |
commit | 7a4702774381103e936cae09ec12301090c6c212 (patch) | |
tree | 537fcd43fb911d9841d2d3ba3790b135bc6aa907 /drivers/scsi | |
parent | cb5172eafd9ffdab6bb7b1eec628ea706d5817c8 (diff) |
[SCSI] lpfc 8.3.11: Driver management improvements via BSG
- Add BSG support for PCI loopback testing.
- Add BSG support for extended mailbox commands.
Signed-off-by: Alex Iannicelli <alex.iannicelli@emulex.com>
Signed-off-by: James Smart <james.smart@emulex.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/lpfc/lpfc.h | 2 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_bsg.c | 257 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_bsg.h | 4 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hw.h | 10 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_init.c | 2 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_mbox.c | 51 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.c | 50 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.h | 3 |
8 files changed, 296 insertions, 83 deletions
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 565e16dd74fc..23b9320539e1 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h | |||
@@ -554,6 +554,7 @@ struct lpfc_hba { | |||
554 | struct lpfc_dmabuf slim2p; | 554 | struct lpfc_dmabuf slim2p; |
555 | 555 | ||
556 | MAILBOX_t *mbox; | 556 | MAILBOX_t *mbox; |
557 | uint32_t *mbox_ext; | ||
557 | uint32_t *inb_ha_copy; | 558 | uint32_t *inb_ha_copy; |
558 | uint32_t *inb_counter; | 559 | uint32_t *inb_counter; |
559 | uint32_t inb_last_counter; | 560 | uint32_t inb_last_counter; |
@@ -622,6 +623,7 @@ struct lpfc_hba { | |||
622 | uint32_t cfg_enable_hba_reset; | 623 | uint32_t cfg_enable_hba_reset; |
623 | uint32_t cfg_enable_hba_heartbeat; | 624 | uint32_t cfg_enable_hba_heartbeat; |
624 | uint32_t cfg_enable_bg; | 625 | uint32_t cfg_enable_bg; |
626 | uint32_t cfg_hostmem_hgp; | ||
625 | uint32_t cfg_log_verbose; | 627 | uint32_t cfg_log_verbose; |
626 | uint32_t cfg_aer_support; | 628 | uint32_t cfg_aer_support; |
627 | uint32_t cfg_suppress_link_up; | 629 | uint32_t cfg_suppress_link_up; |
diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index d62b3e467926..92ad202a9380 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c | |||
@@ -79,6 +79,12 @@ struct lpfc_bsg_iocb { | |||
79 | struct lpfc_bsg_mbox { | 79 | struct lpfc_bsg_mbox { |
80 | LPFC_MBOXQ_t *pmboxq; | 80 | LPFC_MBOXQ_t *pmboxq; |
81 | MAILBOX_t *mb; | 81 | MAILBOX_t *mb; |
82 | struct lpfc_dmabuf *rxbmp; /* for BIU diags */ | ||
83 | struct lpfc_dmabufext *dmp; /* for BIU diags */ | ||
84 | uint8_t *ext; /* extended mailbox data */ | ||
85 | uint32_t mbOffset; /* from app */ | ||
86 | uint32_t inExtWLen; /* from app */ | ||
87 | uint32_t outWxtWLen; /* from app */ | ||
82 | 88 | ||
83 | /* job waiting for this mbox command to finish */ | 89 | /* job waiting for this mbox command to finish */ |
84 | struct fc_bsg_job *set_job; | 90 | struct fc_bsg_job *set_job; |
@@ -2377,35 +2383,68 @@ void | |||
2377 | lpfc_bsg_wake_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) | 2383 | lpfc_bsg_wake_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) |
2378 | { | 2384 | { |
2379 | struct bsg_job_data *dd_data; | 2385 | struct bsg_job_data *dd_data; |
2380 | MAILBOX_t *pmb; | ||
2381 | MAILBOX_t *mb; | ||
2382 | struct fc_bsg_job *job; | 2386 | struct fc_bsg_job *job; |
2383 | uint32_t size; | 2387 | uint32_t size; |
2384 | unsigned long flags; | 2388 | unsigned long flags; |
2389 | uint8_t *to; | ||
2390 | uint8_t *from; | ||
2385 | 2391 | ||
2386 | spin_lock_irqsave(&phba->ct_ev_lock, flags); | 2392 | spin_lock_irqsave(&phba->ct_ev_lock, flags); |
2387 | dd_data = pmboxq->context1; | 2393 | dd_data = pmboxq->context1; |
2394 | /* job already timed out? */ | ||
2388 | if (!dd_data) { | 2395 | if (!dd_data) { |
2389 | spin_unlock_irqrestore(&phba->ct_ev_lock, flags); | 2396 | spin_unlock_irqrestore(&phba->ct_ev_lock, flags); |
2390 | return; | 2397 | return; |
2391 | } | 2398 | } |
2392 | 2399 | ||
2393 | pmb = &dd_data->context_un.mbox.pmboxq->u.mb; | 2400 | /* build the outgoing buffer to do an sg copy |
2394 | mb = dd_data->context_un.mbox.mb; | 2401 | * the format is the response mailbox followed by any extended |
2402 | * mailbox data | ||
2403 | */ | ||
2404 | from = (uint8_t *)&pmboxq->u.mb; | ||
2405 | to = (uint8_t *)dd_data->context_un.mbox.mb; | ||
2406 | memcpy(to, from, sizeof(MAILBOX_t)); | ||
2407 | /* copy the extended data if any, count is in words */ | ||
2408 | if (dd_data->context_un.mbox.outWxtWLen) { | ||
2409 | from = (uint8_t *)dd_data->context_un.mbox.ext; | ||
2410 | to += sizeof(MAILBOX_t); | ||
2411 | memcpy(to, from, | ||
2412 | dd_data->context_un.mbox.outWxtWLen * sizeof(uint32_t)); | ||
2413 | } | ||
2414 | |||
2415 | from = (uint8_t *)dd_data->context_un.mbox.mb; | ||
2395 | job = dd_data->context_un.mbox.set_job; | 2416 | job = dd_data->context_un.mbox.set_job; |
2396 | memcpy(mb, pmb, sizeof(*pmb)); | 2417 | size = job->reply_payload.payload_len; |
2397 | size = job->request_payload.payload_len; | ||
2398 | job->reply->reply_payload_rcv_len = | 2418 | job->reply->reply_payload_rcv_len = |
2399 | sg_copy_from_buffer(job->reply_payload.sg_list, | 2419 | sg_copy_from_buffer(job->reply_payload.sg_list, |
2400 | job->reply_payload.sg_cnt, | 2420 | job->reply_payload.sg_cnt, |
2401 | mb, size); | 2421 | from, size); |
2402 | job->reply->result = 0; | 2422 | job->reply->result = 0; |
2423 | |||
2403 | dd_data->context_un.mbox.set_job = NULL; | 2424 | dd_data->context_un.mbox.set_job = NULL; |
2404 | job->dd_data = NULL; | 2425 | job->dd_data = NULL; |
2405 | job->job_done(job); | 2426 | job->job_done(job); |
2427 | /* need to hold the lock until we call job done to hold off | ||
2428 | * the timeout handler returning to the midlayer while | ||
2429 | * we are stillprocessing the job | ||
2430 | */ | ||
2406 | spin_unlock_irqrestore(&phba->ct_ev_lock, flags); | 2431 | spin_unlock_irqrestore(&phba->ct_ev_lock, flags); |
2432 | |||
2433 | kfree(dd_data->context_un.mbox.mb); | ||
2407 | mempool_free(dd_data->context_un.mbox.pmboxq, phba->mbox_mem_pool); | 2434 | mempool_free(dd_data->context_un.mbox.pmboxq, phba->mbox_mem_pool); |
2408 | kfree(mb); | 2435 | kfree(dd_data->context_un.mbox.ext); |
2436 | if (dd_data->context_un.mbox.dmp) { | ||
2437 | dma_free_coherent(&phba->pcidev->dev, | ||
2438 | dd_data->context_un.mbox.dmp->size, | ||
2439 | dd_data->context_un.mbox.dmp->dma.virt, | ||
2440 | dd_data->context_un.mbox.dmp->dma.phys); | ||
2441 | kfree(dd_data->context_un.mbox.dmp); | ||
2442 | } | ||
2443 | if (dd_data->context_un.mbox.rxbmp) { | ||
2444 | lpfc_mbuf_free(phba, dd_data->context_un.mbox.rxbmp->virt, | ||
2445 | dd_data->context_un.mbox.rxbmp->phys); | ||
2446 | kfree(dd_data->context_un.mbox.rxbmp); | ||
2447 | } | ||
2409 | kfree(dd_data); | 2448 | kfree(dd_data); |
2410 | return; | 2449 | return; |
2411 | } | 2450 | } |
@@ -2468,6 +2507,7 @@ static int lpfc_bsg_check_cmd_access(struct lpfc_hba *phba, | |||
2468 | case MBX_WRITE_EVENT_LOG: | 2507 | case MBX_WRITE_EVENT_LOG: |
2469 | case MBX_PORT_CAPABILITIES: | 2508 | case MBX_PORT_CAPABILITIES: |
2470 | case MBX_PORT_IOV_CONTROL: | 2509 | case MBX_PORT_IOV_CONTROL: |
2510 | case MBX_RUN_BIU_DIAG64: | ||
2471 | break; | 2511 | break; |
2472 | case MBX_SET_VARIABLE: | 2512 | case MBX_SET_VARIABLE: |
2473 | lpfc_printf_log(phba, KERN_INFO, LOG_INIT, | 2513 | lpfc_printf_log(phba, KERN_INFO, LOG_INIT, |
@@ -2482,7 +2522,6 @@ static int lpfc_bsg_check_cmd_access(struct lpfc_hba *phba, | |||
2482 | phba->fc_topology = TOPOLOGY_PT_PT; | 2522 | phba->fc_topology = TOPOLOGY_PT_PT; |
2483 | } | 2523 | } |
2484 | break; | 2524 | break; |
2485 | case MBX_RUN_BIU_DIAG64: | ||
2486 | case MBX_READ_EVENT_LOG: | 2525 | case MBX_READ_EVENT_LOG: |
2487 | case MBX_READ_SPARM64: | 2526 | case MBX_READ_SPARM64: |
2488 | case MBX_READ_LA: | 2527 | case MBX_READ_LA: |
@@ -2518,97 +2557,199 @@ static uint32_t | |||
2518 | lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job, | 2557 | lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job, |
2519 | struct lpfc_vport *vport) | 2558 | struct lpfc_vport *vport) |
2520 | { | 2559 | { |
2521 | LPFC_MBOXQ_t *pmboxq; | 2560 | LPFC_MBOXQ_t *pmboxq = NULL; /* internal mailbox queue */ |
2522 | MAILBOX_t *pmb; | 2561 | MAILBOX_t *pmb; /* shortcut to the pmboxq mailbox */ |
2523 | MAILBOX_t *mb; | 2562 | /* a 4k buffer to hold the mb and extended data from/to the bsg */ |
2524 | struct bsg_job_data *dd_data; | 2563 | MAILBOX_t *mb = NULL; |
2564 | struct bsg_job_data *dd_data = NULL; /* bsg data tracking structure */ | ||
2525 | uint32_t size; | 2565 | uint32_t size; |
2566 | struct lpfc_dmabuf *rxbmp = NULL; /* for biu diag */ | ||
2567 | struct lpfc_dmabufext *dmp = NULL; /* for biu diag */ | ||
2568 | struct ulp_bde64 *rxbpl = NULL; | ||
2569 | struct dfc_mbox_req *mbox_req = (struct dfc_mbox_req *) | ||
2570 | job->request->rqst_data.h_vendor.vendor_cmd; | ||
2571 | uint8_t *ext = NULL; | ||
2526 | int rc = 0; | 2572 | int rc = 0; |
2573 | uint8_t *from; | ||
2574 | |||
2575 | /* in case no data is transferred */ | ||
2576 | job->reply->reply_payload_rcv_len = 0; | ||
2577 | |||
2578 | /* check if requested extended data lengths are valid */ | ||
2579 | if ((mbox_req->inExtWLen > MAILBOX_EXT_SIZE) || | ||
2580 | (mbox_req->outWxtWLen > MAILBOX_EXT_SIZE)) { | ||
2581 | rc = -ERANGE; | ||
2582 | goto job_done; | ||
2583 | } | ||
2527 | 2584 | ||
2528 | /* allocate our bsg tracking structure */ | 2585 | /* allocate our bsg tracking structure */ |
2529 | dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); | 2586 | dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); |
2530 | if (!dd_data) { | 2587 | if (!dd_data) { |
2531 | lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, | 2588 | lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, |
2532 | "2727 Failed allocation of dd_data\n"); | 2589 | "2727 Failed allocation of dd_data\n"); |
2533 | return -ENOMEM; | 2590 | rc = -ENOMEM; |
2591 | goto job_done; | ||
2534 | } | 2592 | } |
2535 | 2593 | ||
2536 | mb = kzalloc(PAGE_SIZE, GFP_KERNEL); | 2594 | mb = kzalloc(PAGE_SIZE, GFP_KERNEL); |
2537 | if (!mb) { | 2595 | if (!mb) { |
2538 | kfree(dd_data); | 2596 | rc = -ENOMEM; |
2539 | return -ENOMEM; | 2597 | goto job_done; |
2540 | } | 2598 | } |
2541 | 2599 | ||
2542 | pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); | 2600 | pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); |
2543 | if (!pmboxq) { | 2601 | if (!pmboxq) { |
2544 | kfree(dd_data); | 2602 | rc = -ENOMEM; |
2545 | kfree(mb); | 2603 | goto job_done; |
2546 | return -ENOMEM; | ||
2547 | } | 2604 | } |
2605 | memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t)); | ||
2548 | 2606 | ||
2549 | size = job->request_payload.payload_len; | 2607 | size = job->request_payload.payload_len; |
2550 | job->reply->reply_payload_rcv_len = | 2608 | sg_copy_to_buffer(job->request_payload.sg_list, |
2551 | sg_copy_to_buffer(job->request_payload.sg_list, | 2609 | job->request_payload.sg_cnt, |
2552 | job->request_payload.sg_cnt, | 2610 | mb, size); |
2553 | mb, size); | ||
2554 | 2611 | ||
2555 | rc = lpfc_bsg_check_cmd_access(phba, mb, vport); | 2612 | rc = lpfc_bsg_check_cmd_access(phba, mb, vport); |
2556 | if (rc != 0) { | 2613 | if (rc != 0) |
2557 | kfree(dd_data); | 2614 | goto job_done; /* must be negative */ |
2558 | kfree(mb); | ||
2559 | mempool_free(pmboxq, phba->mbox_mem_pool); | ||
2560 | return rc; /* must be negative */ | ||
2561 | } | ||
2562 | 2615 | ||
2563 | memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t)); | ||
2564 | pmb = &pmboxq->u.mb; | 2616 | pmb = &pmboxq->u.mb; |
2565 | memcpy(pmb, mb, sizeof(*pmb)); | 2617 | memcpy(pmb, mb, sizeof(*pmb)); |
2566 | pmb->mbxOwner = OWN_HOST; | 2618 | pmb->mbxOwner = OWN_HOST; |
2567 | pmboxq->context1 = NULL; | ||
2568 | pmboxq->vport = vport; | 2619 | pmboxq->vport = vport; |
2569 | 2620 | ||
2621 | /* extended mailbox commands will need an extended buffer */ | ||
2622 | if (mbox_req->inExtWLen || mbox_req->outWxtWLen) { | ||
2623 | ext = kzalloc(MAILBOX_EXT_SIZE, GFP_KERNEL); | ||
2624 | if (!ext) { | ||
2625 | rc = -ENOMEM; | ||
2626 | goto job_done; | ||
2627 | } | ||
2628 | |||
2629 | /* any data for the device? */ | ||
2630 | if (mbox_req->inExtWLen) { | ||
2631 | from = (uint8_t *)mb; | ||
2632 | from += sizeof(MAILBOX_t); | ||
2633 | memcpy((uint8_t *)ext, from, | ||
2634 | mbox_req->inExtWLen * sizeof(uint32_t)); | ||
2635 | } | ||
2636 | |||
2637 | pmboxq->context2 = ext; | ||
2638 | pmboxq->in_ext_byte_len = | ||
2639 | mbox_req->inExtWLen * | ||
2640 | sizeof(uint32_t); | ||
2641 | pmboxq->out_ext_byte_len = | ||
2642 | mbox_req->outWxtWLen * | ||
2643 | sizeof(uint32_t); | ||
2644 | pmboxq->mbox_offset_word = | ||
2645 | mbox_req->mbOffset; | ||
2646 | pmboxq->context2 = ext; | ||
2647 | pmboxq->in_ext_byte_len = | ||
2648 | mbox_req->inExtWLen * sizeof(uint32_t); | ||
2649 | pmboxq->out_ext_byte_len = | ||
2650 | mbox_req->outWxtWLen * sizeof(uint32_t); | ||
2651 | pmboxq->mbox_offset_word = mbox_req->mbOffset; | ||
2652 | } | ||
2653 | |||
2654 | /* biu diag will need a kernel buffer to transfer the data | ||
2655 | * allocate our own buffer and setup the mailbox command to | ||
2656 | * use ours | ||
2657 | */ | ||
2658 | if (pmb->mbxCommand == MBX_RUN_BIU_DIAG64) { | ||
2659 | rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); | ||
2660 | if (!rxbmp) { | ||
2661 | rc = -ENOMEM; | ||
2662 | goto job_done; | ||
2663 | } | ||
2664 | |||
2665 | rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys); | ||
2666 | INIT_LIST_HEAD(&rxbmp->list); | ||
2667 | rxbpl = (struct ulp_bde64 *) rxbmp->virt; | ||
2668 | dmp = diag_cmd_data_alloc(phba, rxbpl, PAGE_SIZE, 0); | ||
2669 | if (!dmp) { | ||
2670 | rc = -ENOMEM; | ||
2671 | goto job_done; | ||
2672 | } | ||
2673 | |||
2674 | dmp->size = PAGE_SIZE; | ||
2675 | INIT_LIST_HEAD(&dmp->dma.list); | ||
2676 | pmb->un.varBIUdiag.un.s2.xmit_bde64.addrHigh = | ||
2677 | putPaddrHigh(dmp->dma.phys); | ||
2678 | pmb->un.varBIUdiag.un.s2.xmit_bde64.addrLow = | ||
2679 | putPaddrLow(dmp->dma.phys); | ||
2680 | |||
2681 | pmb->un.varBIUdiag.un.s2.rcv_bde64.addrHigh = | ||
2682 | putPaddrHigh(dmp->dma.phys + | ||
2683 | pmb->un.varBIUdiag.un.s2. | ||
2684 | xmit_bde64.tus.f.bdeSize); | ||
2685 | pmb->un.varBIUdiag.un.s2.rcv_bde64.addrLow = | ||
2686 | putPaddrLow(dmp->dma.phys + | ||
2687 | pmb->un.varBIUdiag.un.s2. | ||
2688 | xmit_bde64.tus.f.bdeSize); | ||
2689 | dd_data->context_un.mbox.rxbmp = rxbmp; | ||
2690 | dd_data->context_un.mbox.dmp = dmp; | ||
2691 | } else { | ||
2692 | dd_data->context_un.mbox.rxbmp = NULL; | ||
2693 | dd_data->context_un.mbox.dmp = NULL; | ||
2694 | } | ||
2695 | |||
2696 | /* setup wake call as IOCB callback */ | ||
2697 | pmboxq->mbox_cmpl = lpfc_bsg_wake_mbox_wait; | ||
2698 | |||
2699 | /* setup context field to pass wait_queue pointer to wake function */ | ||
2700 | pmboxq->context1 = dd_data; | ||
2701 | dd_data->type = TYPE_MBOX; | ||
2702 | dd_data->context_un.mbox.pmboxq = pmboxq; | ||
2703 | dd_data->context_un.mbox.mb = mb; | ||
2704 | dd_data->context_un.mbox.set_job = job; | ||
2705 | dd_data->context_un.mbox.ext = ext; | ||
2706 | dd_data->context_un.mbox.mbOffset = mbox_req->mbOffset; | ||
2707 | dd_data->context_un.mbox.inExtWLen = mbox_req->inExtWLen; | ||
2708 | dd_data->context_un.mbox.outWxtWLen = mbox_req->outWxtWLen; | ||
2709 | job->dd_data = dd_data; | ||
2710 | |||
2570 | if ((vport->fc_flag & FC_OFFLINE_MODE) || | 2711 | if ((vport->fc_flag & FC_OFFLINE_MODE) || |
2571 | (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE))) { | 2712 | (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE))) { |
2572 | rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); | 2713 | rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); |
2573 | if (rc != MBX_SUCCESS) { | 2714 | if (rc != MBX_SUCCESS) { |
2574 | if (rc != MBX_TIMEOUT) { | 2715 | rc = (rc == MBX_TIMEOUT) ? -ETIME : -ENODEV; |
2575 | kfree(dd_data); | 2716 | goto job_done; |
2576 | kfree(mb); | ||
2577 | mempool_free(pmboxq, phba->mbox_mem_pool); | ||
2578 | } | ||
2579 | return (rc == MBX_TIMEOUT) ? -ETIME : -ENODEV; | ||
2580 | } | 2717 | } |
2581 | 2718 | ||
2719 | /* job finished, copy the data */ | ||
2582 | memcpy(mb, pmb, sizeof(*pmb)); | 2720 | memcpy(mb, pmb, sizeof(*pmb)); |
2583 | job->reply->reply_payload_rcv_len = | 2721 | job->reply->reply_payload_rcv_len = |
2584 | sg_copy_from_buffer(job->reply_payload.sg_list, | 2722 | sg_copy_from_buffer(job->reply_payload.sg_list, |
2585 | job->reply_payload.sg_cnt, | 2723 | job->reply_payload.sg_cnt, |
2586 | mb, size); | 2724 | mb, size); |
2587 | kfree(dd_data); | ||
2588 | kfree(mb); | ||
2589 | mempool_free(pmboxq, phba->mbox_mem_pool); | ||
2590 | /* not waiting mbox already done */ | 2725 | /* not waiting mbox already done */ |
2591 | return 0; | 2726 | rc = 0; |
2727 | goto job_done; | ||
2592 | } | 2728 | } |
2593 | 2729 | ||
2594 | /* setup wake call as IOCB callback */ | ||
2595 | pmboxq->mbox_cmpl = lpfc_bsg_wake_mbox_wait; | ||
2596 | /* setup context field to pass wait_queue pointer to wake function */ | ||
2597 | pmboxq->context1 = dd_data; | ||
2598 | dd_data->type = TYPE_MBOX; | ||
2599 | dd_data->context_un.mbox.pmboxq = pmboxq; | ||
2600 | dd_data->context_un.mbox.mb = mb; | ||
2601 | dd_data->context_un.mbox.set_job = job; | ||
2602 | job->dd_data = dd_data; | ||
2603 | rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT); | 2730 | rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT); |
2604 | if ((rc != MBX_SUCCESS) && (rc != MBX_BUSY)) { | 2731 | if ((rc == MBX_SUCCESS) || (rc == MBX_BUSY)) |
2605 | kfree(dd_data); | 2732 | return 1; /* job started */ |
2606 | kfree(mb); | 2733 | |
2734 | job_done: | ||
2735 | /* common exit for error or job completed inline */ | ||
2736 | kfree(mb); | ||
2737 | if (pmboxq) | ||
2607 | mempool_free(pmboxq, phba->mbox_mem_pool); | 2738 | mempool_free(pmboxq, phba->mbox_mem_pool); |
2608 | return -EIO; | 2739 | kfree(ext); |
2740 | if (dmp) { | ||
2741 | dma_free_coherent(&phba->pcidev->dev, | ||
2742 | dmp->size, dmp->dma.virt, | ||
2743 | dmp->dma.phys); | ||
2744 | kfree(dmp); | ||
2745 | } | ||
2746 | if (rxbmp) { | ||
2747 | lpfc_mbuf_free(phba, rxbmp->virt, rxbmp->phys); | ||
2748 | kfree(rxbmp); | ||
2609 | } | 2749 | } |
2750 | kfree(dd_data); | ||
2610 | 2751 | ||
2611 | return 1; | 2752 | return rc; |
2612 | } | 2753 | } |
2613 | 2754 | ||
2614 | /** | 2755 | /** |
@@ -2638,6 +2779,11 @@ lpfc_bsg_mbox_cmd(struct fc_bsg_job *job) | |||
2638 | goto job_error; | 2779 | goto job_error; |
2639 | } | 2780 | } |
2640 | 2781 | ||
2782 | if (job->reply_payload.payload_len != PAGE_SIZE) { | ||
2783 | rc = -EINVAL; | ||
2784 | goto job_error; | ||
2785 | } | ||
2786 | |||
2641 | if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) { | 2787 | if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) { |
2642 | rc = -EAGAIN; | 2788 | rc = -EAGAIN; |
2643 | goto job_error; | 2789 | goto job_error; |
@@ -3094,6 +3240,7 @@ lpfc_bsg_timeout(struct fc_bsg_job *job) | |||
3094 | job->dd_data = NULL; | 3240 | job->dd_data = NULL; |
3095 | job->reply->reply_payload_rcv_len = 0; | 3241 | job->reply->reply_payload_rcv_len = 0; |
3096 | job->reply->result = -EAGAIN; | 3242 | job->reply->result = -EAGAIN; |
3243 | /* the mbox completion handler can now be run */ | ||
3097 | spin_unlock_irqrestore(&phba->ct_ev_lock, flags); | 3244 | spin_unlock_irqrestore(&phba->ct_ev_lock, flags); |
3098 | job->job_done(job); | 3245 | job->job_done(job); |
3099 | break; | 3246 | break; |
diff --git a/drivers/scsi/lpfc/lpfc_bsg.h b/drivers/scsi/lpfc/lpfc_bsg.h index 5bc630819b9e..e89ed22bbb01 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.h +++ b/drivers/scsi/lpfc/lpfc_bsg.h | |||
@@ -93,9 +93,9 @@ struct get_mgmt_rev_reply { | |||
93 | 93 | ||
94 | struct dfc_mbox_req { | 94 | struct dfc_mbox_req { |
95 | uint32_t command; | 95 | uint32_t command; |
96 | uint32_t mbOffset; | ||
96 | uint32_t inExtWLen; | 97 | uint32_t inExtWLen; |
97 | uint32_t outExtWLen; | 98 | uint32_t outWxtWLen; |
98 | uint8_t mbOffset; | ||
99 | }; | 99 | }; |
100 | 100 | ||
101 | /* Used for menlo command or menlo data. The xri is only used for menlo data */ | 101 | /* Used for menlo command or menlo data. The xri is only used for menlo data */ |
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index 89ff7c09e298..6c71ea416634 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h | |||
@@ -2934,6 +2934,12 @@ typedef struct { | |||
2934 | /* Union of all Mailbox Command types */ | 2934 | /* Union of all Mailbox Command types */ |
2935 | #define MAILBOX_CMD_WSIZE 32 | 2935 | #define MAILBOX_CMD_WSIZE 32 |
2936 | #define MAILBOX_CMD_SIZE (MAILBOX_CMD_WSIZE * sizeof(uint32_t)) | 2936 | #define MAILBOX_CMD_SIZE (MAILBOX_CMD_WSIZE * sizeof(uint32_t)) |
2937 | /* ext_wsize times 4 bytes should not be greater than max xmit size */ | ||
2938 | #define MAILBOX_EXT_WSIZE 512 | ||
2939 | #define MAILBOX_EXT_SIZE (MAILBOX_EXT_WSIZE * sizeof(uint32_t)) | ||
2940 | #define MAILBOX_HBA_EXT_OFFSET 0x100 | ||
2941 | /* max mbox xmit size is a page size for sysfs IO operations */ | ||
2942 | #define MAILBOX_MAX_XMIT_SIZE PAGE_SIZE | ||
2937 | 2943 | ||
2938 | typedef union { | 2944 | typedef union { |
2939 | uint32_t varWords[MAILBOX_CMD_WSIZE - 1]; /* first word is type/ | 2945 | uint32_t varWords[MAILBOX_CMD_WSIZE - 1]; /* first word is type/ |
@@ -3652,7 +3658,8 @@ typedef struct _IOCB { /* IOCB structure */ | |||
3652 | /* Maximum IOCBs that will fit in SLI2 slim */ | 3658 | /* Maximum IOCBs that will fit in SLI2 slim */ |
3653 | #define MAX_SLI2_IOCB 498 | 3659 | #define MAX_SLI2_IOCB 498 |
3654 | #define MAX_SLIM_IOCB_SIZE (SLI2_SLIM_SIZE - \ | 3660 | #define MAX_SLIM_IOCB_SIZE (SLI2_SLIM_SIZE - \ |
3655 | (sizeof(MAILBOX_t) + sizeof(PCB_t))) | 3661 | (sizeof(MAILBOX_t) + sizeof(PCB_t) + \ |
3662 | sizeof(uint32_t) * MAILBOX_EXT_WSIZE)) | ||
3656 | 3663 | ||
3657 | /* HBQ entries are 4 words each = 4k */ | 3664 | /* HBQ entries are 4 words each = 4k */ |
3658 | #define LPFC_TOTAL_HBQ_SIZE (sizeof(struct lpfc_hbq_entry) * \ | 3665 | #define LPFC_TOTAL_HBQ_SIZE (sizeof(struct lpfc_hbq_entry) * \ |
@@ -3660,6 +3667,7 @@ typedef struct _IOCB { /* IOCB structure */ | |||
3660 | 3667 | ||
3661 | struct lpfc_sli2_slim { | 3668 | struct lpfc_sli2_slim { |
3662 | MAILBOX_t mbx; | 3669 | MAILBOX_t mbx; |
3670 | uint32_t mbx_ext_words[MAILBOX_EXT_WSIZE]; | ||
3663 | PCB_t pcb; | 3671 | PCB_t pcb; |
3664 | IOCB_t IOCBs[MAX_SLIM_IOCB_SIZE]; | 3672 | IOCB_t IOCBs[MAX_SLIM_IOCB_SIZE]; |
3665 | }; | 3673 | }; |
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index f8e88bb423cb..feba3be90cb2 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c | |||
@@ -5059,6 +5059,8 @@ lpfc_sli_pci_mem_setup(struct lpfc_hba *phba) | |||
5059 | 5059 | ||
5060 | memset(phba->slim2p.virt, 0, SLI2_SLIM_SIZE); | 5060 | memset(phba->slim2p.virt, 0, SLI2_SLIM_SIZE); |
5061 | phba->mbox = phba->slim2p.virt + offsetof(struct lpfc_sli2_slim, mbx); | 5061 | phba->mbox = phba->slim2p.virt + offsetof(struct lpfc_sli2_slim, mbx); |
5062 | phba->mbox_ext = (phba->slim2p.virt + | ||
5063 | offsetof(struct lpfc_sli2_slim, mbx_ext_words)); | ||
5062 | phba->pcb = (phba->slim2p.virt + offsetof(struct lpfc_sli2_slim, pcb)); | 5064 | phba->pcb = (phba->slim2p.virt + offsetof(struct lpfc_sli2_slim, pcb)); |
5063 | phba->IOCBs = (phba->slim2p.virt + | 5065 | phba->IOCBs = (phba->slim2p.virt + |
5064 | offsetof(struct lpfc_sli2_slim, IOCBs)); | 5066 | offsetof(struct lpfc_sli2_slim, IOCBs)); |
diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index 72e6adb0643e..a6b7f5a0210b 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c | |||
@@ -1216,7 +1216,7 @@ lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) | |||
1216 | phba->pcb->feature = FEATURE_INITIAL_SLI2; | 1216 | phba->pcb->feature = FEATURE_INITIAL_SLI2; |
1217 | 1217 | ||
1218 | /* Setup Mailbox pointers */ | 1218 | /* Setup Mailbox pointers */ |
1219 | phba->pcb->mailBoxSize = sizeof(MAILBOX_t); | 1219 | phba->pcb->mailBoxSize = sizeof(MAILBOX_t) + MAILBOX_EXT_SIZE; |
1220 | offset = (uint8_t *)phba->mbox - (uint8_t *)phba->slim2p.virt; | 1220 | offset = (uint8_t *)phba->mbox - (uint8_t *)phba->slim2p.virt; |
1221 | pdma_addr = phba->slim2p.phys + offset; | 1221 | pdma_addr = phba->slim2p.phys + offset; |
1222 | phba->pcb->mbAddrHigh = putPaddrHigh(pdma_addr); | 1222 | phba->pcb->mbAddrHigh = putPaddrHigh(pdma_addr); |
@@ -1272,28 +1272,41 @@ lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) | |||
1272 | * | 1272 | * |
1273 | */ | 1273 | */ |
1274 | 1274 | ||
1275 | if (phba->sli_rev == 3) { | 1275 | if (phba->cfg_hostmem_hgp && phba->sli_rev != 3) { |
1276 | phba->host_gp = &mb_slim->us.s3.host[0]; | 1276 | phba->host_gp = &phba->mbox->us.s2.host[0]; |
1277 | phba->hbq_put = &mb_slim->us.s3.hbq_put[0]; | ||
1278 | } else { | ||
1279 | phba->host_gp = &mb_slim->us.s2.host[0]; | ||
1280 | phba->hbq_put = NULL; | 1277 | phba->hbq_put = NULL; |
1281 | } | 1278 | offset = (uint8_t *)&phba->mbox->us.s2.host - |
1279 | (uint8_t *)phba->slim2p.virt; | ||
1280 | pdma_addr = phba->slim2p.phys + offset; | ||
1281 | phba->pcb->hgpAddrHigh = putPaddrHigh(pdma_addr); | ||
1282 | phba->pcb->hgpAddrLow = putPaddrLow(pdma_addr); | ||
1283 | } else { | ||
1284 | /* Always Host Group Pointer is in SLIM */ | ||
1285 | mb->un.varCfgPort.hps = 1; | ||
1282 | 1286 | ||
1283 | /* mask off BAR0's flag bits 0 - 3 */ | 1287 | if (phba->sli_rev == 3) { |
1284 | phba->pcb->hgpAddrLow = (bar_low & PCI_BASE_ADDRESS_MEM_MASK) + | 1288 | phba->host_gp = &mb_slim->us.s3.host[0]; |
1285 | (void __iomem *)phba->host_gp - | 1289 | phba->hbq_put = &mb_slim->us.s3.hbq_put[0]; |
1286 | (void __iomem *)phba->MBslimaddr; | 1290 | } else { |
1287 | if (bar_low & PCI_BASE_ADDRESS_MEM_TYPE_64) | 1291 | phba->host_gp = &mb_slim->us.s2.host[0]; |
1288 | phba->pcb->hgpAddrHigh = bar_high; | 1292 | phba->hbq_put = NULL; |
1289 | else | 1293 | } |
1290 | phba->pcb->hgpAddrHigh = 0; | ||
1291 | /* write HGP data to SLIM at the required longword offset */ | ||
1292 | memset(&hgp, 0, sizeof(struct lpfc_hgp)); | ||
1293 | 1294 | ||
1294 | for (i=0; i < phba->sli.num_rings; i++) { | 1295 | /* mask off BAR0's flag bits 0 - 3 */ |
1295 | lpfc_memcpy_to_slim(phba->host_gp + i, &hgp, | 1296 | phba->pcb->hgpAddrLow = (bar_low & PCI_BASE_ADDRESS_MEM_MASK) + |
1297 | (void __iomem *)phba->host_gp - | ||
1298 | (void __iomem *)phba->MBslimaddr; | ||
1299 | if (bar_low & PCI_BASE_ADDRESS_MEM_TYPE_64) | ||
1300 | phba->pcb->hgpAddrHigh = bar_high; | ||
1301 | else | ||
1302 | phba->pcb->hgpAddrHigh = 0; | ||
1303 | /* write HGP data to SLIM at the required longword offset */ | ||
1304 | memset(&hgp, 0, sizeof(struct lpfc_hgp)); | ||
1305 | |||
1306 | for (i = 0; i < phba->sli.num_rings; i++) { | ||
1307 | lpfc_memcpy_to_slim(phba->host_gp + i, &hgp, | ||
1296 | sizeof(*phba->host_gp)); | 1308 | sizeof(*phba->host_gp)); |
1309 | } | ||
1297 | } | 1310 | } |
1298 | 1311 | ||
1299 | /* Setup Port Group offset */ | 1312 | /* Setup Port Group offset */ |
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index dd879a7d04a3..2f7018821531 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c | |||
@@ -4891,9 +4891,34 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, | |||
4891 | mb->mbxOwner = OWN_CHIP; | 4891 | mb->mbxOwner = OWN_CHIP; |
4892 | 4892 | ||
4893 | if (psli->sli_flag & LPFC_SLI_ACTIVE) { | 4893 | if (psli->sli_flag & LPFC_SLI_ACTIVE) { |
4894 | /* First copy command data to host SLIM area */ | 4894 | /* Populate mbox extension offset word. */ |
4895 | if (pmbox->in_ext_byte_len || pmbox->out_ext_byte_len) { | ||
4896 | *(((uint32_t *)mb) + pmbox->mbox_offset_word) | ||
4897 | = (uint8_t *)phba->mbox_ext | ||
4898 | - (uint8_t *)phba->mbox; | ||
4899 | } | ||
4900 | |||
4901 | /* Copy the mailbox extension data */ | ||
4902 | if (pmbox->in_ext_byte_len && pmbox->context2) { | ||
4903 | lpfc_sli_pcimem_bcopy(pmbox->context2, | ||
4904 | (uint8_t *)phba->mbox_ext, | ||
4905 | pmbox->in_ext_byte_len); | ||
4906 | } | ||
4907 | /* Copy command data to host SLIM area */ | ||
4895 | lpfc_sli_pcimem_bcopy(mb, phba->mbox, MAILBOX_CMD_SIZE); | 4908 | lpfc_sli_pcimem_bcopy(mb, phba->mbox, MAILBOX_CMD_SIZE); |
4896 | } else { | 4909 | } else { |
4910 | /* Populate mbox extension offset word. */ | ||
4911 | if (pmbox->in_ext_byte_len || pmbox->out_ext_byte_len) | ||
4912 | *(((uint32_t *)mb) + pmbox->mbox_offset_word) | ||
4913 | = MAILBOX_HBA_EXT_OFFSET; | ||
4914 | |||
4915 | /* Copy the mailbox extension data */ | ||
4916 | if (pmbox->in_ext_byte_len && pmbox->context2) { | ||
4917 | lpfc_memcpy_to_slim(phba->MBslimaddr + | ||
4918 | MAILBOX_HBA_EXT_OFFSET, | ||
4919 | pmbox->context2, pmbox->in_ext_byte_len); | ||
4920 | |||
4921 | } | ||
4897 | if (mb->mbxCommand == MBX_CONFIG_PORT) { | 4922 | if (mb->mbxCommand == MBX_CONFIG_PORT) { |
4898 | /* copy command data into host mbox for cmpl */ | 4923 | /* copy command data into host mbox for cmpl */ |
4899 | lpfc_sli_pcimem_bcopy(mb, phba->mbox, MAILBOX_CMD_SIZE); | 4924 | lpfc_sli_pcimem_bcopy(mb, phba->mbox, MAILBOX_CMD_SIZE); |
@@ -5003,15 +5028,22 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, | |||
5003 | if (psli->sli_flag & LPFC_SLI_ACTIVE) { | 5028 | if (psli->sli_flag & LPFC_SLI_ACTIVE) { |
5004 | /* copy results back to user */ | 5029 | /* copy results back to user */ |
5005 | lpfc_sli_pcimem_bcopy(phba->mbox, mb, MAILBOX_CMD_SIZE); | 5030 | lpfc_sli_pcimem_bcopy(phba->mbox, mb, MAILBOX_CMD_SIZE); |
5031 | /* Copy the mailbox extension data */ | ||
5032 | if (pmbox->out_ext_byte_len && pmbox->context2) { | ||
5033 | lpfc_sli_pcimem_bcopy(phba->mbox_ext, | ||
5034 | pmbox->context2, | ||
5035 | pmbox->out_ext_byte_len); | ||
5036 | } | ||
5006 | } else { | 5037 | } else { |
5007 | /* First copy command data */ | 5038 | /* First copy command data */ |
5008 | lpfc_memcpy_from_slim(mb, phba->MBslimaddr, | 5039 | lpfc_memcpy_from_slim(mb, phba->MBslimaddr, |
5009 | MAILBOX_CMD_SIZE); | 5040 | MAILBOX_CMD_SIZE); |
5010 | if ((mb->mbxCommand == MBX_DUMP_MEMORY) && | 5041 | /* Copy the mailbox extension data */ |
5011 | pmbox->context2) { | 5042 | if (pmbox->out_ext_byte_len && pmbox->context2) { |
5012 | lpfc_memcpy_from_slim((void *)pmbox->context2, | 5043 | lpfc_memcpy_from_slim(pmbox->context2, |
5013 | phba->MBslimaddr + DMP_RSP_OFFSET, | 5044 | phba->MBslimaddr + |
5014 | mb->un.varDmp.word_cnt); | 5045 | MAILBOX_HBA_EXT_OFFSET, |
5046 | pmbox->out_ext_byte_len); | ||
5015 | } | 5047 | } |
5016 | } | 5048 | } |
5017 | 5049 | ||
@@ -8133,6 +8165,12 @@ lpfc_sli_sp_intr_handler(int irq, void *dev_id) | |||
8133 | if (pmb->mbox_cmpl) { | 8165 | if (pmb->mbox_cmpl) { |
8134 | lpfc_sli_pcimem_bcopy(mbox, pmbox, | 8166 | lpfc_sli_pcimem_bcopy(mbox, pmbox, |
8135 | MAILBOX_CMD_SIZE); | 8167 | MAILBOX_CMD_SIZE); |
8168 | if (pmb->out_ext_byte_len && | ||
8169 | pmb->context2) | ||
8170 | lpfc_sli_pcimem_bcopy( | ||
8171 | phba->mbox_ext, | ||
8172 | pmb->context2, | ||
8173 | pmb->out_ext_byte_len); | ||
8136 | } | 8174 | } |
8137 | if (pmb->mbox_flag & LPFC_MBX_IMED_UNREG) { | 8175 | if (pmb->mbox_flag & LPFC_MBX_IMED_UNREG) { |
8138 | pmb->mbox_flag &= ~LPFC_MBX_IMED_UNREG; | 8176 | pmb->mbox_flag &= ~LPFC_MBX_IMED_UNREG; |
diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h index b4a639c47616..54a5e0bc827f 100644 --- a/drivers/scsi/lpfc/lpfc_sli.h +++ b/drivers/scsi/lpfc/lpfc_sli.h | |||
@@ -110,6 +110,9 @@ typedef struct lpfcMboxq { | |||
110 | 110 | ||
111 | void (*mbox_cmpl) (struct lpfc_hba *, struct lpfcMboxq *); | 111 | void (*mbox_cmpl) (struct lpfc_hba *, struct lpfcMboxq *); |
112 | uint8_t mbox_flag; | 112 | uint8_t mbox_flag; |
113 | uint16_t in_ext_byte_len; | ||
114 | uint16_t out_ext_byte_len; | ||
115 | uint8_t mbox_offset_word; | ||
113 | struct lpfc_mcqe mcqe; | 116 | struct lpfc_mcqe mcqe; |
114 | struct lpfc_mbx_nembed_sge_virt *sge_array; | 117 | struct lpfc_mbx_nembed_sge_virt *sge_array; |
115 | } LPFC_MBOXQ_t; | 118 | } LPFC_MBOXQ_t; |