]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
qla2xxx: Add I2C BSG interface.
authorJoe Carnuccio <joe.carnuccio@qlogic.com>
Wed, 18 Apr 2012 20:19:06 +0000 (13:19 -0700)
committerMaxim Uvarov <maxim.uvarov@oracle.com>
Mon, 23 Jul 2012 08:02:44 +0000 (01:02 -0700)
Add BSG interface to generically access I2C attached devices.

The transferred data limitations:
- the address must be on an even byte boundary,
- the chunk size must be no more than 64 bytes,
(these being limitations of the firmware).

So, to transfer more than 64 bytes, the caller must chunk up
the data into 64 byte chunks and perform multiple accesses.

The caller is responsible for setting the device address,
the data offset, the option bits, and the data length.

JIRA Key: V2632FC-198

drivers/scsi/qla2xxx/qla_bsg.c
drivers/scsi/qla2xxx/qla_bsg.h

index 1b9a6b50467dd666f2a827d510d52cbe2d4fc1d4..e238f38fa7e7084860e7d6f2eeaefabf361a4da2 100644 (file)
@@ -1559,6 +1559,96 @@ done:
        return 0;
 }
 
+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)
 {
@@ -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);
index 70caa63a8930e196229c1f8a5cd2654c7c21b597..1a0ab375ce4370ac5e2b77dcd89e8762ab6e943a 100644 (file)
@@ -19,6 +19,8 @@
 #define QL_VND_SET_FRU_VERSION 0x0B
 #define QL_VND_READ_FRU_STATUS 0x0C
 #define QL_VND_WRITE_FRU_STATUS        0x0D
+#define QL_VND_WRITE_I2C       0x10
+#define QL_VND_READ_I2C                0x11
 
 /* BSG Vendor specific subcode returns */
 #define EXT_STATUS_OK                  0
@@ -183,4 +185,12 @@ struct qla_status_reg {
        uint8_t reserved[7];
 } __packed;
 
+struct qla_i2c_access {
+       uint16_t device;
+       uint16_t offset;
+       uint16_t option;
+       uint16_t length;
+       uint8_t  buffer[0x40];
+} __packed;
+
 #endif