Skip to content

Commit

Permalink
scsi: qla2xxx: Fix DMA error when the DIF sg buffer crosses 4GB boundary
Browse files Browse the repository at this point in the history
When SGE buffer containing DIF information crosses 4G boundary, it results
in DMA error. This patch fixes this issue by calculating SGE buffer size
and if it crosses 4G boundary, driver will split it into multiple SGE
buffers to avoid DMA error.

Signed-off-by: Giridhar Malavali <gmalavali@marvell.com>
Signed-off-by: Himanshu Madhani <hmadhani@marvell.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
  • Loading branch information
Giridhar Malavali authored and Martin K. Petersen committed Jan 12, 2019
1 parent 7855d2b commit 50b8127
Show file tree
Hide file tree
Showing 8 changed files with 503 additions and 68 deletions.
21 changes: 19 additions & 2 deletions drivers/scsi/qla2xxx/qla_attr.c
Original file line number Diff line number Diff line change
Expand Up @@ -1002,7 +1002,7 @@ qla2x00_free_sysfs_attr(scsi_qla_host_t *vha, bool stop_beacon)
/* Scsi_Host attributes. */

static ssize_t
qla2x00_drvr_version_show(struct device *dev,
qla2x00_driver_version_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return scnprintf(buf, PAGE_SIZE, "%s\n", qla2x00_version_str);
Expand Down Expand Up @@ -2059,7 +2059,21 @@ ql2xiniexchg_store(struct device *dev, struct device_attribute *attr,
return strlen(buf);
}

static DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_drvr_version_show, NULL);
static ssize_t
qla2x00_dif_bundle_statistics_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
struct qla_hw_data *ha = vha->hw;

return scnprintf(buf, PAGE_SIZE,
"cross=%llu read=%llu write=%llu kalloc=%llu dma_alloc=%llu unusable=%u\n",
ha->dif_bundle_crossed_pages, ha->dif_bundle_reads,
ha->dif_bundle_writes, ha->dif_bundle_kallocs,
ha->dif_bundle_dma_allocs, ha->pool.unusable.count);
}

static DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_driver_version_show, NULL);
static DEVICE_ATTR(fw_version, S_IRUGO, qla2x00_fw_version_show, NULL);
static DEVICE_ATTR(serial_num, S_IRUGO, qla2x00_serial_num_show, NULL);
static DEVICE_ATTR(isp_name, S_IRUGO, qla2x00_isp_name_show, NULL);
Expand Down Expand Up @@ -2112,6 +2126,8 @@ static DEVICE_ATTR(zio_threshold, 0644,
static DEVICE_ATTR_RW(qlini_mode);
static DEVICE_ATTR_RW(ql2xexchoffld);
static DEVICE_ATTR_RW(ql2xiniexchg);
static DEVICE_ATTR(dif_bundle_statistics, 0444,
qla2x00_dif_bundle_statistics_show, NULL);


struct device_attribute *qla2x00_host_attrs[] = {
Expand Down Expand Up @@ -2150,6 +2166,7 @@ struct device_attribute *qla2x00_host_attrs[] = {
&dev_attr_min_link_speed,
&dev_attr_max_speed_sup,
&dev_attr_zio_threshold,
&dev_attr_dif_bundle_statistics,
NULL, /* reserve for qlini_mode */
NULL, /* reserve for ql2xiniexchg */
NULL, /* reserve for ql2xexchoffld */
Expand Down
28 changes: 28 additions & 0 deletions drivers/scsi/qla2xxx/qla_def.h
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@ struct srb_cmd {
#define SRB_CRC_PROT_DMA_VALID BIT_4 /* DIF: prot DMA valid */
#define SRB_CRC_CTX_DSD_VALID BIT_5 /* DIF: dsd_list valid */
#define SRB_WAKEUP_ON_COMP BIT_6
#define SRB_DIF_BUNDL_DMA_VALID BIT_7 /* DIF: DMA list valid */

/* To identify if a srb is of T10-CRC type. @sp => srb_t pointer */
#define IS_PROT_IO(sp) (sp->flags & SRB_CRC_CTX_DSD_VALID)
Expand Down Expand Up @@ -1892,6 +1893,13 @@ struct crc_context {
/* List of DMA context transfers */
struct list_head dsd_list;

/* List of DIF Bundling context DMA address */
struct list_head ldif_dsd_list;
u8 no_ldif_dsd;

struct list_head ldif_dma_hndl_list;
u32 dif_bundl_len;
u8 no_dif_bundl;
/* This structure should not exceed 512 bytes */
};

Expand Down Expand Up @@ -4184,6 +4192,26 @@ struct qla_hw_data {
uint16_t min_link_speed;
uint16_t max_speed_sup;

/* DMA pool for the DIF bundling buffers */
struct dma_pool *dif_bundl_pool;
#define DIF_BUNDLING_DMA_POOL_SIZE 1024
struct {
struct {
struct list_head head;
uint count;
} good;
struct {
struct list_head head;
uint count;
} unusable;
} pool;

unsigned long long dif_bundle_crossed_pages;
unsigned long long dif_bundle_reads;
unsigned long long dif_bundle_writes;
unsigned long long dif_bundle_kallocs;
unsigned long long dif_bundle_dma_allocs;

atomic_t nvme_active_aen_cnt;
uint16_t nvme_last_rptd_aen; /* Last recorded aen count */

Expand Down
3 changes: 2 additions & 1 deletion drivers/scsi/qla2xxx/qla_gbl.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ extern int ql2xautodetectsfp;
extern int ql2xenablemsix;
extern int qla2xuseresexchforels;
extern int ql2xexlogins;
extern int ql2xdifbundlinginternalbuffers;

extern int qla2x00_loop_reset(scsi_qla_host_t *);
extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int);
Expand Down Expand Up @@ -285,7 +286,7 @@ extern int qla24xx_walk_and_build_sglist_no_difb(struct qla_hw_data *, srb_t *,
extern int qla24xx_walk_and_build_sglist(struct qla_hw_data *, srb_t *,
uint32_t *, uint16_t, struct qla_tc_param *);
extern int qla24xx_walk_and_build_prot_sglist(struct qla_hw_data *, srb_t *,
uint32_t *, uint16_t, struct qla_tc_param *);
uint32_t *, uint16_t, struct qla_tgt_cmd *);
extern int qla24xx_get_one_block_sg(uint32_t, struct qla2_sgx *, uint32_t *);
extern int qla24xx_configure_prot_mode(srb_t *, uint16_t *);
extern int qla24xx_build_scsi_crc_2_iocbs(srb_t *,
Expand Down
Loading

0 comments on commit 50b8127

Please sign in to comment.