aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorSarang Radke <sarang.radke@qlogic.com>2010-05-28 18:08:21 -0400
committerJames Bottomley <James.Bottomley@suse.de>2010-07-27 13:01:22 -0400
commit23f2ebd17a13835c5b34994d2c2e5faacc127947 (patch)
tree2fce122a5ecceffa8c52e334d9dfeee0e33e3e7f /drivers/scsi
parent3a6478df74c271cb3be5895b39fddf75e9cef89c (diff)
[SCSI] qla2xxx: Add internal loopback support for ISP81xx.
Signed-off-by: Giridhar Malavali <giridhar.malavali@qlogic.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/qla2xxx/qla_bsg.c196
-rw-r--r--drivers/scsi/qla2xxx/qla_bsg.h7
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h4
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h5
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c7
-rw-r--r--drivers/scsi/qla2xxx/qla_mbx.c66
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c1
7 files changed, 269 insertions, 17 deletions
diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
index b905dfe5ea61..3a0248388505 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.c
+++ b/drivers/scsi/qla2xxx/qla_bsg.c
@@ -483,6 +483,98 @@ done:
483 return rval; 483 return rval;
484} 484}
485 485
486/* Set the port configuration to enable the
487 * internal loopback on ISP81XX
488 */
489static inline int
490qla81xx_set_internal_loopback(scsi_qla_host_t *vha, uint16_t *config,
491 uint16_t *new_config)
492{
493 int ret = 0;
494 int rval = 0;
495 struct qla_hw_data *ha = vha->hw;
496
497 if (!IS_QLA81XX(ha))
498 goto done_set_internal;
499
500 new_config[0] = config[0] | (ENABLE_INTERNAL_LOOPBACK << 1);
501 memcpy(&new_config[1], &config[1], sizeof(uint16_t) * 3) ;
502
503 ha->notify_dcbx_comp = 1;
504 ret = qla81xx_set_port_config(vha, new_config);
505 if (ret != QLA_SUCCESS) {
506 DEBUG2(printk(KERN_ERR
507 "%s(%lu): Set port config failed\n",
508 __func__, vha->host_no));
509 ha->notify_dcbx_comp = 0;
510 rval = -EINVAL;
511 goto done_set_internal;
512 }
513
514 /* Wait for DCBX complete event */
515 if (!wait_for_completion_timeout(&ha->dcbx_comp, (20 * HZ))) {
516 DEBUG2(qla_printk(KERN_WARNING, ha,
517 "State change notificaition not received.\n"));
518 } else
519 DEBUG2(qla_printk(KERN_INFO, ha,
520 "State change RECEIVED\n"));
521
522 ha->notify_dcbx_comp = 0;
523
524done_set_internal:
525 return rval;
526}
527
528/* Set the port configuration to disable the
529 * internal loopback on ISP81XX
530 */
531static inline int
532qla81xx_reset_internal_loopback(scsi_qla_host_t *vha, uint16_t *config,
533 int wait)
534{
535 int ret = 0;
536 int rval = 0;
537 uint16_t new_config[4];
538 struct qla_hw_data *ha = vha->hw;
539
540 if (!IS_QLA81XX(ha))
541 goto done_reset_internal;
542
543 memset(new_config, 0 , sizeof(new_config));
544 if ((config[0] & INTERNAL_LOOPBACK_MASK) >> 1 ==
545 ENABLE_INTERNAL_LOOPBACK) {
546 new_config[0] = config[0] & ~INTERNAL_LOOPBACK_MASK;
547 memcpy(&new_config[1], &config[1], sizeof(uint16_t) * 3) ;
548
549 ha->notify_dcbx_comp = wait;
550 ret = qla81xx_set_port_config(vha, new_config);
551 if (ret != QLA_SUCCESS) {
552 DEBUG2(printk(KERN_ERR
553 "%s(%lu): Set port config failed\n",
554 __func__, vha->host_no));
555 ha->notify_dcbx_comp = 0;
556 rval = -EINVAL;
557 goto done_reset_internal;
558 }
559
560 /* Wait for DCBX complete event */
561 if (wait && !wait_for_completion_timeout(&ha->dcbx_comp,
562 (20 * HZ))) {
563 DEBUG2(qla_printk(KERN_WARNING, ha,
564 "State change notificaition not received.\n"));
565 ha->notify_dcbx_comp = 0;
566 rval = -EINVAL;
567 goto done_reset_internal;
568 } else
569 DEBUG2(qla_printk(KERN_INFO, ha,
570 "State change RECEIVED\n"));
571
572 ha->notify_dcbx_comp = 0;
573 }
574done_reset_internal:
575 return rval;
576}
577
486static int 578static int
487qla2x00_process_loopback(struct fc_bsg_job *bsg_job) 579qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
488{ 580{
@@ -494,6 +586,7 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
494 char *type; 586 char *type;
495 struct msg_echo_lb elreq; 587 struct msg_echo_lb elreq;
496 uint16_t response[MAILBOX_REGISTER_COUNT]; 588 uint16_t response[MAILBOX_REGISTER_COUNT];
589 uint16_t config[4], new_config[4];
497 uint8_t *fw_sts_ptr; 590 uint8_t *fw_sts_ptr;
498 uint8_t *req_data = NULL; 591 uint8_t *req_data = NULL;
499 dma_addr_t req_data_dma; 592 dma_addr_t req_data_dma;
@@ -568,29 +661,102 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
568 661
569 elreq.options = bsg_job->request->rqst_data.h_vendor.vendor_cmd[1]; 662 elreq.options = bsg_job->request->rqst_data.h_vendor.vendor_cmd[1];
570 663
571 if (ha->current_topology != ISP_CFG_F) { 664 if ((ha->current_topology == ISP_CFG_F ||
572 type = "FC_BSG_HST_VENDOR_LOOPBACK"; 665 (IS_QLA81XX(ha) &&
666 le32_to_cpu(*(uint32_t *)req_data) == ELS_OPCODE_BYTE
667 && req_data_len == MAX_ELS_FRAME_PAYLOAD)) &&
668 elreq.options == EXTERNAL_LOOPBACK) {
669 type = "FC_BSG_HST_VENDOR_ECHO_DIAG";
573 DEBUG2(qla_printk(KERN_INFO, ha, 670 DEBUG2(qla_printk(KERN_INFO, ha,
574 "scsi(%ld) bsg rqst type: %s\n", 671 "scsi(%ld) bsg rqst type: %s\n", vha->host_no, type));
575 vha->host_no, type)); 672 command_sent = INT_DEF_LB_ECHO_CMD;
576 673 rval = qla2x00_echo_test(vha, &elreq, response);
577 command_sent = INT_DEF_LB_LOOPBACK_CMD; 674 } else {
578 rval = qla2x00_loopback_test(vha, &elreq, response);
579 if (IS_QLA81XX(ha)) { 675 if (IS_QLA81XX(ha)) {
676 memset(config, 0, sizeof(config));
677 memset(new_config, 0, sizeof(new_config));
678 if (qla81xx_get_port_config(vha, config)) {
679 DEBUG2(printk(KERN_ERR
680 "%s(%lu): Get port config failed\n",
681 __func__, vha->host_no));
682 bsg_job->reply->reply_payload_rcv_len = 0;
683 bsg_job->reply->result = (DID_ERROR << 16);
684 rval = -EPERM;
685 goto done_free_dma_req;
686 }
687
688 if (elreq.options != EXTERNAL_LOOPBACK) {
689 DEBUG2(qla_printk(KERN_INFO, ha,
690 "Internal: current port config = %x\n",
691 config[0]));
692 if (qla81xx_set_internal_loopback(vha, config,
693 new_config)) {
694 bsg_job->reply->reply_payload_rcv_len =
695 0;
696 bsg_job->reply->result =
697 (DID_ERROR << 16);
698 rval = -EPERM;
699 goto done_free_dma_req;
700 }
701 } else {
702 /* For external loopback to work
703 * ensure internal loopback is disabled
704 */
705 if (qla81xx_reset_internal_loopback(vha,
706 config, 1)) {
707 bsg_job->reply->reply_payload_rcv_len =
708 0;
709 bsg_job->reply->result =
710 (DID_ERROR << 16);
711 rval = -EPERM;
712 goto done_free_dma_req;
713 }
714 }
715
716 type = "FC_BSG_HST_VENDOR_LOOPBACK";
717 DEBUG2(qla_printk(KERN_INFO, ha,
718 "scsi(%ld) bsg rqst type: %s\n",
719 vha->host_no, type));
720
721 command_sent = INT_DEF_LB_LOOPBACK_CMD;
722 rval = qla2x00_loopback_test(vha, &elreq, response);
723
724 if (new_config[1]) {
725 /* Revert back to original port config
726 * Also clear internal loopback
727 */
728 qla81xx_reset_internal_loopback(vha,
729 new_config, 0);
730 }
731
580 if (response[0] == MBS_COMMAND_ERROR && 732 if (response[0] == MBS_COMMAND_ERROR &&
581 response[1] == MBS_LB_RESET) { 733 response[1] == MBS_LB_RESET) {
582 DEBUG2(printk(KERN_ERR "%s(%ld): ABORTing " 734 DEBUG2(printk(KERN_ERR "%s(%ld): ABORTing "
583 "ISP\n", __func__, vha->host_no)); 735 "ISP\n", __func__, vha->host_no));
584 set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); 736 set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
585 qla2xxx_wake_dpc(vha); 737 qla2xxx_wake_dpc(vha);
738 qla2x00_wait_for_chip_reset(vha);
739 /* Also reset the MPI */
740 if (qla81xx_restart_mpi_firmware(vha) !=
741 QLA_SUCCESS) {
742 qla_printk(KERN_INFO, ha,
743 "MPI reset failed for host%ld.\n",
744 vha->host_no);
745 }
746
747 bsg_job->reply->reply_payload_rcv_len = 0;
748 bsg_job->reply->result = (DID_ERROR << 16);
749 rval = -EIO;
750 goto done_free_dma_req;
586 } 751 }
752 } else {
753 type = "FC_BSG_HST_VENDOR_LOOPBACK";
754 DEBUG2(qla_printk(KERN_INFO, ha,
755 "scsi(%ld) bsg rqst type: %s\n",
756 vha->host_no, type));
757 command_sent = INT_DEF_LB_LOOPBACK_CMD;
758 rval = qla2x00_loopback_test(vha, &elreq, response);
587 } 759 }
588 } else {
589 type = "FC_BSG_HST_VENDOR_ECHO_DIAG";
590 DEBUG2(qla_printk(KERN_INFO, ha,
591 "scsi(%ld) bsg rqst type: %s\n", vha->host_no, type));
592 command_sent = INT_DEF_LB_ECHO_CMD;
593 rval = qla2x00_echo_test(vha, &elreq, response);
594 } 760 }
595 761
596 if (rval) { 762 if (rval) {
diff --git a/drivers/scsi/qla2xxx/qla_bsg.h b/drivers/scsi/qla2xxx/qla_bsg.h
index 76ed92dd2ef2..1f096dabc015 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.h
+++ b/drivers/scsi/qla2xxx/qla_bsg.h
@@ -19,6 +19,13 @@
19#define INT_DEF_LB_LOOPBACK_CMD 0 19#define INT_DEF_LB_LOOPBACK_CMD 0
20#define INT_DEF_LB_ECHO_CMD 1 20#define INT_DEF_LB_ECHO_CMD 1
21 21
22/* Loopback related definations */
23#define EXTERNAL_LOOPBACK 0xF2
24#define ENABLE_INTERNAL_LOOPBACK 0x02
25#define INTERNAL_LOOPBACK_MASK 0x000E
26#define MAX_ELS_FRAME_PAYLOAD 252
27#define ELS_OPCODE_BYTE 0x10
28
22/* BSG Vendor specific definations */ 29/* BSG Vendor specific definations */
23#define A84_ISSUE_WRITE_TYPE_CMD 0 30#define A84_ISSUE_WRITE_TYPE_CMD 0
24#define A84_ISSUE_READ_TYPE_CMD 1 31#define A84_ISSUE_READ_TYPE_CMD 1
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index f8239bff0924..2895855adc9a 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -714,6 +714,8 @@ typedef struct {
714#define MBC_SEND_RNFT_ELS 0x5e /* Send RNFT ELS request */ 714#define MBC_SEND_RNFT_ELS 0x5e /* Send RNFT ELS request */
715#define MBC_GET_LINK_PRIV_STATS 0x6d /* Get link & private data. */ 715#define MBC_GET_LINK_PRIV_STATS 0x6d /* Get link & private data. */
716#define MBC_SET_VENDOR_ID 0x76 /* Set Vendor ID. */ 716#define MBC_SET_VENDOR_ID 0x76 /* Set Vendor ID. */
717#define MBC_SET_PORT_CONFIG 0x122 /* Set port configuration */
718#define MBC_GET_PORT_CONFIG 0x123 /* Get port configuration */
717 719
718/* Firmware return data sizes */ 720/* Firmware return data sizes */
719#define FCAL_MAP_SIZE 128 721#define FCAL_MAP_SIZE 128
@@ -2631,6 +2633,8 @@ struct qla_hw_data {
2631 struct mutex vport_lock; /* Virtual port synchronization */ 2633 struct mutex vport_lock; /* Virtual port synchronization */
2632 struct completion mbx_cmd_comp; /* Serialize mbx access */ 2634 struct completion mbx_cmd_comp; /* Serialize mbx access */
2633 struct completion mbx_intr_comp; /* Used for completion notification */ 2635 struct completion mbx_intr_comp; /* Used for completion notification */
2636 struct completion dcbx_comp; /* For set port config notification */
2637 int notify_dcbx_comp;
2634 2638
2635 /* Basic firmware related information. */ 2639 /* Basic firmware related information. */
2636 uint16_t fw_major_version; 2640 uint16_t fw_major_version;
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 2247ef8702e4..7ae2ee42564e 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -357,6 +357,11 @@ qla2x00_write_ram_word(scsi_qla_host_t *, uint32_t, uint32_t);
357extern int qla2x00_get_data_rate(scsi_qla_host_t *); 357extern int qla2x00_get_data_rate(scsi_qla_host_t *);
358extern int qla24xx_set_fcp_prio(scsi_qla_host_t *, uint16_t, uint16_t, 358extern int qla24xx_set_fcp_prio(scsi_qla_host_t *, uint16_t, uint16_t,
359 uint16_t *); 359 uint16_t *);
360extern int
361qla81xx_get_port_config(scsi_qla_host_t *, uint16_t *);
362
363extern int
364qla81xx_set_port_config(scsi_qla_host_t *, uint16_t *);
360 365
361/* 366/*
362 * Global Function Prototypes in qla_isr.c source file. 367 * Global Function Prototypes in qla_isr.c source file.
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 912befdceb16..e51fc5f9fcdb 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -545,10 +545,13 @@ skip_rio:
545 if (IS_QLA2100(ha)) 545 if (IS_QLA2100(ha))
546 break; 546 break;
547 547
548 if (IS_QLA8XXX_TYPE(ha)) 548 if (IS_QLA8XXX_TYPE(ha)) {
549 DEBUG2(printk("scsi(%ld): DCBX Completed -- %04x %04x " 549 DEBUG2(printk("scsi(%ld): DCBX Completed -- %04x %04x "
550 "%04x\n", vha->host_no, mb[1], mb[2], mb[3])); 550 "%04x\n", vha->host_no, mb[1], mb[2], mb[3]));
551 else 551 if (ha->notify_dcbx_comp)
552 complete(&ha->dcbx_comp);
553
554 } else
552 DEBUG2(printk("scsi(%ld): Asynchronous P2P MODE " 555 DEBUG2(printk("scsi(%ld): Asynchronous P2P MODE "
553 "received.\n", vha->host_no)); 556 "received.\n", vha->host_no));
554 557
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 043f808ba3f4..10f4815aec77 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -3950,6 +3950,72 @@ qla2x00_get_data_rate(scsi_qla_host_t *vha)
3950} 3950}
3951 3951
3952int 3952int
3953qla81xx_get_port_config(scsi_qla_host_t *vha, uint16_t *mb)
3954{
3955 int rval;
3956 mbx_cmd_t mc;
3957 mbx_cmd_t *mcp = &mc;
3958 struct qla_hw_data *ha = vha->hw;
3959
3960 DEBUG11(printk(KERN_INFO
3961 "%s(%ld): entered.\n", __func__, vha->host_no));
3962
3963 if (!IS_QLA81XX(ha))
3964 return QLA_FUNCTION_FAILED;
3965 mcp->mb[0] = MBC_GET_PORT_CONFIG;
3966 mcp->out_mb = MBX_0;
3967 mcp->in_mb = MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
3968 mcp->tov = MBX_TOV_SECONDS;
3969 mcp->flags = 0;
3970
3971 rval = qla2x00_mailbox_command(vha, mcp);
3972
3973 if (rval != QLA_SUCCESS) {
3974 DEBUG2_3_11(printk(KERN_WARNING
3975 "%s(%ld): failed=%x (%x).\n", __func__,
3976 vha->host_no, rval, mcp->mb[0]));
3977 } else {
3978 /* Copy all bits to preserve original value */
3979 memcpy(mb, &mcp->mb[1], sizeof(uint16_t) * 4);
3980
3981 DEBUG11(printk(KERN_INFO
3982 "%s(%ld): done.\n", __func__, vha->host_no));
3983 }
3984 return rval;
3985}
3986
3987int
3988qla81xx_set_port_config(scsi_qla_host_t *vha, uint16_t *mb)
3989{
3990 int rval;
3991 mbx_cmd_t mc;
3992 mbx_cmd_t *mcp = &mc;
3993
3994 DEBUG11(printk(KERN_INFO
3995 "%s(%ld): entered.\n", __func__, vha->host_no));
3996
3997 mcp->mb[0] = MBC_SET_PORT_CONFIG;
3998 /* Copy all bits to preserve original setting */
3999 memcpy(&mcp->mb[1], mb, sizeof(uint16_t) * 4);
4000 mcp->out_mb = MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
4001 mcp->in_mb = MBX_0;
4002 mcp->tov = MBX_TOV_SECONDS;
4003 mcp->flags = 0;
4004 rval = qla2x00_mailbox_command(vha, mcp);
4005
4006 if (rval != QLA_SUCCESS) {
4007 DEBUG2_3_11(printk(KERN_WARNING
4008 "%s(%ld): failed=%x (%x).\n", __func__,
4009 vha->host_no, rval, mcp->mb[0]));
4010 } else
4011 DEBUG11(printk(KERN_INFO
4012 "%s(%ld): done.\n", __func__, vha->host_no));
4013
4014 return rval;
4015}
4016
4017
4018int
3953qla24xx_set_fcp_prio(scsi_qla_host_t *vha, uint16_t loop_id, uint16_t priority, 4019qla24xx_set_fcp_prio(scsi_qla_host_t *vha, uint16_t loop_id, uint16_t priority,
3954 uint16_t *mb) 4020 uint16_t *mb)
3955{ 4021{
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 9e656296b757..fa59181bcb02 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -2128,6 +2128,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
2128 init_completion(&ha->mbx_cmd_comp); 2128 init_completion(&ha->mbx_cmd_comp);
2129 complete(&ha->mbx_cmd_comp); 2129 complete(&ha->mbx_cmd_comp);
2130 init_completion(&ha->mbx_intr_comp); 2130 init_completion(&ha->mbx_intr_comp);
2131 init_completion(&ha->dcbx_comp);
2131 2132
2132 set_bit(0, (unsigned long *) ha->vp_idx_map); 2133 set_bit(0, (unsigned long *) ha->vp_idx_map);
2133 2134