summaryrefslogtreecommitdiff
path: root/drivers/scsi/qla2xxx/qla_bsg.c
diff options
context:
space:
mode:
authorJoe Carnuccio <joe.carnuccio@qlogic.com>2012-08-22 22:20:56 +0400
committerJames Bottomley <JBottomley@Parallels.com>2012-09-14 21:28:45 +0400
commit9ebb5d9c69f1f5721f9f6f49e501c674c1e184ae (patch)
treec08ecb3ae2b128bbb5996b651623366ad6756c66 /drivers/scsi/qla2xxx/qla_bsg.c
parent650f528f3581344df96f9b372a7c803919aa7d6f (diff)
downloadlinux-9ebb5d9c69f1f5721f9f6f49e501c674c1e184ae.tar.xz
[SCSI] qla2xxx: Add I2C BSG interface.
Add BSG interface to generically access I2C attached devices. Signed-off-by: Joe Carnuccio <joe.carnuccio@qlogic.com> Signed-off-by: Chad Dupuis <chad.dupuis@qlogic.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/qla2xxx/qla_bsg.c')
-rw-r--r--drivers/scsi/qla2xxx/qla_bsg.c96
1 files changed, 96 insertions, 0 deletions
diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
index c68883806c54..462ac707b8d6 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.c
+++ b/drivers/scsi/qla2xxx/qla_bsg.c
@@ -1560,6 +1560,96 @@ done:
}
static int
+qla2x00_write_i2c(struct fc_bsg_job *bsg_job)
+{
+ struct Scsi_Host *host = bsg_job->shost;
+ scsi_qla_host_t *vha = shost_priv(host);
+ struct qla_hw_data *ha = vha->hw;
+ int rval = 0;
+ uint8_t bsg[DMA_POOL_SIZE];
+ struct qla_i2c_access *i2c = (void *)bsg;
+ dma_addr_t sfp_dma;
+ uint8_t *sfp = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma);
+ if (!sfp) {
+ bsg_job->reply->reply_data.vendor_reply.vendor_rsp[0] =
+ EXT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ sg_copy_to_buffer(bsg_job->request_payload.sg_list,
+ bsg_job->request_payload.sg_cnt, i2c, sizeof(*i2c));
+
+ memcpy(sfp, i2c->buffer, i2c->length);
+ rval = qla2x00_write_sfp(vha, sfp_dma, sfp,
+ i2c->device, i2c->offset, i2c->length, i2c->option);
+
+ if (rval) {
+ bsg_job->reply->reply_data.vendor_reply.vendor_rsp[0] =
+ EXT_STATUS_MAILBOX;
+ goto dealloc;
+ }
+
+ bsg_job->reply->reply_data.vendor_reply.vendor_rsp[0] = 0;
+
+dealloc:
+ dma_pool_free(ha->s_dma_pool, sfp, sfp_dma);
+
+done:
+ bsg_job->reply_len = sizeof(struct fc_bsg_reply);
+ bsg_job->reply->result = DID_OK << 16;
+ bsg_job->job_done(bsg_job);
+
+ return 0;
+}
+
+static int
+qla2x00_read_i2c(struct fc_bsg_job *bsg_job)
+{
+ struct Scsi_Host *host = bsg_job->shost;
+ scsi_qla_host_t *vha = shost_priv(host);
+ struct qla_hw_data *ha = vha->hw;
+ int rval = 0;
+ uint8_t bsg[DMA_POOL_SIZE];
+ struct qla_i2c_access *i2c = (void *)bsg;
+ dma_addr_t sfp_dma;
+ uint8_t *sfp = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma);
+ if (!sfp) {
+ bsg_job->reply->reply_data.vendor_reply.vendor_rsp[0] =
+ EXT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ sg_copy_to_buffer(bsg_job->request_payload.sg_list,
+ bsg_job->request_payload.sg_cnt, i2c, sizeof(*i2c));
+
+ rval = qla2x00_read_sfp(vha, sfp_dma, sfp,
+ i2c->device, i2c->offset, i2c->length, i2c->option);
+
+ if (rval) {
+ bsg_job->reply->reply_data.vendor_reply.vendor_rsp[0] =
+ EXT_STATUS_MAILBOX;
+ goto dealloc;
+ }
+
+ memcpy(i2c->buffer, sfp, i2c->length);
+ sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
+ bsg_job->reply_payload.sg_cnt, i2c, sizeof(*i2c));
+
+ bsg_job->reply->reply_data.vendor_reply.vendor_rsp[0] = 0;
+
+dealloc:
+ dma_pool_free(ha->s_dma_pool, sfp, sfp_dma);
+
+done:
+ bsg_job->reply_len = sizeof(struct fc_bsg_reply);
+ bsg_job->reply->reply_payload_rcv_len = sizeof(*i2c);
+ bsg_job->reply->result = DID_OK << 16;
+ bsg_job->job_done(bsg_job);
+
+ return 0;
+}
+
+static int
qla2x00_process_vendor_specific(struct fc_bsg_job *bsg_job)
{
switch (bsg_job->request->rqst_data.h_vendor.vendor_cmd[0]) {
@@ -1596,6 +1686,12 @@ qla2x00_process_vendor_specific(struct fc_bsg_job *bsg_job)
case QL_VND_WRITE_FRU_STATUS:
return qla2x00_write_fru_status(bsg_job);
+ case QL_VND_WRITE_I2C:
+ return qla2x00_write_i2c(bsg_job);
+
+ case QL_VND_READ_I2C:
+ return qla2x00_read_i2c(bsg_job);
+
default:
bsg_job->reply->result = (DID_ERROR << 16);
bsg_job->job_done(bsg_job);