diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c index c68883806c54b8092e81ff82f62db06fd8ee822f..462ac707b8d6dccaf5b465f23a6b13ba01f61311 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.c +++ b/drivers/scsi/qla2xxx/qla_bsg.c @@ -1559,6 +1559,96 @@ qla2x00_write_fru_status(struct fc_bsg_job *bsg_job) 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); diff --git a/drivers/scsi/qla2xxx/qla_bsg.h b/drivers/scsi/qla2xxx/qla_bsg.h index 70caa63a8930e196229c1f8a5cd2654c7c21b597..1a0ab375ce4370ac5e2b77dcd89e8762ab6e943a 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.h +++ b/drivers/scsi/qla2xxx/qla_bsg.h @@ -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