Browse Source

[SCSI] qla2xxx: Provide method for updating I2C attached VPD.

Provide bsg interface for updating VPD attached on the I2C serial bus.

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>
Joe Carnuccio 14 years ago
parent
commit
697a4bc691
2 changed files with 193 additions and 0 deletions
  1. 151 0
      drivers/scsi/qla2xxx/qla_bsg.c
  2. 42 0
      drivers/scsi/qla2xxx/qla_bsg.h

+ 151 - 0
drivers/scsi/qla2xxx/qla_bsg.c

@@ -1447,6 +1447,148 @@ qla2x00_update_optrom(struct fc_bsg_job *bsg_job)
 	return rval;
 }
 
+static int
+qla2x00_update_fru_versions(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_image_version_list *list = (void *)bsg;
+	struct qla_image_version *image;
+	uint32_t count;
+	dma_addr_t sfp_dma;
+	void *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, list, sizeof(bsg));
+
+	image = list->version;
+	count = list->count;
+	while (count--) {
+		memcpy(sfp, &image->field_info, sizeof(image->field_info));
+		rval = qla2x00_write_sfp(vha, sfp_dma, sfp,
+		    image->field_address.device, image->field_address.offset,
+		    sizeof(image->field_info), image->field_address.option);
+		if (rval) {
+			bsg_job->reply->reply_data.vendor_reply.vendor_rsp[0] =
+			    EXT_STATUS_MAILBOX;
+			goto dealloc;
+		}
+		image++;
+	}
+
+	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_fru_status(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_status_reg *sr = (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, sr, sizeof(*sr));
+
+	rval = qla2x00_read_sfp(vha, sfp_dma, sfp,
+	    sr->field_address.device, sr->field_address.offset,
+	    sizeof(sr->status_reg), sr->field_address.option);
+	sr->status_reg = *sfp;
+
+	if (rval) {
+		bsg_job->reply->reply_data.vendor_reply.vendor_rsp[0] =
+		    EXT_STATUS_MAILBOX;
+		goto dealloc;
+	}
+
+	sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
+	    bsg_job->reply_payload.sg_cnt, sr, sizeof(*sr));
+
+	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(*sr);
+	bsg_job->reply->result = DID_OK << 16;
+	bsg_job->job_done(bsg_job);
+
+	return 0;
+}
+
+static int
+qla2x00_write_fru_status(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_status_reg *sr = (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, sr, sizeof(*sr));
+
+	*sfp = sr->status_reg;
+	rval = qla2x00_write_sfp(vha, sfp_dma, sfp,
+	    sr->field_address.device, sr->field_address.offset,
+	    sizeof(sr->status_reg), sr->field_address.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_process_vendor_specific(struct fc_bsg_job *bsg_job)
 {
@@ -1475,6 +1617,15 @@ qla2x00_process_vendor_specific(struct fc_bsg_job *bsg_job)
 	case QL_VND_UPDATE_FLASH:
 		return qla2x00_update_optrom(bsg_job);
 
+	case QL_VND_SET_FRU_VERSION:
+		return qla2x00_update_fru_versions(bsg_job);
+
+	case QL_VND_READ_FRU_STATUS:
+		return qla2x00_read_fru_status(bsg_job);
+
+	case QL_VND_WRITE_FRU_STATUS:
+		return qla2x00_write_fru_status(bsg_job);
+
 	default:
 		bsg_job->reply->result = (DID_ERROR << 16);
 		bsg_job->job_done(bsg_job);

+ 42 - 0
drivers/scsi/qla2xxx/qla_bsg.h

@@ -16,6 +16,16 @@
 #define QL_VND_FCP_PRIO_CFG_CMD	0x06
 #define QL_VND_READ_FLASH	0x07
 #define QL_VND_UPDATE_FLASH	0x08
+#define QL_VND_SET_FRU_VERSION	0x0B
+#define QL_VND_READ_FRU_STATUS	0x0C
+#define QL_VND_WRITE_FRU_STATUS	0x0D
+
+/* BSG Vendor specific subcode returns */
+#define EXT_STATUS_OK			0
+#define EXT_STATUS_ERR			1
+#define EXT_STATUS_INVALID_PARAM	6
+#define EXT_STATUS_MAILBOX		11
+#define EXT_STATUS_NO_MEMORY		17
 
 /* BSG definations for interpreting CommandSent field */
 #define INT_DEF_LB_LOOPBACK_CMD         0
@@ -141,4 +151,36 @@ struct qla_port_param {
 	uint16_t mode;
 	uint16_t speed;
 } __attribute__ ((packed));
+
+
+/* FRU VPD */
+
+#define MAX_FRU_SIZE	36
+
+struct qla_field_address {
+	uint16_t offset;
+	uint16_t device;
+	uint16_t option;
+} __packed;
+
+struct qla_field_info {
+	uint8_t version[MAX_FRU_SIZE];
+} __packed;
+
+struct qla_image_version {
+	struct qla_field_address field_address;
+	struct qla_field_info field_info;
+} __packed;
+
+struct qla_image_version_list {
+	uint32_t count;
+	struct qla_image_version version[0];
+} __packed;
+
+struct qla_status_reg {
+	struct qla_field_address field_address;
+	uint8_t status_reg;
+	uint8_t reserved[7];
+} __packed;
+
 #endif