Acked-by: Xie XiuQi xiexiuqi@huawei.com
On 2022/1/5 16:10, Yanling Song wrote:
Ramaxel inclusion category: features bugzilla: https://gitee.com/openeuler/kernel/issues/I4JXCG CVE: NA
Changes:
- Use bsg module to replace with ioctrl
- Split scmd_tmout_nonpt into two parameters: scmd_tmout_vd/scmd_tmout_rawdisk
- Return -ETIME instead of -EINVAL when command is timeout.
- Add one module parameters: max_io_force.
- Remove some unnecessary module parameters.
- Report disks by the order of channel/target id.
- Add host_reset handler.
- Use get_unaligned_be24.
Signed-off-by: Yanling Song songyl@ramaxel.com Reviewed-by: Jiang Yuyujiang@ramaxel.com
drivers/scsi/spraid/Kconfig | 6 +- drivers/scsi/spraid/spraid.h | 142 ++- drivers/scsi/spraid/spraid_main.c | 1633 +++++++++++++++-------------- 3 files changed, 968 insertions(+), 813 deletions(-)
diff --git a/drivers/scsi/spraid/Kconfig b/drivers/scsi/spraid/Kconfig index 83962efaab07..bfbba3db8db0 100644 --- a/drivers/scsi/spraid/Kconfig +++ b/drivers/scsi/spraid/Kconfig @@ -5,7 +5,9 @@ config RAMAXEL_SPRAID tristate "Ramaxel spraid Adapter" depends on PCI && SCSI
- select BLK_DEV_BSGLIB depends on ARM64 || X86_64
- default m help
This driver supports Ramaxel spraid driver.
- This driver supports Ramaxel SPRxxx serial
- raid controller, which has PCIE Gen4 interface
- with host and supports SAS/SATA Hdd/ssd.
diff --git a/drivers/scsi/spraid/spraid.h b/drivers/scsi/spraid/spraid.h index da46d8e1b4b6..983d7af2faa8 100644 --- a/drivers/scsi/spraid/spraid.h +++ b/drivers/scsi/spraid/spraid.h @@ -1,4 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright(c) 2021 Ramaxel Memory Technology, Ltd */
#ifndef __SPRAID_H_ #define __SPRAID_H_ @@ -24,7 +25,7 @@ #define SENSE_SIZE(depth) ((depth) * SCSI_SENSE_BUFFERSIZE)
#define SPRAID_AQ_DEPTH 128 -#define SPRAID_NR_AEN_COMMANDS 1 +#define SPRAID_NR_AEN_COMMANDS 16 #define SPRAID_AQ_BLK_MQ_DEPTH (SPRAID_AQ_DEPTH - SPRAID_NR_AEN_COMMANDS) #define SPRAID_AQ_MQ_TAG_DEPTH (SPRAID_AQ_BLK_MQ_DEPTH - 1)
@@ -44,7 +45,7 @@
#define SMALL_POOL_SIZE 256 #define MAX_SMALL_POOL_NUM 16 -#define MAX_CMD_PER_DEV 32 +#define MAX_CMD_PER_DEV 64 #define MAX_CDB_LEN 32
#define SPRAID_UP_TO_MULTY4(x) (((x) + 4) & (~0x03)) @@ -53,7 +54,7 @@
#define PCI_VENDOR_ID_RAMAXEL_LOGIC 0x1E81
-#define SPRAID_SERVER_DEVICE_HAB_DID 0x2100 +#define SPRAID_SERVER_DEVICE_HBA_DID 0x2100 #define SPRAID_SERVER_DEVICE_RAID_DID 0x2200
#define IO_6_DEFAULT_TX_LEN 256 @@ -142,11 +143,15 @@ enum {
enum { SPRAID_AEN_DEV_CHANGED = 0x00,
- SPRAID_AEN_FW_ACT_START = 0x01, SPRAID_AEN_HOST_PROBING = 0x10,
};
enum {
- SPRAID_AEN_TIMESYN = 0x07
- SPRAID_AEN_TIMESYN = 0x00,
- SPRAID_AEN_FW_ACT_FINISH = 0x02,
- SPRAID_AEN_EVENT_MIN = 0x80,
- SPRAID_AEN_EVENT_MAX = 0xff,
};
enum { @@ -175,6 +180,16 @@ enum spraid_state { SPRAID_DEAD, };
+enum {
- SPRAID_CARD_HBA,
- SPRAID_CARD_RAID,
+};
+enum spraid_cmd_type {
- SPRAID_CMD_ADM,
- SPRAID_CMD_IOPT,
+};
struct spraid_completion { __le32 result; union { @@ -217,8 +232,6 @@ struct spraid_dev { struct dma_pool *prp_page_pool; struct dma_pool *prp_small_pool[MAX_SMALL_POOL_NUM]; mempool_t *iod_mempool;
- struct blk_mq_tag_set admin_tagset;
- struct request_queue *admin_q; void __iomem *bar; u32 max_qid; u32 num_vecs;
@@ -232,23 +245,27 @@ struct spraid_dev { u32 ctrl_config; u32 online_queues; u64 cap;
struct device ctrl_device;
struct cdev cdev; int instance; struct spraid_ctrl_info *ctrl_info; struct spraid_dev_info *devices;
struct spraid_ioq_ptcmd *ioq_ptcmds;
- struct spraid_cmd *adm_cmds;
- struct list_head adm_cmd_list;
- spinlock_t adm_cmd_lock;
- struct spraid_cmd *ioq_ptcmds; struct list_head ioq_pt_list; spinlock_t ioq_pt_lock;
- struct work_struct aen_work; struct work_struct scan_work; struct work_struct timesyn_work; struct work_struct reset_work;
struct work_struct fw_act_work;
enum spraid_state state; spinlock_t state_lock;
struct request_queue *bsg_queue;
};
struct spraid_sgl_desc { @@ -347,6 +364,35 @@ struct spraid_get_info { __u32 rsvd12[4]; };
+struct spraid_usr_cmd {
- __u8 opcode;
- __u8 flags;
- __u16 command_id;
- __le32 hdid;
- union {
struct {
__le16 subopcode;
__le16 rsvd1;
} info_0;
__le32 cdw2;
- };
- union {
struct {
__le16 data_len;
__le16 param_len;
} info_1;
__le32 cdw3;
- };
- __u64 metadata;
- union spraid_data_ptr dptr;
- __le32 cdw10;
- __le32 cdw11;
- __le32 cdw12;
- __le32 cdw13;
- __le32 cdw14;
- __le32 cdw15;
+};
enum { SPRAID_CMD_FLAG_SGL_METABUF = (1 << 6), SPRAID_CMD_FLAG_SGL_METASEG = (1 << 7), @@ -393,6 +439,7 @@ struct spraid_admin_command { struct spraid_get_info get_info; struct spraid_abort_cmd abort; struct spraid_reset_cmd reset;
};struct spraid_usr_cmd usr_cmd;
};
@@ -456,9 +503,6 @@ struct spraid_ioq_command { }; };
-#define SPRAID_IOCTL_RESET_CMD _IOWR('N', 0x80, struct spraid_passthru_common_cmd) -#define SPRAID_IOCTL_ADMIN_CMD _IOWR('N', 0x41, struct spraid_passthru_common_cmd)
struct spraid_passthru_common_cmd { __u8 opcode; __u8 flags; @@ -494,8 +538,6 @@ struct spraid_passthru_common_cmd { __u32 result1; };
-#define SPRAID_IOCTL_IOQ_CMD _IOWR('N', 0x42, struct spraid_ioq_passthru_cmd)
struct spraid_ioq_passthru_cmd { __u8 opcode; __u8 flags; @@ -560,7 +602,21 @@ struct spraid_ioq_passthru_cmd { __u32 result1; };
-struct spraid_ioq_ptcmd { +struct spraid_bsg_request {
- u32 msgcode;
- u32 control;
- union {
struct spraid_passthru_common_cmd admcmd;
struct spraid_ioq_passthru_cmd ioqcmd;
- };
+};
+enum {
- SPRAID_BSG_ADM,
- SPRAID_BSG_IOQ,
+};
+struct spraid_cmd { int qid; int cid; u32 result0; @@ -572,14 +628,6 @@ struct spraid_ioq_ptcmd { struct list_head list; };
-struct spraid_admin_request {
- struct spraid_admin_command *cmd;
- u32 result0;
- u32 result1;
- u16 flags;
- u16 status;
-};
struct spraid_queue { struct spraid_dev *hdev; spinlock_t sq_lock; /* spinlock for lock handling */ @@ -607,7 +655,6 @@ struct spraid_queue { };
struct spraid_iod {
- struct spraid_admin_request req; struct spraid_queue *spraidq; enum spraid_cmd_state state; int npages;
@@ -623,13 +670,51 @@ struct spraid_iod { };
#define SPRAID_DEV_INFO_ATTR_BOOT(attr) ((attr) & 0x01) -#define SPRAID_DEV_INFO_ATTR_HDD(attr) ((attr) & 0x02) +#define SPRAID_DEV_INFO_ATTR_VD(attr) (((attr) & 0x02) == 0x0) #define SPRAID_DEV_INFO_ATTR_PT(attr) (((attr) & 0x22) == 0x02) #define SPRAID_DEV_INFO_ATTR_RAWDISK(attr) ((attr) & 0x20)
#define SPRAID_DEV_INFO_FLAG_VALID(flag) ((flag) & 0x01) #define SPRAID_DEV_INFO_FLAG_CHANGE(flag) ((flag) & 0x02)
+#define BGTASK_TYPE_REBUILD 4 +#define USR_CMD_READ 0xc2 +#define USR_CMD_RDLEN 0x1000 +#define USR_CMD_VDINFO 0x704 +#define USR_CMD_BGTASK 0x504 +#define VDINFO_PARAM_LEN 0x04
+struct spraid_vd_info {
- __u8 name[32];
- __le16 id;
- __u8 rg_id;
- __u8 rg_level;
- __u8 sg_num;
- __u8 sg_disk_num;
- __u8 vd_status;
- __u8 vd_type;
- __u8 rsvd1[4056];
+};
+#define MAX_REALTIME_BGTASK_NUM 32
+struct bgtask_info {
- __u8 type;
- __u8 progress;
- __u8 rate;
- __u8 rsvd0;
- __le16 vd_id;
- __le16 time_left;
- __u8 rsvd1[4];
+};
+struct spraid_bgtask {
- __u8 sw;
- __u8 task_num;
- __u8 rsvd[6];
- struct bgtask_info bgtask[MAX_REALTIME_BGTASK_NUM];
+};
struct spraid_dev_info { __le32 hdid; __le16 target; @@ -649,6 +734,11 @@ struct spraid_dev_list {
struct spraid_sdev_hostdata { u32 hdid;
- u16 max_io_kb;
- u8 attr;
- u8 flag;
- u8 rg_id;
- u8 rsvd[3];
};
#endif diff --git a/drivers/scsi/spraid/spraid_main.c b/drivers/scsi/spraid/spraid_main.c index a0a75ecb0027..c6d2a0b8e35e 100644 --- a/drivers/scsi/spraid/spraid_main.c +++ b/drivers/scsi/spraid/spraid_main.c @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 -/*
- Linux spraid device driver
- Copyright(c) 2021 Ramaxel Memory Technology, Ltd
- */
+/* Copyright(c) 2021 Ramaxel Memory Technology, Ltd */
+/* Ramaxel Raid SPXXX Series Linux Driver */
#define pr_fmt(fmt) "spraid: " fmt
#include <linux/sched/signal.h> @@ -23,6 +23,9 @@ #include <linux/debugfs.h> #include <linux/io-64-nonatomic-lo-hi.h> #include <linux/blkdev.h> +#include <linux/bsg-lib.h> +#include <asm/unaligned.h> +#include <linux/sort.h>
#include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> @@ -31,27 +34,24 @@ #include <scsi/scsi_transport.h> #include <scsi/scsi_dbg.h>
#include "spraid.h"
static u32 admin_tmout = 60; module_param(admin_tmout, uint, 0644); MODULE_PARM_DESC(admin_tmout, "admin commands timeout (seconds)");
-static u32 scmd_tmout_pt = 30; -module_param(scmd_tmout_pt, uint, 0644); -MODULE_PARM_DESC(scmd_tmout_pt, "scsi commands timeout for passthrough(seconds)"); +static u32 scmd_tmout_rawdisk = 180; +module_param(scmd_tmout_rawdisk, uint, 0644); +MODULE_PARM_DESC(scmd_tmout_rawdisk, "scsi commands timeout for rawdisk(seconds)");
-static u32 scmd_tmout_nonpt = 180; -module_param(scmd_tmout_nonpt, uint, 0644); -MODULE_PARM_DESC(scmd_tmout_nonpt, "scsi commands timeout for rawdisk&raid(seconds)"); +static u32 scmd_tmout_vd = 180; +module_param(scmd_tmout_vd, uint, 0644); +MODULE_PARM_DESC(scmd_tmout_vd, "scsi commands timeout for vd(seconds)");
-static u32 wait_abl_tmout = 3; -module_param(wait_abl_tmout, uint, 0644); -MODULE_PARM_DESC(wait_abl_tmout, "wait abnormal io timeout(seconds)");
-static bool use_sgl_force; -module_param(use_sgl_force, bool, 0644); -MODULE_PARM_DESC(use_sgl_force, "force IO use sgl format, default false"); +static bool max_io_force; +module_param(max_io_force, bool, 0644); +MODULE_PARM_DESC(max_io_force, "force max_hw_sectors_kb = 1024, default false(performance first)");
static int ioq_depth_set(const char *val, const struct kernel_param *kp); static const struct kernel_param_ops ioq_depth_ops = { @@ -106,16 +106,20 @@ static const struct kernel_param_ops small_pool_num_ops = { .get = param_get_byte, };
+/* It was found that the spindlock of a single pool conflicts
- a lot with multiple CPUs.So multiple pools are introduced
- to reduce the conflictions.
- */
static unsigned char small_pool_num = 4; module_param_cb(small_pool_num, &small_pool_num_ops, &small_pool_num, 0644); MODULE_PARM_DESC(small_pool_num, "set prp small pool num, default 4, MAX 16");
static void spraid_free_queue(struct spraid_queue *spraidq); static void spraid_handle_aen_notice(struct spraid_dev *hdev, u32 result); -static void spraid_handle_aen_vs(struct spraid_dev *hdev, u32 result); +static void spraid_handle_aen_vs(struct spraid_dev *hdev, u32 result, u32 result1);
static DEFINE_IDA(spraid_instance_ida); -static dev_t spraid_chr_devt;
static struct class *spraid_class;
#define SPRAID_CAP_TIMEOUT_UNIT_MS (HZ / 2) @@ -131,9 +135,8 @@ static struct workqueue_struct *spraid_wq; #define SPRAID_DRV_VERSION "1.0.0.0"
#define ADMIN_TIMEOUT (admin_tmout * HZ) -#define ADMIN_ERR_TIMEOUT 32757
-#define SPRAID_WAIT_ABNL_CMD_TIMEOUT (wait_abl_tmout * 2) +#define SPRAID_WAIT_ABNL_CMD_TIMEOUT (3 * 2)
#define SPRAID_DMA_MSK_BIT_MAX 64
@@ -147,6 +150,13 @@ enum FW_STAT_CODE { FW_STAT_NEED_RETRY };
+static const char * const raid_levels[] = {"0", "1", "5", "6", "10", "50", "60", "NA"};
+static const char * const raid_states[] = {
- "NA", "NORMAL", "FAULT", "DEGRADE", "NOT_FORMATTED", "FORMATTING", "SANITIZING",
- "INITIALIZING", "INITIALIZE_FAIL", "DELETING", "DELETE_FAIL", "WRITE_PROTECT"
+};
static int ioq_depth_set(const char *val, const struct kernel_param *kp) { int n = 0; @@ -231,12 +241,6 @@ static int spraid_pci_enable(struct spraid_dev *hdev) goto disable; }
- ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
- if (ret < 0) {
dev_err(hdev->dev, "Allocate one IRQ for setup admin channel failed\n");
goto disable;
- }
- hdev->cap = lo_hi_readq(hdev->bar + SPRAID_REG_CAP); hdev->ioq_depth = min_t(u32, SPRAID_CAP_MQES(hdev->cap) + 1, io_queue_depth); hdev->db_stride = 1 << SPRAID_CAP_STRIDE(hdev->cap);
@@ -246,13 +250,20 @@ static int spraid_pci_enable(struct spraid_dev *hdev) dev_err(hdev->dev, "err, dma mask invalid[%llu], set to default\n", maskbit); maskbit = SPRAID_DMA_MSK_BIT_MAX; }
- if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(maskbit))) {
if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(maskbit)) &&
dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32))) {
dev_err(hdev->dev, "set dma mask and coherent failed\n"); goto disable; }
dev_info(hdev->dev, "set dma mask[%llu] success\n", maskbit);
ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
if (ret < 0) {
dev_err(hdev->dev, "Allocate one IRQ for setup admin channel failed\n");
goto disable;
}
pci_enable_pcie_error_reporting(pdev); pci_save_state(pdev);
@@ -263,12 +274,6 @@ static int spraid_pci_enable(struct spraid_dev *hdev) return ret; }
-static inline -struct spraid_admin_request *spraid_admin_req(struct request *req) -{
- return blk_mq_rq_to_pdu(req);
-}
static int spraid_npages_prp(u32 size, struct spraid_dev *hdev) { u32 nprps = DIV_ROUND_UP(size + hdev->page_size, hdev->page_size); @@ -419,7 +424,7 @@ static void spraid_submit_cmd(struct spraid_queue *spraidq, const void *cmd) writel(spraidq->sq_tail, spraidq->q_db); spin_unlock_irqrestore(&spraidq->sq_lock, flags);
- dev_log_dbg(spraidq->hdev->dev, "cid[%d], qid[%d], opcode[0x%x], flags[0x%x], hdid[%u]\n",
- dev_log_dbg(spraidq->hdev->dev, "cid[%d] qid[%d], opcode[0x%x], flags[0x%x], hdid[%u]\n", acd->command_id, spraidq->qid, acd->opcode, acd->flags, le32_to_cpu(acd->hdid));
}
@@ -605,18 +610,15 @@ static void spraid_setup_rw_cmd(struct spraid_dev *hdev, if (scmd->cmd_len == 6) { datalength = (u32)(scmd->cmnd[4] == 0 ? IO_6_DEFAULT_TX_LEN : scmd->cmnd[4]);
start_lba_lo = ((u32)scmd->cmnd[1] << 16) |
((u32)scmd->cmnd[2] << 8) | (u32)scmd->cmnd[3];
start_lba_lo = (u32)get_unaligned_be24(&scmd->cmnd[1]);
start_lba_lo &= 0x1FFFFF; }
/* 10-byte READ(0x28) or WRITE(0x2A) cdb */ else if (scmd->cmd_len == 10) {
datalength = (u32)scmd->cmnd[8] | ((u32)scmd->cmnd[7] << 8);
start_lba_lo = ((u32)scmd->cmnd[2] << 24) |
((u32)scmd->cmnd[3] << 16) |
((u32)scmd->cmnd[4] << 8) | (u32)scmd->cmnd[5];
datalength = (u32)get_unaligned_be16(&scmd->cmnd[7]);
start_lba_lo = get_unaligned_be32(&scmd->cmnd[2]);
if (scmd->cmnd[1] & FUA_MASK) control |= SPRAID_RW_FUA;
@@ -624,42 +626,26 @@ static void spraid_setup_rw_cmd(struct spraid_dev *hdev,
/* 12-byte READ(0xA8) or WRITE(0xAA) cdb */ else if (scmd->cmd_len == 12) {
datalength = ((u32)scmd->cmnd[6] << 24) |
((u32)scmd->cmnd[7] << 16) |
((u32)scmd->cmnd[8] << 8) | (u32)scmd->cmnd[9];
start_lba_lo = ((u32)scmd->cmnd[2] << 24) |
((u32)scmd->cmnd[3] << 16) |
((u32)scmd->cmnd[4] << 8) | (u32)scmd->cmnd[5];
datalength = get_unaligned_be32(&scmd->cmnd[6]);
start_lba_lo = get_unaligned_be32(&scmd->cmnd[2]);
if (scmd->cmnd[1] & FUA_MASK) control |= SPRAID_RW_FUA; } /* 16-byte READ(0x88) or WRITE(0x8A) cdb */ else if (scmd->cmd_len == 16) {
datalength = ((u32)scmd->cmnd[10] << 24) |
((u32)scmd->cmnd[11] << 16) |
((u32)scmd->cmnd[12] << 8) | (u32)scmd->cmnd[13];
start_lba_lo = ((u32)scmd->cmnd[6] << 24) |
((u32)scmd->cmnd[7] << 16) |
((u32)scmd->cmnd[8] << 8) | (u32)scmd->cmnd[9];
start_lba_hi = ((u32)scmd->cmnd[2] << 24) |
((u32)scmd->cmnd[3] << 16) |
((u32)scmd->cmnd[4] << 8) | (u32)scmd->cmnd[5];
datalength = get_unaligned_be32(&scmd->cmnd[10]);
start_lba_lo = get_unaligned_be32(&scmd->cmnd[6]);
start_lba_hi = get_unaligned_be32(&scmd->cmnd[2]);
if (scmd->cmnd[1] & FUA_MASK) control |= SPRAID_RW_FUA; } /* 32-byte READ(0x88) or WRITE(0x8A) cdb */ else if (scmd->cmd_len == 32) {
datalength = ((u32)scmd->cmnd[28] << 24) |
((u32)scmd->cmnd[29] << 16) |
((u32)scmd->cmnd[30] << 8) | (u32)scmd->cmnd[31];
start_lba_lo = ((u32)scmd->cmnd[16] << 24) |
((u32)scmd->cmnd[17] << 16) |
((u32)scmd->cmnd[18] << 8) | (u32)scmd->cmnd[19];
start_lba_hi = ((u32)scmd->cmnd[12] << 24) |
((u32)scmd->cmnd[13] << 16) |
((u32)scmd->cmnd[14] << 8) | (u32)scmd->cmnd[15];
datalength = get_unaligned_be32(&scmd->cmnd[28]);
start_lba_lo = get_unaligned_be32(&scmd->cmnd[16]);
start_lba_hi = get_unaligned_be32(&scmd->cmnd[12]);
if (scmd->cmnd[10] & FUA_MASK) control |= SPRAID_RW_FUA;
@@ -814,7 +800,7 @@ static void spraid_map_status(struct spraid_iod *iod, struct scsi_cmnd *scmd, if (scmd->result & SAM_STAT_CHECK_CONDITION) { memset(scmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); memcpy(scmd->sense_buffer, iod->sense, SCSI_SENSE_BUFFERSIZE);
set_driver_byte(scmd, DRIVER_SENSE);
} break; case FW_STAT_ABORTED:scmd->result = (scmd->result & 0x00ffffff) | (DRIVER_SENSE << 24);
@@ -825,6 +811,8 @@ static void spraid_map_status(struct spraid_iod *iod, struct scsi_cmnd *scmd, break; default: set_host_byte(scmd, DID_BAD_TARGET);
dev_warn(iod->spraidq->hdev->dev, "[%s] cid[%d] qid[%d] bad status[0x%x]\n",
break; }__func__, cqe->cmd_id, le16_to_cpu(cqe->sq_id), le16_to_cpu(cqe->status));
} @@ -850,14 +838,13 @@ static int spraid_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd) int ret;
if (unlikely(!scmd)) {
dev_err(hdev->dev, "err, scmd is null, return 0\n");
dev_err(hdev->dev, "err, scmd is null\n");
return 0; }
if (unlikely(hdev->state != SPRAID_LIVE)) { set_host_byte(scmd, DID_NO_CONNECT); scmd->scsi_done(scmd);
return 0; }dev_err(hdev->dev, "[%s] err, hdev state is not live\n", __func__);
@@ -894,7 +881,7 @@ static int spraid_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd) WRITE_ONCE(iod->state, SPRAID_CMD_IN_FLIGHT); spraid_submit_cmd(ioq, &ioq_cmd); elapsed = jiffies - scmd->jiffies_at_alloc;
- dev_log_dbg(hdev->dev, "cid[%d], qid[%d] submit IO cost %3ld.%3ld seconds\n",
- dev_log_dbg(hdev->dev, "cid[%d] qid[%d] submit IO cost %3ld.%3ld seconds\n", cid, hwq, elapsed / HZ, elapsed % HZ); return 0;
@@ -945,6 +932,10 @@ static int spraid_slave_alloc(struct scsi_device *sdev)
scan_host: hostdata->hdid = le32_to_cpu(hdev->devices[idx].hdid);
- hostdata->max_io_kb = le16_to_cpu(hdev->devices[idx].max_io_kb);
- hostdata->attr = hdev->devices[idx].attr;
- hostdata->flag = hdev->devices[idx].flag;
- hostdata->rg_id = 0xff; sdev->hostdata = hostdata; up_read(&hdev->devices_rwsem); return 0;
@@ -958,30 +949,17 @@ static void spraid_slave_destroy(struct scsi_device *sdev)
static int spraid_slave_configure(struct scsi_device *sdev) {
- u16 idx;
- unsigned int timeout = scmd_tmout_nonpt * HZ;
- unsigned int timeout = scmd_tmout_rawdisk * HZ; struct spraid_dev *hdev = shost_priv(sdev->host); struct spraid_sdev_hostdata *hostdata = sdev->hostdata; u32 max_sec = sdev->host->max_sectors;
- if (!hostdata) {
idx = hostdata->hdid - 1;
if (sdev->channel == hdev->devices[idx].channel &&
sdev->id == le16_to_cpu(hdev->devices[idx].target) &&
sdev->lun < hdev->devices[idx].lun) {
if (SPRAID_DEV_INFO_ATTR_PT(hdev->devices[idx].attr))
timeout = scmd_tmout_pt * HZ;
else
timeout = scmd_tmout_nonpt * HZ;
max_sec = le16_to_cpu(hdev->devices[idx].max_io_kb) << 1;
} else {
dev_err(hdev->dev, "[%s] err, sdev->channel:id:lun[%d:%d:%lld];"
"devices[%d], channel:target:lun[%d:%d:%d]\n",
__func__, sdev->channel, sdev->id, sdev->lun,
idx, hdev->devices[idx].channel,
hdev->devices[idx].target,
hdev->devices[idx].lun);
}
- if (hostdata) {
if (SPRAID_DEV_INFO_ATTR_VD(hostdata->attr))
timeout = scmd_tmout_vd * HZ;
else if (SPRAID_DEV_INFO_ATTR_RAWDISK(hostdata->attr))
timeout = scmd_tmout_rawdisk * HZ;
} else { dev_err(hdev->dev, "[%s] err, sdev->hostdata is null\n", __func__); }max_sec = hostdata->max_io_kb << 1;
@@ -991,7 +969,9 @@ static int spraid_slave_configure(struct scsi_device *sdev)
if ((max_sec == 0) || (max_sec > sdev->host->max_sectors)) max_sec = sdev->host->max_sectors;
- blk_queue_max_hw_sectors(sdev->request_queue, max_sec);
if (!max_io_force)
blk_queue_max_hw_sectors(sdev->request_queue, max_sec);
dev_info(hdev->dev, "[%s] sdev->channel:id:lun[%d:%d:%lld], scmd_timeout[%d]s, maxsec[%d]\n", __func__, sdev->channel, sdev->id, sdev->lun, timeout / HZ, max_sec);
@@ -1176,6 +1156,75 @@ static inline bool spraid_cqe_pending(struct spraid_queue *spraidq) spraidq->cq_phase; }
+static void spraid_sata_report_zone_handle(struct scsi_cmnd *scmd, struct spraid_iod *iod) +{
- int i = 0;
- unsigned int bytes = 0;
- struct scatterlist *sg = scsi_sglist(scmd);
- scsi_for_each_sg(scmd, sg, iod->nsge, i) {
unsigned int offset = 0;
if (bytes == 0) {
char *hdr;
u32 list_length;
u64 max_lba, opt_lba;
u16 same;
hdr = sg_virt(sg);
list_length = get_unaligned_le32(&hdr[0]);
same = get_unaligned_le16(&hdr[4]);
max_lba = get_unaligned_le64(&hdr[8]);
opt_lba = get_unaligned_le64(&hdr[16]);
put_unaligned_be32(list_length, &hdr[0]);
hdr[4] = same & 0xf;
put_unaligned_be64(max_lba, &hdr[8]);
put_unaligned_be64(opt_lba, &hdr[16]);
offset += 64;
bytes += 64;
}
while (offset < sg_dma_len(sg)) {
char *rec;
u8 cond, type, non_seq, reset;
u64 size, start, wp;
rec = sg_virt(sg) + offset;
type = rec[0] & 0xf;
cond = (rec[1] >> 4) & 0xf;
non_seq = (rec[1] & 2);
reset = (rec[1] & 1);
size = get_unaligned_le64(&rec[8]);
start = get_unaligned_le64(&rec[16]);
wp = get_unaligned_le64(&rec[24]);
rec[0] = type;
rec[1] = (cond << 4) | non_seq | reset;
put_unaligned_be64(size, &rec[8]);
put_unaligned_be64(start, &rec[16]);
put_unaligned_be64(wp, &rec[24]);
WARN_ON(offset + 64 > sg_dma_len(sg));
offset += 64;
bytes += 64;
}
- }
+}
+static inline void spraid_handle_ata_cmd(struct spraid_dev *hdev, struct scsi_cmnd *scmd,
struct spraid_iod *iod)
+{
- if (hdev->ctrl_info->card_type != SPRAID_CARD_HBA)
return;
- switch (scmd->cmnd[0]) {
- case ZBC_IN:
dev_info(hdev->dev, "[%s] process report zone\n", __func__);
spraid_sata_report_zone_handle(scmd, iod);
break;
- default:
break;
- }
+}
static void spraid_complete_ioq_cmnd(struct spraid_queue *ioq, struct spraid_completion *cqe) { struct spraid_dev *hdev = ioq->hdev; @@ -1197,12 +1246,12 @@ static void spraid_complete_ioq_cmnd(struct spraid_queue *ioq, struct spraid_com iod = scsi_cmd_priv(scmd);
elapsed = jiffies - scmd->jiffies_at_alloc;
- dev_log_dbg(hdev->dev, "cid[%d], qid[%d] finish IO cost %3ld.%3ld seconds\n",
dev_log_dbg(hdev->dev, "cid[%d] qid[%d] finish IO cost %3ld.%3ld seconds\n", cqe->cmd_id, ioq->qid, elapsed / HZ, elapsed % HZ);
if (cmpxchg(&iod->state, SPRAID_CMD_IN_FLIGHT, SPRAID_CMD_COMPLETE) != SPRAID_CMD_IN_FLIGHT) {
dev_warn(hdev->dev, "cid[%d], qid[%d] enters abnormal handler, cost %3ld.%3ld seconds\n",
WRITE_ONCE(iod->state, SPRAID_CMD_TMO_COMPLETE);dev_warn(hdev->dev, "cid[%d] qid[%d] enters abnormal handler, cost %3ld.%3ld seconds\n", cqe->cmd_id, ioq->qid, elapsed / HZ, elapsed % HZ);
@@ -1215,6 +1264,8 @@ static void spraid_complete_ioq_cmnd(struct spraid_queue *ioq, struct spraid_com return; }
- spraid_handle_ata_cmd(hdev, scmd, iod);
- spraid_map_status(iod, scmd, cqe); if (iod->nsge) { iod->nsge = 0;
@@ -1224,38 +1275,36 @@ static void spraid_complete_ioq_cmnd(struct spraid_queue *ioq, struct spraid_com scmd->scsi_done(scmd); }
-static inline void spraid_end_admin_request(struct request *req, __le16 status,
__le32 result0, __le32 result1)
-{
- struct spraid_admin_request *rq = spraid_admin_req(req);
- rq->status = le16_to_cpu(status) >> 1;
- rq->result0 = le32_to_cpu(result0);
- rq->result1 = le32_to_cpu(result1);
- blk_mq_complete_request(req);
-}
static void spraid_complete_adminq_cmnd(struct spraid_queue *adminq, struct spraid_completion *cqe) {
- struct blk_mq_tags *tags = adminq->hdev->admin_tagset.tags[0];
- struct request *req;
- struct spraid_dev *hdev = adminq->hdev;
- struct spraid_cmd *adm_cmd;
- req = blk_mq_tag_to_rq(tags, cqe->cmd_id);
- if (unlikely(!req)) {
- adm_cmd = hdev->adm_cmds + cqe->cmd_id;
- if (unlikely(adm_cmd->state == SPRAID_CMD_IDLE)) { dev_warn(adminq->hdev->dev, "Invalid id %d completed on queue %d\n", cqe->cmd_id, le16_to_cpu(cqe->sq_id)); return; }
- spraid_end_admin_request(req, cqe->status, cqe->result, cqe->result1);
- adm_cmd->status = le16_to_cpu(cqe->status) >> 1;
- adm_cmd->result0 = le32_to_cpu(cqe->result);
- adm_cmd->result1 = le32_to_cpu(cqe->result1);
- complete(&adm_cmd->cmd_done);
}
+static void spraid_send_aen(struct spraid_dev *hdev, u16 cid);
static void spraid_complete_aen(struct spraid_queue *spraidq, struct spraid_completion *cqe) { struct spraid_dev *hdev = spraidq->hdev; u32 result = le32_to_cpu(cqe->result);
- dev_info(hdev->dev, "rcv aen, status[%x], result[%x]\n",
le16_to_cpu(cqe->status) >> 1, result);
dev_info(hdev->dev, "rcv aen, cid[%d], status[0x%x], result[0x%x]\n",
cqe->cmd_id, le16_to_cpu(cqe->status) >> 1, result);
spraid_send_aen(hdev, cqe->cmd_id);
if ((le16_to_cpu(cqe->status) >> 1) != SPRAID_SC_SUCCESS) return;
@@ -1264,22 +1313,19 @@ static void spraid_complete_aen(struct spraid_queue *spraidq, struct spraid_comp spraid_handle_aen_notice(hdev, result); break; case SPRAID_AEN_VS:
spraid_handle_aen_vs(hdev, result);
break; default: dev_warn(hdev->dev, "Unsupported async event type: %u\n", result & 0x7); break; }spraid_handle_aen_vs(hdev, result, le32_to_cpu(cqe->result1));
- queue_work(spraid_wq, &hdev->aen_work);
}
-static void spraid_put_ioq_ptcmd(struct spraid_dev *hdev, struct spraid_ioq_ptcmd *cmd);
static void spraid_complete_ioq_sync_cmnd(struct spraid_queue *ioq, struct spraid_completion *cqe) { struct spraid_dev *hdev = ioq->hdev;
- struct spraid_ioq_ptcmd *ptcmd;
struct spraid_cmd *ptcmd;
ptcmd = hdev->ioq_ptcmds + (ioq->qid - 1) * SPRAID_PTCMDS_PERQ + cqe->cmd_id - SPRAID_IO_BLK_MQ_DEPTH;
@@ -1289,8 +1335,6 @@ static void spraid_complete_ioq_sync_cmnd(struct spraid_queue *ioq, struct sprai ptcmd->result1 = le32_to_cpu(cqe->result1);
complete(&ptcmd->cmd_done);
- spraid_put_ioq_ptcmd(hdev, ptcmd);
}
static inline void spraid_handle_cqe(struct spraid_queue *spraidq, u16 idx) @@ -1304,7 +1348,7 @@ static inline void spraid_handle_cqe(struct spraid_queue *spraidq, u16 idx) return; }
- dev_log_dbg(hdev->dev, "cid[%d], qid[%d], result[0x%x], sq_id[%d], status[0x%x]\n",
- dev_log_dbg(hdev->dev, "cid[%d] qid[%d], result[0x%x], sq_id[%d], status[0x%x]\n", cqe->cmd_id, spraidq->qid, le32_to_cpu(cqe->result), le16_to_cpu(cqe->sq_id), le16_to_cpu(cqe->status));
@@ -1452,62 +1496,119 @@ static u32 spraid_bar_size(struct spraid_dev *hdev, u32 nr_ioqs) return (SPRAID_REG_DBS + ((nr_ioqs + 1) * 8 * hdev->db_stride)); }
-static inline void spraid_clear_spraid_request(struct request *req) +static int spraid_alloc_admin_cmds(struct spraid_dev *hdev) {
- if (!(req->rq_flags & RQF_DONTPREP)) {
spraid_admin_req(req)->flags = 0;
req->rq_flags |= RQF_DONTPREP;
- int i;
- INIT_LIST_HEAD(&hdev->adm_cmd_list);
- spin_lock_init(&hdev->adm_cmd_lock);
- hdev->adm_cmds = kcalloc_node(SPRAID_AQ_BLK_MQ_DEPTH, sizeof(struct spraid_cmd),
GFP_KERNEL, hdev->numa_node);
- if (!hdev->adm_cmds) {
dev_err(hdev->dev, "Alloc admin cmds failed\n");
return -ENOMEM;
- }
- for (i = 0; i < SPRAID_AQ_BLK_MQ_DEPTH; i++) {
hdev->adm_cmds[i].qid = 0;
hdev->adm_cmds[i].cid = i;
}list_add_tail(&(hdev->adm_cmds[i].list), &hdev->adm_cmd_list);
- dev_info(hdev->dev, "Alloc admin cmds success, num[%d]\n", SPRAID_AQ_BLK_MQ_DEPTH);
- return 0;
}
-static struct request *spraid_alloc_admin_request(struct request_queue *q,
struct spraid_admin_command *cmd,
blk_mq_req_flags_t flags)
+static void spraid_free_admin_cmds(struct spraid_dev *hdev) {
- u32 op = COMMAND_IS_WRITE(cmd) ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN;
- struct request *req;
- kfree(hdev->adm_cmds);
- hdev->adm_cmds = NULL;
- INIT_LIST_HEAD(&hdev->adm_cmd_list);
+}
+static struct spraid_cmd *spraid_get_cmd(struct spraid_dev *hdev, enum spraid_cmd_type type) +{
- struct spraid_cmd *cmd = NULL;
- unsigned long flags;
- struct list_head *head = &hdev->adm_cmd_list;
- spinlock_t *slock = &hdev->adm_cmd_lock;
- if (type == SPRAID_CMD_IOPT) {
head = &hdev->ioq_pt_list;
slock = &hdev->ioq_pt_lock;
- }
- spin_lock_irqsave(slock, flags);
- if (list_empty(head)) {
spin_unlock_irqrestore(slock, flags);
dev_err(hdev->dev, "err, cmd[%d] list empty\n", type);
return NULL;
- }
- cmd = list_entry(head->next, struct spraid_cmd, list);
- list_del_init(&cmd->list);
- spin_unlock_irqrestore(slock, flags);
- req = blk_mq_alloc_request(q, op, flags);
- if (IS_ERR(req))
return req;
- req->cmd_flags |= REQ_FAILFAST_DRIVER;
- spraid_clear_spraid_request(req);
- spraid_admin_req(req)->cmd = cmd;
- WRITE_ONCE(cmd->state, SPRAID_CMD_IN_FLIGHT);
- return req;
- return cmd;
}
-static int spraid_submit_admin_sync_cmd(struct request_queue *q,
struct spraid_admin_command *cmd,
u32 *result, void *buffer,
- u32 bufflen, u32 timeout, int at_head, blk_mq_req_flags_t flags)
+static void spraid_put_cmd(struct spraid_dev *hdev, struct spraid_cmd *cmd,
enum spraid_cmd_type type)
{
- struct request *req;
- int ret;
- unsigned long flags;
- struct list_head *head = &hdev->adm_cmd_list;
- spinlock_t *slock = &hdev->adm_cmd_lock;
- req = spraid_alloc_admin_request(q, cmd, flags);
- if (IS_ERR(req))
return PTR_ERR(req);
- if (type == SPRAID_CMD_IOPT) {
head = &hdev->ioq_pt_list;
slock = &hdev->ioq_pt_lock;
- }
- req->timeout = timeout ? timeout : ADMIN_TIMEOUT;
- if (buffer && bufflen) {
ret = blk_rq_map_kern(q, req, buffer, bufflen, GFP_KERNEL);
if (ret)
goto out;
- spin_lock_irqsave(slock, flags);
- WRITE_ONCE(cmd->state, SPRAID_CMD_IDLE);
- list_add_tail(&cmd->list, head);
- spin_unlock_irqrestore(slock, flags);
+}
+static int spraid_submit_admin_sync_cmd(struct spraid_dev *hdev, struct spraid_admin_command *cmd,
u32 *result0, u32 *result1, u32 timeout)
+{
- struct spraid_cmd *adm_cmd = spraid_get_cmd(hdev, SPRAID_CMD_ADM);
- if (!adm_cmd) {
dev_err(hdev->dev, "err, get admin cmd failed\n");
}return -EFAULT;
blk_execute_rq(req->q, NULL, req, at_head);
if (result)
*result = spraid_admin_req(req)->result0;
- timeout = timeout ? timeout : ADMIN_TIMEOUT;
- if (spraid_admin_req(req)->flags & SPRAID_REQ_CANCELLED)
ret = -EINTR;
- else
ret = spraid_admin_req(req)->status;
- init_completion(&adm_cmd->cmd_done);
-out:
- blk_mq_free_request(req);
- return ret;
- cmd->common.command_id = adm_cmd->cid;
- spraid_submit_cmd(&hdev->queues[0], cmd);
- if (!wait_for_completion_timeout(&adm_cmd->cmd_done, timeout)) {
dev_err(hdev->dev, "[%s] cid[%d] qid[%d] timeout, opcode[0x%x] subopcode[0x%x]\n",
__func__, adm_cmd->cid, adm_cmd->qid, cmd->usr_cmd.opcode,
cmd->usr_cmd.info_0.subopcode);
WRITE_ONCE(adm_cmd->state, SPRAID_CMD_TIMEOUT);
spraid_put_cmd(hdev, adm_cmd, SPRAID_CMD_ADM);
return -ETIME;
- }
- if (result0)
*result0 = adm_cmd->result0;
- if (result1)
*result1 = adm_cmd->result1;
- spraid_put_cmd(hdev, adm_cmd, SPRAID_CMD_ADM);
- return adm_cmd->status;
}
static int spraid_create_cq(struct spraid_dev *hdev, u16 qid, @@ -1524,8 +1625,7 @@ static int spraid_create_cq(struct spraid_dev *hdev, u16 qid, admin_cmd.create_cq.cq_flags = cpu_to_le16(flags); admin_cmd.create_cq.irq_vector = cpu_to_le16(cq_vector);
- return spraid_submit_admin_sync_cmd(hdev->admin_q, &admin_cmd, NULL,
NULL, 0, 0, 0, 0);
- return spraid_submit_admin_sync_cmd(hdev, &admin_cmd, NULL, NULL, 0);
}
static int spraid_create_sq(struct spraid_dev *hdev, u16 qid, @@ -1542,8 +1642,7 @@ static int spraid_create_sq(struct spraid_dev *hdev, u16 qid, admin_cmd.create_sq.sq_flags = cpu_to_le16(flags); admin_cmd.create_sq.cqid = cpu_to_le16(qid);
- return spraid_submit_admin_sync_cmd(hdev->admin_q, &admin_cmd, NULL,
NULL, 0, 0, 0, 0);
- return spraid_submit_admin_sync_cmd(hdev, &admin_cmd, NULL, NULL, 0);
}
static void spraid_free_queue(struct spraid_queue *spraidq) @@ -1581,8 +1680,7 @@ static int spraid_delete_queue(struct spraid_dev *hdev, u8 op, u16 id) admin_cmd.delete_queue.opcode = op; admin_cmd.delete_queue.qid = cpu_to_le16(id);
- ret = spraid_submit_admin_sync_cmd(hdev->admin_q, &admin_cmd, NULL,
NULL, 0, 0, 0, 0);
ret = spraid_submit_admin_sync_cmd(hdev, &admin_cmd, NULL, NULL, 0);
if (ret) dev_err(hdev->dev, "Delete %s:[%d] failed\n",
@@ -1663,19 +1761,28 @@ static int spraid_set_features(struct spraid_dev *hdev, u32 fid, u32 dword11, vo size_t buflen, u32 *result) { struct spraid_admin_command admin_cmd;
- u32 res; int ret;
u8 *data_ptr = NULL;
dma_addr_t data_dma = 0;
if (buffer && buflen) {
data_ptr = dma_alloc_coherent(hdev->dev, buflen, &data_dma, GFP_KERNEL);
if (!data_ptr)
return -ENOMEM;
memcpy(data_ptr, buffer, buflen);
}
memset(&admin_cmd, 0, sizeof(admin_cmd)); admin_cmd.features.opcode = SPRAID_ADMIN_SET_FEATURES; admin_cmd.features.fid = cpu_to_le32(fid); admin_cmd.features.dword11 = cpu_to_le32(dword11);
admin_cmd.common.dptr.prp1 = cpu_to_le64(data_dma);
- ret = spraid_submit_admin_sync_cmd(hdev->admin_q, &admin_cmd, &res,
buffer, buflen, 0, 0, 0);
- ret = spraid_submit_admin_sync_cmd(hdev, &admin_cmd, result, NULL, 0);
- if (!ret && result)
*result = res;
if (data_ptr)
dma_free_coherent(hdev->dev, buflen, data_ptr, data_dma);
return ret;
} @@ -1764,8 +1871,7 @@ static int spraid_setup_io_queues(struct spraid_dev *hdev) break; } dev_info(hdev->dev, "[%s] max_qid: %d, queue_count: %d, online_queue: %d, ioq_depth: %d\n",
__func__, hdev->max_qid, hdev->queue_count,
- hdev->online_queues, hdev->ioq_depth);
__func__, hdev->max_qid, hdev->queue_count, hdev->online_queues, hdev->ioq_depth);
return spraid_create_io_queues(hdev);
} @@ -1889,10 +1995,11 @@ static int spraid_get_dev_list(struct spraid_dev *hdev, struct spraid_dev_info * u32 nd = le32_to_cpu(hdev->ctrl_info->nd); struct spraid_admin_command admin_cmd; struct spraid_dev_list *list_buf;
- dma_addr_t data_dma = 0; u32 i, idx, hdid, ndev; int ret = 0;
- list_buf = kmalloc(sizeof(*list_buf), GFP_KERNEL);
- list_buf = dma_alloc_coherent(hdev->dev, PAGE_SIZE, &data_dma, GFP_KERNEL); if (!list_buf) return -ENOMEM;
@@ -1901,9 +2008,9 @@ static int spraid_get_dev_list(struct spraid_dev *hdev, struct spraid_dev_info * admin_cmd.get_info.opcode = SPRAID_ADMIN_GET_INFO; admin_cmd.get_info.type = SPRAID_GET_INFO_DEV_LIST; admin_cmd.get_info.cdw11 = cpu_to_le32(idx);
admin_cmd.common.dptr.prp1 = cpu_to_le64(data_dma);
ret = spraid_submit_admin_sync_cmd(hdev->admin_q, &admin_cmd, NULL, list_buf,
sizeof(*list_buf), 0, 0, 0);
ret = spraid_submit_admin_sync_cmd(hdev, &admin_cmd, NULL, NULL, 0);
if (ret) { dev_err(hdev->dev, "Get device list failed, nd: %u, idx: %u, ret: %d\n",
@@ -1916,12 +2023,11 @@ static int spraid_get_dev_list(struct spraid_dev *hdev, struct spraid_dev_info *
for (i = 0; i < ndev; i++) { hdid = le32_to_cpu(list_buf->devices[i].hdid);
dev_info(hdev->dev, "list_buf->devices[%d], hdid: %u target: %d, channel: %d, lun: %d, attr[%x]\n",
i, hdid,
le16_to_cpu(list_buf->devices[i].target),
list_buf->devices[i].channel,
list_buf->devices[i].lun,
list_buf->devices[i].attr);
dev_info(hdev->dev, "list_buf->devices[%d], hdid: %u target: %d, channel: %d, lun: %d, attr[0x%x]\n",
i, hdid, le16_to_cpu(list_buf->devices[i].target),
list_buf->devices[i].channel,
list_buf->devices[i].lun,
list_buf->devices[i].attr); if (hdid > nd || hdid == 0) { dev_err(hdev->dev, "err, hdid[%d] invalid\n", hdid); continue;
@@ -1936,21 +2042,29 @@ static int spraid_get_dev_list(struct spraid_dev *hdev, struct spraid_dev_info * }
out:
- kfree(list_buf);
- dma_free_coherent(hdev->dev, PAGE_SIZE, list_buf, data_dma); return ret;
}
-static void spraid_send_aen(struct spraid_dev *hdev) +static void spraid_send_aen(struct spraid_dev *hdev, u16 cid) { struct spraid_queue *adminq = &hdev->queues[0]; struct spraid_admin_command admin_cmd;
memset(&admin_cmd, 0, sizeof(admin_cmd)); admin_cmd.common.opcode = SPRAID_ADMIN_ASYNC_EVENT;
- admin_cmd.common.command_id = SPRAID_AQ_BLK_MQ_DEPTH;
admin_cmd.common.command_id = cid;
spraid_submit_cmd(adminq, &admin_cmd);
- dev_info(hdev->dev, "send aen, cid[%d]\n", SPRAID_AQ_BLK_MQ_DEPTH);
- dev_info(hdev->dev, "send aen, cid[%d]\n", cid);
+}
+static inline void spraid_send_all_aen(struct spraid_dev *hdev) +{
- u16 i;
- for (i = 0; i < hdev->ctrl_info->aerl; i++)
spraid_send_aen(hdev, i + SPRAID_AQ_BLK_MQ_DEPTH);
}
static int spraid_add_device(struct spraid_dev *hdev, struct spraid_dev_info *device) @@ -1958,6 +2072,10 @@ static int spraid_add_device(struct spraid_dev *hdev, struct spraid_dev_info *de struct Scsi_Host *shost = hdev->shost; struct scsi_device *sdev;
- dev_info(hdev->dev, "add device, hdid: %u target: %d, channel: %d, lun: %d, attr[0x%x]\n",
le32_to_cpu(device->hdid), le16_to_cpu(device->target),
device->channel, device->lun, device->attr);
- sdev = scsi_device_lookup(shost, device->channel, le16_to_cpu(device->target), 0); if (sdev) { dev_warn(hdev->dev, "Device is already exist, channel: %d, target_id: %d, lun: %d\n",
@@ -1974,9 +2092,13 @@ static int spraid_rescan_device(struct spraid_dev *hdev, struct spraid_dev_info struct Scsi_Host *shost = hdev->shost; struct scsi_device *sdev;
- dev_info(hdev->dev, "rescan device, hdid: %u target: %d, channel: %d, lun: %d, attr[0x%x]\n",
le32_to_cpu(device->hdid), le16_to_cpu(device->target),
device->channel, device->lun, device->attr);
- sdev = scsi_device_lookup(shost, device->channel, le16_to_cpu(device->target), 0); if (!sdev) {
dev_warn(hdev->dev, "Device is not exit, channel: %d, target_id: %d, lun: %d\n",
return -ENODEV; }dev_warn(hdev->dev, "device is not exit rescan it, channel: %d, target_id: %d, lun: %d\n", device->channel, le16_to_cpu(device->target), 0);
@@ -1991,9 +2113,13 @@ static int spraid_remove_device(struct spraid_dev *hdev, struct spraid_dev_info struct Scsi_Host *shost = hdev->shost; struct scsi_device *sdev;
- dev_info(hdev->dev, "remove device, hdid: %u target: %d, channel: %d, lun: %d, attr[0x%x]\n",
le32_to_cpu(org_device->hdid), le16_to_cpu(org_device->target),
org_device->channel, org_device->lun, org_device->attr);
- sdev = scsi_device_lookup(shost, org_device->channel, le16_to_cpu(org_device->target), 0); if (!sdev) {
dev_warn(hdev->dev, "Device is not exit, channel: %d, target_id: %d, lun: %d\n",
return -ENODEV; }dev_warn(hdev->dev, "device is not exit remove it, channel: %d, target_id: %d, lun: %d\n", org_device->channel, le16_to_cpu(org_device->target), 0);
@@ -2029,36 +2155,54 @@ static int spraid_dev_list_init(struct spraid_dev *hdev) return 0; }
+static int luntarget_cmp_func(const void *l, const void *r) +{
- const struct spraid_dev_info *ln = l;
- const struct spraid_dev_info *rn = r;
- if (ln->channel == rn->channel)
return le16_to_cpu(ln->target) - le16_to_cpu(rn->target);
- return ln->channel - rn->channel;
+}
static void spraid_scan_work(struct work_struct *work) { struct spraid_dev *hdev = container_of(work, struct spraid_dev, scan_work); struct spraid_dev_info *devices, *org_devices;
struct spraid_dev_info *sortdevice; u32 nd = le32_to_cpu(hdev->ctrl_info->nd); u8 flag, org_flag; int i, ret;
int count = 0;
devices = kcalloc(nd, sizeof(struct spraid_dev_info), GFP_KERNEL); if (!devices) return;
sortdevice = kcalloc(nd, sizeof(struct spraid_dev_info), GFP_KERNEL);
if (!sortdevice)
goto free_list;
ret = spraid_get_dev_list(hdev, devices); if (ret)
goto free_list;
org_devices = hdev->devices; for (i = 0; i < nd; i++) { org_flag = org_devices[i].flag; flag = devices[i].flag;goto free_all;
dev_log_dbg(hdev->dev, "i: %d, org_flag: 0x%x, flag: 0x%x\n",
i, org_flag, flag);
dev_log_dbg(hdev->dev, "i: %d, org_flag: 0x%x, flag: 0x%x\n", i, org_flag, flag);
if (SPRAID_DEV_INFO_FLAG_VALID(flag)) { if (!SPRAID_DEV_INFO_FLAG_VALID(org_flag)) { down_write(&hdev->devices_rwsem); memcpy(&org_devices[i], &devices[i],
sizeof(struct spraid_dev_info));
sizeof(struct spraid_dev_info));
memcpy(&sortdevice[count++], &devices[i],
sizeof(struct spraid_dev_info)); up_write(&hdev->devices_rwsem);
spraid_add_device(hdev, &devices[i]); } else if (SPRAID_DEV_INFO_FLAG_CHANGE(flag)) { spraid_rescan_device(hdev, &devices[i]); }
@@ -2071,6 +2215,16 @@ static void spraid_scan_work(struct work_struct *work) } } }
- dev_info(hdev->dev, "scan work add device count = %d\n", count);
- sort(sortdevice, count, sizeof(sortdevice[0]), luntarget_cmp_func, NULL);
- for (i = 0; i < count; i++)
spraid_add_device(hdev, &sortdevice[i]);
+free_all:
- kfree(sortdevice);
free_list: kfree(devices); } @@ -2083,6 +2237,15 @@ static void spraid_timesyn_work(struct work_struct *work) spraid_configure_timestamp(hdev); }
+static int spraid_init_ctrl_info(struct spraid_dev *hdev); +static void spraid_fw_act_work(struct work_struct *work) +{
- struct spraid_dev *hdev = container_of(work, struct spraid_dev, fw_act_work);
- if (spraid_init_ctrl_info(hdev))
dev_err(hdev->dev, "get ctrl info failed after fw act\n");
+}
static void spraid_queue_scan(struct spraid_dev *hdev) { queue_work(spraid_wq, &hdev->scan_work); @@ -2094,6 +2257,9 @@ static void spraid_handle_aen_notice(struct spraid_dev *hdev, u32 result) case SPRAID_AEN_DEV_CHANGED: spraid_queue_scan(hdev); break;
- case SPRAID_AEN_FW_ACT_START:
dev_info(hdev->dev, "fw activation starting\n");
case SPRAID_AEN_HOST_PROBING: break; default:break;
@@ -2101,25 +2267,25 @@ static void spraid_handle_aen_notice(struct spraid_dev *hdev, u32 result) } }
-static void spraid_handle_aen_vs(struct spraid_dev *hdev, u32 result) +static void spraid_handle_aen_vs(struct spraid_dev *hdev, u32 result, u32 result1) {
- switch (result) {
- switch ((result & 0xff00) >> 8) { case SPRAID_AEN_TIMESYN: queue_work(spraid_wq, &hdev->timesyn_work); break;
- case SPRAID_AEN_FW_ACT_FINISH:
dev_info(hdev->dev, "fw activation finish\n");
queue_work(spraid_wq, &hdev->fw_act_work);
break;
- case SPRAID_AEN_EVENT_MIN ... SPRAID_AEN_EVENT_MAX:
dev_info(hdev->dev, "rcv card event[%d], param1[0x%x] param2[0x%x]\n",
(result & 0xff00) >> 8, result, result1);
default:break;
dev_warn(hdev->dev, "async event result: %x\n", result);
}dev_warn(hdev->dev, "async event result: 0x%x\n", result);
}
-static void spraid_async_event_work(struct work_struct *work) -{
- struct spraid_dev *hdev =
container_of(work, struct spraid_dev, aen_work);
- spraid_send_aen(hdev);
-}
static int spraid_alloc_resources(struct spraid_dev *hdev) { int ret, nqueue; @@ -2149,10 +2315,16 @@ static int spraid_alloc_resources(struct spraid_dev *hdev) goto destroy_dma_pools; }
ret = spraid_alloc_admin_cmds(hdev);
if (ret)
goto free_queues;
dev_info(hdev->dev, "[%s] queues num: %d\n", __func__, nqueue);
return 0;
+free_queues:
- kfree(hdev->queues);
destroy_dma_pools: spraid_destroy_dma_pools(hdev); free_ctrl_info: @@ -2164,50 +2336,18 @@ static int spraid_alloc_resources(struct spraid_dev *hdev)
static void spraid_free_resources(struct spraid_dev *hdev) {
- spraid_free_admin_cmds(hdev); kfree(hdev->queues); spraid_destroy_dma_pools(hdev); kfree(hdev->ctrl_info); ida_free(&spraid_instance_ida, hdev->instance);
}
-static void spraid_setup_passthrough(struct request *req, struct spraid_admin_command *cmd) -{
- memcpy(cmd, spraid_admin_req(req)->cmd, sizeof(*cmd));
- cmd->common.flags &= ~SPRAID_CMD_FLAG_SGL_ALL;
-}
-static inline void spraid_clear_hreq(struct request *req) -{
- if (!(req->rq_flags & RQF_DONTPREP)) {
spraid_admin_req(req)->flags = 0;
req->rq_flags |= RQF_DONTPREP;
- }
-}
-static blk_status_t spraid_setup_admin_cmd(struct request *req, struct spraid_admin_command *cmd) +static void spraid_bsg_unmap_data(struct spraid_dev *hdev, struct bsg_job *job) {
- spraid_clear_hreq(req);
- memset(cmd, 0, sizeof(*cmd));
- switch (req_op(req)) {
- case REQ_OP_DRV_IN:
- case REQ_OP_DRV_OUT:
spraid_setup_passthrough(req, cmd);
break;
- default:
WARN_ON_ONCE(1);
return BLK_STS_IOERR;
- }
- cmd->common.command_id = req->tag;
- return BLK_STS_OK;
-}
-static void spraid_unmap_data(struct spraid_dev *hdev, struct request *req) -{
- struct spraid_iod *iod = blk_mq_rq_to_pdu(req);
- enum dma_data_direction dma_dir = rq_data_dir(req) ?
DMA_TO_DEVICE : DMA_FROM_DEVICE;
struct request *rq = blk_mq_rq_from_pdu(job);
struct spraid_iod *iod = job->dd_data;
enum dma_data_direction dma_dir = rq_data_dir(rq) ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
if (iod->nsge) dma_unmap_sg(hdev->dev, iod->sg, iod->nsge, dma_dir);
@@ -2215,36 +2355,36 @@ static void spraid_unmap_data(struct spraid_dev *hdev, struct request *req) spraid_free_iod_res(hdev, iod); }
-static blk_status_t spraid_admin_map_data(struct spraid_dev *hdev, struct request *req,
struct spraid_admin_command *cmd)
+static int spraid_bsg_map_data(struct spraid_dev *hdev, struct bsg_job *job,
struct spraid_admin_command *cmd)
{
- struct spraid_iod *iod = blk_mq_rq_to_pdu(req);
- struct request_queue *admin_q = req->q;
- enum dma_data_direction dma_dir = rq_data_dir(req) ?
DMA_TO_DEVICE : DMA_FROM_DEVICE;
- blk_status_t ret = BLK_STS_IOERR;
- int nr_mapped;
- int res;
- struct request *rq = blk_mq_rq_from_pdu(job);
- struct spraid_iod *iod = job->dd_data;
- enum dma_data_direction dma_dir = rq_data_dir(rq) ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
- int ret = 0;
- iod->sg = job->request_payload.sg_list;
- iod->nsge = job->request_payload.sg_cnt;
- iod->length = job->request_payload.payload_len;
- iod->use_sgl = false;
- iod->npages = -1;
- iod->sg_drv_mgmt = false;
sg_init_table(iod->sg, blk_rq_nr_phys_segments(req));
iod->nsge = blk_rq_map_sg(admin_q, req, iod->sg); if (!iod->nsge) goto out;
dev_info(hdev->dev, "nseg: %u, nsge: %u\n",
blk_rq_nr_phys_segments(req), iod->nsge);
ret = BLK_STS_RESOURCE;
nr_mapped = dma_map_sg_attrs(hdev->dev, iod->sg, iod->nsge, dma_dir, DMA_ATTR_NO_WARN);
if (!nr_mapped)
- ret = dma_map_sg_attrs(hdev->dev, iod->sg, iod->nsge, dma_dir, DMA_ATTR_NO_WARN);
- if (!ret) goto out;
- res = spraid_setup_prps(hdev, iod);
- if (res)
- ret = spraid_setup_prps(hdev, iod);
- if (ret) goto unmap;
- cmd->common.dptr.prp1 = cpu_to_le64(sg_dma_address(iod->sg)); cmd->common.dptr.prp2 = cpu_to_le64(iod->first_dma);
- return BLK_STS_OK;
- return 0;
unmap: dma_unmap_sg(hdev->dev, iod->sg, iod->nsge, dma_dir); @@ -2252,137 +2392,29 @@ static blk_status_t spraid_admin_map_data(struct spraid_dev *hdev, struct reques return ret; }
-static blk_status_t spraid_init_admin_iod(struct request *rq, struct spraid_dev *hdev) -{
- struct spraid_iod *iod = blk_mq_rq_to_pdu(rq);
- int nents = blk_rq_nr_phys_segments(rq);
- unsigned int size = blk_rq_payload_bytes(rq);
- if (nents > SPRAID_INT_PAGES || size > SPRAID_INT_BYTES(hdev)) {
iod->sg = mempool_alloc(hdev->iod_mempool, GFP_ATOMIC);
if (!iod->sg)
return BLK_STS_RESOURCE;
- } else {
iod->sg = iod->inline_sg;
- }
- iod->nsge = 0;
- iod->use_sgl = false;
- iod->npages = -1;
- iod->length = size;
- iod->sg_drv_mgmt = true;
- return BLK_STS_OK;
-}
-static blk_status_t spraid_queue_admin_rq(struct blk_mq_hw_ctx *hctx,
const struct blk_mq_queue_data *bd)
-{
- struct spraid_queue *adminq = hctx->driver_data;
- struct spraid_dev *hdev = adminq->hdev;
- struct request *req = bd->rq;
- struct spraid_iod *iod = blk_mq_rq_to_pdu(req);
- struct spraid_admin_command cmd;
- blk_status_t ret;
- ret = spraid_setup_admin_cmd(req, &cmd);
- if (ret)
goto out;
- ret = spraid_init_admin_iod(req, hdev);
- if (ret)
goto out;
- if (blk_rq_nr_phys_segments(req)) {
ret = spraid_admin_map_data(hdev, req, &cmd);
if (ret)
goto cleanup_iod;
- }
- blk_mq_start_request(req);
- spraid_submit_cmd(adminq, &cmd);
- return BLK_STS_OK;
-cleanup_iod:
- spraid_free_iod_res(hdev, iod);
-out:
- return ret;
-}
-static blk_status_t spraid_error_status(struct request *req) -{
- switch (spraid_admin_req(req)->status & 0x7ff) {
- case SPRAID_SC_SUCCESS:
return BLK_STS_OK;
- default:
return BLK_STS_IOERR;
- }
-}
-static void spraid_complete_admin_rq(struct request *req) -{
- struct spraid_iod *iod = blk_mq_rq_to_pdu(req);
- struct spraid_dev *hdev = iod->spraidq->hdev;
- if (blk_rq_nr_phys_segments(req))
spraid_unmap_data(hdev, req);
- blk_mq_end_request(req, spraid_error_status(req));
-}
-static int spraid_admin_init_hctx(struct blk_mq_hw_ctx *hctx, void *data, unsigned int hctx_idx) -{
- struct spraid_dev *hdev = data;
- struct spraid_queue *adminq = &hdev->queues[0];
- WARN_ON(hctx_idx != 0);
- WARN_ON(hdev->admin_tagset.tags[0] != hctx->tags);
- hctx->driver_data = adminq;
- return 0;
-}
-static int spraid_admin_init_request(struct blk_mq_tag_set *set, struct request *req,
unsigned int hctx_idx, unsigned int numa_node)
-{
- struct spraid_dev *hdev = set->driver_data;
- struct spraid_iod *iod = blk_mq_rq_to_pdu(req);
- struct spraid_queue *adminq = &hdev->queues[0];
- WARN_ON(!adminq);
- iod->spraidq = adminq;
- return 0;
-}
-static enum blk_eh_timer_return -spraid_admin_timeout(struct request *req, bool reserved) -{
- struct spraid_iod *iod = blk_mq_rq_to_pdu(req);
- struct spraid_queue *spraidq = iod->spraidq;
- struct spraid_dev *hdev = spraidq->hdev;
- dev_err(hdev->dev, "Admin cid[%d] qid[%d] timeout\n",
req->tag, spraidq->qid);
- if (spraid_poll_cq(spraidq, req->tag)) {
dev_warn(hdev->dev, "cid[%d] qid[%d] timeout, completion polled\n",
req->tag, spraidq->qid);
return BLK_EH_DONE;
- }
- spraid_end_admin_request(req, cpu_to_le16(-EINVAL), 0, 0);
- return BLK_EH_DONE;
-}
static int spraid_get_ctrl_info(struct spraid_dev *hdev, struct spraid_ctrl_info *ctrl_info) { struct spraid_admin_command admin_cmd;
u8 *data_ptr = NULL;
dma_addr_t data_dma = 0;
int ret;
data_ptr = dma_alloc_coherent(hdev->dev, PAGE_SIZE, &data_dma, GFP_KERNEL);
if (!data_ptr)
return -ENOMEM;
memset(&admin_cmd, 0, sizeof(admin_cmd)); admin_cmd.get_info.opcode = SPRAID_ADMIN_GET_INFO; admin_cmd.get_info.type = SPRAID_GET_INFO_CTRL;
admin_cmd.common.dptr.prp1 = cpu_to_le64(data_dma);
ret = spraid_submit_admin_sync_cmd(hdev, &admin_cmd, NULL, NULL, 0);
if (!ret)
memcpy(ctrl_info, data_ptr, sizeof(struct spraid_ctrl_info));
- return spraid_submit_admin_sync_cmd(hdev->admin_q, &admin_cmd, NULL,
ctrl_info, sizeof(struct spraid_ctrl_info), 0, 0, 0);
- dma_free_coherent(hdev->dev, PAGE_SIZE, data_ptr, data_dma);
- return ret;
}
static int spraid_init_ctrl_info(struct spraid_dev *hdev) @@ -2416,6 +2448,11 @@ static int spraid_init_ctrl_info(struct spraid_dev *hdev) dev_info(hdev->dev, "[%s]sn = %s\n", __func__, hdev->ctrl_info->sn); dev_info(hdev->dev, "[%s]fr = %s\n", __func__, hdev->ctrl_info->fr);
- if (!hdev->ctrl_info->aerl)
hdev->ctrl_info->aerl = 1;
- if (hdev->ctrl_info->aerl > SPRAID_NR_AEN_COMMANDS)
hdev->ctrl_info->aerl = SPRAID_NR_AEN_COMMANDS;
- return 0;
}
@@ -2444,98 +2481,51 @@ static void spraid_free_iod_ext_mem_pool(struct spraid_dev *hdev) mempool_destroy(hdev->iod_mempool); }
-static int spraid_submit_user_cmd(struct request_queue *q, struct spraid_admin_command *cmd,
void __user *ubuffer, unsigned int bufflen, u32 *result,
unsigned int timeout)
+static int spraid_user_admin_cmd(struct spraid_dev *hdev, struct bsg_job *job) {
- struct request *req;
- struct bio *bio = NULL;
- int ret;
- req = spraid_alloc_admin_request(q, cmd, 0);
- if (IS_ERR(req))
return PTR_ERR(req);
- struct spraid_bsg_request *bsg_req = job->request;
- struct spraid_passthru_common_cmd *cmd = &(bsg_req->admcmd);
- struct spraid_admin_command admin_cmd;
- u32 timeout = msecs_to_jiffies(cmd->timeout_ms);
- u32 result[2] = {0};
- int status;
- req->timeout = timeout ? timeout : ADMIN_TIMEOUT;
- spraid_admin_req(req)->flags |= SPRAID_REQ_USERCMD;
- if (hdev->state >= SPRAID_RESETTING) {
dev_err(hdev->dev, "[%s] err, host state:[%d] is not right\n",
__func__, hdev->state);
return -EBUSY;
- }
- if (ubuffer && bufflen) {
ret = blk_rq_map_user(q, req, NULL, ubuffer, bufflen, GFP_KERNEL);
if (ret)
goto out;
bio = req->bio;
- memset(&admin_cmd, 0, sizeof(admin_cmd));
- admin_cmd.common.opcode = cmd->opcode;
- admin_cmd.common.flags = cmd->flags;
- admin_cmd.common.hdid = cpu_to_le32(cmd->nsid);
- admin_cmd.common.cdw2[0] = cpu_to_le32(cmd->cdw2);
- admin_cmd.common.cdw2[1] = cpu_to_le32(cmd->cdw3);
- admin_cmd.common.cdw10 = cpu_to_le32(cmd->cdw10);
- admin_cmd.common.cdw11 = cpu_to_le32(cmd->cdw11);
- admin_cmd.common.cdw12 = cpu_to_le32(cmd->cdw12);
- admin_cmd.common.cdw13 = cpu_to_le32(cmd->cdw13);
- admin_cmd.common.cdw14 = cpu_to_le32(cmd->cdw14);
- admin_cmd.common.cdw15 = cpu_to_le32(cmd->cdw15);
- status = spraid_bsg_map_data(hdev, job, &admin_cmd);
- if (status) {
dev_err(hdev->dev, "[%s] err, map data failed\n", __func__);
}return status;
- blk_execute_rq(req->q, NULL, req, 0);
- if (spraid_admin_req(req)->flags & SPRAID_REQ_CANCELLED)
ret = -EINTR;
- else
ret = spraid_admin_req(req)->status;
- if (result) {
result[0] = spraid_admin_req(req)->result0;
result[1] = spraid_admin_req(req)->result1;
- }
- if (bio)
blk_rq_unmap_user(bio);
-out:
- blk_mq_free_request(req);
- return ret;
-}
-static int spraid_user_admin_cmd(struct spraid_dev *hdev,
struct spraid_passthru_common_cmd __user *ucmd)
-{
- struct spraid_passthru_common_cmd cmd;
- struct spraid_admin_command admin_cmd;
- u32 timeout = 0;
- int status;
- if (!capable(CAP_SYS_ADMIN)) {
dev_err(hdev->dev, "Current user hasn't administrator right, reject service\n");
return -EACCES;
- }
- if (copy_from_user(&cmd, ucmd, sizeof(cmd))) {
dev_err(hdev->dev, "Copy command from user space to kernel space failed\n");
return -EFAULT;
- }
- if (cmd.flags) {
dev_err(hdev->dev, "Invalid flags in user command\n");
return -EINVAL;
- status = spraid_submit_admin_sync_cmd(hdev, &admin_cmd, &result[0], &result[1], timeout);
- if (status >= 0) {
job->reply_len = sizeof(result);
}memcpy(job->reply, result, sizeof(result));
- dev_info(hdev->dev, "user_admin_cmd opcode: 0x%x, subopcode: 0x%x\n",
cmd.opcode, cmd.cdw2 & 0x7ff);
- if (status)
dev_info(hdev->dev, "[%s] opcode[0x%x] subopcode[0x%x], status[0x%x] result0[0x%x] result1[0x%x]\n",
__func__, cmd->opcode, cmd->info_0.subopcode, status, result[0], result[1]);
- memset(&admin_cmd, 0, sizeof(admin_cmd));
- admin_cmd.common.opcode = cmd.opcode;
- admin_cmd.common.flags = cmd.flags;
- admin_cmd.common.hdid = cpu_to_le32(cmd.nsid);
- admin_cmd.common.cdw2[0] = cpu_to_le32(cmd.cdw2);
- admin_cmd.common.cdw2[1] = cpu_to_le32(cmd.cdw3);
- admin_cmd.common.cdw10 = cpu_to_le32(cmd.cdw10);
- admin_cmd.common.cdw11 = cpu_to_le32(cmd.cdw11);
- admin_cmd.common.cdw12 = cpu_to_le32(cmd.cdw12);
- admin_cmd.common.cdw13 = cpu_to_le32(cmd.cdw13);
- admin_cmd.common.cdw14 = cpu_to_le32(cmd.cdw14);
- admin_cmd.common.cdw15 = cpu_to_le32(cmd.cdw15);
- if (cmd.timeout_ms)
timeout = msecs_to_jiffies(cmd.timeout_ms);
- status = spraid_submit_user_cmd(hdev->admin_q, &admin_cmd,
(void __user *)(uintptr_t)cmd.addr, cmd.info_1.data_len,
&cmd.result0, timeout);
- dev_info(hdev->dev, "user_admin_cmd status: 0x%x, result0: 0x%x, result1: 0x%x\n",
status, cmd.result0, cmd.result1);
- if (status >= 0) {
if (put_user(cmd.result0, &ucmd->result0))
return -EFAULT;
if (put_user(cmd.result1, &ucmd->result1))
return -EFAULT;
- }
spraid_bsg_unmap_data(hdev, job);
return status;
} @@ -2548,8 +2538,8 @@ static int spraid_alloc_ioq_ptcmds(struct spraid_dev *hdev) INIT_LIST_HEAD(&hdev->ioq_pt_list); spin_lock_init(&hdev->ioq_pt_lock);
- hdev->ioq_ptcmds = kcalloc_node(ptnum, sizeof(struct spraid_ioq_ptcmd),
GFP_KERNEL, hdev->numa_node);
hdev->ioq_ptcmds = kcalloc_node(ptnum, sizeof(struct spraid_cmd),
GFP_KERNEL, hdev->numa_node);
if (!hdev->ioq_ptcmds) { dev_err(hdev->dev, "Alloc ioq_ptcmds failed\n");
@@ -2567,55 +2557,35 @@ static int spraid_alloc_ioq_ptcmds(struct spraid_dev *hdev) return 0; }
-static struct spraid_ioq_ptcmd *spraid_get_ioq_ptcmd(struct spraid_dev *hdev) -{
- struct spraid_ioq_ptcmd *cmd = NULL;
- unsigned long flags;
- spin_lock_irqsave(&hdev->ioq_pt_lock, flags);
- if (list_empty(&hdev->ioq_pt_list)) {
spin_unlock_irqrestore(&hdev->ioq_pt_lock, flags);
dev_err(hdev->dev, "err, ioq ptcmd list empty\n");
return NULL;
- }
- cmd = list_entry((&hdev->ioq_pt_list)->next, struct spraid_ioq_ptcmd, list);
- list_del_init(&cmd->list);
- spin_unlock_irqrestore(&hdev->ioq_pt_lock, flags);
- WRITE_ONCE(cmd->state, SPRAID_CMD_IDLE);
- return cmd;
-}
-static void spraid_put_ioq_ptcmd(struct spraid_dev *hdev, struct spraid_ioq_ptcmd *cmd) +static void spraid_free_ioq_ptcmds(struct spraid_dev *hdev) {
- unsigned long flags;
- kfree(hdev->ioq_ptcmds);
- hdev->ioq_ptcmds = NULL;
- spin_lock_irqsave(&hdev->ioq_pt_lock, flags);
- list_add(&cmd->list, (&hdev->ioq_pt_list)->next);
- spin_unlock_irqrestore(&hdev->ioq_pt_lock, flags);
- INIT_LIST_HEAD(&hdev->ioq_pt_list);
}
static int spraid_submit_ioq_sync_cmd(struct spraid_dev *hdev, struct spraid_ioq_command *cmd,
u32 *result, void **sense, u32 timeout)
u32 *result, u32 *reslen, u32 timeout)
{
- struct spraid_queue *ioq; int ret; dma_addr_t sense_dma;
- struct spraid_ioq_ptcmd *pt_cmd = spraid_get_ioq_ptcmd(hdev);
- *sense = NULL;
- struct spraid_queue *ioq;
- void *sense_addr = NULL;
- struct spraid_cmd *pt_cmd = spraid_get_cmd(hdev, SPRAID_CMD_IOPT);
- if (!pt_cmd)
- if (!pt_cmd) {
return -EFAULT;dev_err(hdev->dev, "err, get ioq cmd failed\n");
- }
- dev_info(hdev->dev, "[%s] ptcmd, cid[%d], qid[%d]\n", __func__, pt_cmd->cid, pt_cmd->qid);
timeout = timeout ? timeout : ADMIN_TIMEOUT;
init_completion(&pt_cmd->cmd_done);
ioq = &hdev->queues[pt_cmd->qid]; ret = pt_cmd->cid * SCSI_SENSE_BUFFERSIZE;
- pt_cmd->priv = ioq->sense + ret;
sense_addr = ioq->sense + ret; sense_dma = ioq->sense_dma_addr + ret;
cmd->common.sense_addr = cpu_to_le64(sense_dma);
@@ -2625,260 +2595,87 @@ static int spraid_submit_ioq_sync_cmd(struct spraid_dev *hdev, struct spraid_ioq spraid_submit_cmd(ioq, cmd);
if (!wait_for_completion_timeout(&pt_cmd->cmd_done, timeout)) {
dev_err(hdev->dev, "[%s] cid[%d], qid[%d] timeout\n",
__func__, pt_cmd->cid, pt_cmd->qid);
dev_err(hdev->dev, "[%s] cid[%d] qid[%d] timeout, opcode[0x%x] subopcode[0x%x]\n",
__func__, pt_cmd->cid, pt_cmd->qid, cmd->common.opcode,
WRITE_ONCE(pt_cmd->state, SPRAID_CMD_TIMEOUT);(le32_to_cpu(cmd->common.cdw3[0]) & 0xffff));
return -EINVAL;
spraid_put_cmd(hdev, pt_cmd, SPRAID_CMD_IOPT);
}return -ETIME;
- if (result) {
result[0] = pt_cmd->result0;
result[1] = pt_cmd->result1;
- if (result && reslen) {
if ((pt_cmd->status & 0x17f) == 0x101) {
memcpy(result, sense_addr, SCSI_SENSE_BUFFERSIZE);
*reslen = SCSI_SENSE_BUFFERSIZE;
}}
- if ((pt_cmd->status & 0x17f) == 0x101)
*sense = pt_cmd->priv;
spraid_put_cmd(hdev, pt_cmd, SPRAID_CMD_IOPT);
return pt_cmd->status;
}
-static int spraid_user_ioq_cmd(struct spraid_dev *hdev,
struct spraid_ioq_passthru_cmd __user *ucmd)
+static int spraid_user_ioq_cmd(struct spraid_dev *hdev, struct bsg_job *job) {
- struct spraid_ioq_passthru_cmd cmd;
- struct spraid_bsg_request *bsg_req = (struct spraid_bsg_request *)(job->request);
- struct spraid_ioq_passthru_cmd *cmd = &(bsg_req->ioqcmd); struct spraid_ioq_command ioq_cmd;
- u32 timeout = 0; int status = 0;
- u8 *data_ptr = NULL;
- dma_addr_t data_dma;
- enum dma_data_direction dma_dir = DMA_NONE;
- void *sense = NULL;
- if (!capable(CAP_SYS_ADMIN)) {
dev_err(hdev->dev, "Current user hasn't administrator right, reject service\n");
return -EACCES;
- }
- u32 timeout = msecs_to_jiffies(cmd->timeout_ms);
- if (copy_from_user(&cmd, ucmd, sizeof(cmd))) {
dev_err(hdev->dev, "Copy command from user space to kernel space failed\n");
return -EFAULT;
- }
- if (cmd.data_len > PAGE_SIZE) {
- if (cmd->data_len > PAGE_SIZE) { dev_err(hdev->dev, "[%s] data len bigger than 4k\n", __func__); return -EFAULT; }
- dev_info(hdev->dev, "[%s] opcode: 0x%x, subopcode: 0x%x, datalen: %d\n",
__func__, cmd.opcode, cmd.info_1.subopcode, cmd.data_len);
- if (cmd.addr && cmd.data_len) {
data_ptr = dma_alloc_coherent(hdev->dev, PAGE_SIZE, &data_dma, GFP_KERNEL);
if (!data_ptr)
return -ENOMEM;
dma_dir = (cmd.opcode & 1) ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
- if (hdev->state != SPRAID_LIVE) {
dev_err(hdev->dev, "[%s] err, host state:[%d] is not live\n",
__func__, hdev->state);
}return -EBUSY;
- if (dma_dir == DMA_TO_DEVICE) {
if (copy_from_user(data_ptr, (void __user *)(uintptr_t)cmd.addr, cmd.data_len)) {
dev_err(hdev->dev, "[%s] copy user data failed\n", __func__);
status = -EFAULT;
goto free_dma_mem;
}
- }
dev_info(hdev->dev, "[%s] opcode[0x%x] subopcode[0x%x] init, datalen[%d]\n",
__func__, cmd->opcode, cmd->info_1.subopcode, cmd->data_len);
memset(&ioq_cmd, 0, sizeof(ioq_cmd));
- ioq_cmd.common.opcode = cmd.opcode;
- ioq_cmd.common.flags = cmd.flags;
- ioq_cmd.common.hdid = cpu_to_le32(cmd.nsid);
- ioq_cmd.common.sense_len = cpu_to_le16(cmd.info_0.res_sense_len);
- ioq_cmd.common.cdb_len = cmd.info_0.cdb_len;
- ioq_cmd.common.rsvd2 = cmd.info_0.rsvd0;
- ioq_cmd.common.cdw3[0] = cpu_to_le32(cmd.cdw3);
- ioq_cmd.common.cdw3[1] = cpu_to_le32(cmd.cdw4);
- ioq_cmd.common.cdw3[2] = cpu_to_le32(cmd.cdw5);
- ioq_cmd.common.dptr.prp1 = cpu_to_le64(data_dma);
- ioq_cmd.common.cdw10[0] = cpu_to_le32(cmd.cdw10);
- ioq_cmd.common.cdw10[1] = cpu_to_le32(cmd.cdw11);
- ioq_cmd.common.cdw10[2] = cpu_to_le32(cmd.cdw12);
- ioq_cmd.common.cdw10[3] = cpu_to_le32(cmd.cdw13);
- ioq_cmd.common.cdw10[4] = cpu_to_le32(cmd.cdw14);
- ioq_cmd.common.cdw10[5] = cpu_to_le32(cmd.data_len);
- memcpy(ioq_cmd.common.cdb, &cmd.cdw16, cmd.info_0.cdb_len);
- ioq_cmd.common.cdw26[0] = cpu_to_le32(cmd.cdw26[0]);
- ioq_cmd.common.cdw26[1] = cpu_to_le32(cmd.cdw26[1]);
- ioq_cmd.common.cdw26[2] = cpu_to_le32(cmd.cdw26[2]);
- ioq_cmd.common.cdw26[3] = cpu_to_le32(cmd.cdw26[3]);
- if (cmd.timeout_ms)
timeout = msecs_to_jiffies(cmd.timeout_ms);
- timeout = timeout ? timeout : ADMIN_TIMEOUT;
- status = spraid_submit_ioq_sync_cmd(hdev, &ioq_cmd, &cmd.result0, &sense, timeout);
- if (status >= 0) {
if (put_user(cmd.result0, &ucmd->result0)) {
status = -EFAULT;
goto free_dma_mem;
}
if (put_user(cmd.result1, &ucmd->result1)) {
status = -EFAULT;
goto free_dma_mem;
}
if (dma_dir == DMA_FROM_DEVICE &&
copy_to_user((void __user *)(uintptr_t)cmd.addr, data_ptr, cmd.data_len)) {
status = -EFAULT;
goto free_dma_mem;
}
- }
- if (sense) {
if (copy_to_user((void *__user *)(uintptr_t)cmd.sense_addr,
sense, cmd.info_0.res_sense_len)) {
status = -EFAULT;
goto free_dma_mem;
}
- }
-free_dma_mem:
- if (data_ptr)
dma_free_coherent(hdev->dev, PAGE_SIZE, data_ptr, data_dma);
- return status;
-}
-static int spraid_reset_work_sync(struct spraid_dev *hdev);
-static int spraid_user_reset_cmd(struct spraid_dev *hdev) -{
- int ret;
- dev_info(hdev->dev, "[%s] start user reset cmd\n", __func__);
- ret = spraid_reset_work_sync(hdev);
- dev_info(hdev->dev, "[%s] stop user reset cmd[%d]\n", __func__, ret);
- return ret;
-}
-static int hdev_open(struct inode *inode, struct file *file) -{
- struct spraid_dev *hdev =
container_of(inode->i_cdev, struct spraid_dev, cdev);
- file->private_data = hdev;
- return 0;
-}
-static long hdev_ioctl(struct file *file, u32 cmd, unsigned long arg) -{
- struct spraid_dev *hdev = file->private_data;
- void __user *argp = (void __user *)arg;
- switch (cmd) {
- case SPRAID_IOCTL_ADMIN_CMD:
return spraid_user_admin_cmd(hdev, argp);
- case SPRAID_IOCTL_IOQ_CMD:
return spraid_user_ioq_cmd(hdev, argp);
- case SPRAID_IOCTL_RESET_CMD:
return spraid_user_reset_cmd(hdev);
- default:
return -ENOTTY;
- }
-}
-static const struct file_operations spraid_dev_fops = {
- .owner = THIS_MODULE,
- .open = hdev_open,
- .unlocked_ioctl = hdev_ioctl,
- .compat_ioctl = hdev_ioctl,
-};
-static int spraid_create_cdev(struct spraid_dev *hdev) -{
- int ret;
- device_initialize(&hdev->ctrl_device);
- hdev->ctrl_device.devt = MKDEV(MAJOR(spraid_chr_devt), hdev->instance);
- hdev->ctrl_device.class = spraid_class;
- hdev->ctrl_device.parent = hdev->dev;
- dev_set_drvdata(&hdev->ctrl_device, hdev);
- ret = dev_set_name(&hdev->ctrl_device, "spraid%d", hdev->instance);
- if (ret)
return ret;
- cdev_init(&hdev->cdev, &spraid_dev_fops);
- hdev->cdev.owner = THIS_MODULE;
- ret = cdev_device_add(&hdev->cdev, &hdev->ctrl_device);
- if (ret) {
dev_err(hdev->dev, "Add cdev failed, ret: %d", ret);
put_device(&hdev->ctrl_device);
kfree_const(hdev->ctrl_device.kobj.name);
return ret;
- }
- return 0;
-}
-static inline void spraid_remove_cdev(struct spraid_dev *hdev) -{
- cdev_device_del(&hdev->cdev, &hdev->ctrl_device);
-}
-static const struct blk_mq_ops spraid_admin_mq_ops = {
- .queue_rq = spraid_queue_admin_rq,
- .complete = spraid_complete_admin_rq,
- .init_hctx = spraid_admin_init_hctx,
- .init_request = spraid_admin_init_request,
- .timeout = spraid_admin_timeout,
-};
-static void spraid_remove_admin_tagset(struct spraid_dev *hdev) -{
- if (hdev->admin_q && !blk_queue_dying(hdev->admin_q)) {
blk_mq_unquiesce_queue(hdev->admin_q);
blk_cleanup_queue(hdev->admin_q);
blk_mq_free_tag_set(&hdev->admin_tagset);
- ioq_cmd.common.opcode = cmd->opcode;
- ioq_cmd.common.flags = cmd->flags;
- ioq_cmd.common.hdid = cpu_to_le32(cmd->nsid);
- ioq_cmd.common.sense_len = cpu_to_le16(cmd->info_0.res_sense_len);
- ioq_cmd.common.cdb_len = cmd->info_0.cdb_len;
- ioq_cmd.common.rsvd2 = cmd->info_0.rsvd0;
- ioq_cmd.common.cdw3[0] = cpu_to_le32(cmd->cdw3);
- ioq_cmd.common.cdw3[1] = cpu_to_le32(cmd->cdw4);
- ioq_cmd.common.cdw3[2] = cpu_to_le32(cmd->cdw5);
- ioq_cmd.common.cdw10[0] = cpu_to_le32(cmd->cdw10);
- ioq_cmd.common.cdw10[1] = cpu_to_le32(cmd->cdw11);
- ioq_cmd.common.cdw10[2] = cpu_to_le32(cmd->cdw12);
- ioq_cmd.common.cdw10[3] = cpu_to_le32(cmd->cdw13);
- ioq_cmd.common.cdw10[4] = cpu_to_le32(cmd->cdw14);
- ioq_cmd.common.cdw10[5] = cpu_to_le32(cmd->data_len);
- memcpy(ioq_cmd.common.cdb, &cmd->cdw16, cmd->info_0.cdb_len);
- ioq_cmd.common.cdw26[0] = cpu_to_le32(cmd->cdw26[0]);
- ioq_cmd.common.cdw26[1] = cpu_to_le32(cmd->cdw26[1]);
- ioq_cmd.common.cdw26[2] = cpu_to_le32(cmd->cdw26[2]);
- ioq_cmd.common.cdw26[3] = cpu_to_le32(cmd->cdw26[3]);
- status = spraid_bsg_map_data(hdev, job, (struct spraid_admin_command *)&ioq_cmd);
- if (status) {
dev_err(hdev->dev, "[%s] err, map data failed\n", __func__);
}return status;
-}
-static int spraid_alloc_admin_tags(struct spraid_dev *hdev) -{
- if (!hdev->admin_q) {
hdev->admin_tagset.ops = &spraid_admin_mq_ops;
hdev->admin_tagset.nr_hw_queues = 1;
- status = spraid_submit_ioq_sync_cmd(hdev, &ioq_cmd, job->reply, &job->reply_len, timeout);
hdev->admin_tagset.queue_depth = SPRAID_AQ_MQ_TAG_DEPTH;
hdev->admin_tagset.timeout = ADMIN_TIMEOUT;
hdev->admin_tagset.numa_node = hdev->numa_node;
hdev->admin_tagset.cmd_size =
spraid_cmd_size(hdev, true, false);
hdev->admin_tagset.flags = BLK_MQ_F_NO_SCHED;
hdev->admin_tagset.driver_data = hdev;
- dev_info(hdev->dev, "[%s] opcode[0x%x] subopcode[0x%x], status[0x%x], reply_len[%d]\n",
__func__, cmd->opcode, cmd->info_1.subopcode, status, job->reply_len);
if (blk_mq_alloc_tag_set(&hdev->admin_tagset)) {
dev_err(hdev->dev, "Allocate admin tagset failed\n");
return -ENOMEM;
}
- spraid_bsg_unmap_data(hdev, job);
hdev->admin_q = blk_mq_init_queue(&hdev->admin_tagset);
if (IS_ERR(hdev->admin_q)) {
dev_err(hdev->dev, "Initialize admin request queue failed\n");
blk_mq_free_tag_set(&hdev->admin_tagset);
return -ENOMEM;
}
if (!blk_get_queue(hdev->admin_q)) {
dev_err(hdev->dev, "Get admin request queue failed\n");
spraid_remove_admin_tagset(hdev);
hdev->admin_q = NULL;
return -ENODEV;
}
- } else {
blk_mq_unquiesce_queue(hdev->admin_q);
- }
- return 0;
- return status;
}
static bool spraid_check_scmd_completed(struct scsi_cmnd *scmd) @@ -2891,7 +2688,7 @@ static bool spraid_check_scmd_completed(struct scsi_cmnd *scmd) spraid_get_tag_from_scmd(scmd, &hwq, &cid); spraidq = &hdev->queues[hwq]; if (READ_ONCE(iod->state) == SPRAID_CMD_COMPLETE || spraid_poll_cq(spraidq, cid)) {
dev_warn(hdev->dev, "cid[%d], qid[%d] has been completed\n",
return true; }dev_warn(hdev->dev, "cid[%d] qid[%d] has been completed\n", cid, spraidq->qid);
@@ -2927,8 +2724,7 @@ static int spraid_send_abort_cmd(struct spraid_dev *hdev, u32 hdid, u16 qid, u16 admin_cmd.abort.sqid = cpu_to_le16(qid); admin_cmd.abort.cid = cpu_to_le16(cid);
- return spraid_submit_admin_sync_cmd(hdev->admin_q, &admin_cmd, NULL,
NULL, 0, 0, 0, 0);
- return spraid_submit_admin_sync_cmd(hdev, &admin_cmd, NULL, NULL, 0);
}
/* send reset command by admin quueue temporary */ @@ -2941,8 +2737,7 @@ static int spraid_send_reset_cmd(struct spraid_dev *hdev, int type, u32 hdid) admin_cmd.reset.hdid = cpu_to_le32(hdid); admin_cmd.reset.type = type;
- return spraid_submit_admin_sync_cmd(hdev->admin_q, &admin_cmd, NULL,
NULL, 0, 0, 0, 0);
- return spraid_submit_admin_sync_cmd(hdev, &admin_cmd, NULL, NULL, 0);
}
static bool spraid_change_host_state(struct spraid_dev *hdev, enum spraid_state newstate) @@ -3022,7 +2817,7 @@ static void spraid_back_fault_cqe(struct spraid_queue *ioq, struct spraid_comple scsi_dma_unmap(scmd); spraid_free_iod_res(hdev, iod); scmd->scsi_done(scmd);
- dev_warn(hdev->dev, "Back fault CQE, cid[%d], qid[%d]\n",
- dev_warn(hdev->dev, "Back fault CQE, cid[%d] qid[%d]\n", cqe->cmd_id, ioq->qid);
}
@@ -3032,6 +2827,8 @@ static void spraid_back_all_io(struct spraid_dev *hdev) struct spraid_queue *ioq; struct spraid_completion cqe = { 0 };
- scsi_block_requests(hdev->shost);
- for (i = 1; i <= hdev->shost->nr_hw_queues; i++) { ioq = &hdev->queues[i]; for (j = 0; j < hdev->shost->can_queue; j++) {
@@ -3039,6 +2836,8 @@ static void spraid_back_all_io(struct spraid_dev *hdev) spraid_back_fault_cqe(ioq, &cqe); } }
- scsi_unblock_requests(hdev->shost);
}
static void spraid_dev_disable(struct spraid_dev *hdev, bool shutdown) @@ -3106,17 +2905,13 @@ static void spraid_reset_work(struct work_struct *work) if (ret) goto pci_disable;
ret = spraid_alloc_admin_tags(hdev);
if (ret)
goto pci_disable;
ret = spraid_setup_io_queues(hdev); if (ret || hdev->online_queues <= hdev->shost->nr_hw_queues) goto pci_disable;
spraid_change_host_state(hdev, SPRAID_LIVE);
spraid_send_aen(hdev);
spraid_send_all_aen(hdev);
return;
@@ -3174,8 +2969,8 @@ static int spraid_abort_handler(struct scsi_cmnd *scmd)
scsi_print_command(scmd);
- if (!spraid_wait_abnl_cmd_done(iod) || spraid_check_scmd_completed(scmd) ||
hdev->state != SPRAID_LIVE)
if (hdev->state != SPRAID_LIVE || !spraid_wait_abnl_cmd_done(iod) ||
spraid_check_scmd_completed(scmd))
return SUCCESS;
hostdata = scmd->device->hostdata;
@@ -3183,7 +2978,7 @@ static int spraid_abort_handler(struct scsi_cmnd *scmd)
dev_warn(hdev->dev, "cid[%d] qid[%d] timeout, aborting\n", cid, hwq); ret = spraid_send_abort_cmd(hdev, hostdata->hdid, hwq, cid);
- if (ret != ADMIN_ERR_TIMEOUT) {
- if (ret != -ETIME) { ret = spraid_wait_abnl_cmd_done(iod); if (ret) { dev_warn(hdev->dev, "cid[%d] qid[%d] abort failed, not found\n", cid, hwq);
@@ -3206,8 +3001,8 @@ static int spraid_tgt_reset_handler(struct scsi_cmnd *scmd)
scsi_print_command(scmd);
- if (!spraid_wait_abnl_cmd_done(iod) || spraid_check_scmd_completed(scmd) ||
hdev->state != SPRAID_LIVE)
if (hdev->state != SPRAID_LIVE || !spraid_wait_abnl_cmd_done(iod) ||
spraid_check_scmd_completed(scmd))
return SUCCESS;
hostdata = scmd->device->hostdata;
@@ -3241,8 +3036,8 @@ static int spraid_bus_reset_handler(struct scsi_cmnd *scmd)
scsi_print_command(scmd);
- if (!spraid_wait_abnl_cmd_done(iod) || spraid_check_scmd_completed(scmd) ||
hdev->state != SPRAID_LIVE)
if (hdev->state != SPRAID_LIVE || !spraid_wait_abnl_cmd_done(iod) ||
spraid_check_scmd_completed(scmd))
return SUCCESS;
hostdata = scmd->device->hostdata;
@@ -3272,7 +3067,7 @@ static int spraid_shost_reset_handler(struct scsi_cmnd *scmd) struct spraid_dev *hdev = shost_priv(scmd->device->host);
scsi_print_command(scmd);
- if (spraid_check_scmd_completed(scmd) || hdev->state != SPRAID_LIVE)
if (hdev->state != SPRAID_LIVE || spraid_check_scmd_completed(scmd)) return SUCCESS;
spraid_get_tag_from_scmd(scmd, &hwq, &cid);
@@ -3288,6 +3083,62 @@ static int spraid_shost_reset_handler(struct scsi_cmnd *scmd) return SUCCESS; }
+static pci_ers_result_t spraid_pci_error_detected(struct pci_dev *pdev,
pci_channel_state_t state)
+{
- struct spraid_dev *hdev = pci_get_drvdata(pdev);
- dev_info(hdev->dev, "enter pci error detect, state:%d\n", state);
- switch (state) {
- case pci_channel_io_normal:
dev_warn(hdev->dev, "channel is normal, do nothing\n");
return PCI_ERS_RESULT_CAN_RECOVER;
- case pci_channel_io_frozen:
dev_warn(hdev->dev, "channel io frozen, need reset controller\n");
scsi_block_requests(hdev->shost);
spraid_change_host_state(hdev, SPRAID_RESETTING);
return PCI_ERS_RESULT_NEED_RESET;
- case pci_channel_io_perm_failure:
dev_warn(hdev->dev, "channel io failure, request disconnect\n");
return PCI_ERS_RESULT_DISCONNECT;
- }
- return PCI_ERS_RESULT_NEED_RESET;
+}
+static pci_ers_result_t spraid_pci_slot_reset(struct pci_dev *pdev) +{
- struct spraid_dev *hdev = pci_get_drvdata(pdev);
- dev_info(hdev->dev, "restart after slot reset\n");
- pci_restore_state(pdev);
- if (!queue_work(spraid_wq, &hdev->reset_work)) {
dev_err(hdev->dev, "[%s] err, the device is resetting state\n", __func__);
return PCI_ERS_RESULT_NONE;
- }
- flush_work(&hdev->reset_work);
- scsi_unblock_requests(hdev->shost);
- return PCI_ERS_RESULT_RECOVERED;
+}
+static void spraid_reset_done(struct pci_dev *pdev) +{
- struct spraid_dev *hdev = pci_get_drvdata(pdev);
- dev_info(hdev->dev, "enter spraid reset done\n");
+}
static ssize_t csts_pp_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -3347,7 +3198,7 @@ static ssize_t fw_version_show(struct device *cdev, struct device_attribute *att struct Scsi_Host *shost = class_to_shost(cdev); struct spraid_dev *hdev = shost_priv(shost);
- return snprintf(buf, sizeof(hdev->ctrl_info->fr), "%s\n", hdev->ctrl_info->fr);
- return snprintf(buf, PAGE_SIZE, "%s\n", hdev->ctrl_info->fr);
}
static DEVICE_ATTR_RO(csts_pp); @@ -3365,6 +3216,185 @@ static struct device_attribute *spraid_host_attrs[] = { NULL, };
+static int spraid_get_vd_info(struct spraid_dev *hdev, struct spraid_vd_info *vd_info, u16 vid) +{
- struct spraid_admin_command admin_cmd;
- u8 *data_ptr = NULL;
- dma_addr_t data_dma = 0;
- int ret;
- data_ptr = dma_alloc_coherent(hdev->dev, PAGE_SIZE, &data_dma, GFP_KERNEL);
- if (!data_ptr)
return -ENOMEM;
- memset(&admin_cmd, 0, sizeof(admin_cmd));
- admin_cmd.usr_cmd.opcode = USR_CMD_READ;
- admin_cmd.usr_cmd.info_0.subopcode = cpu_to_le16(USR_CMD_VDINFO);
- admin_cmd.usr_cmd.info_1.data_len = cpu_to_le16(USR_CMD_RDLEN);
- admin_cmd.usr_cmd.info_1.param_len = cpu_to_le16(VDINFO_PARAM_LEN);
- admin_cmd.usr_cmd.cdw10 = cpu_to_le32(vid);
- admin_cmd.common.dptr.prp1 = cpu_to_le64(data_dma);
- ret = spraid_submit_admin_sync_cmd(hdev, &admin_cmd, NULL, NULL, 0);
- if (!ret)
memcpy(vd_info, data_ptr, sizeof(struct spraid_vd_info));
- dma_free_coherent(hdev->dev, PAGE_SIZE, data_ptr, data_dma);
- return ret;
+}
+static int spraid_get_bgtask(struct spraid_dev *hdev, struct spraid_bgtask *bgtask) +{
- struct spraid_admin_command admin_cmd;
- u8 *data_ptr = NULL;
- dma_addr_t data_dma = 0;
- int ret;
- data_ptr = dma_alloc_coherent(hdev->dev, PAGE_SIZE, &data_dma, GFP_KERNEL);
- if (!data_ptr)
return -ENOMEM;
- memset(&admin_cmd, 0, sizeof(admin_cmd));
- admin_cmd.usr_cmd.opcode = USR_CMD_READ;
- admin_cmd.usr_cmd.info_0.subopcode = cpu_to_le16(USR_CMD_BGTASK);
- admin_cmd.usr_cmd.info_1.data_len = cpu_to_le16(USR_CMD_RDLEN);
- admin_cmd.common.dptr.prp1 = cpu_to_le64(data_dma);
- ret = spraid_submit_admin_sync_cmd(hdev, &admin_cmd, NULL, NULL, 0);
- if (!ret)
memcpy(bgtask, data_ptr, sizeof(struct spraid_bgtask));
- dma_free_coherent(hdev->dev, PAGE_SIZE, data_ptr, data_dma);
- return ret;
+}
+static ssize_t raid_level_show(struct device *dev, struct device_attribute *attr, char *buf) +{
- struct scsi_device *sdev;
- struct spraid_dev *hdev;
- struct spraid_vd_info *vd_info;
- struct spraid_sdev_hostdata *hostdata;
- int ret;
- sdev = to_scsi_device(dev);
- hdev = shost_priv(sdev->host);
- hostdata = sdev->hostdata;
- vd_info = kmalloc(sizeof(*vd_info), GFP_KERNEL);
- if (!vd_info || !SPRAID_DEV_INFO_ATTR_VD(hostdata->attr))
return snprintf(buf, PAGE_SIZE, "NA\n");
- ret = spraid_get_vd_info(hdev, vd_info, sdev->id);
- if (ret)
vd_info->rg_level = ARRAY_SIZE(raid_levels) - 1;
- ret = (vd_info->rg_level < ARRAY_SIZE(raid_levels)) ?
vd_info->rg_level : (ARRAY_SIZE(raid_levels) - 1);
- kfree(vd_info);
- return snprintf(buf, PAGE_SIZE, "RAID-%s\n", raid_levels[ret]);
+}
+static ssize_t raid_state_show(struct device *dev, struct device_attribute *attr, char *buf) +{
- struct scsi_device *sdev;
- struct spraid_dev *hdev;
- struct spraid_vd_info *vd_info;
- struct spraid_sdev_hostdata *hostdata;
- int ret;
- sdev = to_scsi_device(dev);
- hdev = shost_priv(sdev->host);
- hostdata = sdev->hostdata;
- vd_info = kmalloc(sizeof(*vd_info), GFP_KERNEL);
- if (!vd_info || !SPRAID_DEV_INFO_ATTR_VD(hostdata->attr))
return snprintf(buf, PAGE_SIZE, "NA\n");
- ret = spraid_get_vd_info(hdev, vd_info, sdev->id);
- if (ret) {
vd_info->vd_status = 0;
vd_info->rg_id = 0xff;
- }
- ret = (vd_info->vd_status < ARRAY_SIZE(raid_states)) ? vd_info->vd_status : 0;
- kfree(vd_info);
- return snprintf(buf, PAGE_SIZE, "%s\n", raid_states[ret]);
+}
+static ssize_t raid_resync_show(struct device *dev, struct device_attribute *attr, char *buf) +{
- struct scsi_device *sdev;
- struct spraid_dev *hdev;
- struct spraid_vd_info *vd_info;
- struct spraid_bgtask *bgtask;
- struct spraid_sdev_hostdata *hostdata;
- u8 rg_id, i, progress = 0;
- int ret;
- sdev = to_scsi_device(dev);
- hdev = shost_priv(sdev->host);
- hostdata = sdev->hostdata;
- vd_info = kmalloc(sizeof(*vd_info), GFP_KERNEL);
- if (!vd_info || !SPRAID_DEV_INFO_ATTR_VD(hostdata->attr))
return snprintf(buf, PAGE_SIZE, "NA\n");
- ret = spraid_get_vd_info(hdev, vd_info, sdev->id);
- if (ret)
goto out;
- rg_id = vd_info->rg_id;
- bgtask = (struct spraid_bgtask *)vd_info;
- ret = spraid_get_bgtask(hdev, bgtask);
- if (ret)
goto out;
- for (i = 0; i < bgtask->task_num; i++) {
if ((bgtask->bgtask[i].type == BGTASK_TYPE_REBUILD) &&
(le16_to_cpu(bgtask->bgtask[i].vd_id) == rg_id))
progress = bgtask->bgtask[i].progress;
- }
+out:
- kfree(vd_info);
- return snprintf(buf, PAGE_SIZE, "%d\n", progress);
+}
+static DEVICE_ATTR_RO(raid_level); +static DEVICE_ATTR_RO(raid_state); +static DEVICE_ATTR_RO(raid_resync);
+static struct device_attribute *spraid_dev_attrs[] = {
- &dev_attr_raid_level,
- &dev_attr_raid_state,
- &dev_attr_raid_resync,
- NULL,
+};
+static struct pci_error_handlers spraid_err_handler = {
- .error_detected = spraid_pci_error_detected,
- .slot_reset = spraid_pci_slot_reset,
- .reset_done = spraid_reset_done,
+};
+static int spraid_sysfs_host_reset(struct Scsi_Host *shost, int reset_type) +{
- int ret;
- struct spraid_dev *hdev = shost_priv(shost);
- dev_info(hdev->dev, "[%s] start sysfs host reset cmd\n", __func__);
- ret = spraid_reset_work_sync(hdev);
- dev_info(hdev->dev, "[%s] stop sysfs host reset cmd[%d]\n", __func__, ret);
- return ret;
+}
static struct scsi_host_template spraid_driver_template = { .module = THIS_MODULE, .name = "Ramaxel Logic spraid driver", @@ -3379,9 +3409,11 @@ static struct scsi_host_template spraid_driver_template = { .eh_bus_reset_handler = spraid_bus_reset_handler, .eh_host_reset_handler = spraid_shost_reset_handler, .change_queue_depth = scsi_change_queue_depth,
- .host_tagset = 1,
- .host_tagset = 0, .this_id = -1, .shost_attrs = spraid_host_attrs,
- .sdev_attrs = spraid_dev_attrs,
- .host_reset = spraid_sysfs_host_reset,
};
static void spraid_shutdown(struct pci_dev *pdev) @@ -3392,11 +3424,53 @@ static void spraid_shutdown(struct pci_dev *pdev) spraid_disable_admin_queue(hdev, true); }
+/* bsg dispatch user command */ +static int spraid_bsg_host_dispatch(struct bsg_job *job) +{
- struct Scsi_Host *shost = dev_to_shost(job->dev);
- struct spraid_dev *hdev = shost_priv(shost);
- struct request *rq = blk_mq_rq_from_pdu(job);
- struct spraid_bsg_request *bsg_req = job->request;
- int ret = 0;
- dev_log_dbg(hdev->dev, "[%s] msgcode[%d], msglen[%d], timeout[%d], req_nsge[%d], req_len[%d]\n",
__func__, bsg_req->msgcode, job->request_len, rq->timeout,
job->request_payload.sg_cnt, job->request_payload.payload_len);
- job->reply_len = 0;
- switch (bsg_req->msgcode) {
- case SPRAID_BSG_ADM:
ret = spraid_user_admin_cmd(hdev, job);
break;
- case SPRAID_BSG_IOQ:
ret = spraid_user_ioq_cmd(hdev, job);
break;
- default:
dev_info(hdev->dev, "[%s] unsupport msgcode[%d]\n", __func__, bsg_req->msgcode);
break;
- }
- if (ret > 0)
ret = ret | (ret << 8);
- bsg_job_done(job, ret, 0);
- return 0;
+}
+static inline void spraid_remove_bsg(struct spraid_dev *hdev) +{
- if (hdev->bsg_queue) {
bsg_unregister_queue(hdev->bsg_queue);
blk_cleanup_queue(hdev->bsg_queue);
- }
+} static int spraid_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct spraid_dev *hdev; struct Scsi_Host *shost; int node, ret;
char bsg_name[15];
shost = scsi_host_alloc(&spraid_driver_template, sizeof(*hdev)); if (!shost) {
@@ -3421,10 +3495,10 @@ static int spraid_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto put_dev;
init_rwsem(&hdev->devices_rwsem);
- INIT_WORK(&hdev->aen_work, spraid_async_event_work); INIT_WORK(&hdev->scan_work, spraid_scan_work); INIT_WORK(&hdev->timesyn_work, spraid_timesyn_work); INIT_WORK(&hdev->reset_work, spraid_reset_work);
INIT_WORK(&hdev->fw_act_work, spraid_fw_act_work); spin_lock_init(&hdev->state_lock);
ret = spraid_alloc_resources(hdev);
@@ -3439,17 +3513,13 @@ static int spraid_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (ret) goto pci_disable;
- ret = spraid_alloc_admin_tags(hdev);
- if (ret)
goto disable_admin_q;
- ret = spraid_init_ctrl_info(hdev); if (ret)
goto free_admin_tagset;
goto disable_admin_q;
ret = spraid_alloc_iod_ext_mem_pool(hdev); if (ret)
goto free_admin_tagset;
goto disable_admin_q;
ret = spraid_setup_io_queues(hdev); if (ret)
@@ -3464,9 +3534,15 @@ static int spraid_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto remove_io_queues; }
- ret = spraid_create_cdev(hdev);
- if (ret)
snprintf(bsg_name, sizeof(bsg_name), "spraid%d", shost->host_no);
hdev->bsg_queue = bsg_setup_queue(&shost->shost_gendev, bsg_name,
spraid_bsg_host_dispatch, NULL,
spraid_cmd_size(hdev, true, false));
if (IS_ERR(hdev->bsg_queue)) {
dev_err(hdev->dev, "err, setup bsg failed\n");
hdev->bsg_queue = NULL;
goto remove_io_queues;
}
if (hdev->online_queues == SPRAID_ADMIN_QUEUE_NUM) { dev_warn(hdev->dev, "warn only admin queue can be used\n");
@@ -3475,11 +3551,11 @@ static int spraid_probe(struct pci_dev *pdev, const struct pci_device_id *id)
hdev->state = SPRAID_LIVE;
- spraid_send_aen(hdev);
spraid_send_all_aen(hdev);
ret = spraid_dev_list_init(hdev); if (ret)
goto remove_cdev;
goto remove_bsg;
ret = spraid_configure_timestamp(hdev); if (ret)
@@ -3487,20 +3563,18 @@ static int spraid_probe(struct pci_dev *pdev, const struct pci_device_id *id)
ret = spraid_alloc_ioq_ptcmds(hdev); if (ret)
goto remove_cdev;
goto remove_bsg;
scsi_scan_host(hdev->shost);
return 0;
-remove_cdev:
- spraid_remove_cdev(hdev);
+remove_bsg:
- spraid_remove_bsg(hdev);
remove_io_queues: spraid_remove_io_queues(hdev); free_iod_mempool: spraid_free_iod_ext_mem_pool(hdev); -free_admin_tagset:
- spraid_remove_admin_tagset(hdev);
disable_admin_q: spraid_disable_admin_queue(hdev, false); pci_disable: @@ -3524,22 +3598,17 @@ static void spraid_remove(struct pci_dev *pdev) dev_info(hdev->dev, "enter spraid remove\n");
spraid_change_host_state(hdev, SPRAID_DELETING);
- flush_work(&hdev->reset_work);
- if (!pci_device_is_present(pdev)) {
scsi_block_requests(shost);
- if (!pci_device_is_present(pdev)) spraid_back_all_io(hdev);
scsi_unblock_requests(shost);
}
flush_work(&hdev->reset_work);
- spraid_remove_bsg(hdev); scsi_remove_host(shost);
- kfree(hdev->ioq_ptcmds);
- spraid_free_ioq_ptcmds(hdev); kfree(hdev->devices);
- spraid_remove_cdev(hdev); spraid_remove_io_queues(hdev); spraid_free_iod_ext_mem_pool(hdev);
- spraid_remove_admin_tagset(hdev); spraid_disable_admin_queue(hdev, false); spraid_pci_disable(hdev); spraid_free_resources(hdev);
@@ -3551,7 +3620,7 @@ static void spraid_remove(struct pci_dev *pdev) }
static const struct pci_device_id spraid_id_table[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_RAMAXEL_LOGIC, SPRAID_SERVER_DEVICE_HAB_DID) },
- { PCI_DEVICE(PCI_VENDOR_ID_RAMAXEL_LOGIC, SPRAID_SERVER_DEVICE_HBA_DID) }, { PCI_DEVICE(PCI_VENDOR_ID_RAMAXEL_LOGIC, SPRAID_SERVER_DEVICE_RAID_DID) }, { 0, }
}; @@ -3563,6 +3632,7 @@ static struct pci_driver spraid_driver = { .probe = spraid_probe, .remove = spraid_remove, .shutdown = spraid_shutdown,
- .err_handler = &spraid_err_handler,
};
static int __init spraid_init(void) @@ -3573,14 +3643,10 @@ static int __init spraid_init(void) if (!spraid_wq) return -ENOMEM;
- ret = alloc_chrdev_region(&spraid_chr_devt, 0, SPRAID_MINORS, "spraid");
- if (ret < 0)
goto destroy_wq;
- spraid_class = class_create(THIS_MODULE, "spraid"); if (IS_ERR(spraid_class)) { ret = PTR_ERR(spraid_class);
goto unregister_chrdev;
goto destroy_wq;
}
ret = pci_register_driver(&spraid_driver);
@@ -3591,8 +3657,6 @@ static int __init spraid_init(void)
destroy_class: class_destroy(spraid_class); -unregister_chrdev:
- unregister_chrdev_region(spraid_chr_devt, SPRAID_MINORS);
destroy_wq: destroy_workqueue(spraid_wq);
@@ -3603,12 +3667,11 @@ static void __exit spraid_exit(void) { pci_unregister_driver(&spraid_driver); class_destroy(spraid_class);
- unregister_chrdev_region(spraid_chr_devt, SPRAID_MINORS); destroy_workqueue(spraid_wq); ida_destroy(&spraid_instance_ida);
}
-MODULE_AUTHOR("Ramaxel Memory Technology"); +MODULE_AUTHOR("songyl@ramaxel.com"); MODULE_DESCRIPTION("Ramaxel Memory Technology SPraid Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(SPRAID_DRV_VERSION);