Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a355943c authored by Vikas Chaudhary's avatar Vikas Chaudhary Committed by James Bottomley
Browse files

[SCSI] qla4xxx: add bsg support



This patch adds bsg support to qla4xxx.

Signed-off-by: default avatarVikas Chaudhary <vikas.chaudhary@qlogic.com>
Signed-off-by: default avatarHarish Zunjarrao <harish.zunjarrao@qlogic.com>
Signed-off-by: default avatarMike Christie <michaelc@cs.wisc.edu>
Signed-off-by: default avatarJames Bottomley <JBottomley@Parallels.com>
parent 90eeb01a
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
qla4xxx-y := ql4_os.o ql4_init.o ql4_mbx.o ql4_iocb.o ql4_isr.o \
		ql4_nx.o ql4_nvram.o ql4_dbg.o ql4_attr.o
		ql4_nx.o ql4_nvram.o ql4_dbg.o ql4_attr.o ql4_bsg.o

obj-$(CONFIG_SCSI_QLA_ISCSI) += qla4xxx.o
+209 −0
Original line number Diff line number Diff line
/*
 * QLogic iSCSI HBA Driver
 * Copyright (c) 2011 QLogic Corporation
 *
 * See LICENSE.qla4xxx for copyright and licensing details.
 */

#include "ql4_def.h"
#include "ql4_glbl.h"
#include "ql4_bsg.h"

static int
qla4xxx_read_flash(struct bsg_job *bsg_job)
{
	struct Scsi_Host *host = iscsi_job_to_shost(bsg_job);
	struct scsi_qla_host *ha = to_qla_host(host);
	struct iscsi_bsg_reply *bsg_reply = bsg_job->reply;
	struct iscsi_bsg_request *bsg_req = bsg_job->request;
	uint32_t sg_cnt;
	uint32_t offset = 0;
	uint32_t length = 0;
	dma_addr_t flash_dma;
	uint8_t *flash = NULL;
	int rval = 0;

	bsg_reply->reply_payload_rcv_len = 0;

	if (unlikely(pci_channel_offline(ha->pdev)))
		return -EINVAL;

	if (ha->flash_state != QLFLASH_WAITING)
		return -EBUSY;

	/* TODO: Add check for adapter online, reset active?? */
	sg_cnt = dma_map_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list,
			    bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);

	if (!sg_cnt)
		return -ENOMEM;

	if (sg_cnt != bsg_job->reply_payload.sg_cnt) {
		ql4_printk(KERN_ERR, ha, "dma mapping resulted in different"
			   " sg counts, sg_cnt: %x dma_sg_cnt: %x\n",
			   bsg_job->reply_payload.sg_cnt, sg_cnt);
		rval = -EAGAIN;
		goto unmap_sg;
	}

	offset = bsg_req->rqst_data.h_vendor.vendor_cmd[1];
	length = bsg_job->reply_payload.payload_len;

	flash = dma_alloc_coherent(&ha->pdev->dev, length, &flash_dma,
				   GFP_KERNEL);
	if (!flash) {
		ql4_printk(KERN_ERR, ha, "%s: dma alloc failed for flash "
			   "data\n", __func__);
		rval = -ENOMEM;
		goto unmap_sg;
	}

	ha->flash_state = QLFLASH_READING;
	if (qla4xxx_get_flash(ha, flash_dma, offset, length))
		bsg_reply->result = (DID_ERROR << 16);
	else {
		sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
				    bsg_job->reply_payload.sg_cnt,
				    flash, length);

		bsg_reply->result = DID_OK;
		bsg_reply->reply_payload_rcv_len = length;
	}

	if (flash)
		dma_free_coherent(&ha->pdev->dev, length, flash, flash_dma);

	ha->flash_state = QLFLASH_WAITING;
unmap_sg:
	dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list,
		     bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
	if (!rval)
		bsg_job_done(bsg_job, bsg_reply->result,
			     bsg_reply->reply_payload_rcv_len);
	return rval;
}

static int
qla4xxx_update_flash(struct bsg_job *bsg_job)
{
	struct Scsi_Host *host = iscsi_job_to_shost(bsg_job);
	struct scsi_qla_host *ha = to_qla_host(host);
	struct iscsi_bsg_reply *bsg_reply = bsg_job->reply;
	struct iscsi_bsg_request *bsg_req = bsg_job->request;
	uint32_t sg_cnt;
	uint32_t length = 0;
	uint32_t offset = 0;
	uint32_t options = 0;
	dma_addr_t flash_dma;
	uint8_t *flash = NULL;
	int rval = 0;

	bsg_reply->reply_payload_rcv_len = 0;

	if (unlikely(pci_channel_offline(ha->pdev)))
		return -EINVAL;

	if (ha->flash_state != QLFLASH_WAITING)
		return -EBUSY;

	sg_cnt = dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
			    bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);

	if (!sg_cnt)
		return -ENOMEM;

	if (sg_cnt != bsg_job->request_payload.sg_cnt) {
		ql4_printk(KERN_ERR, ha, "dma mapping resulted in different "
			   "sg counts request_sg_cnt: %x dma_request_sg_cnt: "
			   "%x\n", bsg_job->request_payload.sg_cnt, sg_cnt);
		rval = -EAGAIN;
		goto unmap_sg;
	}

	length = bsg_job->request_payload.payload_len;
	offset = bsg_req->rqst_data.h_vendor.vendor_cmd[1];
	options = bsg_req->rqst_data.h_vendor.vendor_cmd[2];

	flash = dma_alloc_coherent(&ha->pdev->dev, length, &flash_dma,
				   GFP_KERNEL);
	if (!flash) {
		ql4_printk(KERN_ERR, ha, "%s: dma alloc failed for flash "
			   "data\n", __func__);
		rval = -ENOMEM;
		goto unmap_sg;
	}

	ha->flash_state = QLFLASH_WRITING;
	sg_copy_to_buffer(bsg_job->request_payload.sg_list,
			  bsg_job->request_payload.sg_cnt, flash, length);

	if (qla4xxx_set_flash(ha, flash_dma, offset, length, options))
		bsg_reply->result = (DID_ERROR << 16);
	else {
		bsg_reply->result = DID_OK;
		bsg_reply->reply_payload_rcv_len = length;
	}

	if (flash)
		dma_free_coherent(&ha->pdev->dev, length, flash, flash_dma);
	ha->flash_state = QLFLASH_WAITING;
unmap_sg:
	dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list,
		     bsg_job->reply_payload.sg_cnt, DMA_TO_DEVICE);

	if (!rval)
		bsg_job_done(bsg_job, bsg_reply->result,
			     bsg_reply->reply_payload_rcv_len);
	return rval;
}

/**
 * qla4xxx_process_vendor_specific - handle vendor specific bsg request
 * @job: iscsi_bsg_job to handle
 **/
int qla4xxx_process_vendor_specific(struct bsg_job *bsg_job)
{
	struct iscsi_bsg_reply *bsg_reply = bsg_job->reply;
	struct iscsi_bsg_request *bsg_req = bsg_job->request;
	struct Scsi_Host *host = iscsi_job_to_shost(bsg_job);
	struct scsi_qla_host *ha = to_qla_host(host);

	switch (bsg_req->rqst_data.h_vendor.vendor_cmd[0]) {
	case QLISCSI_VND_READ_FLASH:
		return qla4xxx_read_flash(bsg_job);

	case QLISCSI_VND_UPDATE_FLASH:
		return qla4xxx_update_flash(bsg_job);

	default:
		ql4_printk(KERN_ERR, ha, "%s: invalid BSG vendor command: "
			   "0x%x\n", __func__, bsg_req->msgcode);
		bsg_reply->result = (DID_ERROR << 16);
		bsg_reply->reply_payload_rcv_len = 0;
		bsg_job_done(bsg_job, bsg_reply->result,
			     bsg_reply->reply_payload_rcv_len);
		return -ENOSYS;
	}
}

/**
 * qla4xxx_bsg_request - handle bsg request from ISCSI transport
 * @job: iscsi_bsg_job to handle
 */
int qla4xxx_bsg_request(struct bsg_job *bsg_job)
{
	struct iscsi_bsg_request *bsg_req = bsg_job->request;
	struct Scsi_Host *host = iscsi_job_to_shost(bsg_job);
	struct scsi_qla_host *ha = to_qla_host(host);

	switch (bsg_req->msgcode) {
	case ISCSI_BSG_HST_VENDOR:
		return qla4xxx_process_vendor_specific(bsg_job);

	default:
		ql4_printk(KERN_ERR, ha, "%s: invalid BSG command: 0x%x\n",
			   __func__, bsg_req->msgcode);
	}

	return -ENOSYS;
}
+14 −0
Original line number Diff line number Diff line
/*
 * QLogic iSCSI HBA Driver
 * Copyright (c) 2011 QLogic Corporation
 *
 * See LICENSE.qla4xxx for copyright and licensing details.
 */
#ifndef __QL4_BSG_H
#define __QL4_BSG_H

/* BSG Vendor specific commands */
#define QLISCSI_VND_READ_FLASH		1
#define QLISCSI_VND_UPDATE_FLASH	2

#endif
+8 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@
#include <linux/interrupt.h>
#include <linux/mutex.h>
#include <linux/aer.h>
#include <linux/bsg-lib.h>

#include <net/tcp.h>
#include <scsi/scsi.h>
@@ -33,6 +34,8 @@
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_transport.h>
#include <scsi/scsi_transport_iscsi.h>
#include <scsi/scsi_bsg_iscsi.h>
#include <scsi/scsi_netlink.h>

#include "ql4_dbg.h"
#include "ql4_nx.h"
@@ -599,6 +602,11 @@ struct scsi_qla_host {
	uint16_t bootload_minor;
	uint16_t bootload_patch;
	uint16_t bootload_build;

	uint32_t flash_state;
#define	QLFLASH_WAITING		0
#define	QLFLASH_READING		1
#define	QLFLASH_WRITING		2
};

static inline int is_ipv4_enabled(struct scsi_qla_host *ha)
+4 −0
Original line number Diff line number Diff line
@@ -151,6 +151,10 @@ void qla4_8xxx_need_qsnt_handler(struct scsi_qla_host *ha);
void qla4_8xxx_clear_drv_active(struct scsi_qla_host *ha);
void qla4_8xxx_set_drv_active(struct scsi_qla_host *ha);

/* BSG Functions */
int qla4xxx_bsg_request(struct bsg_job *bsg_job);
int qla4xxx_process_vendor_specific(struct bsg_job *bsg_job);

extern int ql4xextended_error_logging;
extern int ql4xdontresethba;
extern int ql4xenablemsix;
Loading