From bbae0ca11850da2793282896206974656859a73e Mon Sep 17 00:00:00 2001 From: Steven Song Date: Thu, 2 Mar 2023 09:42:42 +0800 Subject: [PATCH 1/2] SCSI: SSSRAID: Introduce map_queue in sssraid module 3snic inclusion category: feature feature: sssraid bugzilla: https://gitee.com/openeuler/kernel/issues/I6IWOA CVE: NA ------------------------------------------ Introduce map_queue in sssraid module for performance enhancement. Signed-off-by: Steven Song Reviewed-by: liangry Reviewed-by: Jiang Yu --- drivers/scsi/sssraid/sssraid_os.c | 78 ++++++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/sssraid/sssraid_os.c b/drivers/scsi/sssraid/sssraid_os.c index 6cf0b085bb6b0..ac49a439b68e7 100644 --- a/drivers/scsi/sssraid/sssraid_os.c +++ b/drivers/scsi/sssraid/sssraid_os.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -1462,6 +1463,17 @@ void sssraid_back_all_io(struct sssraid_ioc *sdioc) } } +static int sssraid_get_first_sibling(unsigned int cpu) +{ + unsigned int ret; + + ret = cpumask_first(topology_sibling_cpumask(cpu)); + if (ret < nr_cpu_ids) + return ret; + + return cpu; +} + /* * static struct scsi_host_template sssraid_driver_template */ @@ -1536,6 +1548,69 @@ static int sssraid_sysfs_host_reset(struct Scsi_Host *shost, int reset_type) return ret; } +static int sssraid_map_queues(struct Scsi_Host *shost) +{ + struct sssraid_ioc *sdioc = shost_priv(shost); + struct pci_dev *pdev = sdioc->pdev; + struct msi_desc *entry = NULL; + struct irq_affinity_desc *affinity = NULL; + struct blk_mq_tag_set *tag_set = &shost->tag_set; + struct blk_mq_queue_map *queue_map = &tag_set->map[HCTX_TYPE_DEFAULT]; + const struct cpumask *node_mask = NULL; + unsigned int queue_offset = queue_map->queue_offset; + unsigned int *map = queue_map->mq_map; + unsigned int nr_queues = queue_map->nr_queues; + unsigned int node_id, node_id_last = 0xFFFFFFFF; + int cpu, first_sibling, cpu_index = 0; + u8 node_count = 0, i; + unsigned int node_id_array[100]; + + for_each_pci_msi_entry(entry, pdev) { + struct list_head *msi_list = &pdev->dev.msi_list; + + if (list_is_last(msi_list, &entry->list)) + goto get_next_numa_node; + + if (entry->irq) { + affinity = entry->affinity; + node_mask = &affinity->mask; + + cpu = cpumask_first(node_mask); + node_id = cpu_to_node(cpu); + if (node_id_last == node_id) + continue; + + for (i = 0; i < node_count; i++) { + if (node_id == node_id_array[i]) + goto get_next_numa_node; + } + node_id_array[node_count++] = node_id; + node_id_last = node_id; + } +get_next_numa_node: + continue; + } + + for (i = 0; i < node_count; i++) { + node_mask = cpumask_of_node(node_id_array[i]); + dbgprint(sdioc, "NUMA_node = %d\n", node_id_array[i]); + for_each_cpu(cpu, node_mask) { + if (cpu_index < nr_queues) { + map[cpu_index++] = queue_offset + (cpu % nr_queues); + } else { + first_sibling = sssraid_get_first_sibling(cpu); + if (first_sibling == cpu) + map[cpu_index++] = queue_offset + (cpu % nr_queues); + else + map[cpu_index++] = map[first_sibling]; + } + dbgprint(sdioc, "map[%d] = %d\n", cpu_index - 1, map[cpu_index - 1]); + } + } + + return 0; +} + /* queuecommand call back */ static int sssraid_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd) @@ -1989,6 +2064,7 @@ static struct scsi_host_template sssraid_driver_template = { .name = "3SNIC Logic sssraid driver", .proc_name = "sssraid", .queuecommand = sssraid_qcmd, + .map_queues = sssraid_map_queues, .slave_alloc = sssraid_slave_alloc, .slave_destroy = sssraid_slave_destroy, .slave_configure = sssraid_slave_configure, @@ -2330,7 +2406,7 @@ static void __exit sssraid_exit(void) pci_unregister_driver(&sssraid_pci_driver); } -MODULE_AUTHOR("liangry1@3snic.com"); +MODULE_AUTHOR("steven.song@3snic.com"); MODULE_DESCRIPTION("3SNIC Information Technology SSSRAID Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(SSSRAID_DRIVER_VERSION); -- Gitee From 07502d820b36057a7f471f243198651212f06624 Mon Sep 17 00:00:00 2001 From: Steven Song Date: Thu, 2 Mar 2023 09:49:31 +0800 Subject: [PATCH 2/2] SCSI: SSSRAID: Code quality reinforcement content 3snic inclusion category: feature feature: sssraid bugzilla: https://gitee.com/openeuler/kernel/issues/I6IWOA CVE: NA ------------------------------------------ Quality reinforcement content: 1. use bsg_remove_queue replace sssraid_remove_bsg to address insufficient resource release. 2. set pdev private data to NULL when probe process failed to prevent from accessing null pointers in next possible exit process. 3. modifications for code review recommendations. Signed-off-by: Steven Song Reviewed-by: liangry Reviewed-by: Jiang Yu --- drivers/scsi/sssraid/sssraid.h | 9 ++++- drivers/scsi/sssraid/sssraid_fw.c | 51 +++++++++++++++++------- drivers/scsi/sssraid/sssraid_os.c | 64 +++++++++++++++---------------- 3 files changed, 76 insertions(+), 48 deletions(-) diff --git a/drivers/scsi/sssraid/sssraid.h b/drivers/scsi/sssraid/sssraid.h index adcfdf6612738..f2a5979361187 100644 --- a/drivers/scsi/sssraid/sssraid.h +++ b/drivers/scsi/sssraid/sssraid.h @@ -12,7 +12,7 @@ #define SSSRAID_DRIVER_NAME "sssraid" #define SSSRAID_NAME_LENGTH 32 - +#define BSG_NAME_SIZE 15 /* * SSSRAID Vendor ID and Device IDs */ @@ -92,6 +92,13 @@ extern u32 admin_tmout; #define SSSRAID_DMA_MSK_BIT_MAX 64 +enum { + SCSI_6_BYTE_CDB_LEN = 6, + SCSI_10_BYTE_CDB_LEN = 10, + SCSI_12_BYTE_CDB_LEN = 12, + SCSI_16_BYTE_CDB_LEN = 16, +}; + enum { SSSRAID_SGL_FMT_DATA_DESC = 0x00, SSSRAID_SGL_FMT_SEG_DESC = 0x02, diff --git a/drivers/scsi/sssraid/sssraid_fw.c b/drivers/scsi/sssraid/sssraid_fw.c index 25129abb30858..6f553003e19f9 100644 --- a/drivers/scsi/sssraid/sssraid_fw.c +++ b/drivers/scsi/sssraid/sssraid_fw.c @@ -188,14 +188,18 @@ static int sssraid_alloc_resources(struct sssraid_ioc *sdioc) return -ENOMEM; retval = sssraid_create_dma_pools(sdioc); - if (retval) + if (retval) { + ioc_err(sdioc, "err: failure at create dma pool!\n"); goto free_ctrl_info; + } + /* not num_online_cpus */ nqueue = num_possible_cpus() + 1; sdioc->cqinfo = kcalloc_node(nqueue, sizeof(struct sssraid_cqueue), GFP_KERNEL, sdioc->numa_node); if (!sdioc->cqinfo) { retval = -ENOMEM; + ioc_err(sdioc, "err: failure at alloc memory for cqueue!"); goto destroy_dma_pools; } @@ -203,6 +207,7 @@ static int sssraid_alloc_resources(struct sssraid_ioc *sdioc) GFP_KERNEL, sdioc->numa_node); if (!sdioc->sqinfo) { retval = -ENOMEM; + ioc_err(sdioc, "err: failure at alloc memory for squeue!"); goto free_cqueues; } @@ -263,7 +268,7 @@ static int sssraid_setup_resources(struct sssraid_ioc *sdioc) */ retval = sssraid_remap_bar(sdioc, SSSRAID_REG_DBS + 4096); if (retval) { - retval = -ENODEV; + ioc_err(sdioc, "Failed to re-map bar, error %d\n", retval); goto out_failed; } @@ -282,7 +287,7 @@ static int sssraid_setup_resources(struct sssraid_ioc *sdioc) maskbit = SSSRAID_CAP_DMAMASK(sdioc->cap); if (maskbit < 32 || maskbit > SSSRAID_DMA_MSK_BIT_MAX) { - ioc_err(sdioc, "err: DMA MASK BIT invalid[%llu], set to default\n", maskbit); + ioc_notice(sdioc, "err: DMA MASK BIT invalid[%llu], set to default\n", maskbit); maskbit = SSSRAID_DMA_MSK_BIT_MAX; } @@ -352,13 +357,16 @@ static int sssraid_alloc_qpair(struct sssraid_ioc *sdioc, u16 qidx, u16 depth) cqinfo->cqes = dma_alloc_coherent(&sdioc->pdev->dev, CQ_SIZE(depth), &cqinfo->cq_dma_addr, GFP_KERNEL | __GFP_ZERO); - if (!cqinfo->cqes) + if (!cqinfo->cqes) { + ioc_err(sdioc, "failure at alloc dma space for cqueue.\n"); return -ENOMEM; + } sqinfo->sq_cmds = dma_alloc_coherent(&sdioc->pdev->dev, SQ_SIZE(qidx, depth), &sqinfo->sq_dma_addr, GFP_KERNEL); if (!sqinfo->sq_cmds) { retval = -ENOMEM; + ioc_err(sdioc, "failure at alloc dma space for squeue cmds.\n"); goto free_cqes; } @@ -367,6 +375,7 @@ static int sssraid_alloc_qpair(struct sssraid_ioc *sdioc, u16 qidx, u16 depth) &sqinfo->sense_dma_addr, GFP_KERNEL | __GFP_ZERO); if (!sqinfo->sense) { retval = -ENOMEM; + ioc_err(sdioc, "failure at alloc dma space for sense data.\n"); goto free_sq_cmds; } @@ -420,8 +429,10 @@ static int sssraid_setup_admin_qpair(struct sssraid_ioc *sdioc) ioc_info(sdioc, "Starting disable ctrl...\n"); retval = sssraid_disable_ctrl(sdioc); - if (retval) + if (retval) { + ioc_err(sdioc, "disable ctrl failed\n"); return retval; + } /* this func don't alloc admin queue */ @@ -435,6 +446,7 @@ static int sssraid_setup_admin_qpair(struct sssraid_ioc *sdioc) retval = sssraid_enable_ctrl(sdioc); if (retval) { + ioc_err(sdioc, "enable ctrl failed\n"); retval = -ENODEV; return retval; } @@ -633,7 +645,7 @@ static int sssraid_setup_isr(struct sssraid_ioc *sdioc, u8 setup_one) goto out_failed; } if (i != max_vectors) { - ioc_info(sdioc, + ioc_warn(sdioc, "Allocated vectors (%d) are less than requested (%d)\n", i, max_vectors); @@ -643,7 +655,8 @@ static int sssraid_setup_isr(struct sssraid_ioc *sdioc, u8 setup_one) sdioc->intr_info = kzalloc(sizeof(struct sssraid_intr_info) * max_vectors, GFP_KERNEL); if (!sdioc->intr_info) { - retval = -1; + retval = -ENOMEM; + ioc_err(sdioc, "err: failed to alloc memory for intr_info!\n"); pci_free_irq_vectors(sdioc->pdev); goto out_failed; } @@ -651,6 +664,7 @@ static int sssraid_setup_isr(struct sssraid_ioc *sdioc, u8 setup_one) for (i = 0; i < max_vectors; i++) { retval = sssraid_request_irq(sdioc, i); if (retval) { + ioc_err(sdioc, "err: request irq for pci device failed.\n"); sdioc->intr_info_count = i; /* =i is for offload interrupt loop counter */ goto out_failed; } @@ -1174,14 +1188,16 @@ static inline void sssraid_send_all_aen(struct sssraid_ioc *sdioc) sssraid_send_event_ack(sdioc, 0, 0, i + SSSRAID_AMDQ_BLK_MQ_DEPTH); } -static int sssraid_dev_list_init(struct sssraid_ioc *sdioc) +static int sssraid_disk_list_init(struct sssraid_ioc *sdioc) { u32 nd = le32_to_cpu(sdioc->ctrl_info->nd); sdioc->devices = kzalloc_node(nd * sizeof(struct sssraid_dev_info), GFP_KERNEL, sdioc->numa_node); - if (!sdioc->devices) + if (!sdioc->devices) { + ioc_err(sdioc, "err: failed to alloc memory for device info.\n"); return -ENOMEM; + } return 0; } @@ -1331,7 +1347,7 @@ int sssraid_init_ioc(struct sssraid_ioc *sdioc, u8 re_init) sssraid_send_all_aen(sdioc); if (!re_init) { - retval = sssraid_dev_list_init(sdioc); + retval = sssraid_disk_list_init(sdioc); if (retval) { ioc_err(sdioc, "Failed to init device list, error %d\n", retval); @@ -1358,6 +1374,7 @@ void sssraid_cleanup_resources(struct sssraid_ioc *sdioc) { struct pci_dev *pdev = sdioc->pdev; + pci_set_drvdata(pdev, NULL); sssraid_cleanup_isr(sdioc); if (sdioc->bar) { @@ -1372,6 +1389,12 @@ void sssraid_cleanup_resources(struct sssraid_ioc *sdioc) } } +static void sssraid_free_disk_list(struct sssraid_ioc *sdioc) +{ + kfree(sdioc->devices); + sdioc->devices = NULL; +} + static void sssraid_free_ioq_ptcmds(struct sssraid_ioc *sdioc) { kfree(sdioc->ioq_ptcmds); @@ -1382,7 +1405,7 @@ static void sssraid_free_ioq_ptcmds(struct sssraid_ioc *sdioc) static void sssraid_delete_io_queues(struct sssraid_ioc *sdioc) { - u16 queues = sdioc->init_done_queue_cnt - 1; + u16 queues = sdioc->init_done_queue_cnt - SSSRAID_ADM_QUEUE_NUM; u8 opcode = SSSRAID_ADM_DELETE_SQ; u16 i, pass; @@ -1391,7 +1414,7 @@ static void sssraid_delete_io_queues(struct sssraid_ioc *sdioc) return; } - if (sdioc->init_done_queue_cnt < 2) { + if (sdioc->init_done_queue_cnt <= SSSRAID_ADM_QUEUE_NUM) { ioc_err(sdioc, "Err: io queue has been delete\n"); return; } @@ -1669,8 +1692,10 @@ static void sssraid_free_resources(struct sssraid_ioc *sdioc) void sssraid_cleanup_ioc(struct sssraid_ioc *sdioc, u8 re_init) { - if (!re_init) + if (!re_init) { + sssraid_free_disk_list(sdioc); sssraid_free_ioq_ptcmds(sdioc); + } sssraid_delete_io_queues(sdioc); sssraid_disable_admin_queue(sdioc, !re_init); diff --git a/drivers/scsi/sssraid/sssraid_os.c b/drivers/scsi/sssraid/sssraid_os.c index ac49a439b68e7..45542dc0e0e1c 100644 --- a/drivers/scsi/sssraid/sssraid_os.c +++ b/drivers/scsi/sssraid/sssraid_os.c @@ -308,7 +308,7 @@ void sssraid_cleanup_fwevt_list(struct sssraid_ioc *sdioc) */ static int sssraid_npages_prp(struct sssraid_ioc *sdioc) { - u32 size = 1U << ((sdioc->ctrl_info->mdts) * 1U) << 12; + u32 size = (1U << ((sdioc->ctrl_info->mdts) * 1U)) << 12; u32 nprps = DIV_ROUND_UP(size + sdioc->page_size, sdioc->page_size); return DIV_ROUND_UP(PRP_ENTRY_SIZE * nprps, sdioc->page_size - PRP_ENTRY_SIZE); @@ -619,7 +619,7 @@ static int sssraid_setup_rw_cmd(struct sssraid_ioc *sdioc, } /* 6-byte READ(0x08) or WRITE(0x0A) cdb */ - if (scmd->cmd_len == 6) { + if (scmd->cmd_len == SCSI_6_BYTE_CDB_LEN) { datalength = (u32)(scmd->cmnd[4] == 0 ? IO_6_DEFAULT_TX_LEN : scmd->cmnd[4]); start_lba_lo = (u32)get_unaligned_be24(&scmd->cmnd[1]); @@ -628,7 +628,7 @@ static int sssraid_setup_rw_cmd(struct sssraid_ioc *sdioc, } /* 10-byte READ(0x28) or WRITE(0x2A) cdb */ - else if (scmd->cmd_len == 10) { + else if (scmd->cmd_len == SCSI_10_BYTE_CDB_LEN) { datalength = (u32)get_unaligned_be16(&scmd->cmnd[7]); start_lba_lo = get_unaligned_be32(&scmd->cmnd[2]); @@ -637,7 +637,7 @@ static int sssraid_setup_rw_cmd(struct sssraid_ioc *sdioc, } /* 12-byte READ(0xA8) or WRITE(0xAA) cdb */ - else if (scmd->cmd_len == 12) { + else if (scmd->cmd_len == SCSI_12_BYTE_CDB_LEN) { datalength = get_unaligned_be32(&scmd->cmnd[6]); start_lba_lo = get_unaligned_be32(&scmd->cmnd[2]); @@ -645,7 +645,7 @@ static int sssraid_setup_rw_cmd(struct sssraid_ioc *sdioc, control |= SSSRAID_RW_FUA; } /* 16-byte READ(0x88) or WRITE(0x8A) cdb */ - else if (scmd->cmd_len == 16) { + else if (scmd->cmd_len == SCSI_16_BYTE_CDB_LEN) { 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]); @@ -1068,6 +1068,7 @@ bool sssraid_change_host_state(struct sssraid_ioc *sdioc, enum sssraid_state new default: break; } + if (change) sdioc->state = newstate; spin_unlock_irqrestore(&sdioc->state_lock, flags); @@ -1387,14 +1388,6 @@ static int sssraid_bsg_host_dispatch(struct bsg_job *job) return 0; } -static inline void sssraid_remove_bsg(struct sssraid_ioc *sdioc) -{ - if (sdioc->bsg_queue) { - bsg_unregister_queue(sdioc->bsg_queue); - blk_cleanup_queue(sdioc->bsg_queue); - } -} - static void sssraid_back_fault_cqe(struct sssraid_squeue *sqinfo, struct sssraid_completion *cqe) { struct sssraid_ioc *sdioc = sqinfo->sdioc; @@ -2102,7 +2095,7 @@ sssraid_probe(struct pci_dev *pdev, const struct pci_device_id *id) struct sssraid_ioc *sdioc; struct Scsi_Host *shost; int node; - char bsg_name[15]; + char bsg_name[BSG_NAME_SIZE]; int retval = 0; node = dev_to_node(&pdev->dev); @@ -2114,14 +2107,15 @@ sssraid_probe(struct pci_dev *pdev, const struct pci_device_id *id) shost = scsi_host_alloc(&sssraid_driver_template, sizeof(*sdioc)); if (!shost) { retval = -ENODEV; - ioc_err(sdioc, "err: failed to allocate scsi host\n"); + dev_err(&pdev->dev, "err: failed to allocate scsi host\n"); goto shost_failed; } sdioc = shost_priv(shost); sdioc->numa_node = node; sdioc->instance = shost->host_no; /* for device instance */ - sprintf(sdioc->name, "%s%d", SSSRAID_DRIVER_NAME, sdioc->instance); + snprintf(sdioc->name, sizeof(sdioc->name), + "%s%d", SSSRAID_DRIVER_NAME, sdioc->instance); init_rwsem(&sdioc->devices_rwsem); spin_lock_init(&sdioc->state_lock); @@ -2131,7 +2125,6 @@ sssraid_probe(struct pci_dev *pdev, const struct pci_device_id *id) INIT_LIST_HEAD(&sdioc->fwevt_list); -// logging_level = 1; //garden test sdioc->logging_level = logging_level; /* according to log_debug_switch*/ snprintf(sdioc->fwevt_worker_name, sizeof(sdioc->fwevt_worker_name), @@ -2139,8 +2132,7 @@ sssraid_probe(struct pci_dev *pdev, const struct pci_device_id *id) sdioc->fwevt_worker_thread = alloc_ordered_workqueue( sdioc->fwevt_worker_name, WQ_MEM_RECLAIM); if (!sdioc->fwevt_worker_thread) { - ioc_err(sdioc, "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); + ioc_err(sdioc, "err: fail to alloc workqueue for fwevt_work!\n"); retval = -ENODEV; goto out_fwevtthread_failed; } @@ -2149,8 +2141,7 @@ sssraid_probe(struct pci_dev *pdev, const struct pci_device_id *id) sdioc->pdev = pdev; if (sssraid_init_ioc(sdioc, 0)) { - ioc_err(sdioc, "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); + ioc_err(sdioc, "err: failure at init sssraid_ioc!\n"); retval = -ENODEV; goto out_iocinit_failed; } @@ -2159,8 +2150,7 @@ sssraid_probe(struct pci_dev *pdev, const struct pci_device_id *id) retval = scsi_add_host(shost, &pdev->dev); if (retval) { - ioc_err(sdioc, "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); + ioc_err(sdioc, "err: add shost to system failed!\n"); goto addhost_failed; } @@ -2168,16 +2158,22 @@ sssraid_probe(struct pci_dev *pdev, const struct pci_device_id *id) sdioc->bsg_queue = bsg_setup_queue(&shost->shost_gendev, bsg_name, sssraid_bsg_host_dispatch, NULL, sssraid_cmd_size(sdioc)); if (IS_ERR(sdioc->bsg_queue)) { - ioc_err(sdioc, "err: setup bsg failed\n"); + ioc_err(sdioc, "err: setup bsg failed!\n"); sdioc->bsg_queue = NULL; goto bsg_setup_failed; } - sssraid_change_host_state(sdioc, SSSRAID_LIVE); + if (!sssraid_change_host_state(sdioc, SSSRAID_LIVE)) { + retval = -ENODEV; + ioc_err(sdioc, "err: change host state failed!\n"); + goto sssraid_state_change_failed; + } scsi_scan_host(shost); return retval; +sssraid_state_change_failed: + bsg_remove_queue(sdioc->bsg_queue); bsg_setup_failed: scsi_remove_host(shost); addhost_failed: @@ -2193,15 +2189,15 @@ sssraid_probe(struct pci_dev *pdev, const struct pci_device_id *id) static void sssraid_remove(struct pci_dev *pdev) { struct Scsi_Host *shost = pci_get_drvdata(pdev); - struct sssraid_ioc *sdioc; + struct sssraid_ioc *sdioc = NULL; - if (!shost) + if (!shost) { + dev_err(&pdev->dev, "driver probe process failed, remove not be allowed.\n"); return; - - ioc_info(sdioc, "sssraid remove entry\n"); - + } sdioc = shost_priv(shost); + ioc_info(sdioc, "sssraid remove entry\n"); sssraid_change_host_state(sdioc, SSSRAID_DELETING); if (!pci_device_is_present(pdev)) @@ -2210,7 +2206,7 @@ static void sssraid_remove(struct pci_dev *pdev) sssraid_cleanup_fwevt_list(sdioc); destroy_workqueue(sdioc->fwevt_worker_thread); - sssraid_remove_bsg(sdioc); + bsg_remove_queue(sdioc->bsg_queue); scsi_remove_host(shost); sssraid_cleanup_ioc(sdioc, 0); @@ -2399,11 +2395,11 @@ static int __init sssraid_init(void) static void __exit sssraid_exit(void) { + pci_unregister_driver(&sssraid_pci_driver); + class_destroy(sssraid_class); + pr_info("Unloading %s version %s\n", SSSRAID_DRIVER_NAME, SSSRAID_DRIVER_VERSION); - - class_destroy(sssraid_class); - pci_unregister_driver(&sssraid_pci_driver); } MODULE_AUTHOR("steven.song@3snic.com"); -- Gitee