aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/qla2xxx/qla_bsg.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/qla2xxx/qla_bsg.c')
-rw-r--r--drivers/scsi/qla2xxx/qla_bsg.c93
1 files changed, 69 insertions, 24 deletions
diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
index 392c147d5793..643014f82f7d 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.c
+++ b/drivers/scsi/qla2xxx/qla_bsg.c
@@ -2246,53 +2246,94 @@ qla2x00_get_priv_stats(struct fc_bsg_job *bsg_job)
struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
struct link_statistics *stats = NULL;
dma_addr_t stats_dma;
- int rval = QLA_FUNCTION_FAILED;
+ int rval;
+ uint32_t *cmd = bsg_job->request->rqst_data.h_vendor.vendor_cmd;
+ uint options = cmd[0] == QL_VND_GET_PRIV_STATS_EX ? cmd[1] : 0;
if (test_bit(UNLOADING, &vha->dpc_flags))
- goto done;
+ return -ENODEV;
if (unlikely(pci_channel_offline(ha->pdev)))
- goto done;
+ return -ENODEV;
if (qla2x00_reset_active(vha))
- goto done;
+ return -EBUSY;
if (!IS_FWI2_CAPABLE(ha))
- goto done;
+ return -EPERM;
stats = dma_alloc_coherent(&ha->pdev->dev,
- sizeof(struct link_statistics), &stats_dma, GFP_KERNEL);
+ sizeof(*stats), &stats_dma, GFP_KERNEL);
if (!stats) {
ql_log(ql_log_warn, vha, 0x70e2,
- "Failed to allocate memory for stats.\n");
- goto done;
+ "Failed to allocate memory for stats.\n");
+ return -ENOMEM;
}
- memset(stats, 0, sizeof(struct link_statistics));
+ memset(stats, 0, sizeof(*stats));
- rval = qla24xx_get_isp_stats(base_vha, stats, stats_dma);
+ rval = qla24xx_get_isp_stats(base_vha, stats, stats_dma, options);
- if (rval != QLA_SUCCESS)
- goto done_free;
+ if (rval == QLA_SUCCESS) {
+ ql_dump_buffer(ql_dbg_user + ql_dbg_verbose, vha, 0x70e3,
+ (uint8_t *)stats, sizeof(*stats));
+ sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
+ bsg_job->reply_payload.sg_cnt, stats, sizeof(*stats));
+ }
- ql_dump_buffer(ql_dbg_user + ql_dbg_verbose, vha, 0x70e3,
- (uint8_t *)stats, sizeof(struct link_statistics));
+ bsg_job->reply->reply_payload_rcv_len = sizeof(*stats);
+ bsg_job->reply->reply_data.vendor_reply.vendor_rsp[0] =
+ rval ? EXT_STATUS_MAILBOX : EXT_STATUS_OK;
- sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
- bsg_job->reply_payload.sg_cnt, stats, sizeof(struct link_statistics));
- bsg_job->reply->reply_payload_rcv_len = sizeof(struct link_statistics);
+ bsg_job->reply_len = sizeof(*bsg_job->reply);
+ bsg_job->reply->result = DID_OK << 16;
+ bsg_job->job_done(bsg_job);
- bsg_job->reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_OK;
+ dma_free_coherent(&ha->pdev->dev, sizeof(*stats),
+ stats, stats_dma);
- bsg_job->reply_len = sizeof(struct fc_bsg_reply);
+ return 0;
+}
+
+static int
+qla2x00_do_dport_diagnostics(struct fc_bsg_job *bsg_job)
+{
+ struct Scsi_Host *host = bsg_job->shost;
+ scsi_qla_host_t *vha = shost_priv(host);
+ int rval;
+ struct qla_dport_diag *dd;
+
+ if (!IS_QLA83XX(vha->hw) && !IS_QLA27XX(vha->hw))
+ return -EPERM;
+
+ dd = kmalloc(sizeof(*dd), GFP_KERNEL);
+ if (!dd) {
+ ql_log(ql_log_warn, vha, 0x70db,
+ "Failed to allocate memory for dport.\n");
+ return -ENOMEM;
+ }
+
+ sg_copy_to_buffer(bsg_job->request_payload.sg_list,
+ bsg_job->request_payload.sg_cnt, dd, sizeof(*dd));
+
+ rval = qla26xx_dport_diagnostics(
+ vha, dd->buf, sizeof(dd->buf), dd->options);
+ if (rval == QLA_SUCCESS) {
+ sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
+ bsg_job->reply_payload.sg_cnt, dd, sizeof(*dd));
+ }
+
+ bsg_job->reply->reply_payload_rcv_len = sizeof(*dd);
+ bsg_job->reply->reply_data.vendor_reply.vendor_rsp[0] =
+ rval ? EXT_STATUS_MAILBOX : EXT_STATUS_OK;
+
+ bsg_job->reply_len = sizeof(*bsg_job->reply);
bsg_job->reply->result = DID_OK << 16;
bsg_job->job_done(bsg_job);
-done_free:
- dma_free_coherent(&ha->pdev->dev, sizeof(struct link_statistics),
- stats, stats_dma);
-done:
- return rval;
+ kfree(dd);
+
+ return 0;
}
static int
@@ -2360,8 +2401,12 @@ qla2x00_process_vendor_specific(struct fc_bsg_job *bsg_job)
return qla27xx_get_bbcr_data(bsg_job);
case QL_VND_GET_PRIV_STATS:
+ case QL_VND_GET_PRIV_STATS_EX:
return qla2x00_get_priv_stats(bsg_job);
+ case QL_VND_DPORT_DIAGNOSTICS:
+ return qla2x00_do_dport_diagnostics(bsg_job);
+
default:
return -ENOSYS;
}